Python: Fix stateless replay of reasoning-paired tool calls#7233
Merged
moonbox3 merged 14 commits intoJul 22, 2026
Conversation
Contributor
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes stateless replay for reasoning-model Responses by ensuring tool-call history that was originally paired with server-scoped reasoning items is not replayed “orphaned” (which Foundry rejects with HTTP 400), covering both hosted MCP calls and client-side function calls across workflow/multi-agent boundaries.
Changes:
- Extend stateless replay sanitization to identify tool-call IDs paired with
text_reasoning, including completed client-sidefunction_callloops (call + result) and hosted MCP calls. - Update OpenAI chat client serialization behavior/tests so completed reasoning-paired function-call groups are removed when service-side storage is unavailable, while active tool loops remain unchanged.
- Add deterministic end-to-end regression tests covering workflow cross-agent replay (FoundryAgent/WorkflowBuilder) and hosted server replay (ResponsesHostServer).
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| python/packages/openai/agent_framework_openai/_chat_client.py | Drops reasoning-paired tool-call items atomically during stateless replay, including completed function-call loops. |
| python/packages/openai/tests/openai/test_openai_chat_client.py | Updates unit coverage to assert completed reasoning-paired function-call history is stripped without storage, while active loops remain. |
| python/packages/foundry/tests/foundry/test_foundry_agent.py | Adds deterministic workflow regression to ensure cross-agent replay doesn’t send orphaned function_call items. |
| python/packages/foundry_hosting/tests/test_responses_int.py | Adds deterministic hosted-server regression ensuring second turn doesn’t replay mcp_call without its paired reasoning item. |
moonbox3
marked this pull request as ready for review
July 21, 2026 03:44
moonbox3
enabled auto-merge
July 21, 2026 06:57
Contributor
|
Why did we choose to drop the function call and result pair instead of replaying the reasonings? |
Key decisions: - Request encrypted reasoning on client-managed Responses calls while preserving caller include values. - Store encrypted payloads in Content.protected_data and reconstruct one provider reasoning item per reasoning id. - Replay active and completed function call/result groups; retain continuation-owned history behavior and the existing orphan-safe MCP path. Files changed: - python/packages/openai/agent_framework_openai/_chat_client.py - python/packages/openai/tests/openai/test_openai_chat_client.py Next iteration: - Extend encrypted reasoning preservation to streaming and framework serialization boundaries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Key decisions: - Capture encrypted reasoning from terminal streamed output items in Content.protected_data. - Preserve summary and private reasoning as distinct framework contents while reconstructing one provider reasoning item per id. - Prove replay after Message JSON and workflow checkpoint round trips, including encrypted-only and completed function groups. Files changed: - python/packages/core/agent_framework/_types.py - python/packages/openai/agent_framework_openai/_chat_client.py - python/packages/openai/tests/openai/test_openai_chat_client.py Next iteration: - Extend lossless stateless reasoning replay to hosted MCP call/output groups. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Key decisions: - Preserve hosted MCP call/output groups in client-managed history instead of deleting them when reasoning cannot be reconstructed. - Keep call/result coalescing and orphan-result exclusion intact, while retaining continuation-owned duplicate avoidance. - Cover completed, active, and multi-call reasoning groups plus the public outgoing request boundary. Files changed: - python/packages/openai/agent_framework_openai/_chat_client.py - python/packages/openai/tests/openai/test_openai_chat_client.py Next iteration: - Preserve middleware-terminated and parallel function groups atomically. - Add preflight rejection for non-replayable reasoning groups in the dedicated validation slice. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Key decisions: - Return ordinary function results when middleware terminates a loop, removing the provider-specific durable marker. - Preserve every parallel call and available sibling result as one encrypted reasoning group in stateless replay. - Prove successful and policy-blocked batches through the public two-agent Foundry workflow and outgoing HTTP boundary. Files changed: - python/packages/core/agent_framework/_tools.py - python/packages/core/tests/core/test_function_invocation_logic.py - python/packages/openai/tests/openai/test_openai_chat_client.py - python/packages/foundry/tests/foundry/test_foundry_agent.py Next iteration: - Add preflight rejection for non-replayable and partially compacted reasoning groups. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Key decisions: - Validate client-managed reasoning groups after compaction and report every affected reasoning and call identifier before transport. - Permit service-owned continuation and fully excluded atomic groups while rejecting partial compaction projections. - Surface encrypted-reasoning capability failures without lossy retries. Files changed: - python/packages/openai/agent_framework_openai/_chat_client.py - python/packages/openai/tests/openai/test_openai_chat_client.py Next iteration: - Run the resource-specific Foundry proof and finish PR microsoft#7233; that live proof remains intentionally local and requires the configured developer resource. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
Author
I fixed this in latest commits. |
moonbox3
had a problem deploying
to
github-app-auth
July 22, 2026 12:11 — with
GitHub Actions
Failure
eavanvalkenburg
approved these changes
Jul 22, 2026
TaoChenOSU
approved these changes
Jul 22, 2026
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Jul 22, 2026
… into issue-6074-mcp-reasoning-latest
moonbox3
enabled auto-merge
July 22, 2026 23:44
alliscode
approved these changes
Jul 22, 2026
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
Reasoning-model responses can bind a reasoning item to a tool-call item. During stateless replay, Agent Framework strips response-scoped reasoning items, but the client-side MCP path continued to serialize the paired
function_callandfunction_call_output. Foundry rejects that orphaned call with HTTP 400 in multi-agent workflows. The earlier fix in #6907 covered hostedmcp_callitems but not client-side MCP tools represented as function calls.Description & Review Guide
WorkflowBuilder,FoundryAgent,AgentExecutor, Responses SDK serialization, and Foundry hosting, including the middleware-terminated path.function_callormcp_callitems when service-side storage is unavailable. Existing non-reasoning tool history and active client-side function loops retain their current behavior._tool_call_ids_paired_with_reasoning, the batch-wide middleware-termination marker, and the public workflow regression that distinguishes active tool execution from historical cross-agent replay.Related Issue
Fixes #6074
No other open PR exists for this issue. This completes the client-side function-call path that remained after #6907.
Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.