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
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>O2AIChat.vue</strong><dd><code>Handle streamed errors
and finalize tool calls</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

web/src/components/O2AIChat.vue

<ul><li>Add <code>data.type === 'error'</code> handling in stream
loops<br> <li> Convert any <code>activeToolCall</code> into a completed
<code>tool_call</code> block<br> <li> Append/create assistant message
with formatted error and optional <br>suggestion<br> <li> Save error to
history, scroll, then return</ul>


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10383/files#diff-a6a125719a7b32b31b53fcfe05c12081d82c139a401699affdda0db8e73887e3">+112/-0</a>&nbsp;
</td>

</tr>
</table></td></tr></tr></tbody></table>

</details>

___
This commit is contained in:
Harsh Mahajan
2026-02-05 15:20:33 +05:30
committed by GitHub
parent f00fe6b1ec
commit 2e6d970946
+130
View File
@@ -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) {