diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 9324aca51c..3cf7619332 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -1637,8 +1637,8 @@ async def chat_completion( # When the upstream provider returns an error (e.g. HTTP 400 # content-filter, quota exceeded), generate_chat_completion # returns a JSONResponse instead of raising. Detect this and - # raise so the except-block below emits chat:message:error + - # chat:tasks:cancel, unblocking the frontend. + # raise so the except-block below emits a terminal + # chat:message:error, unblocking the frontend. if isinstance(response, JSONResponse) and response.status_code >= 400: raise Exception(get_response_error_detail(response)) @@ -1674,6 +1674,7 @@ async def chat_completion( { 'parentId': metadata.get('user_message_id', None), 'error': {'content': error_detail}, + 'done': True, }, ) @@ -1682,12 +1683,9 @@ async def chat_completion( await event_emitter( { 'type': 'chat:message:error', - 'data': {'error': {'content': error_detail}}, + 'data': {'error': {'content': error_detail}, 'done': True}, } ) - await event_emitter( - {'type': 'chat:tasks:cancel'}, - ) except Exception: pass diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 472c74be1d..d5e1d2db6f 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -2222,7 +2222,11 @@ async def load_messages_from_db(chat_id: str, message_id: str) -> Optional[list[ if not db_messages: return None - return [{k: v for k, v in msg.items() if k in MESSAGE_REPLAY_KEYS} for msg in db_messages] + return [ + {k: v for k, v in msg.items() if k in MESSAGE_REPLAY_KEYS} + for msg in db_messages + if not (msg.get('role') == 'assistant' and msg.get('error') and not msg.get('content') and not msg.get('output')) + ] def get_reasoning_format(model: dict) -> str | None: @@ -2274,6 +2278,8 @@ def process_messages_with_output( if output_messages: processed.extend(output_messages) continue + if not message.get('content'): + continue clean_message = dict(message) for key in ('id', 'files', 'output', 'model', 'contextSummary', 'context_summary', 'usage'): @@ -4163,13 +4169,14 @@ async def non_streaming_chat_response_handler(response, ctx): metadata['message_id'], { 'error': {'content': error}, + 'done': True, }, ) if isinstance(error, str) or isinstance(error, dict): await event_emitter( { 'type': 'chat:message:error', - 'data': {'error': {'content': error}}, + 'data': {'error': {'content': error}, 'done': True}, } ) diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index b966c3ef7b..99b0e8a0f3 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -1281,6 +1281,13 @@ }, 100); } else if (type === 'chat:message:error') { message.error = data.error; + if (data.done === true && !message.done) { + message.done = true; + dismissContextCompactionToast(); + if (event.message_id === history.currentId) { + await processNextInQueue(event.chat_id); + } + } } else if (type === 'chat:message:follow_ups') { message.followUps = data.follow_ups; @@ -3188,16 +3195,6 @@ } } - if (history?.currentId) { - const currentMessage = history.messages[history.currentId]; - - if (currentMessage.error && !currentMessage.content) { - // Error in response - toast.error($i18n.t(`Oops! There was an error in the previous response.`)); - return; - } - } - // Clear input and submit messageInput?.setText(''); prompt = '';