Skip to content

fix: guard stop_reason/stop_sequence/stop_details against None in accumulate_event - #1944

Open
priyadarshnisundararajan wants to merge 1 commit into
anthropics:mainfrom
priyadarshnisundararajan:fix/issue-1940-accumulate-stop-reason
Open

priyadarshnisundararajan wants to merge 1 commit into
anthropics:mainfrom
priyadarshnisundararajan:fix/issue-1940-accumulate-stop-reason

Conversation

@priyadarshnisundararajan

Copy link
Copy Markdown

What

In accumulate_event's message_delta branch, stop_reason, stop_sequence, and stop_details were assigned unconditionally from event.delta, while the neighbouring container assignment was already guarded with an is not None check. Since all four fields are Optional[...] = None on Delta, a later message_delta that omits them (e.g. a usage-only delta) would wipe a value an earlier delta had already set.

This applies the same guard to the three stop_* fields in both the regular accumulator (src/anthropic/lib/streaming/_messages.py) and the beta accumulator (src/anthropic/lib/streaming/_beta_messages.py).

Why

The unconditional assignment contradicts the convention stated twenty lines below for usage fields ("optional ones are omitted when not applicable, in which case the message_start value must survive") and is visible to callers through MessageStream.current_message_snapshot / get_final_message(). Code that branches on stop_reason (refusal handling, max_tokens continuation, tool-loop termination) can't distinguish the reset from "the stream never finished".

Fixes #1940

Tests

  • Drove the issue's repro script (message_start -> message_delta with stop_reason -> usage-only message_delta) through RawMessageDeltaEvent.model_validate and the shipped accumulate_event: stop_reason now stays end_turn (was None before).
  • Added regression tests test_message_delta_omitted_stop_fields_keep_earlier_values in tests/lib/streaming/test_messages.py and tests/lib/streaming/test_beta_messages.py.
  • Ran the two full streaming test files: 69 passed.

…umulate_event

A message_delta that omits the stop_* fields (all Optional on Delta) used to
overwrite a previously accumulated stop_reason with None, while the
neighbouring container field was already guarded. Only overwrite the
accumulated values when the incoming delta actually carries them.

Fixes anthropics#1940

This branch has not been deployed

No deployments
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.

streaming: a later message_delta that omits stop_reason resets it to None (container is guarded, the stop_* fields are not)

1 participant