-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Python: fix: inject synthetic tool results for pending frontend tool calls #4935
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -194,6 +194,26 @@ def _sanitize_tool_history(messages: list[Message]) -> list[Message]: | |
| pending_tool_call_ids = None | ||
| pending_confirm_changes_id = None | ||
|
|
||
| # If the conversation ends with pending tool calls (e.g. a declaration-only | ||
| # frontend tool was called with no user message following), inject synthetic | ||
| # results so the next OpenAI call doesn't get a 400 for unmatched tool_call_ids. | ||
| if pending_tool_call_ids: | ||
| logger.info( | ||
| f"Messages ended with {len(pending_tool_call_ids)} pending tool calls - " | ||
| "injecting synthetic results" | ||
| ) | ||
| for pending_call_id in pending_tool_call_ids: | ||
| logger.info(f"Injecting synthetic tool result for pending call_id={pending_call_id}") | ||
| sanitized.append(Message( | ||
| role="tool", | ||
| contents=[ | ||
| Content.from_function_result( | ||
| call_id=pending_call_id, | ||
| result="Tool execution skipped - frontend tool result not yet received", | ||
| ) | ||
| ], | ||
| )) | ||
|
|
||
| return sanitized | ||
|
Comment on lines
+197
to
217
|
||
|
|
||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Injecting a synthetic tool result at the end will cause any later real tool result for the same call_id (arriving in a subsequent request) to be treated as unmatched and dropped by
_sanitize_tool_history(the synthetic result clearspending_tool_call_idsbefore the real tool message is processed). If frontend tools can legitimately return results asynchronously, consider limiting this end-of-history injection to tools known to be result-less (declaration-only), or adjust the sanitization logic to prefer/replace the synthetic placeholder when a real tool result is later received.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot
Currently we do not foresee how this theoretic case turns into a real one, but considering we want to avoid "ship now, bug later", allow me to suggest the following safeguard:
If there's no user message at all after the pending tool call, it means we're in a "tool result submission only" request, real results might still be coming. Don't inject in that case. Only inject when we know the user is
moving the conversation forward.
Would that be sufficient? anything else in mind?