Repository navigation
Python: fix(openai): preserve reasoning_content on tool-call follow-up messages - #8405
Merged
Eduard van Valkenburg (eavanvalkenburg) merged 2 commits intoSep 16, 2026
Conversation
When one assistant turn contains text, tool calls and reasoning, the Chat Completions serializer emitted two assistant dicts (text-only, then tool_calls) and the buffered reasoning field only travelled with the second one. OpenAI-compatible providers such as DeepSeek in thinking mode reject the tool-result follow-up because the message that carries the content no longer carries its reasoning. Attach the tool calls of a turn to the assistant dict built from that turn's plain text (and text that follows coalesced tool calls to the tool_calls dict), so content, tool_calls and the reasoning field are sent as a single assistant message. Reasoning text surfaced via the response_parser hook keeps its own dict so message_preparer correlation is unchanged; refusals, images and other content are not merged. Fixes microsoft#8382 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Anish Mehta (anishmehta24)
temporarily deployed
to
github-app-auth
September 15, 2026 18:53 — with
GitHub Actions
Inactive
Anish Mehta (anishmehta24)
temporarily deployed
to
github-app-auth
September 15, 2026 18:53 — with
GitHub Actions
Inactive
Anish Mehta (anishmehta24)
had a problem deploying
to
github-app-auth
September 15, 2026 18:53 — with
GitHub Actions
Error
Anish Mehta (anishmehta24)
temporarily deployed
to
github-app-auth
September 15, 2026 18:53 — with
GitHub Actions
Inactive
Member
|
Thanks for the contribution. Before this is ready, please complete the Microsoft CLA; |
Eduard van Valkenburg (eavanvalkenburg)
approved these changes
Sep 16, 2026
Eduard van Valkenburg (eavanvalkenburg)
temporarily deployed
to
github-app-auth
September 16, 2026 10:04 — with
GitHub Actions
Inactive
Eduard van Valkenburg (eavanvalkenburg)
enabled auto-merge
September 16, 2026 10:05
Contributor
Author
|
@microsoft-github-policy-service agree |
Contributor
Author
|
Eduard van Valkenburg (@eavanvalkenburg) CLA is signed and |
This branch was previously deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation & Context
With
OpenAIChatCompletionClientagainst OpenAI-compatible thinking models (reproduced with DeepSeek,thinking.type=enabled), a response containing text, a tool call and reasoning was serialised on the follow-up request as two assistant messages:{content}followed by{tool_calls, reasoning_*}. DeepSeek requires the reasoning on the message that carries the content and returns400: The reasoning_content in the thinking mode must be passed back to the API.Description & Review Guide
_build_openai_messagesnow attaches a turn's tool calls to the assistant dict built from that turn's text (and text that follows coalesced tool calls to thetool_callsdict), so content,tool_callsand the buffered reasoning field travel as one assistant message. Six unit tests, including an end-to-end DeepSeek-stylereasoning_contentround trip through the existingresponse_parser/message_preparerhooks.response_parserkeeps its own dict, somessage_preparercorrelation (the vLLM example) is unchanged; refusals and non-text content are not merged. No stockreasoning_contentbranch was added, perpackages/openai/AGENTS.md; a parser/preparer pair is still needed to surface and echo DeepSeek's field, and it now works._build_openai_messages(only plain text and tool calls of the same turn, only when adjacent) and whether the single-message shape is acceptable for all providers.Prepared with AI assistance (Claude Code) and human-verified: the new tests fail on
mainand pass with the fix;poe fmt,poe lint,poe pyright -P openai,poe mypy -P openaiand theopenaiandfoundry_localtest suites were run locally.Related Issue
Fixes #8382
Contribution Checklist
🤖 Generated with Claude Code