From df613704569489870025510de83ed7b64c51fb2b Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 29 Oct 2026 17:20:55 +0900 Subject: [PATCH] refac --- backend/open_webui/utils/misc.py | 21 ++++-------- backend/open_webui/utils/session_records.py | 38 ++++++++++++--------- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/backend/open_webui/utils/misc.py b/backend/open_webui/utils/misc.py index b6be078bda..65739bee56 100644 --- a/backend/open_webui/utils/misc.py +++ b/backend/open_webui/utils/misc.py @@ -386,17 +386,6 @@ def convert_output_to_messages( pending_reasoning_details = [] pending_tool_image_urls = [] pending_tool_outputs = [] - completed_call_ids = { - item.get('call_id') - for item in output - if item.get('type') == 'function_call' - and item.get('call_id') - and item.get('status') in {'completed', 'failed', 'rejected'} - } - result_call_ids = { - item.get('call_id') for item in output if item.get('type') == 'function_call_output' and item.get('call_id') - } - function_call_ids = completed_call_ids & result_call_ids def flush_pending(): nonlocal pending_content, pending_tool_calls, pending_reasoning, pending_reasoning_details @@ -448,6 +437,11 @@ def convert_output_to_messages( if not pending_tool_outputs: return + pending_tool_outputs = [ + result + for result in pending_tool_outputs + if any(call['id'] == result.get('call_id') for call in pending_tool_calls) + ] flush_pending() for output_item in pending_tool_outputs: output_parts = output_item.get('output', []) @@ -510,7 +504,7 @@ def convert_output_to_messages( pending_content.append(text) elif item_type == 'function_call': - if item.get('call_id') not in function_call_ids: + if not item.get('call_id') or item.get('status') not in {'completed', 'failed', 'rejected'}: continue # Collect tool calls to batch into assistant message @@ -523,9 +517,6 @@ def convert_output_to_messages( ) elif item_type == 'function_call_output': - if item.get('call_id') not in function_call_ids: - continue - pending_tool_outputs.append(item) elif item_type == 'reasoning': diff --git a/backend/open_webui/utils/session_records.py b/backend/open_webui/utils/session_records.py index 5a7eb106ef..80af860208 100644 --- a/backend/open_webui/utils/session_records.py +++ b/backend/open_webui/utils/session_records.py @@ -32,34 +32,38 @@ def normalize_tool_output(output): if not isinstance(output, list): return output items = [dict(item) for item in output if isinstance(item, dict)] - deduped = [] - positions = {} + normalized = [] + indices = {} + start = 0 for item in items: - kind = item.get('type') + item_type = item.get('type') + # A new assistant item after tool results starts a new round. + if normalized and normalized[-1].get('type') == 'function_call_output' and item_type != 'function_call_output': + pair_results(normalized[start:]) + indices.clear() + start = len(normalized) call_id = item.get('call_id') or item.get('id') - if kind in {'function_call', 'function_call_output'} and call_id: - key = (kind, call_id) - if key in positions: - deduped[positions[key]] = {**deduped[positions[key]], **item} + if item_type in {'function_call', 'function_call_output'} and call_id: + key = (item_type, call_id) + if key in indices: + normalized[indices[key]] = {**normalized[indices[key]], **item} continue - positions[key] = len(deduped) - deduped.append(item) - return pair_results(deduped) + indices[key] = len(normalized) + normalized.append(item) + pair_results(normalized[start:]) + return normalized -def pair_results(deduped): - results = {item.get('call_id'): item for item in deduped if item.get('type') == 'function_call_output'} - for item in deduped: +def pair_results(output): + results = {item.get('call_id'): item for item in output if item.get('type') == 'function_call_output'} + for item in output: if item.get('type') != 'function_call': continue result = results.get(item.get('call_id')) if result: - if result.get('status'): - item['status'] = result['status'] for key in ('started_at', 'ended_at', 'duration', 'error_type'): if key in result and key not in item: item[key] = result[key] elif item.get('status') == 'completed': item['status'] = 'unknown' - return deduped - + return output