anthropics / anthropics/anthropic-sdk-python
Bedrock stream decoder drops SSE event types; type-less chunks construct as RawMessageStartEvent(message=None)
- 主要語言
- Python
- 星號
- 3.9k
- 分支
- 853
- 平均合併
- 1 天 18 小時
- 30 天內合併 PR
- 11
描述
### Summary
The Bedrock stream decoder (`anthropic/lib/bedrock/_stream_decoder.py`) hardcodes `ServerSentEvent(event="completion")` for every chunk, discarding the real event type. Downstream, the `"completion"` branch in `_streaming.py::__stream__` never backfills `data["type"]` (unlike the direct-SSE branch). Chunks without a `type` field — notably Bedrock's `amazon-bedrock-invocationMetrics` trailer — then hit non-validating `construct_type` against the stream-event union, which falls back to the **first union member** and yields `RawMessageStartEvent(message=None)` — an object that violates the SDK's own type contract (`message` is typed as non-optional).
### Reproduction (anthropic 0.105.2, offline)
```python
from anthropic._models import construct_type
from anthropic.types.beta import BetaRawMessageStreamEvent
event = construct_type(
value={"amazon-bedrock-invocationMetrics": {"inputTokenCount": 1}},
type_=BetaRawMessageStreamEvent,
)
print(type(event).__name__, event.message)
# BetaRawMessageStartEvent None
```
Any consumer that trusts the type annotations (e.g. `event.message.usage`) crashes with `AttributeError: 'NoneType' object has no attribute 'usage'`. We hit this in production via pydantic-ai's streaming path on `AsyncAnthropicBedrock` — intermittent 500s whenever a stream contained the invocationMetrics trailer.
### Expected
Either:
- the Bedrock decoder preserves/backfills the event type from the chunk payload's `type` field (the payloads do carry one for real events), and drops/ignores non-Messages chunks like `amazon-bedrock-invocationMetrics`, or
- stream-event construction validates and raises a clear error instead of silently producing a contract-violating first-union-member object.
### Notes
- Related but distinct from #1477 (decoder raises `ValueError` on error SSE events) — same file, different gap: this one is about *successful* streams containing type-less chunks.
- Direct (non-Bedrock) SSE is unaffected: that branch carries the event type and backfills `data["type"]`.
貢獻指南
評估
這個 Issue 還沒有評估資料。