Skip to content

Python: Capture code interpreter outputs on output_item.done - #9744

Merged
Eduard van Valkenburg (eavanvalkenburg) merged 2 commits into
microsoft:mainfrom
cr-sbarbouche:fix-code-interpreter-output-item-done-outputs
Oct 27, 2026
Merged

Eduard van Valkenburg (eavanvalkenburg) merged 2 commits into
microsoft:mainfrom
cr-sbarbouche:fix-code-interpreter-output-item-done-outputs

Conversation

@cr-sbarbouche

Copy link
Copy Markdown
Contributor

Motivation & Context

response.output_item.done is where every other hosted-tool item type (shell_call, computer_call, image_generation_call, mcp_call, web_search_call/file_search_call, custom_tool_call, tool_search_call, function_call_output) gets its final, complete state captured during streaming - a couple of the existing branches even say so explicitly in their comments. code_interpreter_call is missing from that dispatch entirely. The only other place a code interpreter call's outputs (logs, generated images) are read from is response.output_item.added, which fires before the call has run, so a streamed code_interpreter_tool_result.outputs was always empty no matter what the sandbox actually produced. See #9743 for a runnable repro against the real client.

Description & Review Guide

  • What are the major changes? Added a code_interpreter_call branch to the response.output_item.done dispatch in OpenAIChatClient, mirroring the existing non-streaming parser's and response.output_item.added's handling of the same item shape (parse outputs into code_interpreter_tool_result, parse code into code_interpreter_tool_call). Both are tagged merge_mode="replace", matching how code_interpreter_call_code.done already tags the code, since a normal stream can send both events for the same call and the merge layer needs to recognize the second one as a repeat of the authoritative final value rather than append onto the first.
  • What is the impact of these changes? Streamed code interpreter calls now surface their logs/images the same way a non-streaming get_response() call already does. No change for callers who never inspect code_interpreter_tool_result.outputs.
  • What do you want reviewers to focus on? Whether replace is the right mode for outputs specifically. Outputs are never streamed incrementally (no delta event for them), so the done item's list is always the complete, authoritative set; I treated it the same as the already-done code rather than append, but wanted to flag the choice explicitly.

Related Issue

Fixes #9743

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR is linked to an issue and there is no other open PR for this issue (see Related Issue above).
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

response.output_item.done handles every other hosted-tool item type by capturing its final, complete state there - several branches note explicitly that the completed item is the only place their full data is populated - but code_interpreter_call had no branch there at all. The only other place outputs (logs/images) are read from is response.output_item.added, which fires before the call has run, so a streamed code_interpreter_tool_result.outputs was always empty regardless of what the sandbox produced.

Added the missing branch, tagging the done item's code and outputs with merge_mode="replace" like code_interpreter_call_code.done's code already is, since a normal stream sends both for the same call and the merge needs to recognize the second one as a repeat of the authoritative value rather than append onto the first.

Fixes microsoft#9743

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The generated-image behavior addressed by this fix still needs completed-item regression coverage under the repository's testing standards.

1 open issue
What changed in this PR

This PR addresses #9743 by capturing completed code interpreter outputs in the Python OpenAI client's streaming parser.

Changes:

  • Parse logs, images, and final code from response.output_item.done.
  • Use replacement merging for completed calls and results to avoid duplicating final code.
  • Add regression tests for streamed log capture and code deduplication.
File Description
python/​packages/​openai/​tests/​openai/​test_openai_chat_client.py Adds completed-item and streaming-sequence regression tests.
python/​packages/​openai/​agent_framework_openai/​_chat_client.py Captures final code interpreter outputs and code during streaming.

Review effort: Balanced

Comment thread python/packages/openai/tests/openai/test_openai_chat_client.py
The completed-item test only exercised the logs branch of the new code, leaving the image branch (also added in this PR) unverified.
Merged via the queue into microsoft:main with commit 10a94cf Oct 27, 2026
53 checks passed

This branch was previously deployed

1 inactive deployment
github-app-auth — 04250a05 Deployed Oct 27, 2026 by cr-sbarbouche via add_label #26250
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: Streamed code interpreter outputs (logs/images) are always empty

3 participants