diff --git a/frontend/src/components/Chat.tsx b/frontend/src/components/Chat.tsx
index 6c765c8..02ec9e3 100644
--- a/frontend/src/components/Chat.tsx
+++ b/frontend/src/components/Chat.tsx
@@ -798,6 +798,12 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) {
setQueuedMessages([...queuedMessagesRef.current]);
}, []);
+ const handleStopAgent = useCallback((storyId: string, agentName: string) => {
+ agentsApi.stopAgent(storyId, agentName).catch((err: unknown) => {
+ console.error("Failed to stop agent:", err);
+ });
+ }, []);
+
return (
setSelectedWorkItemId(item.story_id)}
+ onStopAgent={handleStopAgent}
/>
setSelectedWorkItemId(item.story_id)}
+ onStopAgent={handleStopAgent}
/>
setSelectedWorkItemId(item.story_id)}
+ onStopAgent={handleStopAgent}
/>
>
diff --git a/frontend/src/components/StagePanel.tsx b/frontend/src/components/StagePanel.tsx
index d0b7766..7189f5a 100644
--- a/frontend/src/components/StagePanel.tsx
+++ b/frontend/src/components/StagePanel.tsx
@@ -43,6 +43,7 @@ interface StagePanelProps {
items: PipelineStageItem[];
emptyMessage?: string;
onItemClick?: (item: PipelineStageItem) => void;
+ onStopAgent?: (storyId: string, agentName: string) => void;
/** Map of story_id → total_cost_usd for displaying cost badges. */
costs?: Map;
/** Agent roster to populate the start agent dropdown. */
@@ -56,9 +57,11 @@ interface StagePanelProps {
function AgentLozenge({
agent,
storyId,
+ onStop,
}: {
agent: AgentAssignment;
storyId: string;
+ onStop?: () => void;
}) {
const { saveSlotRect, pendingFlyIns } = useLozengeFly();
const lozengeRef = useRef(null);
@@ -128,6 +131,31 @@ function AgentLozenge({
/>
)}
{label}
+ {isRunning && onStop && (
+
+ )}
);
}
@@ -224,6 +252,7 @@ export function StagePanel({
items,
emptyMessage = "Empty.",
onItemClick,
+ onStopAgent,
costs,
agentRoster,
busyAgentNames,
@@ -391,7 +420,19 @@ export function StagePanel({
)}
{item.agent && (
-
+
+ onStopAgent(
+ item.story_id,
+ item.agent?.agent_name ?? "",
+ )
+ : undefined
+ }
+ />
)}
{canStart && onStartAgent && (