From dcbc51e22dcd3d7b5a01d6c3b7b0285efa49bca4 Mon Sep 17 00:00:00 2001
From: Adam Malczewski <github@tradam.dev>
Date: Fri, 29 May 2026 18:45:45 +0900
Subject: feat: stop generation button with abort signal plumbing

- Add POST /chat/stop endpoint on API
- Thread abortSignal from agent-manager through Agent.run() to streamText
- Thread abortSignal option through the Agent.run() signature
- Emit status:idle on stopTab() so frontend WS gets the update
- Add stopGeneration() store method on frontend tabStore
- Add stop button in ChatInput (btn-sm lg:btn-xs for mobile tap target)
- Add tests for /chat/stop endpoint
- Refactor processMessage to pass abortSignal to agent.run
---
 packages/frontend/src/lib/components/ChatInput.svelte | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

(limited to 'packages/frontend/src/lib/components/ChatInput.svelte')

diff --git a/packages/frontend/src/lib/components/ChatInput.svelte b/packages/frontend/src/lib/components/ChatInput.svelte
index 3bbc4ab..f9c9546 100644
--- a/packages/frontend/src/lib/components/ChatInput.svelte
+++ b/packages/frontend/src/lib/components/ChatInput.svelte
@@ -5,6 +5,7 @@ let inputEl: HTMLInputElement | undefined;
 let inputValue = $state("");
 
 const agentStatus = $derived(tabStore.activeTab?.agentStatus ?? "idle");
+const tabId = $derived(tabStore.activeTab?.id ?? "");
 
 $effect(() => {
 	inputEl?.focus();
@@ -27,7 +28,15 @@ function submit() {
 
 <div class="flex items-center gap-2 p-3">
 	{#if agentStatus === "running"}
-		<span class="loading loading-spinner loading-sm text-primary"></span>
+		<button
+			type="button"
+			class="btn btn-ghost gap-1 btn-sm lg:btn-xs"
+			onclick={() => tabStore.stopGeneration(tabId)}
+			title="Stop generation"
+		>
+			<span class="loading loading-spinner loading-sm text-primary"></span>
+			<span class="text-xs">Stop</span>
+		</button>
 	{:else if agentStatus === "idle"}
 		<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="w-5 h-5 text-success">
 			<polyline points="20 6 9 17 4 12"></polyline>
-- 
cgit v1.2.3

