diff --git a/backend/open_webui/constants.py b/backend/open_webui/constants.py
index cb65e0d77..86d87a2c3 100644
--- a/backend/open_webui/constants.py
+++ b/backend/open_webui/constants.py
@@ -57,7 +57,7 @@ class ERROR_MESSAGES(str, Enum):
)
FILE_NOT_SENT = "FILE_NOT_SENT"
- FILE_NOT_SUPPORTED = "Oops! It seems like the file format you're trying to upload is not supported. Please upload a file with a supported format (e.g., JPG, PNG, PDF, TXT) and try again."
+ FILE_NOT_SUPPORTED = "Oops! It seems like the file format you're trying to upload is not supported. Please upload a file with a supported format and try again."
NOT_FOUND = "We could not find what you're looking for :/"
USER_NOT_FOUND = "We could not find what you're looking for :/"
diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py
index 11e36cecf..ffccdca87 100644
--- a/backend/open_webui/utils/middleware.py
+++ b/backend/open_webui/utils/middleware.py
@@ -1107,9 +1107,15 @@ async def process_chat_response(
reasoning_duration = block.get("duration", None)
if reasoning_duration:
- content = f'{content}\nThought for {reasoning_duration} seconds
\n{reasoning_display_content}\n \n'
+ if raw:
+ content = f'{content}<{block["tag"]}>{block["content"]}{block["tag"]}>\n'
+ else:
+ content = f'{content}\nThought for {reasoning_duration} seconds
\n{reasoning_display_content}\n \n'
else:
- content = f'{content}\nThinking…
\n{reasoning_display_content}\n \n'
+ if raw:
+ content = f'{content}<{block["tag"]}>{block["content"]}{block["tag"]}>\n'
+ else:
+ content = f'{content}\nThinking…
\n{reasoning_display_content}\n \n'
elif block["type"] == "code_interpreter":
attributes = block.get("attributes", {})
@@ -1120,11 +1126,14 @@ async def process_chat_response(
output = html.escape(json.dumps(output))
if raw:
- content = f'{content}\nAnalyzed
\n```{lang}\n{block["content"]}\n```\n```output\n{output}\n```\n \n'
+ content = f'{content}\n{block["content"]}\n\n```output\n{output}\n```\n'
else:
content = f'{content}\nAnalyzed
\n```{lang}\n{block["content"]}\n```\n \n'
else:
- content = f'{content}\nAnalyzing...
\n```{lang}\n{block["content"]}\n```\n \n'
+ if raw:
+ content = f'{content}\n{block["content"]}\n\n'
+ else:
+ content = f'{content}\nAnalyzing...
\n```{lang}\n{block["content"]}\n```\n \n'
else:
block_content = str(block["content"]).strip()
@@ -1355,6 +1364,15 @@ async def process_chat_response(
if not content_blocks[-1]["content"]:
content_blocks.pop()
+ await event_emitter(
+ {
+ "type": "chat:completion",
+ "data": {
+ "content": serialize_content_blocks(content_blocks),
+ },
+ }
+ )
+
if response.background:
await response.background()
diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte
index 89fedb919..4e8d002dc 100644
--- a/src/lib/components/chat/Chat.svelte
+++ b/src/lib/components/chat/Chat.svelte
@@ -45,7 +45,7 @@
promptTemplate,
splitStream,
sleep,
- removeDetailsWithReasoning,
+ removeDetails,
getPromptVariables
} from '$lib/utils';
@@ -1338,8 +1338,17 @@
parentId: string,
{ modelId = null, modelIdx = null, newChat = false } = {}
) => {
- const _chatId = JSON.parse(JSON.stringify($chatId));
+ // If modelId is provided, use it, else use selected model
+ let selectedModelIds = modelId
+ ? [modelId]
+ : atSelectedModel !== undefined
+ ? [atSelectedModel.id]
+ : selectedModels;
+ // Create response messages for each selected model
+ const responseMessageIds: Record = {};
+
+ const _chatId = JSON.parse(JSON.stringify($chatId));
// Create new chat if newChat is true and first user message
if (
newChat &&
@@ -1351,15 +1360,6 @@
await saveChatHandler(_chatId);
}
- // If modelId is provided, use it, else use selected model
- let selectedModelIds = modelId
- ? [modelId]
- : atSelectedModel !== undefined
- ? [atSelectedModel.id]
- : selectedModels;
-
- // Create response messages for each selected model
- const responseMessageIds: Record = {};
for (const [_modelIdx, modelId] of selectedModelIds.entries()) {
const model = $models.filter((m) => m.id === modelId).at(0);
@@ -1515,7 +1515,7 @@
: undefined,
...createMessagesList(history, responseMessageId).map((message) => ({
...message,
- content: removeDetailsWithReasoning(message.content)
+ content: removeDetails(message.content, ['reasoning', 'code_interpreter'])
}))
]
.filter((message) => message?.content?.trim())
diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts
index 2ccc1bf5d..0a5b72e36 100644
--- a/src/lib/utils/index.ts
+++ b/src/lib/utils/index.ts
@@ -668,8 +668,15 @@ export const cleanText = (content: string) => {
return removeFormattings(removeEmojis(content.trim()));
};
-export const removeDetailsWithReasoning = (content) => {
- return content.replace(/]*>.*?<\/details>/gis, '').trim();
+export const removeDetails = (content, types) => {
+ for (const type of types) {
+ content = content.replace(
+ new RegExp(`]*>.*?<\\/details>`, 'gis'),
+ ''
+ );
+ }
+
+ return content;
};
// This regular expression matches code blocks marked by triple backticks
@@ -741,7 +748,7 @@ export const extractSentencesForAudio = (text: string) => {
};
export const getMessageContentParts = (content: string, split_on: string = 'punctuation') => {
- content = removeDetailsWithReasoning(content);
+ content = removeDetails(content, ['reasoning', 'code_interpreter']);
const messageContentParts: string[] = [];
switch (split_on) {