Repository navigation
Description
Description
Streaming a code_interpreter_tool_call (or code_interpreter_tool_result) in small chunks can silently drop one of the chunks instead of concatenating them, corrupting the code the model generated.
_merge_content_item_lists in agent_framework/_types.py is what ChatResponse.from_updates / AgentResponse.from_updates use to fold streamed inputs/outputs chunks for a code interpreter call together. It has to tell apart two situations: a provider sending a genuine incremental delta (concatenate it) versus a provider resending the complete value after streaming finishes (replace the accumulated text with it) — the OpenAI Responses API does the latter via its code_interpreter_call_code.done event, which repeats the full code once after a run of .delta events for the same call.
It tells these apart by checking whether one chunk's text is a string-prefix of the other (incoming_text.startswith(existing_text) / existing_text.startswith(incoming_text)), and if so assumes it's the full-resend case and throws the other one away. That's a guess, and it's wrong whenever two ordinary, unrelated deltas simply happen to line up that way — which isn't rare for code: repeated indentation, a closing paren arriving right after an opening one, a one-digit number followed by a longer one that starts with the same digit, etc. Nothing raises in this case; the earlier (or later) chunk is just quietly dropped.
Expected behavior
Two genuine streamed deltas for the same call should always concatenate in arrival order. Only a chunk that is actually a full resend should replace what's been accumulated so far.
Actual behavior
from agent_framework import ChatResponse, ChatResponseUpdate, Content
updates = [
ChatResponseUpdate(
contents=[Content.from_code_interpreter_tool_call(call_id="ci_1", inputs=[Content.from_text(text="(")])]
),
ChatResponseUpdate(
contents=[Content.from_code_interpreter_tool_call(call_id="ci_1", inputs=[Content.from_text(text="()")])]
),
]
resp = ChatResponse.from_updates(updates)
print("".join(i.text or "" for i in resp.messages[0].contents[0].inputs))prints (), not ((). The first delta is discarded outright because "()" happens to start with "(". Swap the order ("()" then "(") and it's the opposite chunk that disappears, again leaving just ().
Code Sample
from agent_framework import ChatResponse, ChatResponseUpdate, Content
# A new line's leading indentation (4 spaces) happens to be a prefix of the next
# delta (the same 4 spaces followed by the line's actual content).
deltas = [" ", " print(i)\n"]
updates = [
ChatResponseUpdate(
contents=[Content.from_code_interpreter_tool_call(call_id="ci_1", inputs=[Content.from_text(text=d)])]
)
for d in deltas
]
resp = ChatResponse.from_updates(updates)
print(repr("".join(i.text or "" for i in resp.messages[0].contents[0].inputs)))
# prints ' print(i)\n' - expected ' print(i)\n' (both deltas concatenated)Error Messages / Stack Traces
No exception is raised. The code the agent believes it ran (and may show the user, or re-send on the next turn) is silently truncated or duplicated.
Package Versions
agent-framework-core: 1.19.0, agent-framework-openai: 1.14.4
Python Version
Python 3.12
Metadata
Metadata
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
github-actions commentedon Oct 1, 2026
🤖 Automated triage reproduction notes (agent-authored — trust but verify)
Agent analysis
Repro:
python/packages/core/agent_framework/_types.py::_merge_content_item_listsat lines 2333-2351 drops one streamed text chunk when either text is a prefix of the other, affecting code-interpreter call inputs and result outputs finalized by ChatResponse or AgentResponse. Minimal repro: create twoChatResponseUpdateobjects for one code-interpreter call with input texts"("and"()", callChatResponse.from_updates, and assert the joined inputs equal"(()"; the current output is"()".python/packages/core/tests/core/test_types.pyagent-framework-core 1.19.0, agent-framework-openai 1.14.4agent-framework-core 1.19.0fix(python): address microsoft#8955 review -- empty list and done marker
fix(python): use generic stream_complete for code-interpreter merge (m…
Python: Concatenate code-interpreter stream deltas with prefix overlap (