fix(anthropic-streaming): insert content_block_stop between held delta and final message_delta

When the stream exhausts with both `holding_chunk` (a content_block_delta)
and `holding_stop_reason_chunk` (a message_delta) buffered, the after-loop
cleanup previously emitted them back-to-back, producing the invalid
Anthropic SSE sequence `content_block_delta -> message_delta`. Insert a
`content_block_stop` between them in both the sync `__next__` and async
`__anext__` paths so the emitted ordering remains
`content_block_delta -> content_block_stop -> message_delta`.

Co-authored-by: Yassin Kortam <yassin@berri.ai>
This commit is contained in:
Cursor Agent 2026-05-28 07:13:23 +00:00
parent fd6e5be46b
commit 0adbb24633
No known key found for this signature in database

View file

@ -459,6 +459,20 @@ class AnthropicStreamWrapper(AdapterCompletionStreamWrapper):
if self.holding_chunk is not None:
self.chunk_queue.append(self.holding_chunk)
self.holding_chunk = None
# If a final ``message_delta`` is also held, the
# dangling ``content_block_delta`` must be followed
# by ``content_block_stop`` before the
# ``message_delta`` so the emitted SSE stays in
# valid Anthropic order (content_block_delta ->
# content_block_stop -> message_delta) rather than
# the invalid content_block_delta -> message_delta.
if self.holding_stop_reason_chunk is not None:
self.chunk_queue.append(
{
"type": "content_block_stop",
"index": self.current_content_block_index,
}
)
if self.holding_stop_reason_chunk is not None:
self.chunk_queue.append(
self._augment_message_delta_usage(
@ -677,6 +691,20 @@ class AnthropicStreamWrapper(AdapterCompletionStreamWrapper):
if self.holding_chunk is not None:
self.chunk_queue.append(self.holding_chunk)
self.holding_chunk = None
# If a final ``message_delta`` is also held, the
# dangling ``content_block_delta`` must be followed
# by ``content_block_stop`` before the
# ``message_delta`` so the emitted SSE stays in
# valid Anthropic order (content_block_delta ->
# content_block_stop -> message_delta) rather than
# the invalid content_block_delta -> message_delta.
if self.holding_stop_reason_chunk is not None:
self.chunk_queue.append(
{
"type": "content_block_stop",
"index": self.current_content_block_index,
}
)
if self.holding_stop_reason_chunk is not None:
self.chunk_queue.append(
self._augment_message_delta_usage(