From fa2abe4cb6a085a4c9045bf8d8ff4b6beffdef6a Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Wed, 1 Jul 2026 03:17:06 -0500 Subject: [PATCH] refac --- backend/open_webui/utils/middleware.py | 78 +++++++++++++++++++------- 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 8bd0b175b0..13597731b4 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -157,6 +157,29 @@ def output_id(prefix: str) -> str: return f'{prefix}_{uuid4().hex[:24]}' +def merge_streamed_reasoning_details(target: list, details) -> None: + items = details if isinstance(details, list) else [details] + for item in items: + if not isinstance(item, dict): + continue + + index = item.get('index') + existing = ( + next((detail for detail in target if detail.get('index') == index), None) + if isinstance(index, int) + else None + ) + if existing is None: + target.append(dict(item)) + continue + + for key, value in item.items(): + if key in ('text', 'summary') and isinstance(value, str) and isinstance(existing.get(key), str): + existing[key] += value + else: + existing[key] = value + + def _split_tool_calls( tool_calls: list[dict], ) -> list[dict]: @@ -4282,21 +4305,35 @@ async def streaming_chat_response_handler(response, ctx): ) reasoning_details = delta.get('reasoning_details') if reasoning_content or reasoning_details: - if not output or output[-1].get('type') != 'reasoning': - reasoning_item = { - 'type': 'reasoning', - 'id': output_id('r'), - 'status': 'in_progress', - 'start_tag': '', - 'end_tag': '', - 'attributes': {'type': 'reasoning_content'}, - 'content': [], - 'summary': None, - 'started_at': time.time(), - } - output.append(reasoning_item) - else: - reasoning_item = output[-1] + reasoning_item = ( + next( + ( + item + for item in reversed(output) + if item.get('type') == 'reasoning' + ), + None, + ) + if reasoning_details and not reasoning_content + else None + ) + + if reasoning_item is None: + if not output or output[-1].get('type') != 'reasoning': + reasoning_item = { + 'type': 'reasoning', + 'id': output_id('r'), + 'status': 'in_progress', + 'start_tag': '', + 'end_tag': '', + 'attributes': {'type': 'reasoning_content'}, + 'content': [], + 'summary': None, + 'started_at': time.time(), + } + output.append(reasoning_item) + else: + reasoning_item = output[-1] if reasoning_content: # Append to reasoning content @@ -4317,11 +4354,14 @@ async def streaming_chat_response_handler(response, ctx): delta_type = 'content' if reasoning_details: - reasoning_item.setdefault('reasoning_details', []).extend( - reasoning_details - if isinstance(reasoning_details, list) - else [reasoning_details] + merge_streamed_reasoning_details( + reasoning_item.setdefault('reasoning_details', []), + reasoning_details, ) + data = { + 'output': full_output(), + } + delta_type = 'content' if value: if (