Skip to content

Commit 3bac67a

Browse files
committed
Reconcile the staging rebase: finish rename-followed ports, async selector resolution
Rebasing onto origin/staging carried staging's lib/copilot work into our renamed lib/mothership files via rename detection; this finishes what the replay left incomplete: - Complete the #7151 port: cancel_workflow_run handler + registration on the mothership executor (types, tests, and catalog entry had already rename-followed in). - pickRunBlockOutputs awaits the now-async resolveOutputIds (#7346 made selector resolution child-workflow-aware) and re-imports isValidUuid. - Slack execution stream + tool-call-lifecycle import getToolDisplayTitle from the mothership tool-display module (#7296 semantics kept). - Resolve leftover conflict markers from the first replay's failed batch checkout (browser-tool hardening #7311, YAML bounds #7319 kept). - Drop the obsolete lib/mothership/tools/server/blocks scan root: the block-metadata tool died in the dead-code sweep; blocks reads flow through the already-guarded v2 blocks routes. - Regenerate OpenAPI, CLI API, and CLI docs from the merged contracts. Claude-Session: https://claude.ai/code/session_01CgaxNAaeD3taGdghbXn17w
1 parent 756ba71 commit 3bac67a

16 files changed

Lines changed: 88 additions & 74 deletions

File tree

apps/docs/content/docs/cli/reference.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5157,7 +5157,7 @@ sim workflows run <workflowId> [options]
51575157
| `--input <json\|@file>` | No | Trigger input as JSON (JSON, or @path / @- to read a file or stdin). |
51585158
| `--async` | No | Queue the run and return immediately. |
51595159
| `--execution-timeout-seconds <value>` | No | Requested server-side timeout for an asynchronous run, in seconds. An upper bound, not the effective timeout: the run uses the smaller of this value and the plan's execution timeout, so requesting more than the plan allows silently yields the plan timeout. Rejected with `400` unless `async` is true. |
5160-
| `--select-output <value...>` | No | Return blockName.field values (e.g. agent_1.content) — in blockOutputs on a sync run, or from the streamed result with --follow; missing fields are omitted. Not available with --async (space-separated, or @path / @- with one value per line; @@value for a literal leading @). |
5160+
| `--select-output <value...>` | No | Return blockName.field values (e.g. agent_1.content), or childWorkflowId.blockName.field for a child workflow (applies to every invocation) — in blockOutputs on a sync run, or from the streamed result with --follow; missing fields are omitted. Not available with --async (space-separated, or @path / @- with one value per line; @@value for a literal leading @). |
51615161
| `--include-file-base64` | No | Inline eligible output files as base64 content. Rejected when `async` is true. |
51625162
| `--no-include-file-base64` | No | Send --include-file-base64 as false. |
51635163
| `--base64-max-bytes <value>` | No | Maximum total bytes of file content to inline as base64, lowering but never raising the server limit of 16 MiB. Rejected when `async` is true. |

apps/docs/content/docs/cli/workflows.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ sim workflows run <workflowId> [options]
532532
| `--input <json\|@file>` | No | Trigger input as JSON (JSON, or @path / @- to read a file or stdin). |
533533
| `--async` | No | Queue the run and return immediately. |
534534
| `--execution-timeout-seconds <value>` | No | Requested server-side timeout for an asynchronous run, in seconds. An upper bound, not the effective timeout: the run uses the smaller of this value and the plan's execution timeout, so requesting more than the plan allows silently yields the plan timeout. Rejected with `400` unless `async` is true. |
535-
| `--select-output <value...>` | No | Return blockName.field values (e.g. agent_1.content) — in blockOutputs on a sync run, or from the streamed result with --follow; missing fields are omitted. Not available with --async (space-separated, or @path / @- with one value per line; @@value for a literal leading @). |
535+
| `--select-output <value...>` | No | Return blockName.field values (e.g. agent_1.content), or childWorkflowId.blockName.field for a child workflow (applies to every invocation) — in blockOutputs on a sync run, or from the streamed result with --follow; missing fields are omitted. Not available with --async (space-separated, or @path / @- with one value per line; @@value for a literal leading @). |
536536
| `--include-file-base64` | No | Inline eligible output files as base64 content. Rejected when `async` is true. |
537537
| `--no-include-file-base64` | No | Send --include-file-base64 as false. |
538538
| `--base64-max-bytes <value>` | No | Maximum total bytes of file content to inline as base64, lowering but never raising the server limit of 16 MiB. Rejected when `async` is true. |

apps/docs/openapi-v2-workflows.json

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8600,6 +8600,10 @@
86008600
"StoredChatDeploymentOutputConfig": {
86018601
"type": "object",
86028602
"properties": {
8603+
"workflowId": {
8604+
"description": "Child workflow containing the selected block. Omitted for the deployed workflow.",
8605+
"type": "string"
8606+
},
86038607
"blockId": {
86048608
"type": "string",
86058609
"description": "Block whose output the chat streams."
@@ -8909,6 +8913,11 @@
89098913
"ChatDeploymentOutputConfig": {
89108914
"type": "object",
89118915
"properties": {
8916+
"workflowId": {
8917+
"description": "Child workflow containing the selected block. Omit for the deployed workflow.",
8918+
"type": "string",
8919+
"minLength": 1
8920+
},
89128921
"blockId": {
89138922
"type": "string",
89148923
"minLength": 1,
@@ -9330,7 +9339,7 @@
93309339
"type": "boolean"
93319340
},
93329341
"selectedOutputs": {
9333-
"description": "Block output references to include in the response, as `blockId`, `blockId.path`, or `BlockName.path` (resolved against the workflow state being run). On a sync request the named outputs come back in `blockOutputs`, keyed by these selector strings; on a stream they shape the streamed envelope. Selectors that resolve to no block or no value are omitted. Rejected when `async` is true — a queued run has produced nothing to select; narrow the finished run via the run resource instead.",
9342+
"description": "Block output references to include in the response. Use `<blockName>.<outputPath>` for the executed workflow or `<childWorkflowId>.<blockName>.<outputPath>` for a child workflow; block names are normalized workflow reference names, and selecting a child workflow applies to every invocation of it. On a sync request the named outputs come back in `blockOutputs`, keyed by these selector strings; on a stream they shape the streamed envelope. Selectors that resolve to no block or no value are omitted. Rejected when `async` is true — a queued run has produced nothing to select; narrow the finished run via the run resource instead.",
93349343
"maxItems": 100,
93359344
"type": "array",
93369345
"items": {
@@ -10023,7 +10032,7 @@
1002310032
"description": "Whether a paused execution was cancelled."
1002410033
},
1002510034
"reason": {
10026-
"description": "Machine-readable cancellation outcome, present on every cancellation including full successes. `recorded` is the success value. `already_cancelled`, `already_completed`, and `already_failed` mean the run had already reached that terminal state, so nothing was cancelled and `durablyRecorded` is false. `redis_unavailable` and `redis_write_failed` mean the distributed cancellation signal was not written, so an already-running execution may not observe the cancellation. `paused_event_publish_failed` and `paused_database_cancel_failed` name the failing step for a paused run.",
10035+
"description": "Machine-readable cancellation outcome, present on every cancellation including full successes. `recorded` and `queue_cancelled` are successful cancellation values. `already_cancelled`, `already_completed`, and `already_failed` mean the run had already reached that terminal state, so nothing was cancelled and `durablyRecorded` is false. The remaining values identify a degraded or incomplete cancellation step.",
1002710036
"type": "string",
1002810037
"enum": [
1002910038
"recorded",
@@ -10033,7 +10042,10 @@
1003310042
"redis_unavailable",
1003410043
"redis_write_failed",
1003510044
"paused_event_publish_failed",
10036-
"paused_database_cancel_failed"
10045+
"paused_database_cancel_failed",
10046+
"queue_cancelled",
10047+
"active_resume_signal_failed",
10048+
"cancellation_not_finalized"
1003710049
]
1003810050
}
1003910051
},

apps/sim/components/agent-stream/tool-call-lifecycle.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@
77
* implementation so the three surfaces cannot drift.
88
*/
99

10-
<<<<<<< HEAD
11-
import { getToolDisplayTitle } from '@/lib/copilot/tools/tool-display'
12-
=======
13-
import { humanizeToolName } from '@/lib/mothership/tools/tool-display'
14-
>>>>>>> 2ff9a4fa01 (feat: sim side of the mothership revamp)
10+
import { getToolDisplayTitle } from '@/lib/mothership/tools/tool-display'
1511

1612
export type AgentStreamToolStatus = 'running' | 'success' | 'error' | 'cancelled'
1713

apps/sim/lib/mothership/tool-executor/register-handlers.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { createLogger } from '@sim/logger'
22
import {
3+
CancelWorkflowRun,
34
RunBlock,
45
RunFromBlock,
56
RunWorkflow,
@@ -11,6 +12,7 @@ import { executeFunctionExecute } from '../tools/handlers/function-execute'
1112
import { executeRunCode } from '../tools/handlers/run-code'
1213
import { executeSimCli } from '../tools/handlers/sim-cli'
1314
import {
15+
executeCancelWorkflowRun,
1416
executeRunBlock,
1517
executeRunFromBlock,
1618
executeRunWorkflow,
@@ -47,6 +49,7 @@ function h(fn: (params: any, context: any) => Promise<any>): ToolHandler {
4749
*/
4850
function buildHandlerMap(): Record<string, ToolHandler> {
4951
return {
52+
[CancelWorkflowRun.id]: h(executeCancelWorkflowRun),
5053
[RunWorkflow.id]: h(executeRunWorkflow),
5154
[RunWorkflowUntilBlock.id]: h(executeRunWorkflowUntilBlock),
5255
[RunFromBlock.id]: h(executeRunFromBlock),

apps/sim/lib/mothership/tool-executor/router.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
*/
44

55
import { describe, expect, it } from 'vitest'
6-
import { hasHandler } from '@/lib/copilot/tool-executor/executor'
7-
import { ensureHandlersRegistered } from '@/lib/copilot/tool-executor/register-handlers'
6+
import { hasHandler } from '@/lib/mothership/tool-executor/executor'
7+
import { ensureHandlersRegistered } from '@/lib/mothership/tool-executor/register-handlers'
88
import {
99
getToolEntry,
1010
isSimExecuted,
1111
toolRequiresApproval,
12-
} from '@/lib/copilot/tool-executor/router'
12+
} from '@/lib/mothership/tool-executor/router'
1313

1414
describe('workflow-run cancellation tool routing', () => {
1515
it('routes cancellation through Sim with write permission and explicit approval', () => {

apps/sim/lib/mothership/tools/client/browser-tool-execution.test.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,8 @@ vi.mock('@/lib/mothership/tools/client/completion', () => ({
2929
reportClientToolCompletionOnPageExit: mockReportCompletionOnPageExit,
3030
}))
3131

32-
<<<<<<< HEAD:apps/sim/lib/copilot/tools/client/browser-tool-execution.test.ts
33-
import { executeBrowserToolOnClient } from '@/lib/copilot/tools/client/browser-tool-execution'
34-
import { BrowserToolReplayLedger } from '@/lib/copilot/tools/client/browser-tool-replay-ledger'
35-
=======
3632
import { executeBrowserToolOnClient } from '@/lib/mothership/tools/client/browser-tool-execution'
37-
>>>>>>> 2ff9a4fa01 (feat: sim side of the mothership revamp):apps/sim/lib/mothership/tools/client/browser-tool-execution.test.ts
33+
import { BrowserToolReplayLedger } from '@/lib/mothership/tools/client/browser-tool-replay-ledger'
3834
import { useBrowserSessionStore } from '@/stores/browser-session/store'
3935

4036
const CHAT_SCOPE = 'chat-test'

apps/sim/lib/mothership/tools/client/browser-tool-execution.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,9 @@ import {
2727
ASYNC_TOOL_CONFIRMATION_STATUS,
2828
type AsyncCompletionData,
2929
type AsyncConfirmationStatus,
30-
<<<<<<< HEAD:apps/sim/lib/copilot/tools/client/browser-tool-execution.ts
31-
} from '@/lib/copilot/async-runs/lifecycle'
32-
import { COPILOT_CONFIRM_API_PATH } from '@/lib/copilot/constants'
33-
import { BrowserToolReplayLedger } from '@/lib/copilot/tools/client/browser-tool-replay-ledger'
34-
=======
3530
} from '@/lib/mothership/async-runs/lifecycle'
3631
import { COPILOT_CONFIRM_API_PATH } from '@/lib/mothership/constants'
37-
>>>>>>> 2ff9a4fa01 (feat: sim side of the mothership revamp):apps/sim/lib/mothership/tools/client/browser-tool-execution.ts
32+
import { BrowserToolReplayLedger } from '@/lib/mothership/tools/client/browser-tool-replay-ledger'
3833
import {
3934
reportClientToolCompletion,
4035
reportClientToolCompletionOnPageExit,

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,9 @@
22
* @vitest-environment node
33
*/
44
import { beforeEach, describe, expect, it, vi } from 'vitest'
5-
<<<<<<< HEAD:apps/sim/lib/copilot/tools/handlers/workflow/mutations.test.ts
6-
import type { ExecutionContext } from '@/lib/copilot/request/types'
7-
import type { CancelWorkflowRunParams } from '@/lib/copilot/tools/handlers/param-types'
85
import { WorkflowRunAlreadyTerminalError } from '@/lib/execution/workflow-run-already-terminal-error'
9-
=======
106
import type { ExecutionContext } from '@/lib/mothership/request/types'
11-
>>>>>>> 2ff9a4fa01 (feat: sim side of the mothership revamp):apps/sim/lib/mothership/tools/handlers/workflow/mutations.test.ts
7+
import type { CancelWorkflowRunParams } from '@/lib/mothership/tools/handlers/param-types'
128

139
const { mocks } = vi.hoisted(() => ({
1410
mocks: {

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
type ToolEffectPhase,
1515
} from '@/lib/mothership/tool-executor/types'
1616
import type {
17+
CancelWorkflowRunParams,
1718
CreateWorkflowParams,
1819
GenerateApiKeyParams,
1920
MoveWorkflowParams,
@@ -28,6 +29,7 @@ import type {
2829
} from '@/lib/mothership/tools/handlers/param-types'
2930
import { requireCopilotWorkspace } from '@/lib/mothership/tools/server/workspace-scope'
3031
import { decodeVfsPathSegments, encodeVfsPathSegments } from '@/lib/mothership/vfs/path-utils'
32+
import { cancelWorkflowRun } from '@/lib/workflows/application/cancel-run'
3133
import { createWorkflow } from '@/lib/workflows/application/create-workflow'
3234
import { moveWorkflowsBulk } from '@/lib/workflows/application/move-workflows-bulk'
3335
import {
@@ -281,6 +283,45 @@ export async function executeRunWorkflow(
281283
}
282284
}
283285

286+
export async function executeCancelWorkflowRun(
287+
params: CancelWorkflowRunParams,
288+
context: ExecutionContext
289+
): Promise<ToolCallResult> {
290+
try {
291+
const executionId = resolveInputFromExecutionId(params.executionId)
292+
if (!executionId) {
293+
return { success: false, error: 'executionId is required' }
294+
}
295+
296+
assertWorkflowMutationNotAborted(
297+
context,
298+
'Request aborted before workflow run cancellation could be applied.'
299+
)
300+
const result = await executeCopilotWorkflowUseCase(context, cancelWorkflowRun, {
301+
runId: executionId,
302+
...(context.abortSignal ? { abortSignal: context.abortSignal } : {}),
303+
})
304+
305+
return {
306+
success: result.success,
307+
output: {
308+
workflowId: result.workflowId,
309+
executionId: result.executionId,
310+
durablyRecorded: result.durablyRecorded,
311+
locallyAborted: result.locallyAborted,
312+
pausedCancelled: result.pausedCancelled,
313+
reason: result.reason,
314+
},
315+
error: result.success ? undefined : 'Workflow run cancellation could not be completed',
316+
}
317+
} catch (error) {
318+
return {
319+
success: false,
320+
error: messageForCopilotWorkflowError(error, 'Failed to cancel workflow run'),
321+
}
322+
}
323+
}
324+
284325
export async function executeSetGlobalWorkflowVariables(
285326
params: SetGlobalWorkflowVariablesParams,
286327
context: ExecutionContext

0 commit comments

Comments
 (0)