anthropics / anthropics/anthropic-sdk-python

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

Offen
#1,806 4 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
Python
Sterne
3.9k
Forks
853
Ø Merge
1 T. 18 Std.
Gemergte PRs (30 T.)
11

Beschreibung

### 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

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.