Skip to content

Commit 4719b98

Browse files
icecrasher321claude
andcommitted
fix(copilot): stop calling a cancelled run performed
`performed` claims the run reached the end of its work, so a caller reads it as "never retry, just read the outcome". Every returned result carried it, including a cancelled or paused one — which stopped partway and may have run every block, one, or none. Those are `attempted`: an execution exists under this id, resolve it before deciding anything. That is true whether the cancellation landed before the first block or after the last. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 6caff35 commit 4719b98

2 files changed

Lines changed: 29 additions & 1 deletion

File tree

apps/sim/lib/copilot/tools/handlers/workflow/mutations.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,19 @@ describe('workflow mutation Copilot adapters', () => {
295295
run: () => executeRunWorkflow({ workflowId: 'workflow-1' }, context),
296296
effect: { phase: 'attempted', ids: { executionId: 'execution-1' } },
297297
},
298+
{
299+
label: 'cancelled before it could finish',
300+
arrange: () =>
301+
mocks.executeWorkflowUseCase.mockResolvedValueOnce({
302+
success: false,
303+
output: {},
304+
logs: [],
305+
status: 'cancelled',
306+
metadata: { executionId: 'execution-1' },
307+
}),
308+
run: () => executeRunWorkflow({ workflowId: 'workflow-1' }, context),
309+
effect: { phase: 'attempted', ids: { executionId: 'execution-1' } },
310+
},
298311
{
299312
label: 'completed',
300313
arrange: () =>

apps/sim/lib/copilot/tools/handlers/workflow/mutations.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,28 @@ function runRejected(error: string): ToolCallResult {
6060
return { success: false, error, effect: executionEffect(TOOL_EFFECT_PHASE.notAttempted) }
6161
}
6262

63+
/**
64+
* `performed` claims the run reached the end of its work, so only a run that terminated on
65+
* its own may carry it. A cancelled or paused one stopped partway — it may have run every
66+
* block, one, or none — and `attempted` is the phase that says exactly that: an execution
67+
* exists under this id, resolve it before deciding anything.
68+
*/
69+
function executionPhase(status: ExecutionResultStatus): ToolEffectPhase {
70+
return status === 'cancelled' || status === 'paused'
71+
? TOOL_EFFECT_PHASE.attempted
72+
: TOOL_EFFECT_PHASE.performed
73+
}
74+
75+
type ExecutionResultStatus = 'completed' | 'paused' | 'cancelled' | undefined
76+
6377
function buildExecutionOutput(
6478
result: {
6579
success: boolean
6680
metadata?: { executionId?: string }
6781
output?: unknown
6882
logs?: unknown[]
6983
error?: string
84+
status?: ExecutionResultStatus
7085
},
7186
extra?: Record<string, unknown>
7287
): ToolCallResult {
@@ -80,7 +95,7 @@ function buildExecutionOutput(
8095
logs: stripBinaryFields(result.logs),
8196
},
8297
error: result.success ? undefined : result.error || 'Workflow execution failed',
83-
effect: executionEffect(TOOL_EFFECT_PHASE.performed, result.metadata?.executionId),
98+
effect: executionEffect(executionPhase(result.status), result.metadata?.executionId),
8499
}
85100
}
86101

0 commit comments

Comments
 (0)