diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 319407e4cf..5544888813 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -3974,9 +3974,10 @@ async def streaming_chat_response_handler(response, ctx): except Exception as e: pass - content = ( + initial_content = ( message.get('content', '') if message else last_assistant_message if last_assistant_message else '' ) + content_parts = [initial_content] if initial_content else [] # Initialize output: use existing from message if continuing, else create new existing_output = message.get('output') if message else None @@ -3984,14 +3985,14 @@ async def streaming_chat_response_handler(response, ctx): output = existing_output else: # Only create an initial message item if there is content to initialize with - if content: + if initial_content: output = [ { 'type': 'message', 'id': output_id('msg'), 'status': 'in_progress', 'role': 'assistant', - 'content': [{'type': 'output_text', 'text': content}], + 'content': [{'type': 'output_text', 'text': initial_content}], } ] else: @@ -4053,7 +4054,7 @@ async def streaming_chat_response_handler(response, ctx): ) async def stream_body_handler(response, form_data): - nonlocal content + nonlocal content_parts nonlocal usage nonlocal output nonlocal prior_output @@ -4504,12 +4505,8 @@ async def streaming_chat_response_handler(response, ctx): user, ) - if isinstance(value, str): - # In-place append — avoids copying the full - # accumulated response on every chunk. - content += value - else: - content = f'{content}{value}' + # closure-cell str += recopies per chunk; append + join once at read is O(n) + content_parts.append(value if isinstance(value, str) else f'{value}') # Check if we're inside a tag-based block # (reasoning, code_interpreter, or solution). @@ -5374,7 +5371,7 @@ async def streaming_chat_response_handler(response, ctx): {'done': True}, ) - await publish_chat_finished_event(request, user, metadata, title, content, output) + await publish_chat_finished_event(request, user, metadata, title, ''.join(content_parts), output) await event_emitter( {