From 93415a48e8893139db13d02d0a6d24e8604a2ac5 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sat, 21 Mar 2026 20:46:25 -0500 Subject: [PATCH] refac --- backend/open_webui/routers/openai.py | 36 ++++++++++++++++++--- backend/open_webui/utils/middleware.py | 45 +++++++++++++++----------- 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/backend/open_webui/routers/openai.py b/backend/open_webui/routers/openai.py index fa4626ee2..26ec7ebcb 100644 --- a/backend/open_webui/routers/openai.py +++ b/backend/open_webui/routers/openai.py @@ -858,6 +858,9 @@ def convert_to_responses_payload(payload: dict) -> dict: if 'max_tokens' in responses_payload: responses_payload['max_output_tokens'] = responses_payload.pop('max_tokens') + if 'max_completion_tokens' in responses_payload: + responses_payload['max_output_tokens'] = responses_payload.pop('max_completion_tokens') + # Remove Chat Completions-only parameters not supported by the Responses API for unsupported_key in ( 'stream_options', @@ -896,11 +899,36 @@ def convert_to_responses_payload(payload: dict) -> dict: def convert_responses_result(response: dict) -> dict: """ - Convert non-streaming Responses API result. - Just add done flag - pass through raw response, frontend handles output. + Convert non-streaming Responses API result to Chat Completions format. + + Extracts text from message output items so all downstream consumers + (frontend tasks, get_content_from_response) work without modification. """ - response['done'] = True - return response + output_items = response.get('output', []) + + content = '' + for item in output_items: + if item.get('type') == 'message': + for part in item.get('content', []): + if part.get('type') == 'output_text': + content += part.get('text', '') + + return { + 'id': response.get('id', ''), + 'object': 'chat.completion', + 'model': response.get('model', ''), + 'choices': [ + { + 'index': 0, + 'message': { + 'role': 'assistant', + 'content': content, + }, + 'finish_reason': 'stop', + } + ], + 'usage': response.get('usage', {}), + } @router.post('/chat/completions') diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 91b4502c0..6378cc83c 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -3367,6 +3367,9 @@ async def streaming_chat_response_handler(response, ctx): usage = None prior_output = [] + def full_output(): + return prior_output + output if prior_output else output + reasoning_tags_param = metadata.get('params', {}).get('reasoning_tags') DETECT_REASONING_TAGS = reasoning_tags_param is not False DETECT_CODE_INTERPRETER = metadata.get('features', {}).get('code_interpreter', False) @@ -3476,8 +3479,8 @@ async def streaming_chat_response_handler(response, ctx): output, response_metadata = handle_responses_streaming_event(data, output) processed_data = { - 'output': prior_output + output, - 'content': serialize_output(prior_output + output), + 'output': full_output(), + 'content': serialize_output(full_output()), } # print(data) @@ -3832,13 +3835,13 @@ async def streaming_chat_response_handler(response, ctx): metadata['chat_id'], metadata['message_id'], { - 'content': serialize_output(output), - 'output': output, + 'content': serialize_output(full_output()), + 'output': full_output(), }, ) else: data = { - 'content': serialize_output(output), + 'content': serialize_output(full_output()), } if delta: @@ -3952,26 +3955,32 @@ async def streaming_chat_response_handler(response, ctx): response_tool_calls = tool_calls.pop(0) # Append function_call items for each tool call + # (Responses API already has them from streaming, so skip duplicates) + existing_call_ids = { + item.get('call_id') for item in output + if item.get('type') == 'function_call' + } for tc in response_tool_calls: call_id = tc.get('id', '') - func = tc.get('function', {}) - output.append( - { - 'type': 'function_call', - 'id': call_id or output_id('fc'), - 'call_id': call_id, - 'name': func.get('name', ''), - 'arguments': func.get('arguments', '{}'), - 'status': 'in_progress', - } - ) + if call_id not in existing_call_ids: + func = tc.get('function', {}) + output.append( + { + 'type': 'function_call', + 'id': call_id or output_id('fc'), + 'call_id': call_id, + 'name': func.get('name', ''), + 'arguments': func.get('arguments', '{}'), + 'status': 'in_progress', + } + ) await event_emitter( { 'type': 'chat:completion', 'data': { - 'content': serialize_output(output), - 'output': output, + 'content': serialize_output(full_output()), + 'output': full_output(), }, } )