Skip to content

Commit 8a2eacf

Browse files
committed
Fix skip and mtb
1 parent 18f1d76 commit 8a2eacf

File tree

3 files changed

+71
-49
lines changed

3 files changed

+71
-49
lines changed

apps/sim/lib/copilot/orchestrator/sse-handlers/handlers.ts

Lines changed: 68 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,24 @@ export const sseHandlers: Record<string, SSEHandler> = {
211211
options.timeout || STREAM_TIMEOUT_MS,
212212
options.abortSignal
213213
)
214+
if (completion?.status === 'background') {
215+
toolCall.status = 'skipped'
216+
toolCall.endTime = Date.now()
217+
markToolComplete(
218+
toolCall.id,
219+
toolCall.name,
220+
202,
221+
completion.message || 'Tool execution moved to background',
222+
{ background: true }
223+
).catch((err) => {
224+
logger.error('markToolComplete fire-and-forget failed (run tool background)', {
225+
toolCallId: toolCall.id,
226+
error: err instanceof Error ? err.message : String(err),
227+
})
228+
})
229+
markToolResultSeen(toolCallId)
230+
return
231+
}
214232
const success = completion?.status === 'success'
215233
toolCall.status = success ? 'success' : 'error'
216234
toolCall.endTime = Date.now()
@@ -235,48 +253,40 @@ export const sseHandlers: Record<string, SSEHandler> = {
235253
if (decision?.status === 'rejected' || decision?.status === 'error') {
236254
toolCall.status = 'rejected'
237255
toolCall.endTime = Date.now()
238-
await markToolComplete(
256+
// Fire-and-forget: must NOT await — see deadlock note in executeToolAndReport
257+
markToolComplete(
239258
toolCall.id,
240259
toolCall.name,
241260
400,
242261
decision.message || 'Tool execution rejected',
243262
{ skipped: true, reason: 'user_rejected' }
244-
)
245-
markToolResultSeen(toolCall.id)
246-
await options.onEvent?.({
247-
type: 'tool_result',
248-
toolCallId: toolCall.id,
249-
data: {
250-
id: toolCall.id,
251-
name: toolCall.name,
252-
success: false,
253-
result: { skipped: true, reason: 'user_rejected' },
254-
},
263+
).catch((err) => {
264+
logger.error('markToolComplete fire-and-forget failed (rejected)', {
265+
toolCallId: toolCall.id,
266+
error: err instanceof Error ? err.message : String(err),
267+
})
255268
})
269+
markToolResultSeen(toolCall.id)
256270
return
257271
}
258272

259273
if (decision?.status === 'background') {
260274
toolCall.status = 'skipped'
261275
toolCall.endTime = Date.now()
262-
await markToolComplete(
276+
// Fire-and-forget: must NOT await — see deadlock note in executeToolAndReport
277+
markToolComplete(
263278
toolCall.id,
264279
toolCall.name,
265280
202,
266281
decision.message || 'Tool execution moved to background',
267282
{ background: true }
268-
)
269-
markToolResultSeen(toolCall.id)
270-
await options.onEvent?.({
271-
type: 'tool_result',
272-
toolCallId: toolCall.id,
273-
data: {
274-
id: toolCall.id,
275-
name: toolCall.name,
276-
success: true,
277-
result: { background: true },
278-
},
283+
).catch((err) => {
284+
logger.error('markToolComplete fire-and-forget failed (background)', {
285+
toolCallId: toolCall.id,
286+
error: err instanceof Error ? err.message : String(err),
287+
})
279288
})
289+
markToolResultSeen(toolCall.id)
280290
return
281291
}
282292
}
@@ -436,47 +446,39 @@ export const subAgentHandlers: Record<string, SSEHandler> = {
436446
if (decision?.status === 'rejected' || decision?.status === 'error') {
437447
toolCall.status = 'rejected'
438448
toolCall.endTime = Date.now()
439-
await markToolComplete(
449+
// Fire-and-forget: must NOT await — see deadlock note in executeToolAndReport
450+
markToolComplete(
440451
toolCall.id,
441452
toolCall.name,
442453
400,
443454
decision.message || 'Tool execution rejected',
444455
{ skipped: true, reason: 'user_rejected' }
445-
)
446-
markToolResultSeen(toolCall.id)
447-
await options?.onEvent?.({
448-
type: 'tool_result',
449-
toolCallId: toolCall.id,
450-
data: {
451-
id: toolCall.id,
452-
name: toolCall.name,
453-
success: false,
454-
result: { skipped: true, reason: 'user_rejected' },
455-
},
456+
).catch((err) => {
457+
logger.error('markToolComplete fire-and-forget failed (subagent rejected)', {
458+
toolCallId: toolCall.id,
459+
error: err instanceof Error ? err.message : String(err),
460+
})
456461
})
462+
markToolResultSeen(toolCall.id)
457463
return
458464
}
459465
if (decision?.status === 'background') {
460466
toolCall.status = 'skipped'
461467
toolCall.endTime = Date.now()
462-
await markToolComplete(
468+
// Fire-and-forget: must NOT await — see deadlock note in executeToolAndReport
469+
markToolComplete(
463470
toolCall.id,
464471
toolCall.name,
465472
202,
466473
decision.message || 'Tool execution moved to background',
467474
{ background: true }
468-
)
469-
markToolResultSeen(toolCall.id)
470-
await options?.onEvent?.({
471-
type: 'tool_result',
472-
toolCallId: toolCall.id,
473-
data: {
474-
id: toolCall.id,
475-
name: toolCall.name,
476-
success: true,
477-
result: { background: true },
478-
},
475+
).catch((err) => {
476+
logger.error('markToolComplete fire-and-forget failed (subagent background)', {
477+
toolCallId: toolCall.id,
478+
error: err instanceof Error ? err.message : String(err),
479+
})
479480
})
481+
markToolResultSeen(toolCall.id)
480482
return
481483
}
482484
}
@@ -507,6 +509,24 @@ export const subAgentHandlers: Record<string, SSEHandler> = {
507509
markToolResultSeen(toolCallId)
508510
return
509511
}
512+
if (completion?.status === 'background') {
513+
toolCall.status = 'skipped'
514+
toolCall.endTime = Date.now()
515+
markToolComplete(
516+
toolCall.id,
517+
toolCall.name,
518+
202,
519+
completion.message || 'Tool execution moved to background',
520+
{ background: true }
521+
).catch((err) => {
522+
logger.error('markToolComplete fire-and-forget failed (subagent run tool background)', {
523+
toolCallId: toolCall.id,
524+
error: err instanceof Error ? err.message : String(err),
525+
})
526+
})
527+
markToolResultSeen(toolCallId)
528+
return
529+
}
510530
const success = completion?.status === 'success'
511531
toolCall.status = success ? 'success' : 'error'
512532
toolCall.endTime = Date.now()

apps/sim/lib/copilot/orchestrator/sse-handlers/tool-execution.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,8 @@ export async function waitForToolCompletion(
172172
if (
173173
decision?.status === 'success' ||
174174
decision?.status === 'error' ||
175-
decision?.status === 'rejected'
175+
decision?.status === 'rejected' ||
176+
decision?.status === 'background'
176177
) {
177178
return decision
178179
}

apps/sim/stores/panel/copilot/store.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,6 +1500,7 @@ export const useCopilotStore = create<CopilotStore>()(
15001500
else if (newState === 'success' || newState === 'accepted')
15011501
norm = ClientToolCallState.success
15021502
else if (newState === 'aborted') norm = ClientToolCallState.aborted
1503+
else if (newState === 'background') norm = ClientToolCallState.background
15031504
else if (typeof newState === 'number') norm = newState as unknown as ClientToolCallState
15041505
map[id] = {
15051506
...current,

0 commit comments

Comments
 (0)