Describe the bug
In web/pgadmin/llm/providers/openai.py, chat_stream() accumulates streamed function-call arguments in a tool_calls_data dict keyed by call_id:
elif event_type == 'response.output_item.added':
item = data.get('item', {})
if item.get('type') == 'function_call':
call_id = item.get('call_id', '')
tool_calls_data[call_id] = {'name': item.get('name', ''), 'arguments': ''}
elif event_type == 'response.function_call_arguments.delta':
call_id = data.get('call_id', '')
if call_id not in tool_calls_data:
tool_calls_data[call_id] = {'name': '', 'arguments': ''}
tool_calls_data[call_id]['arguments'] += data.get('delta', '')
But per OpenAI's Responses API streaming event reference, response.function_call_arguments.delta events carry item_id, output_index, delta and sequence_number — there is no call_id field on that event type (source). So data.get('call_id', '') always evaluates to ''.
That means every response.function_call_arguments.delta event fails the call_id not in tool_calls_data check (since the real call_id entry was already created by response.output_item.added), creates a second dict entry keyed by the empty string, and accumulates all the argument deltas there instead. The result: a tool call comes back as two separate ToolCall entries — one with the correct name and empty arguments, and another with empty name and the actual (accumulated) arguments — rather than one complete tool call.
To Reproduce
- Configure the AI Assistant / SQL Chat feature with an OpenAI provider and a model exposed via the Responses API (
/v1/responses).
- Ask a question that triggers a streamed tool/function call.
- Inspect the resulting tool calls: the name and arguments arrive in two separate entries instead of one.
Expected behavior
The delta events should be correlated using item_id (matching item.id from the response.output_item.added event, not item.call_id) so all argument deltas accumulate against the same entry that was seeded with the function name, and the final ToolCall is emitted with both name and arguments populated correctly.
Found while re-verifying #9795 (which is otherwise correctly fixed for the "unsupported model" fallback to /v1/responses) — this is a separate, follow-up defect in that same streaming path.
Describe the bug
In
web/pgadmin/llm/providers/openai.py,chat_stream()accumulates streamed function-call arguments in atool_calls_datadict keyed bycall_id:But per OpenAI's Responses API streaming event reference,
response.function_call_arguments.deltaevents carryitem_id,output_index,deltaandsequence_number— there is nocall_idfield on that event type (source). Sodata.get('call_id', '')always evaluates to''.That means every
response.function_call_arguments.deltaevent fails thecall_id not in tool_calls_datacheck (since the real call_id entry was already created byresponse.output_item.added), creates a second dict entry keyed by the empty string, and accumulates all the argument deltas there instead. The result: a tool call comes back as two separateToolCallentries — one with the correctnameand emptyarguments, and another with emptynameand the actual (accumulated)arguments— rather than one complete tool call.To Reproduce
/v1/responses).Expected behavior
The delta events should be correlated using
item_id(matchingitem.idfrom theresponse.output_item.addedevent, notitem.call_id) so all argument deltas accumulate against the same entry that was seeded with the function name, and the finalToolCallis emitted with both name and arguments populated correctly.Found while re-verifying #9795 (which is otherwise correctly fixed for the "unsupported model" fallback to
/v1/responses) — this is a separate, follow-up defect in that same streaming path.