-
Notifications
You must be signed in to change notification settings - Fork 4.4k
feat: Populate name field in ResponseFunctionCallArgumentsDoneEvent from snapshot #2731
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?
Conversation
…shot Fixes openai#2723 Problem: When streaming Responses API with multiple function tools, the response.function_call_arguments.done event returns name=None, making it impossible to determine which function to call. Root Cause: ResponseStreamState.handle_event() only handles delta events for function calls, but not done events. The done event falls through to 'else: events.append(event)', returning the raw event without processing. The raw event from the API doesn't include the name field - it must be taken from the accumulated snapshot. Solution: Added elif block to handle response.function_call_arguments.done events, following the proven pattern from Chat Completions API's _add_tool_done_event() method. Changes: 1. Added ResponseFunctionCallArgumentsDoneEvent import 2. Added parse_function_tool_arguments import 3. Added elif block to emit done event with: - name from accumulated snapshot (not raw event) - parsed_arguments using input_tools 4. Exported ResponseFunctionCallArgumentsDoneEvent in __init__.py Pattern: This follows the same approach as Chat Completions streaming, which correctly emits done events with name from the snapshot. Impact: Non-breaking change - only populates a field that was previously None. Existing code continues to work, new code can now access the function name to determine which function was called.
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.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| elif event.type == "response.function_call_arguments.done": | ||
| output = snapshot.output[event.output_index] | ||
| assert output.type == "function_call" | ||
|
|
||
| # Parse arguments using input_tools | ||
| parsed_arguments = parse_function_tool_arguments( | ||
| input_tools=self._input_tools, | ||
| function_call=output | ||
| ) | ||
| output.parsed_arguments = parsed_arguments | ||
|
|
||
| # Emit event with name from accumulated snapshot | ||
| events.append( | ||
| build( | ||
| ResponseFunctionCallArgumentsDoneEvent, | ||
| arguments=output.arguments, | ||
| item_id=event.item_id, | ||
| name=output.name, # FROM SNAPSHOT, not raw event | ||
| output_index=event.output_index, | ||
| sequence_number=event.sequence_number, | ||
| type="response.function_call_arguments.done", |
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.
Preserve arguments when only a done event is emitted
The new handler builds ResponseFunctionCallArgumentsDoneEvent using output.arguments, which is only populated by prior response.function_call_arguments.delta events. If the server delivers the full arguments payload only in the response.function_call_arguments.done event (and never emits deltas), output.arguments remains empty and callers now see blank arguments even though the raw event contained them. Previously the raw event was forwarded untouched so the arguments were available. Consider sourcing the field from event.arguments (or falling back to it) to avoid dropping data in backends that do not emit delta updates.
Useful? React with 👍 / 👎.
Address bot feedback on PR openai#2731. The bot correctly identified an edge case where the server might emit a response.function_call_arguments.done event WITHOUT prior delta events. In this scenario: - output.arguments would be empty (only populated by deltas) - event.arguments contains the complete arguments payload Changed to use event.arguments as the source of truth, which ensures arguments are preserved in all scenarios: ✅ With deltas: event.arguments contains accumulated result ✅ Without deltas: event.arguments contains full payload This maintains backward compatibility while fixing the edge case. Co-authored-by: chatgpt-codex-connector[bot]
Problem
When using Responses API streaming with multiple function tools, the
response.function_call_arguments.doneevent returnsname=None, making it impossible to determine which function to call.Example from issue #2723:
This breaks multi-tool scenarios where the application needs to know which function was called to route the execution correctly.
Root Cause
ResponseStreamState.handle_event()only processes delta events for function calls, not done events:The raw event from the API doesn't include the
namefield - it must be taken from the accumulated snapshot.Solution
Added
elifblock to handleresponse.function_call_arguments.doneevents, following the proven pattern from Chat Completions API's_add_tool_done_event()method.Changes:
ResponseFunctionCallArgumentsDoneEventimportparse_function_tool_argumentsimportnamefrom accumulated snapshot (not raw event)parsed_argumentsusing input_toolsResponseFunctionCallArgumentsDoneEventin__init__.pyAfter fix:
Pattern
This follows the same approach as Chat Completions streaming (
src/openai/lib/streaming/chat/_completions.py:708-731), which correctly emits done events with name from the snapshot.Impact
Non-breaking change:
NoneRelated Issues
Example Usage
Before:
After:
Files Changed
src/openai/lib/streaming/responses/_responses.py: Added elif block + imports (24 lines)src/openai/lib/streaming/responses/__init__.py: Exported done event (1 line)Testing
The fix follows the proven pattern from Chat Completions, which has been working correctly for months. The type
ResponseFunctionCallArgumentsDoneEventalready has thenamefield defined, and the snapshotParsedResponseFunctionToolCallcontains the name - this change simply connects them.