Skip to content

fix(streaming): propagate message_delta.container into final Message#1444

Open
abhicris wants to merge 2 commits intoanthropics:mainfrom
abhicris:fix/stream-aggregator-propagate-container
Open

fix(streaming): propagate message_delta.container into final Message#1444
abhicris wants to merge 2 commits intoanthropics:mainfrom
abhicris:fix/stream-aggregator-propagate-container

Conversation

@abhicris
Copy link
Copy Markdown

Closes #1424.

Bug

The non-beta streaming aggregator in `lib/streaming/_messages.py` merges `stop_reason`, `stop_sequence`, and `usage` from the `message_delta` SSE event, but drops `delta.container`. With `code_execution_20260120` (or any container-backed tool), `stream.get_final_message().container` is therefore `None`, even though the SSE stream did carry the container info on the `message_delta` event.

The next request then fails:

```
anthropic.BadRequestError: 400 - container_id is required when there are pending tool uses generated by code execution with tools.
```

Fix

The beta path already does the right thing — `lib/streaming/_beta_messages.py:537` assigns `current_snapshot.container = event.delta.container`. This PR mirrors that single line in the non-beta path so both paths surface the container id consistently.

```diff
elif event.type == "message_delta":

  •    # Mirror the beta accumulator (lib/streaming/_beta_messages.py): the
    
  •    # \`container\` field is delivered on the \`message_delta\` SSE event
    
  •    # and has to be merged into the accumulated Message, otherwise
    
  •    # \`stream.get_final_message().container\` is None for code-execution
    
  •    # / container-backed tool runs and the next request fails with
    
  •    # \`container_id is required when there are pending tool uses …\`.
    
  •    current_snapshot.container = event.delta.container
       current_snapshot.stop_reason = event.delta.stop_reason
       current_snapshot.stop_sequence = event.delta.stop_sequence
       current_snapshot.usage.output_tokens = event.usage.output_tokens
    

```

Test

New regression test `test_message_delta_propagates_container_to_snapshot` constructs a synthetic `RawMessageDeltaEvent` with a `Container`, calls `accumulate_event` directly, and asserts `snapshot.container.id` is set (plus the existing `stop_reason` / `usage.output_tokens` merges still work).

Diff size

`+58 / -0` (1 line of fix + 1 comment block + 50-line regression test). No public-API change; affects only what the streaming aggregator preserves on the final `Message`.


Contributed by kcolbchain.

…ror (closes anthropics#1430)

The 'Streaming is required' ValueError pointed at
https://github.com/anthropics/anthropic-sdk-python#long-requests, a README
heading removed in 0e40921. The same project already references the canonical
location for this guidance — https://docs.anthropic.com/en/api/errors#long-requests
— from src/anthropic/_exceptions.py:90 (the timeout error). Adopt the same URL
here so users hitting either path land on the same page.
…loses anthropics#1424)

The non-beta streaming aggregator at lib/streaming/_messages.py merges
stop_reason / stop_sequence / usage from `message_delta`, but drops
`delta.container`. The result: with `code_execution_20260120` (or any
container-backed tool) the `Message` returned by
`stream.get_final_message()` has `container=None`, even though the SSE
stream did carry it on the `message_delta` event. The next request then
fails:

    anthropic.BadRequestError: 400 - container_id is required when there
    are pending tool uses generated by code execution with tools.

The beta path already does the right thing (lib/streaming/_beta_messages.py:537
assigns `current_snapshot.container = event.delta.container`). This PR
mirrors that single line in the non-beta path so both paths surface the
container id consistently.

`+1` line of fix, `+50` lines of regression test that constructs a
synthetic `RawMessageDeltaEvent` with a `Container`, calls
`accumulate_event` directly, and asserts `snapshot.container.id` is set
(plus the existing `stop_reason` / `usage.output_tokens` merges still
work).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

get_final_message() does not propagate message_delta.container into aggregated Message (breaks code_execution continuation)

1 participant