Skip to content

Commit 05830df

Browse files
committed
address bugbot comment
1 parent 10d7cda commit 05830df

3 files changed

Lines changed: 75 additions & 22 deletions

File tree

apps/sim/app/api/copilot/chat/stop/route.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,18 @@ export const POST = withRouteHandler((req: NextRequest) =>
5151

5252
const hasContent = content.trim().length > 0
5353
const hasBlocks = Array.isArray(contentBlocks) && contentBlocks.length > 0
54-
const synthesizedStoppedBlocks = hasBlocks
54+
const assistantBlocks = hasBlocks
5555
? contentBlocks
5656
: hasContent
57-
? [{ type: 'text', channel: 'assistant', content }, { type: 'stopped' }]
58-
: [{ type: 'stopped' }]
57+
? [{ type: 'text', channel: 'assistant', content }]
58+
: []
5959
const assistantMessage: PersistedMessage = withStoppedContentBlock(
6060
normalizeMessage({
6161
id: generateId(),
6262
role: 'assistant',
6363
content,
6464
timestamp: new Date().toISOString(),
65-
contentBlocks: synthesizedStoppedBlocks,
65+
contentBlocks: assistantBlocks,
6666
...(requestId ? { requestId } : {}),
6767
})
6868
)

apps/sim/lib/copilot/request/lifecycle/run.test.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,4 +165,61 @@ describe('runCopilotLifecycle', () => {
165165
})
166166
)
167167
})
168+
169+
it('returns the cancelled result when cancelled completion persistence fails', async () => {
170+
const abortController = new AbortController()
171+
abortController.abort('stop')
172+
const onComplete = vi.fn().mockRejectedValue(new Error('db unavailable'))
173+
const onError = vi.fn()
174+
const executionContext: ExecutionContext = {
175+
userId: 'user-1',
176+
workflowId: '',
177+
workspaceId: 'ws-1',
178+
chatId: 'chat-1',
179+
decryptedEnvVars: {},
180+
}
181+
182+
mockRunStreamLoop.mockImplementationOnce(
183+
async (
184+
_fetchUrl: string,
185+
_fetchOptions: RequestInit,
186+
context: StreamingContext
187+
): Promise<void> => {
188+
context.accumulatedContent = 'partial answer'
189+
throw new Error('publisher closed after stop')
190+
}
191+
)
192+
193+
const result = await runCopilotLifecycle(
194+
{ message: 'hello', messageId: 'stream-1' },
195+
{
196+
userId: 'user-1',
197+
workspaceId: 'ws-1',
198+
chatId: 'chat-1',
199+
executionId: 'exec-1',
200+
runId: 'run-1',
201+
abortSignal: abortController.signal,
202+
executionContext,
203+
onComplete,
204+
onError,
205+
}
206+
)
207+
208+
expect(onError).not.toHaveBeenCalled()
209+
expect(onComplete).toHaveBeenCalledWith(
210+
expect.objectContaining({
211+
success: false,
212+
cancelled: true,
213+
content: 'partial answer',
214+
})
215+
)
216+
expect(result).toEqual(
217+
expect.objectContaining({
218+
success: false,
219+
cancelled: true,
220+
content: 'partial answer',
221+
error: 'publisher closed after stop',
222+
})
223+
)
224+
})
168225
})

apps/sim/lib/copilot/request/lifecycle/run.ts

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -167,24 +167,7 @@ export async function runCopilotLifecycle(
167167
// Return `cancelled: true` so upstream classification stays
168168
// consistent with the success-path cancel result.
169169
const wasCancelled = lifecycleOptions.abortSignal?.aborted ?? false
170-
if (!wasCancelled) {
171-
await lifecycleOptions.onError?.(err)
172-
} else if (!onCompleteStarted && lifecycleOptions.onComplete) {
173-
await lifecycleOptions.onComplete({
174-
success: false,
175-
cancelled: true,
176-
content: context.accumulatedContent,
177-
contentBlocks: context.contentBlocks,
178-
toolCalls: buildToolCallSummaries(context),
179-
chatId: context.chatId,
180-
requestId: context.requestId,
181-
error: err.message,
182-
errors: context.errors.length ? context.errors : undefined,
183-
usage: context.usage,
184-
cost: context.cost,
185-
})
186-
}
187-
return {
170+
const result: OrchestratorResult = {
188171
success: false,
189172
cancelled: wasCancelled,
190173
content: wasCancelled ? context.accumulatedContent : '',
@@ -197,6 +180,19 @@ export async function runCopilotLifecycle(
197180
usage: context.usage,
198181
cost: context.cost,
199182
}
183+
184+
if (!wasCancelled) {
185+
await lifecycleOptions.onError?.(err)
186+
} else if (!onCompleteStarted && lifecycleOptions.onComplete) {
187+
try {
188+
await lifecycleOptions.onComplete(result)
189+
} catch (completeError) {
190+
logger.error('Cancelled copilot completion callback failed', {
191+
error: toError(completeError).message,
192+
})
193+
}
194+
}
195+
return result
200196
}
201197
}
202198

0 commit comments

Comments
 (0)