From 961112ff8392bd7445e2f0bdf82d630349a37f02 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Fri, 10 Oct 2025 01:40:59 +0200 Subject: [PATCH] Fix abort detection to use message stopReason instead of global isStreaming When abort happens during tool call streaming, the tool result should show as aborted. Previously used global isStreaming state which would flip when new messages streamed in, causing spinner to reappear incorrectly. Changes: - Use message.stopReason === "aborted" to detect aborted tool calls - Create synthetic error result for aborted tool calls in ToolMessage component - Fix Ollama provider key test to return true (can't know which model to test) - Add newline before HTML execution logs in artifacts update --- packages/web-ui/src/components/Messages.ts | 13 +++++++++++-- packages/web-ui/src/components/ProviderKeyInput.ts | 3 ++- packages/web-ui/src/tools/artifacts/artifacts.ts | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/web-ui/src/components/Messages.ts b/packages/web-ui/src/components/Messages.ts index 8e121123..433faca3 100644 --- a/packages/web-ui/src/components/Messages.ts +++ b/packages/web-ui/src/components/Messages.ts @@ -112,7 +112,8 @@ export class AssistantMessage extends LitElement { const tool = this.tools?.find((t) => t.name === chunk.name); const pending = this.pendingToolCalls?.has(chunk.id) ?? false; const result = this.toolResultsById?.get(chunk.id); - const aborted = !pending && !result && !this.isStreaming; + // A tool call is aborted if the message was aborted and there's no result for this tool call + const aborted = this.message.stopReason === "aborted" && !result; orderedParts.push( html` | undefined = this.aborted + ? { role: "toolResult", isError: true, output: "", toolCallId: this.toolCall.id, toolName: this.toolCall.name } + : this.result; + const toolContent = renderTool( + toolName, + this.toolCall.arguments, + result, + !this.aborted && (this.isStreaming || this.pending), + ); return html`
diff --git a/packages/web-ui/src/components/ProviderKeyInput.ts b/packages/web-ui/src/components/ProviderKeyInput.ts index db5ccee9..e569c1bd 100644 --- a/packages/web-ui/src/components/ProviderKeyInput.ts +++ b/packages/web-ui/src/components/ProviderKeyInput.ts @@ -45,7 +45,8 @@ export class ProviderKeyInput extends LitElement { private async testApiKey(provider: string, apiKey: string): Promise { try { const modelId = TEST_MODELS[provider]; - if (!modelId) return false; + // Returning true here for Ollama and friends. Can' know which model to use for testing + if (!modelId) return true; let model = getModel(provider as any, modelId); if (!model) return false; diff --git a/packages/web-ui/src/tools/artifacts/artifacts.ts b/packages/web-ui/src/tools/artifacts/artifacts.ts index 1b25feac..4ffee7d5 100644 --- a/packages/web-ui/src/tools/artifacts/artifacts.ts +++ b/packages/web-ui/src/tools/artifacts/artifacts.ts @@ -449,7 +449,7 @@ export class ArtifactsPanel extends LitElement { let result = `Updated file ${params.filename}`; if (this.getFileType(params.filename) === "html" && !options.skipWait) { const logs = await this.waitForHtmlExecution(params.filename); - result += logs; + result += `\n${logs}`; } return result;