Skip to content

Commit 024f144

Browse files
committed
feat(cli): add cancelled status for interrupted subagents
- Add cancelled status to AgentContentBlock type - Show ⊘ cancelled indicator in red when user interrupts response - Mark running subagents as cancelled on abort - Clear streamingAgents set so cancelled status displays correctly
1 parent 5a693c9 commit 024f144

File tree

6 files changed

+52
-2
lines changed

6 files changed

+52
-2
lines changed

cli/src/hooks/helpers/__tests__/send-message.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ describe('setupStreamingContext', () => {
101101
setIsRetrying: (value: boolean) => {
102102
isRetrying = value
103103
},
104+
setStreamingAgents: () => {},
104105
})
105106

106107
// Trigger abort
@@ -163,6 +164,7 @@ describe('setupStreamingContext', () => {
163164
isQueuePausedRef,
164165
updateChainInProgress: () => {},
165166
setIsRetrying: () => {},
167+
setStreamingAgents: () => {},
166168
})
167169

168170
// Trigger abort
@@ -192,6 +194,7 @@ describe('setupStreamingContext', () => {
192194
isProcessingQueueRef,
193195
updateChainInProgress: () => {},
194196
setIsRetrying: () => {},
197+
setStreamingAgents: () => {},
195198
})
196199

197200
// Verify ref starts as true
@@ -238,6 +241,7 @@ describe('setupStreamingContext', () => {
238241
setIsRetrying: (value) => {
239242
isRetrying = value
240243
},
244+
setStreamingAgents: () => {},
241245
})
242246

243247
// Sanity check initial state
@@ -278,6 +282,7 @@ describe('setupStreamingContext', () => {
278282
setCanProcessQueue: () => {},
279283
updateChainInProgress: () => {},
280284
setIsRetrying: () => {},
285+
setStreamingAgents: () => {},
281286
})
282287

283288
// Verify abortController is stored in ref
@@ -306,6 +311,7 @@ describe('setupStreamingContext', () => {
306311
setCanProcessQueue: () => {},
307312
updateChainInProgress: () => {},
308313
setIsRetrying: () => {},
314+
setStreamingAgents: () => {},
309315
})
310316

311317
// Verify streamRefs was reset

cli/src/hooks/helpers/send-message.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
} from '../../utils/error-handling'
88
import { invalidateActivityQuery } from '../use-activity-query'
99
import { usageQueryKeys } from '../use-usage-query'
10+
import { markRunningAgentsAsCancelled } from '../../utils/block-operations'
1011
import { formatElapsedTime } from '../../utils/format-elapsed-time'
1112
import { processImagesForMessage } from '../../utils/image-processor'
1213
import { logger } from '../../utils/logger'
@@ -192,6 +193,7 @@ export const setupStreamingContext = (params: {
192193
isProcessingQueueRef?: MutableRefObject<boolean>
193194
updateChainInProgress: (value: boolean) => void
194195
setIsRetrying: (value: boolean) => void
196+
setStreamingAgents: (updater: (prev: Set<string>) => Set<string>) => void
195197
}) => {
196198
const {
197199
aiMessageId,
@@ -205,6 +207,7 @@ export const setupStreamingContext = (params: {
205207
isProcessingQueueRef,
206208
updateChainInProgress,
207209
setIsRetrying,
210+
setStreamingAgents,
208211
} = params
209212

210213
streamRefs.reset()
@@ -229,7 +232,13 @@ export const setupStreamingContext = (params: {
229232
setIsRetrying(false)
230233
timerController.stop('aborted')
231234

232-
updater.updateAiMessageBlocks((blocks) => appendInterruptionNotice(blocks))
235+
// Clear streaming agents so cancelled status displays correctly in UI
236+
setStreamingAgents(() => new Set())
237+
238+
updater.updateAiMessageBlocks((blocks) => {
239+
const cancelledBlocks = markRunningAgentsAsCancelled(blocks)
240+
return appendInterruptionNotice(cancelledBlocks)
241+
})
233242
updater.markComplete()
234243
})
235244

cli/src/hooks/use-send-message.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ export const useSendMessage = ({
343343
isProcessingQueueRef,
344344
updateChainInProgress,
345345
setIsRetrying,
346+
setStreamingAgents,
346347
})
347348
setStreamStatus('waiting')
348349
setMessages((prev) => [...prev, aiMessage])

cli/src/types/chat.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export type AgentContentBlock = {
4949
agentName: string
5050
agentType: string
5151
content: string
52-
status: 'running' | 'complete' | 'failed'
52+
status: 'running' | 'complete' | 'failed' | 'cancelled'
5353
blocks?: ContentBlock[]
5454
initialPrompt?: string
5555
params?: Record<string, any>

cli/src/utils/agent-helpers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export function getAgentStatusInfo(
1919
return { indicator: '✗', label: 'failed', color: 'red', text: '✗ failed' }
2020
case 'complete':
2121
return { indicator: '✓', label: 'completed', color: theme.foreground, text: 'completed ✓' }
22+
case 'cancelled':
23+
return { indicator: '⊘', label: 'cancelled', color: 'red', text: '⊘ cancelled' }
2224
default:
2325
return { indicator: '○', label: 'waiting', color: theme.muted, text: '○ waiting' }
2426
}

cli/src/utils/block-operations.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,3 +355,35 @@ export const markAgentComplete = (blocks: ContentBlock[], agentId: string) =>
355355
}
356356
return { ...block, status: 'complete' as const }
357357
})
358+
359+
/**
360+
* Recursively marks all agent blocks with status 'running' as 'cancelled'.
361+
* Used when the user interrupts a response to indicate subagents were stopped.
362+
*/
363+
export const markRunningAgentsAsCancelled = (
364+
blocks: ContentBlock[],
365+
): ContentBlock[] => {
366+
return blocks.map((block) => {
367+
if (block.type !== 'agent') {
368+
return block
369+
}
370+
371+
const updatedBlocks = block.blocks
372+
? markRunningAgentsAsCancelled(block.blocks)
373+
: undefined
374+
375+
if (block.status === 'running') {
376+
return {
377+
...block,
378+
status: 'cancelled' as const,
379+
...(updatedBlocks && { blocks: updatedBlocks }),
380+
}
381+
}
382+
383+
if (updatedBlocks && updatedBlocks !== block.blocks) {
384+
return { ...block, blocks: updatedBlocks }
385+
}
386+
387+
return block
388+
})
389+
}

0 commit comments

Comments
 (0)