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 (