Python: keep the approval response under service-side storage so a paused run resumes#7133
Open
he-yufeng wants to merge 1 commit into
Open
Conversation
…used run resumes _prepare_message_for_openai handled function_approval_response and function_approval_request in one case and skipped both under service-side storage. That is right for the request (a server-issued item the server already has, so replaying it inline duplicates it -- microsoft#3295) but wrong for the response: the response is the user's approval decision, references the prior request by approval_request_id, and is not itself a server-stored item, so stripping it means the decision never reaches the model and an approval-paused run never resumes (approval-gated tools can never execute under service-side storage). Split the two into separate cases: the approval request keeps the storage skip (like function_call), the approval response is always sent (like function_result). Fixes microsoft#7125
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a Python OpenAI client serialization bug that prevented approval-gated runs from resuming when continuing via service-side storage (previous_response_id / conversation_id). It ensures the user’s function_approval_response is still sent to the model under continuation requests, while continuing to skip replaying the server-issued function_approval_request to avoid duplicate-item errors.
Changes:
- Split
_prepare_message_for_openaihandling sofunction_approval_requestis skipped under service-side storage butfunction_approval_responseis always serialized. - Added a regression test asserting the approval response is preserved when
request_uses_service_side_storage=True.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| python/packages/openai/agent_framework_openai/_chat_client.py | Separates approval request vs response handling to prevent dropping the user’s approval decision under service-side storage. |
| python/packages/openai/tests/openai/test_openai_chat_client.py | Adds a regression test to ensure approval responses survive continuation requests. |
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.
Summary
Fixes #7125.
When an approval-gated run pauses for tool approval and the follow-up request continues a stored response (service-side storage:
previous_response_id/conversation_id), the user'sfunction_approval_responsewas silently stripped from the outgoing request, so the approval decision never reached the model. The model then re-issued the same approval request and the run paused again — approval-gated tools could never execute under service-side storage.Root cause
_prepare_message_for_openaihandledfunction_approval_responseandfunction_approval_requestin onecaseand skipped both under service-side storage. That is correct for the request (a server-issued item the server already has via the prior response, so replaying it inline duplicates it — #3295), but wrong for the response: the response is the user's decision, references the prior request byapproval_request_id, and is not itself a server-stored item, so it must reach the model.Fix
Split the two into separate cases: the approval request keeps the storage skip (same treatment as
function_call), the approval response is always sent (same treatment asfunction_resultdirectly above it).Test
test_prepare_message_for_openai_keeps_approval_response_under_service_side_storageasserts the response survives withrequest_uses_service_side_storage=True(before the fix the prepared result is empty). The existingtest_prepare_message_for_openai_with_function_approval_responsealready pins the storage-off serialization.I verified the change by reading: the existing storage-off test confirms the
mcp_approval_responseserialization, and the fix mirrors thefunction_resultbranch directly above. A local pytest run was blocked by a workspace-install issue in my environment (agent_frameworkcore not resolving underuv run), so the added test is exercised by CI rather than a local run.