Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Show continue options on abort
  • Loading branch information
Sg312 committed Mar 24, 2026
commit c535baec40fba7566752ff2545649149ee9d7acc
Original file line number Diff line number Diff line change
Expand Up @@ -413,9 +413,7 @@ export function MessageContent({
return (
<div key={`stopped-${i}`} className='flex items-center gap-[8px]'>
<CircleStop className='h-[16px] w-[16px] flex-shrink-0 text-[var(--text-icon)]' />
<span className='font-base text-[14px] text-[var(--text-body)]'>
Stopped by user
</span>
<span className='font-base text-[14px] text-[var(--text-body)]'>Stopped</span>
</div>
)
}
Expand Down
72 changes: 51 additions & 21 deletions apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1190,16 +1190,22 @@ export function useChat(

if (storedBlocks.length > 0) {
storedBlocks.push({ type: 'stopped' })
storedBlocks.push({ type: 'text', content: CONTINUE_OPTIONS_CONTENT })
}

const persistedContent =
content && !content.includes('<options>')
? content + '\n\n' + CONTINUE_OPTIONS_CONTENT
: content

try {
const res = await fetch(stopPathRef.current, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
chatId,
streamId,
content,
content: persistedContent,
...(storedBlocks.length > 0 && { contentBlocks: storedBlocks }),
}),
})
Expand All @@ -1225,6 +1231,45 @@ export function useChat(
const messagesRef = useRef(messages)
messagesRef.current = messages

const CONTINUE_OPTIONS_CONTENT =
'<options>{"continue":{"title":"Continue","description":"Pick up where we left off"}}</options>'
Comment thread
Sg312 marked this conversation as resolved.
Outdated

const resolveInterruptedToolCalls = useCallback(() => {
setMessages((prev) => {
let lastAssistantIdx = -1
for (let i = prev.length - 1; i >= 0; i--) {
if (prev[i].role === 'assistant') {
lastAssistantIdx = i
break
}
}
return prev.map((msg, idx) => {
const hasExecuting = msg.contentBlocks?.some((b) => b.toolCall?.status === 'executing')
const isLastAssistant = idx === lastAssistantIdx
if (!hasExecuting && !isLastAssistant) return msg

const blocks: ContentBlock[] = (msg.contentBlocks ?? []).map((block) => {
if (block.toolCall?.status !== 'executing') return block
return {
...block,
toolCall: {
...block.toolCall,
status: 'cancelled' as const,
displayTitle: 'Stopped',
},
}
})
if (isLastAssistant && !blocks.some((b) => b.type === 'stopped')) {
blocks.push({ type: 'stopped' as const })
}
if (isLastAssistant && !blocks.some((b) => b.type === 'text' && b.content?.includes('<options>'))) {
blocks.push({ type: 'text', content: CONTINUE_OPTIONS_CONTENT })
}
return { ...msg, contentBlocks: blocks.length > 0 ? blocks : msg.contentBlocks }
Comment thread
Sg312 marked this conversation as resolved.
})
})
}, [])

const finalize = useCallback(
(options?: { error?: boolean }) => {
sendingRef.current = false
Expand All @@ -1239,6 +1284,8 @@ export function useChat(
}
Comment thread
Sg312 marked this conversation as resolved.
}

resolveInterruptedToolCalls()

if (options?.error) {
setMessageQueue([])
return
Expand All @@ -1254,7 +1301,7 @@ export function useChat(
})
}
},
[invalidateChatQueries]
[invalidateChatQueries, resolveInterruptedToolCalls]
)
finalizeRef.current = finalize

Expand Down Expand Up @@ -1412,24 +1459,7 @@ export function useChat(
sendingRef.current = false
setIsSending(false)

setMessages((prev) =>
prev.map((msg) => {
if (!msg.contentBlocks?.some((b) => b.toolCall?.status === 'executing')) return msg
const updated = msg.contentBlocks!.map((block) => {
if (block.toolCall?.status !== 'executing') return block
return {
...block,
toolCall: {
...block.toolCall,
status: 'cancelled' as const,
displayTitle: 'Stopped by user',
},
}
})
updated.push({ type: 'stopped' as const })
return { ...msg, contentBlocks: updated }
})
)
resolveInterruptedToolCalls()

if (sid) {
fetch('/api/copilot/chat/abort', {
Expand Down Expand Up @@ -1495,7 +1525,7 @@ export function useChat(

reportManualRunToolStop(workflowId, toolCallId).catch(() => {})
}
}, [invalidateChatQueries, persistPartialResponse, executionStream])
}, [invalidateChatQueries, persistPartialResponse, executionStream, resolveInterruptedToolCalls])

const removeFromQueue = useCallback((id: string) => {
messageQueueRef.current = messageQueueRef.current.filter((m) => m.id !== id)
Expand Down
1 change: 0 additions & 1 deletion bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading