Skip to content

Commit c535bae

Browse files
committed
Show continue options on abort
1 parent 77eafab commit c535bae

File tree

3 files changed

+52
-25
lines changed

3 files changed

+52
-25
lines changed

apps/sim/app/workspace/[workspaceId]/home/components/message-content/message-content.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -413,9 +413,7 @@ export function MessageContent({
413413
return (
414414
<div key={`stopped-${i}`} className='flex items-center gap-[8px]'>
415415
<CircleStop className='h-[16px] w-[16px] flex-shrink-0 text-[var(--text-icon)]' />
416-
<span className='font-base text-[14px] text-[var(--text-body)]'>
417-
Stopped by user
418-
</span>
416+
<span className='font-base text-[14px] text-[var(--text-body)]'>Stopped</span>
419417
</div>
420418
)
421419
}

apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,16 +1190,22 @@ export function useChat(
11901190

11911191
if (storedBlocks.length > 0) {
11921192
storedBlocks.push({ type: 'stopped' })
1193+
storedBlocks.push({ type: 'text', content: CONTINUE_OPTIONS_CONTENT })
11931194
}
11941195

1196+
const persistedContent =
1197+
content && !content.includes('<options>')
1198+
? content + '\n\n' + CONTINUE_OPTIONS_CONTENT
1199+
: content
1200+
11951201
try {
11961202
const res = await fetch(stopPathRef.current, {
11971203
method: 'POST',
11981204
headers: { 'Content-Type': 'application/json' },
11991205
body: JSON.stringify({
12001206
chatId,
12011207
streamId,
1202-
content,
1208+
content: persistedContent,
12031209
...(storedBlocks.length > 0 && { contentBlocks: storedBlocks }),
12041210
}),
12051211
})
@@ -1225,6 +1231,45 @@ export function useChat(
12251231
const messagesRef = useRef(messages)
12261232
messagesRef.current = messages
12271233

1234+
const CONTINUE_OPTIONS_CONTENT =
1235+
'<options>{"continue":{"title":"Continue","description":"Pick up where we left off"}}</options>'
1236+
1237+
const resolveInterruptedToolCalls = useCallback(() => {
1238+
setMessages((prev) => {
1239+
let lastAssistantIdx = -1
1240+
for (let i = prev.length - 1; i >= 0; i--) {
1241+
if (prev[i].role === 'assistant') {
1242+
lastAssistantIdx = i
1243+
break
1244+
}
1245+
}
1246+
return prev.map((msg, idx) => {
1247+
const hasExecuting = msg.contentBlocks?.some((b) => b.toolCall?.status === 'executing')
1248+
const isLastAssistant = idx === lastAssistantIdx
1249+
if (!hasExecuting && !isLastAssistant) return msg
1250+
1251+
const blocks: ContentBlock[] = (msg.contentBlocks ?? []).map((block) => {
1252+
if (block.toolCall?.status !== 'executing') return block
1253+
return {
1254+
...block,
1255+
toolCall: {
1256+
...block.toolCall,
1257+
status: 'cancelled' as const,
1258+
displayTitle: 'Stopped',
1259+
},
1260+
}
1261+
})
1262+
if (isLastAssistant && !blocks.some((b) => b.type === 'stopped')) {
1263+
blocks.push({ type: 'stopped' as const })
1264+
}
1265+
if (isLastAssistant && !blocks.some((b) => b.type === 'text' && b.content?.includes('<options>'))) {
1266+
blocks.push({ type: 'text', content: CONTINUE_OPTIONS_CONTENT })
1267+
}
1268+
return { ...msg, contentBlocks: blocks.length > 0 ? blocks : msg.contentBlocks }
1269+
})
1270+
})
1271+
}, [])
1272+
12281273
const finalize = useCallback(
12291274
(options?: { error?: boolean }) => {
12301275
sendingRef.current = false
@@ -1239,6 +1284,8 @@ export function useChat(
12391284
}
12401285
}
12411286

1287+
resolveInterruptedToolCalls()
1288+
12421289
if (options?.error) {
12431290
setMessageQueue([])
12441291
return
@@ -1254,7 +1301,7 @@ export function useChat(
12541301
})
12551302
}
12561303
},
1257-
[invalidateChatQueries]
1304+
[invalidateChatQueries, resolveInterruptedToolCalls]
12581305
)
12591306
finalizeRef.current = finalize
12601307

@@ -1412,24 +1459,7 @@ export function useChat(
14121459
sendingRef.current = false
14131460
setIsSending(false)
14141461

1415-
setMessages((prev) =>
1416-
prev.map((msg) => {
1417-
if (!msg.contentBlocks?.some((b) => b.toolCall?.status === 'executing')) return msg
1418-
const updated = msg.contentBlocks!.map((block) => {
1419-
if (block.toolCall?.status !== 'executing') return block
1420-
return {
1421-
...block,
1422-
toolCall: {
1423-
...block.toolCall,
1424-
status: 'cancelled' as const,
1425-
displayTitle: 'Stopped by user',
1426-
},
1427-
}
1428-
})
1429-
updated.push({ type: 'stopped' as const })
1430-
return { ...msg, contentBlocks: updated }
1431-
})
1432-
)
1462+
resolveInterruptedToolCalls()
14331463

14341464
if (sid) {
14351465
fetch('/api/copilot/chat/abort', {
@@ -1495,7 +1525,7 @@ export function useChat(
14951525

14961526
reportManualRunToolStop(workflowId, toolCallId).catch(() => {})
14971527
}
1498-
}, [invalidateChatQueries, persistPartialResponse, executionStream])
1528+
}, [invalidateChatQueries, persistPartialResponse, executionStream, resolveInterruptedToolCalls])
14991529

15001530
const removeFromQueue = useCallback((id: string) => {
15011531
messageQueueRef.current = messageQueueRef.current.filter((m) => m.id !== id)

bun.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)