From 2e6d970946837ddbf0afffd8a8e2f854acb5a755 Mon Sep 17 00:00:00 2001 From: Harsh Mahajan <115500013+007harshmahajan@users.noreply.github.com> Date: Thu, 5 Feb 2026 15:20:33 +0530 Subject: [PATCH] fix: sre-agent error propogation (#10383) ### **PR Type** Bug fix ___ ### **Description** - Display streamed `error` events in chat - Finalize active tool calls on errors - Persist error messages to history - Stop further stream processing on error ___ ### Diagram Walkthrough ```mermaid flowchart LR stream["Streamed event payloads"] toolcall["Active tool call state"] chat["Assistant chat message"] history["Saved chat history"] stream -- "type=error" --> toolcall toolcall -- "finalize tool_call block" --> chat stream -- "format error + suggestion" --> chat chat -- "saveToHistory()" --> history ```

File Walkthrough

Relevant files
Bug fix
O2AIChat.vue
Handle streamed errors and finalize tool calls                     

web/src/components/O2AIChat.vue
  • Add data.type === 'error' handling in stream loops
  • Convert any activeToolCall into a completed tool_call block
  • Append/create assistant message with formatted error and optional
    suggestion
  • Save error to history, scroll, then return
+112/-0 
___ --- web/src/components/O2AIChat.vue | 130 ++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/web/src/components/O2AIChat.vue b/web/src/components/O2AIChat.vue index 71811fb1f5..2f4d41b62c 100644 --- a/web/src/components/O2AIChat.vue +++ b/web/src/components/O2AIChat.vue @@ -816,6 +816,71 @@ export default defineComponent({ continue; } + // Handle error events - display error message to user + if (data && data.type === 'error') { + // Complete any active tool call first + let lastMessage = chatMessages.value[chatMessages.value.length - 1]; + if (activeToolCall.value) { + const completedToolBlock: ContentBlock = { + type: 'tool_call', + tool: activeToolCall.value.tool, + message: activeToolCall.value.message, + context: activeToolCall.value.context + }; + if (lastMessage && lastMessage.role === 'assistant') { + if (!lastMessage.contentBlocks) lastMessage.contentBlocks = []; + lastMessage.contentBlocks.push(completedToolBlock); + } else { + pendingToolCalls.value.push(completedToolBlock); + } + activeToolCall.value = null; + } + + // Format error message with suggestion if available + // Handle case where error/message might be an object instead of string + const rawError = data.error ?? data.message ?? 'An unexpected error occurred'; + const errorText = typeof rawError === 'string' ? rawError : JSON.stringify(rawError, null, 2); + + let errorMessage = `Error: ${errorText}`; + if (data.suggestion) { + errorMessage += `\n\n${data.suggestion}`; + } + + // Get or create assistant message for error (reuse lastMessage) + lastMessage = chatMessages.value[chatMessages.value.length - 1]; + if (!lastMessage || lastMessage.role !== 'assistant') { + chatMessages.value.push({ + role: 'assistant', + content: errorMessage, + contentBlocks: [...pendingToolCalls.value, { type: 'text', text: errorMessage }] + }); + pendingToolCalls.value = []; + } else { + // Append error to existing message + if (lastMessage.content) { + lastMessage.content += '\n\n' + errorMessage; + } else { + lastMessage.content = errorMessage; + } + if (!lastMessage.contentBlocks) { + lastMessage.contentBlocks = []; + } + lastMessage.contentBlocks.push({ type: 'text', text: errorMessage }); + // Clear pending tool calls to avoid leaking into later messages + pendingToolCalls.value = []; + } + + // Reset streaming state + currentTextSegment.value = ''; + + // Save error message to history + await saveToHistory(); + await scrollToBottom(); + + // Stop processing further as error occurred + return; + } + // Handle complete events - complete any active tool call if (data && data.type === 'complete') { if (activeToolCall.value) { @@ -969,6 +1034,71 @@ export default defineComponent({ continue; } + // Handle error events - display error message to user + if (data && data.type === 'error') { + // Complete any active tool call first + let lastMessage = chatMessages.value[chatMessages.value.length - 1]; + if (activeToolCall.value) { + const completedToolBlock: ContentBlock = { + type: 'tool_call', + tool: activeToolCall.value.tool, + message: activeToolCall.value.message, + context: activeToolCall.value.context + }; + if (lastMessage && lastMessage.role === 'assistant') { + if (!lastMessage.contentBlocks) lastMessage.contentBlocks = []; + lastMessage.contentBlocks.push(completedToolBlock); + } else { + pendingToolCalls.value.push(completedToolBlock); + } + activeToolCall.value = null; + } + + // Format error message with suggestion if available + // Handle case where error/message might be an object instead of string + const rawError = data.error ?? data.message ?? 'An unexpected error occurred'; + const errorText = typeof rawError === 'string' ? rawError : JSON.stringify(rawError, null, 2); + + let errorMessage = `Error: ${errorText}`; + if (data.suggestion) { + errorMessage += `\n\n${data.suggestion}`; + } + + // Get or create assistant message for error (reuse lastMessage) + lastMessage = chatMessages.value[chatMessages.value.length - 1]; + if (!lastMessage || lastMessage.role !== 'assistant') { + chatMessages.value.push({ + role: 'assistant', + content: errorMessage, + contentBlocks: [...pendingToolCalls.value, { type: 'text', text: errorMessage }] + }); + pendingToolCalls.value = []; + } else { + // Append error to existing message + if (lastMessage.content) { + lastMessage.content += '\n\n' + errorMessage; + } else { + lastMessage.content = errorMessage; + } + if (!lastMessage.contentBlocks) { + lastMessage.contentBlocks = []; + } + lastMessage.contentBlocks.push({ type: 'text', text: errorMessage }); + // Clear pending tool calls to avoid leaking into later messages + pendingToolCalls.value = []; + } + + // Reset streaming state + currentTextSegment.value = ''; + + // Save error message to history + await saveToHistory(); + await scrollToBottom(); + + // Stop processing further as error occurred + return; + } + // Handle complete events - complete any active tool call if (data && data.type === 'complete') { if (activeToolCall.value) {