diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 775a703384..97233737dd 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -1403,13 +1403,18 @@ async def process_chat_response( for block in content_blocks: if block["type"] == "text": - content = f"{content}{block['content'].strip()}\n" + block_content = block["content"].strip() + if block_content: + content = f"{content}{block_content}\n" elif block["type"] == "tool_calls": attributes = block.get("attributes", {}) tool_calls = block.get("content", []) results = block.get("results", []) + if content and not content.endswith("\n"): + content += "\n" + if results: tool_calls_display_content = "" @@ -1432,12 +1437,12 @@ async def process_chat_response( break if tool_result: - tool_calls_display_content = f'{tool_calls_display_content}\n
\nTool Executed\n
\n' + tool_calls_display_content = f'{tool_calls_display_content}
\nTool Executed\n
\n' else: - tool_calls_display_content = f'{tool_calls_display_content}\n
\nExecuting...\n
' + tool_calls_display_content = f'{tool_calls_display_content}
\nExecuting...\n
\n' if not raw: - content = f"{content}\n{tool_calls_display_content}\n\n" + content = f"{content}{tool_calls_display_content}" else: tool_calls_display_content = "" @@ -1450,10 +1455,10 @@ async def process_chat_response( "arguments", "" ) - tool_calls_display_content = f'{tool_calls_display_content}\n
\nExecuting...\n
' + tool_calls_display_content = f'{tool_calls_display_content}\n
\nExecuting...\n
\n' if not raw: - content = f"{content}\n{tool_calls_display_content}\n\n" + content = f"{content}{tool_calls_display_content}" elif block["type"] == "reasoning": reasoning_display_content = "\n".join( @@ -1466,16 +1471,23 @@ async def process_chat_response( start_tag = block.get("start_tag", "") end_tag = block.get("end_tag", "") + if content and not content.endswith("\n"): + content += "\n" + if reasoning_duration is not None: if raw: - content = f'{content}\n{start_tag}{block["content"]}{end_tag}\n' + content = ( + f'{content}{start_tag}{block["content"]}{end_tag}\n' + ) else: - content = f'{content}\n
\nThought for {reasoning_duration} seconds\n{reasoning_display_content}\n
\n' + content = f'{content}
\nThought for {reasoning_duration} seconds\n{reasoning_display_content}\n
\n' else: if raw: - content = f'{content}\n{start_tag}{block["content"]}{end_tag}\n' + content = ( + f'{content}{start_tag}{block["content"]}{end_tag}\n' + ) else: - content = f'{content}\n
\nThinking…\n{reasoning_display_content}\n
\n' + content = f'{content}
\nThinking…\n{reasoning_display_content}\n
\n' elif block["type"] == "code_interpreter": attributes = block.get("attributes", {}) @@ -1495,22 +1507,26 @@ async def process_chat_response( # Keep content as is - either closing backticks or no backticks content = content_stripped + original_whitespace + if content and not content.endswith("\n"): + content += "\n" + if output: output = html.escape(json.dumps(output)) if raw: - content = f'{content}\n\n{block["content"]}\n\n```output\n{output}\n```\n' + content = f'{content}\n{block["content"]}\n\n```output\n{output}\n```\n' else: - content = f'{content}\n
\nAnalyzed\n```{lang}\n{block["content"]}\n```\n
\n' + content = f'{content}
\nAnalyzed\n```{lang}\n{block["content"]}\n```\n
\n' else: if raw: - content = f'{content}\n\n{block["content"]}\n\n' + content = f'{content}\n{block["content"]}\n\n' else: - content = f'{content}\n
\nAnalyzing...\n```{lang}\n{block["content"]}\n```\n
\n' + content = f'{content}
\nAnalyzing...\n```{lang}\n{block["content"]}\n```\n
\n' else: block_content = str(block["content"]).strip() - content = f"{content}{block['type']}: {block_content}\n" + if block_content: + content = f"{content}{block['type']}: {block_content}\n" return content.strip()