fix(streaming): keep reasoning_items when reassembling a streamed response

stream_chunk_builder dropped delta.reasoning_items on both of its paths. The
simple-text fast path returned before any aggregation ran, and the full path
had no reasoning_items branch, so the encrypted reasoning state a provider
sends back never reached the assembled assistant message.

That message is what gets cached by _assemble_complete_response_from_streaming_chunks
and what the Responses API bridge reads through _get_reasoning_items to rebuild
its input, so a streamed reasoning turn lost its reasoning state and could not
be round-tripped.

Add reasoning_items to the fast-path bail-out condition so such a stream is no
longer classified as simple text, and merge the items from every chunk in the
full path, matching how annotations and images are already handled.


Suppress the two type-discipline LIT002 hits the gate flagged on the new
lines with `# mutable-ok:` reasons; the neighbouring provider_specific block
is the same shape and is grandfathered into the budget.
This commit is contained in:
Vineeth Sai 2026-08-25 12:38:23 -07:00
parent 49e549d9e9
commit 13260f91d0

View file

@ -8744,7 +8744,7 @@ def stream_chunk_builder(
# Reasoning items carry the provider's encrypted reasoning state, which the
# Responses API bridge reads back off the assembled assistant message.
reasoning_item_chunks: Final = [
reasoning_item_chunks: Final = [ # mutable-ok: local filter over chunks, never escapes this function
chunk
for chunk in chunks
if len(chunk["choices"]) > 0
@ -8753,7 +8753,7 @@ def stream_chunk_builder(
]
if len(reasoning_item_chunks) > 0:
all_reasoning_items: Final[list] = []
all_reasoning_items: Final[list] = [] # mutable-ok: accumulator, extended in the loop below
for chunk in reasoning_item_chunks:
all_reasoning_items.extend(chunk["choices"][0]["delta"]["reasoning_items"])
response["choices"][0]["message"]["reasoning_items"] = all_reasoning_items