anthropics / anthropics/anthropic-sdk-python

Streaming accumulator crashes when message_start omits usage as shown in thinking docs

Đang mở
#1,806 4 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
Python
Star
3.9k
Fork
853
Merge trung bình
1 ngày 18 giờ
Pull request đã merge (30 ngày)
11

Mô tả

### Summary

Anthropic's official [streaming documentation](https://platform.claude.com/docs/en/build-with-claude/streaming) shows a **"Streaming request with thinking"** event sequence where both `message_start.message.usage` and `message_delta.usage` are omitted.

However, the latest Python SDK has a conflicting contract:

1. `Message.usage` is generated as a required field:
https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/types/message.py#L113
2. When it is omitted from `message_start`, the streamed message snapshot contains `usage=None`.
3. The accumulator later unconditionally dereferences that value when a `message_delta` does contain usage:
https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/lib/streaming/_messages.py#L503-L518

This causes the official SDK to crash while consuming an event sequence compatible with the official thinking-streaming example.

### Reproduction

This reproduces with the latest release, `anthropic==0.120.2`, without any third-party gateway:

```python
import anthropic
import httpx

sse = """event: message_start
data: {"type":"message_start","message":{"id":"msg_test","type":"message","role":"assistant","content":[],"model":"claude-test","stop_reason":null,"stop_sequence":null}}

event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}

event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"hi"}}

event: content_block_stop
data: {"type":"content_block_stop","index":0}

event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":1}}

event: message_stop
data: {"type":"message_stop"}

"""

def handler(request: httpx.Request) -> httpx.Response:
return httpx.Response(
200,
headers={"content-type": "text/event-stream"},
content=sse,
request=request,
)

client = anthropic.Anthropic(
api_key="test",
http_client=httpx.Client(transport=httpx.MockTransport(handler)),
)

with client.messages.stream(
model="claude-test",
max_tokens=1,
messages=[{"role": "user", "content": "hi"}],
) as stream:
stream.get_final_message()
```

### Actual behavior

```text
File "anthropic/lib/streaming/_messages.py", line 508, in accumulate_event
current_snapshot.usage.output_tokens = event.usage.output_tokens
AttributeError: 'NoneType' object has no attribute 'output_tokens'
and no __dict__ for setting new attributes
```

### Expected behavior / contract question

The documentation and SDK should agree on whether `usage` may be omitted from streaming events.

- If omission is valid, `Message.usage` should be optional and the accumulator should initialize usage when a later delta supplies it (and tolerate streams that never supply it).
- If omission is invalid, the thinking-streaming documentation should include the required usage fields, and the SDK should ideally report a clear response-validation error instead of failing later with an unrelated `AttributeError`.

This was originally observed with a compatible gateway, but the mock transport above demonstrates that the failure is entirely reproducible at the documented event/SDK boundary. Related downstream report: https://github.com/maximhq/bifrost/issues/5885

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.