Skip to content

Python: fix: coalesce code_interpreter_tool_call chunks with same call_id in finalize_response (fixes #5793)#6205

Open
hanhan761 wants to merge 2 commits into
microsoft:mainfrom
hanhan761:fix-5793-coalesce-code-interpreter-chunks
Open

Python: fix: coalesce code_interpreter_tool_call chunks with same call_id in finalize_response (fixes #5793)#6205
hanhan761 wants to merge 2 commits into
microsoft:mainfrom
hanhan761:fix-5793-coalesce-code-interpreter-chunks

Conversation

@hanhan761
Copy link
Copy Markdown

Summary

Coalesces code_interpreter_tool_call content items sharing the same call_id during response finalization, so each code interpreter invocation appears as a single content item with complete aggregated text instead of hundreds of chunk-by-chunk entries.

Issue

Closes #5793

Root Cause

During streaming, each response.code_interpreter_call_code.delta event creates a separate code_interpreter_tool_call content item with one text chunk. The existing _finalize_response already coalesced text and text_reasoning items but did not handle code_interpreter_tool_call. When persisted by a history provider like CosmosHistoryProvider, each delta chunk was stored individually — producing thousands of redundant items for a single code invocation.

Change

Added _coalesce_code_interpreter_content() in _types.py, called from _finalize_response. It merges code_interpreter_tool_call items with the same call_id into one item with all inputs concatenated, preserving the first item and extending its inputs list from subsequent items.

Verification

  • Existing sync tests in test_types.py (197 tests) pass
  • test_response_content_creation_with_code_interpreter passes
  • test_parse_chunk_from_openai_code_interpreter, _delta, _done all pass
  • Unit test of _coalesce_code_interpreter_content confirms 3 chunks → 1 item with 3 inputs

hanhan761 added 2 commits May 30, 2026 15:22
…finalize_response

Closes microsoft#5793

During streaming, each code_interpreter_call_code.delta event creates a
separate code_interpreter_tool_call content item with one text chunk.
The final response then accumulates these as multiple items rather than
coalescing them into a single item with the complete aggregated text.

When stored by a history provider (e.g. CosmosHistoryProvider), each
chunk becomes a separate content item, producing thousands of redundant
entries for a single code interpreter invocation.

Fix: add _coalesce_code_interpreter_content in _finalize_response that
merges code_interpreter_tool_call items sharing the same call_id into
one item with all inputs concatenated.
Copilot AI review requested due to automatic review settings May 30, 2026 07:27
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Fixes tool invocation to preserve explicit None arguments rather than stripping them, and adds coalescing logic for code_interpreter_tool_call content items sharing the same call_id.

Changes:

  • Switch model_dump calls from exclude_none=True to exclude_none=False in tool invocation paths so explicit None values are passed through.
  • Add _coalesce_code_interpreter_content to merge code_interpreter_tool_call items by call_id during response finalization.
  • Add a test verifying explicit None arguments are preserved on tool invocation.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
python/packages/core/agent_framework/_tools.py Preserve None values through model_dump during tool invocation.
python/packages/core/agent_framework/_types.py Add coalescing of code_interpreter_tool_call items by call_id.
python/packages/core/tests/core/test_tools.py Add test for invoking tools with explicit None arguments.

Comment on lines +1976 to +1992
def _coalesce_code_interpreter_content(contents: list[Content]) -> None:
"""Coalesce code_interpreter_tool_call items with the same call_id into a single item."""
if not contents:
return
seen: dict[str, Content] = {}
coalesced: list[Content] = []
for content in contents:
if content.type == "code_interpreter_tool_call" and content.call_id:
if content.call_id in seen:
existing = seen[content.call_id]
if content.inputs:
if existing.inputs is None:
existing.inputs = []
existing.inputs.extend(content.inputs)
else:
seen[content.call_id] = content
coalesced.append(content)
Comment on lines 638 to 640
parsed_arguments = self.input_model.model_validate(parsed_arguments).model_dump(
exclude_none=True
exclude_none=False
)
Comment on lines +1466 to +1467
def test_invoke_preserves_explicit_none_arguments() -> None:
"""Optional parameters explicitly set to None must not be stripped before invocation."""
@github-actions github-actions Bot changed the title fix: coalesce code_interpreter_tool_call chunks with same call_id in finalize_response (fixes #5793) Python: fix: coalesce code_interpreter_tool_call chunks with same call_id in finalize_response (fixes #5793) May 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: CosmosHistoryProvider Code interpreter tool calls are saved chunk by chunk

3 participants