Skip to content

Commit 2ae47cf

Browse files
committed
refac
1 parent adcbba3 commit 2ae47cf

1 file changed

Lines changed: 35 additions & 2 deletions

File tree

backend/open_webui/utils/middleware.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3402,6 +3402,11 @@ async def stream_body_handler(response, form_data):
34023402

34033403
response_tool_calls = []
34043404

3405+
# Responses API output_index values are relative to the
3406+
# current response (0, 1, ...). During re-invocations,
3407+
# output has accumulated history, so we offset indices.
3408+
responses_output_offset = len(output)
3409+
34053410
delta_count = 0
34063411
delta_chunk_size = max(
34073412
CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE,
@@ -3470,6 +3475,10 @@ async def flush_pending_delta_data(threshold: int = 0):
34703475
)
34713476
# Check for Responses API events (type field starts with "response.")
34723477
elif data.get('type', '').startswith('response.'):
3478+
# Offset output_index for re-invocations
3479+
if responses_output_offset and 'output_index' in data:
3480+
data = {**data, 'output_index': data['output_index'] + responses_output_offset}
3481+
34733482
output, response_metadata = handle_responses_streaming_event(data, output)
34743483

34753484
processed_data = {
@@ -3480,9 +3489,14 @@ async def flush_pending_delta_data(threshold: int = 0):
34803489
# print(data)
34813490
# print(processed_data)
34823491

3483-
# Merge any metadata (usage, done, etc.)
3492+
# Merge any metadata (usage, etc.)
3493+
# Strip 'done' — response.completed emits
3494+
# it but we may still need to execute tool
3495+
# calls. The outer middleware manages the
3496+
# actual completion signal.
34843497
if response_metadata:
34853498
processed_data.update(response_metadata)
3499+
processed_data.pop('done', None)
34863500

34873501
await event_emitter(
34883502
{
@@ -3889,9 +3903,18 @@ async def flush_pending_delta_data(threshold: int = 0):
38893903

38903904
# Responses API path: extract function_call items from output
38913905
if not response_tool_calls and output:
3906+
# Collect call_ids that already have results
3907+
handled_call_ids = {
3908+
item.get('call_id')
3909+
for item in output
3910+
if item.get('type') == 'function_call_output'
3911+
}
38923912
responses_api_tool_calls = []
38933913
for item in output:
3894-
if item.get('type') == 'function_call' and item.get('status') != 'completed':
3914+
if (
3915+
item.get('type') == 'function_call'
3916+
and item.get('call_id') not in handled_call_ids
3917+
):
38953918
arguments = item.get('arguments', '{}')
38963919
responses_api_tool_calls.append({
38973920
'id': item.get('call_id', ''),
@@ -4210,7 +4233,17 @@ async def flush_pending_delta_data(threshold: int = 0):
42104233
)
42114234

42124235
if isinstance(res, StreamingResponse):
4236+
# Save output before re-invocation. Responses API
4237+
# response.completed replaces the entire output
4238+
# with only the new response's items, losing tool
4239+
# call history. Restore previous items afterward.
4240+
output_prefix = list(output)
42134241
await stream_body_handler(res, new_form_data)
4242+
if output_prefix and (
4243+
not output
4244+
or output[0].get('id') != output_prefix[0].get('id')
4245+
):
4246+
output[:0] = output_prefix
42144247
else:
42154248
break
42164249
except Exception as e:

0 commit comments

Comments
 (0)