@bastani/atomic 0.9.0-alpha.1 → 0.9.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/dist/builtin/cursor/CHANGELOG.md +6 -0
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/intercom/CHANGELOG.md +6 -0
- package/dist/builtin/intercom/package.json +2 -2
- package/dist/builtin/mcp/CHANGELOG.md +6 -0
- package/dist/builtin/mcp/package.json +3 -3
- package/dist/builtin/subagents/CHANGELOG.md +6 -0
- package/dist/builtin/subagents/package.json +4 -4
- package/dist/builtin/web-access/CHANGELOG.md +6 -0
- package/dist/builtin/web-access/package.json +2 -2
- package/dist/builtin/workflows/CHANGELOG.md +12 -0
- package/dist/builtin/workflows/README.md +189 -122
- package/dist/builtin/workflows/builtin/deep-research-codebase.ts +30 -27
- package/dist/builtin/workflows/builtin/goal-runner.ts +10 -17
- package/dist/builtin/workflows/builtin/goal.ts +39 -44
- package/dist/builtin/workflows/builtin/index.d.ts +1 -0
- package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +16 -17
- package/dist/builtin/workflows/builtin/open-claude-design.d.ts +1 -0
- package/dist/builtin/workflows/builtin/open-claude-design.ts +42 -50
- package/dist/builtin/workflows/builtin/ralph.ts +44 -41
- package/dist/builtin/workflows/package.json +2 -2
- package/dist/builtin/workflows/src/authoring/typebox-defaults.d.ts +41 -0
- package/dist/builtin/workflows/src/authoring/typebox-defaults.ts +217 -0
- package/dist/builtin/workflows/src/authoring/workflow.ts +184 -0
- package/dist/builtin/workflows/src/authoring.d.ts +14 -66
- package/dist/builtin/workflows/src/engine/graph-inference.ts +100 -0
- package/dist/builtin/workflows/src/engine/options.ts +40 -0
- package/dist/builtin/workflows/src/engine/primitives/chain.ts +29 -0
- package/dist/builtin/workflows/src/engine/primitives/exit.ts +2 -0
- package/dist/builtin/workflows/src/engine/primitives/parallel.ts +47 -0
- package/dist/builtin/workflows/src/engine/primitives/task.ts +108 -0
- package/dist/builtin/workflows/src/engine/primitives/ui.ts +41 -0
- package/dist/builtin/workflows/src/engine/primitives/workflow.ts +159 -0
- package/dist/builtin/workflows/src/engine/replay.ts +8 -0
- package/dist/builtin/workflows/src/engine/run.ts +356 -0
- package/dist/builtin/workflows/src/engine/runtime.ts +160 -0
- package/dist/builtin/workflows/src/extension/workflow-module-loader.ts +9 -3
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +0 -18
- package/dist/builtin/workflows/src/index.ts +0 -2
- package/dist/builtin/workflows/src/runs/background/runner.ts +6 -3
- package/dist/builtin/workflows/src/runs/foreground/executor-child-boundary.ts +3 -3
- package/dist/builtin/workflows/src/runs/foreground/executor-child-helpers.ts +4 -4
- package/dist/builtin/workflows/src/runs/foreground/executor-child-workflow.ts +1 -158
- package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-outputs.ts +2 -2
- package/dist/builtin/workflows/src/runs/foreground/executor-prompt-nodes.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-run.ts +1 -359
- package/dist/builtin/workflows/src/runs/foreground/executor-scheduler.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +2 -5
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +12 -4
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-replay.ts +4 -3
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-types.ts +9 -2
- package/dist/builtin/workflows/src/runs/foreground/executor-task-context.ts +2 -132
- package/dist/builtin/workflows/src/runs/foreground/executor-types.ts +2 -2
- package/dist/builtin/workflows/src/runs/shared/graph-inference.ts +2 -100
- package/dist/builtin/workflows/src/sdk-surface.ts +6 -9
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +9 -3
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +17 -3
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +3 -33
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +9 -81
- package/dist/builtin/workflows/src/shared/types.ts +25 -8
- package/dist/builtin/workflows/src/shared/workflow-authoring-types.d.ts +49 -0
- package/dist/builtin/workflows/src/shared/workflow-authoring-types.ts +84 -0
- package/dist/builtin/workflows/src/workflows/registry.ts +7 -3
- package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-auto-compaction.js +6 -1
- package/dist/core/agent-session-auto-compaction.js.map +1 -1
- package/dist/core/agent-session-bash.d.ts.map +1 -1
- package/dist/core/agent-session-bash.js +0 -5
- package/dist/core/agent-session-bash.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +0 -2
- package/dist/core/agent-session-methods.d.ts.map +1 -1
- package/dist/core/agent-session-methods.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +0 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +0 -1
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
- package/dist/core/agent-session-tool-registry.js +0 -2
- package/dist/core/agent-session-tool-registry.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +0 -2
- package/dist/core/agent-session-types.d.ts.map +1 -1
- package/dist/core/agent-session-types.js.map +1 -1
- package/dist/core/agent-session.d.ts +0 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +0 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/atomic-guide-command.d.ts.map +1 -1
- package/dist/core/atomic-guide-command.js +1 -1
- package/dist/core/atomic-guide-command.js.map +1 -1
- package/dist/core/extensions/loader-core.d.ts +1 -3
- package/dist/core/extensions/loader-core.d.ts.map +1 -1
- package/dist/core/extensions/loader-core.js +13 -6
- package/dist/core/extensions/loader-core.js.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts +7 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.js +34 -2
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +2 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +2 -1
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/index.d.ts +0 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +0 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/model-registry-builtins.d.ts.map +1 -1
- package/dist/core/model-registry-builtins.js +6 -0
- package/dist/core/model-registry-builtins.js.map +1 -1
- package/dist/core/model-registry-schemas.d.ts +65 -13
- package/dist/core/model-registry-schemas.d.ts.map +1 -1
- package/dist/core/model-registry-schemas.js +10 -0
- package/dist/core/model-registry-schemas.js.map +1 -1
- package/dist/core/resource-loader-core.d.ts +1 -0
- package/dist/core/resource-loader-core.d.ts.map +1 -1
- package/dist/core/resource-loader-core.js +2 -0
- package/dist/core/resource-loader-core.js.map +1 -1
- package/dist/core/resource-loader-extensions.d.ts.map +1 -1
- package/dist/core/resource-loader-extensions.js +3 -3
- package/dist/core/resource-loader-extensions.js.map +1 -1
- package/dist/core/resource-loader-internals.d.ts +1 -0
- package/dist/core/resource-loader-internals.d.ts.map +1 -1
- package/dist/core/resource-loader-internals.js.map +1 -1
- package/dist/core/resource-loader-reload.d.ts.map +1 -1
- package/dist/core/resource-loader-reload.js +6 -2
- package/dist/core/resource-loader-reload.js.map +1 -1
- package/dist/core/sdk-exports.d.ts +1 -1
- package/dist/core/sdk-exports.d.ts.map +1 -1
- package/dist/core/sdk-exports.js.map +1 -1
- package/dist/core/sdk-types.d.ts +0 -3
- package/dist/core/sdk-types.d.ts.map +1 -1
- package/dist/core/sdk-types.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +0 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager-history.d.ts.map +1 -1
- package/dist/core/session-manager-history.js +2 -1
- package/dist/core/session-manager-history.js.map +1 -1
- package/dist/core/tools/bash.d.ts +0 -5
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +10 -11
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-diff-preserve.d.ts +18 -0
- package/dist/core/tools/edit-diff-preserve.d.ts.map +1 -0
- package/dist/core/tools/edit-diff-preserve.js +85 -0
- package/dist/core/tools/edit-diff-preserve.js.map +1 -0
- package/dist/core/tools/edit-diff.d.ts +3 -2
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +15 -18
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/index.d.ts +0 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +0 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +2 -2
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/model-search.d.ts +5 -0
- package/dist/modes/interactive/model-search.d.ts.map +1 -1
- package/dist/modes/interactive/model-search.js +9 -0
- package/dist/modes/interactive/model-search.js.map +1 -1
- package/dist/utils/shell.d.ts +1 -0
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +12 -5
- package/dist/utils/shell.js.map +1 -1
- package/docs/custom-provider.md +4 -3
- package/docs/models.md +3 -2
- package/docs/packages.md +2 -2
- package/docs/quickstart.md +1 -1
- package/docs/sdk.md +2 -40
- package/docs/security.md +1 -1
- package/docs/workflows.md +238 -173
- package/package.json +5 -5
- package/dist/builtin/workflows/src/workflows/define-workflow.ts +0 -277
- package/dist/core/tools/bash-policy-compile.d.ts +0 -5
- package/dist/core/tools/bash-policy-compile.d.ts.map +0 -1
- package/dist/core/tools/bash-policy-compile.js +0 -241
- package/dist/core/tools/bash-policy-compile.js.map +0 -1
- package/dist/core/tools/bash-policy-evaluate.d.ts +0 -3
- package/dist/core/tools/bash-policy-evaluate.d.ts.map +0 -1
- package/dist/core/tools/bash-policy-evaluate.js +0 -92
- package/dist/core/tools/bash-policy-evaluate.js.map +0 -1
- package/dist/core/tools/bash-policy-format.d.ts +0 -5
- package/dist/core/tools/bash-policy-format.d.ts.map +0 -1
- package/dist/core/tools/bash-policy-format.js +0 -49
- package/dist/core/tools/bash-policy-format.js.map +0 -1
- package/dist/core/tools/bash-policy-parser.d.ts +0 -4
- package/dist/core/tools/bash-policy-parser.d.ts.map +0 -1
- package/dist/core/tools/bash-policy-parser.js +0 -155
- package/dist/core/tools/bash-policy-parser.js.map +0 -1
- package/dist/core/tools/bash-policy-segment.d.ts +0 -3
- package/dist/core/tools/bash-policy-segment.d.ts.map +0 -1
- package/dist/core/tools/bash-policy-segment.js +0 -275
- package/dist/core/tools/bash-policy-segment.js.map +0 -1
- package/dist/core/tools/bash-policy-shell.d.ts +0 -11
- package/dist/core/tools/bash-policy-shell.d.ts.map +0 -1
- package/dist/core/tools/bash-policy-shell.js +0 -267
- package/dist/core/tools/bash-policy-shell.js.map +0 -1
- package/dist/core/tools/bash-policy-types.d.ts +0 -146
- package/dist/core/tools/bash-policy-types.d.ts.map +0 -1
- package/dist/core/tools/bash-policy-types.js +0 -2
- package/dist/core/tools/bash-policy-types.js.map +0 -1
- package/dist/core/tools/bash-policy.d.ts +0 -6
- package/dist/core/tools/bash-policy.d.ts.map +0 -1
- package/dist/core/tools/bash-policy.js +0 -5
- package/dist/core/tools/bash-policy.js.map +0 -1
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
import type { RunSnapshot } from "../shared/store-types.js";
|
|
2
|
+
import type {
|
|
3
|
+
WorkflowDefinition,
|
|
4
|
+
WorkflowInputValues,
|
|
5
|
+
WorkflowOutputValues,
|
|
6
|
+
WorkflowRunContext,
|
|
7
|
+
} from "../shared/types.js";
|
|
8
|
+
import type { WorkflowFailure } from "../shared/workflow-failures.js";
|
|
9
|
+
import { classifyWorkflowFailure } from "../shared/workflow-failures.js";
|
|
10
|
+
import { store as defaultStore } from "../shared/store.js";
|
|
11
|
+
import { appendRunStart } from "../shared/persistence-session-entries.js";
|
|
12
|
+
import { GraphFrontierTracker } from "./graph-inference.js";
|
|
13
|
+
import { EngineRuntime } from "./runtime.js";
|
|
14
|
+
import type { EngineChildRunOptions, EngineStageRuntimeOptions, EngineWorkflowBoundaryOptions } from "./options.js";
|
|
15
|
+
import { createContinuationReplayIndex } from "./replay.js";
|
|
16
|
+
import { buildExitGatedUiContext } from "./primitives/ui.js";
|
|
17
|
+
import { createWorkflowExitManager } from "./primitives/exit.js";
|
|
18
|
+
import { createWorkflowTaskRunners } from "./primitives/task.js";
|
|
19
|
+
import { createChildWorkflowRunner } from "./primitives/workflow.js";
|
|
20
|
+
import { createRunLimiter } from "../runs/shared/concurrency.js";
|
|
21
|
+
import { stageControlRegistry as defaultStageControlRegistry } from "../runs/foreground/stage-control-registry.js";
|
|
22
|
+
import type { RunOpts, RunResult } from "../runs/foreground/executor-types.js";
|
|
23
|
+
import { unknownErrorMessage, findWorkflowExitSignal, parentWorkflowExitAbortReason } from "../runs/foreground/executor-abort.js";
|
|
24
|
+
import { resolveAndValidateInputs, resolveInputConcurrency, resolveInputRuntimeDefaults } from "../runs/foreground/executor-inputs.js";
|
|
25
|
+
import { workflowCwdWithInputWorktree } from "../runs/foreground/executor-direct-helpers.js";
|
|
26
|
+
import { createStageScheduler } from "../runs/foreground/executor-scheduler.js";
|
|
27
|
+
import { createRunFinalizers } from "../runs/foreground/executor-run-finalizers.js";
|
|
28
|
+
import { buildPromptNodeUiAdapter } from "../runs/foreground/executor-prompt-nodes.js";
|
|
29
|
+
import {
|
|
30
|
+
appendRunEndWhenRecorded,
|
|
31
|
+
assertWorkflowCreatedStage,
|
|
32
|
+
finalizeKilled,
|
|
33
|
+
finalizeKilledByFailure,
|
|
34
|
+
recordActiveBlockedFailure,
|
|
35
|
+
reconcileTerminalRunResult,
|
|
36
|
+
selectRunFailureDisposition,
|
|
37
|
+
} from "../runs/foreground/executor-lifecycle.js";
|
|
38
|
+
import { assertWorkflowRunOutputs, normalizeWorkflowRunOutput } from "../runs/foreground/executor-outputs.js";
|
|
39
|
+
import { isWorkflowDefinition, workflowDefinitionRequirementMessage } from "../runs/foreground/executor-child-helpers.js";
|
|
40
|
+
|
|
41
|
+
function nextEventLoopTurn(): Promise<void> {
|
|
42
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
type WorkflowRunInputArgument = Parameters<typeof resolveAndValidateInputs>[1];
|
|
46
|
+
|
|
47
|
+
export function run<
|
|
48
|
+
TInputs extends WorkflowInputValues,
|
|
49
|
+
TOutputs extends WorkflowOutputValues,
|
|
50
|
+
TRunInputs extends WorkflowInputValues = TInputs,
|
|
51
|
+
>(
|
|
52
|
+
def: WorkflowDefinition<TInputs, TOutputs, TRunInputs>,
|
|
53
|
+
inputs: WorkflowRunInputArgument,
|
|
54
|
+
opts?: RunOpts,
|
|
55
|
+
): Promise<RunResult<TOutputs>>;
|
|
56
|
+
export async function run<
|
|
57
|
+
TInputs extends WorkflowInputValues,
|
|
58
|
+
TRunInputs extends WorkflowInputValues = TInputs,
|
|
59
|
+
>(
|
|
60
|
+
def: WorkflowDefinition<TInputs, WorkflowOutputValues, TRunInputs>,
|
|
61
|
+
inputs: WorkflowRunInputArgument,
|
|
62
|
+
opts: RunOpts = {},
|
|
63
|
+
): Promise<RunResult> {
|
|
64
|
+
if (!isWorkflowDefinition(def)) throw new Error(workflowDefinitionRequirementMessage("run(definition, inputs)", def));
|
|
65
|
+
|
|
66
|
+
const activeStore = opts.store ?? defaultStore;
|
|
67
|
+
const adapters = opts.adapters ?? {};
|
|
68
|
+
// Prompt-node UI is the graph-mode transport and intentionally takes precedence
|
|
69
|
+
// over an injected RunOpts.ui adapter; warn because that adapter will be ignored.
|
|
70
|
+
if (opts.usePromptNodesForUi === true && opts.ui !== undefined) {
|
|
71
|
+
console.warn("atomic-workflows: usePromptNodesForUi ignores the provided RunOpts.ui adapter");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const depth = opts.depth ?? 0;
|
|
75
|
+
const maxDepth = opts.config?.maxDepth ?? 4;
|
|
76
|
+
if (depth >= maxDepth) {
|
|
77
|
+
return {
|
|
78
|
+
runId: opts.runId ?? crypto.randomUUID(),
|
|
79
|
+
status: "failed",
|
|
80
|
+
error: `atomic-workflows: maxDepth exceeded (max ${maxDepth})`,
|
|
81
|
+
stages: [],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const resolvedInputs = resolveAndValidateInputs(def.inputs, inputs, `workflow "${def.name}"`);
|
|
86
|
+
const runId = opts.runId ?? crypto.randomUUID();
|
|
87
|
+
const exitScope = Symbol(`workflow-exit:${runId}`);
|
|
88
|
+
const ownController = new AbortController();
|
|
89
|
+
const callerSignal = opts.signal;
|
|
90
|
+
if (callerSignal) {
|
|
91
|
+
if (callerSignal.aborted) ownController.abort(callerSignal.reason);
|
|
92
|
+
else callerSignal.addEventListener("abort", () => { ownController.abort(callerSignal.reason); }, { once: true });
|
|
93
|
+
}
|
|
94
|
+
const exit = createWorkflowExitManager({ runId, exitScope, controller: ownController });
|
|
95
|
+
|
|
96
|
+
const runSnapshot: RunSnapshot = {
|
|
97
|
+
id: runId,
|
|
98
|
+
name: def.name,
|
|
99
|
+
inputs: Object.freeze(resolvedInputs),
|
|
100
|
+
status: "running" as const,
|
|
101
|
+
stages: [],
|
|
102
|
+
startedAt: Date.now(),
|
|
103
|
+
...(opts.parentRun !== undefined ? {
|
|
104
|
+
parentRunId: opts.parentRun.runId,
|
|
105
|
+
parentStageId: opts.parentRun.stageId,
|
|
106
|
+
rootRunId: opts.parentRun.rootRunId,
|
|
107
|
+
} : {}),
|
|
108
|
+
...(opts.continuation !== undefined ? {
|
|
109
|
+
resumedFromRunId: opts.continuation.source.id,
|
|
110
|
+
resumeFromStageId: opts.continuation.resumeFromStageId,
|
|
111
|
+
} : {}),
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const classifiedFailures = new Map<unknown, WorkflowFailure>();
|
|
115
|
+
const classifyExecutorFailure = (error: unknown): WorkflowFailure => {
|
|
116
|
+
const cached = classifiedFailures.get(error);
|
|
117
|
+
if (cached !== undefined) return cached;
|
|
118
|
+
let classified: WorkflowFailure;
|
|
119
|
+
try {
|
|
120
|
+
classified = classifyWorkflowFailure(error);
|
|
121
|
+
} catch {
|
|
122
|
+
classified = classifyWorkflowFailure(new Error(unknownErrorMessage(error)));
|
|
123
|
+
}
|
|
124
|
+
classifiedFailures.set(error, classified);
|
|
125
|
+
return classified;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
activeStore.recordRunStart(runSnapshot);
|
|
129
|
+
if (!opts.signal) opts.cancellation?.register(runId, ownController);
|
|
130
|
+
opts.onRunStart?.(runSnapshot);
|
|
131
|
+
if (opts.persistence) {
|
|
132
|
+
appendRunStart(opts.persistence, {
|
|
133
|
+
runId,
|
|
134
|
+
name: def.name,
|
|
135
|
+
inputs: resolvedInputs,
|
|
136
|
+
...(runSnapshot.parentRunId !== undefined ? { parentRunId: runSnapshot.parentRunId } : {}),
|
|
137
|
+
...(runSnapshot.parentStageId !== undefined ? { parentStageId: runSnapshot.parentStageId } : {}),
|
|
138
|
+
...(runSnapshot.rootRunId !== undefined ? { rootRunId: runSnapshot.rootRunId } : {}),
|
|
139
|
+
...(runSnapshot.resumedFromRunId !== undefined ? { resumedFromRunId: runSnapshot.resumedFromRunId } : {}),
|
|
140
|
+
...(runSnapshot.resumeFromStageId !== undefined ? { resumeFromStageId: runSnapshot.resumeFromStageId } : {}),
|
|
141
|
+
ts: runSnapshot.startedAt,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const tracker = new GraphFrontierTracker();
|
|
146
|
+
const inputConcurrency = resolveInputConcurrency(def.inputs, resolvedInputs);
|
|
147
|
+
const inputRuntimeDefaults = resolveInputRuntimeDefaults(def, resolvedInputs);
|
|
148
|
+
const workflowInvocationCwd = opts.cwd ?? process.cwd();
|
|
149
|
+
let workflowCwd: string | undefined;
|
|
150
|
+
const resolveWorkflowCwd = (): string => {
|
|
151
|
+
workflowCwd ??= workflowCwdWithInputWorktree(inputRuntimeDefaults, workflowInvocationCwd);
|
|
152
|
+
return workflowCwd;
|
|
153
|
+
};
|
|
154
|
+
const limiter = createRunLimiter(inputConcurrency ?? opts.config?.defaultConcurrency);
|
|
155
|
+
const stageRegistry = opts.stageControlRegistry ?? defaultStageControlRegistry;
|
|
156
|
+
const replayIndex = createContinuationReplayIndex(opts.continuation);
|
|
157
|
+
const scheduler = createStageScheduler({
|
|
158
|
+
runId,
|
|
159
|
+
runSnapshot,
|
|
160
|
+
activeStore,
|
|
161
|
+
tracker,
|
|
162
|
+
stageRegistry: () => stageRegistry,
|
|
163
|
+
});
|
|
164
|
+
ownController.signal.addEventListener(
|
|
165
|
+
"abort",
|
|
166
|
+
() => scheduler.rejectReleaseBarriers(ownController.signal.reason ?? new Error("atomic-workflows: run aborted")),
|
|
167
|
+
{ once: true },
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
const finalizers = createRunFinalizers({
|
|
171
|
+
def,
|
|
172
|
+
runId,
|
|
173
|
+
runSnapshot,
|
|
174
|
+
activeStore,
|
|
175
|
+
opts,
|
|
176
|
+
classifyExecutorFailure,
|
|
177
|
+
drainWorkflowExitCleanups: exit.drainWorkflowExitCleanups,
|
|
178
|
+
});
|
|
179
|
+
const stageOptions: EngineStageRuntimeOptions = {
|
|
180
|
+
continuation: opts.continuation,
|
|
181
|
+
models: opts.models,
|
|
182
|
+
executionMode: opts.executionMode,
|
|
183
|
+
defaultSessionDir: opts.defaultSessionDir,
|
|
184
|
+
persistence: opts.persistence,
|
|
185
|
+
onStageStart: opts.onStageStart,
|
|
186
|
+
onStageEnd: opts.onStageEnd,
|
|
187
|
+
confirmStageReadiness: opts.confirmStageReadiness,
|
|
188
|
+
usePromptNodesForUi: opts.usePromptNodesForUi,
|
|
189
|
+
};
|
|
190
|
+
const workflowBoundaryOptions: EngineWorkflowBoundaryOptions = {
|
|
191
|
+
persistence: opts.persistence,
|
|
192
|
+
onStageStart: opts.onStageStart,
|
|
193
|
+
onStageEnd: opts.onStageEnd,
|
|
194
|
+
};
|
|
195
|
+
const childRunOptions: EngineChildRunOptions = {
|
|
196
|
+
adapters: opts.adapters,
|
|
197
|
+
ui: opts.ui,
|
|
198
|
+
executionMode: opts.executionMode,
|
|
199
|
+
defaultSessionDir: opts.defaultSessionDir,
|
|
200
|
+
usePromptNodesForUi: opts.usePromptNodesForUi,
|
|
201
|
+
confirmStageReadiness: opts.confirmStageReadiness,
|
|
202
|
+
store: opts.store,
|
|
203
|
+
persistence: opts.persistence,
|
|
204
|
+
mcp: opts.mcp,
|
|
205
|
+
cancellation: opts.cancellation,
|
|
206
|
+
overlay: opts.overlay,
|
|
207
|
+
config: opts.config,
|
|
208
|
+
models: opts.models,
|
|
209
|
+
registry: opts.registry,
|
|
210
|
+
stageControlRegistry: opts.stageControlRegistry,
|
|
211
|
+
onStageStart: opts.onStageStart,
|
|
212
|
+
onStageEnd: opts.onStageEnd,
|
|
213
|
+
};
|
|
214
|
+
const runtime = new EngineRuntime({
|
|
215
|
+
runId,
|
|
216
|
+
depth,
|
|
217
|
+
runSnapshot,
|
|
218
|
+
activeStore,
|
|
219
|
+
stageOptions,
|
|
220
|
+
workflowBoundaryOptions,
|
|
221
|
+
childRunOptions,
|
|
222
|
+
parentRootRunId: opts.parentRun?.rootRunId,
|
|
223
|
+
adapters,
|
|
224
|
+
signal: ownController.signal,
|
|
225
|
+
tracker,
|
|
226
|
+
scheduler,
|
|
227
|
+
replayIndex,
|
|
228
|
+
limiter,
|
|
229
|
+
inputRuntimeDefaults,
|
|
230
|
+
workflowInvocationCwd,
|
|
231
|
+
stageRegistry,
|
|
232
|
+
exit,
|
|
233
|
+
classifyExecutorFailure,
|
|
234
|
+
});
|
|
235
|
+
const workflowBoundaryReplayCounts = new Map<string, number>();
|
|
236
|
+
const nextWorkflowBoundaryReplayKey = (name: string): string => {
|
|
237
|
+
const next = (workflowBoundaryReplayCounts.get(name) ?? 0) + 1;
|
|
238
|
+
workflowBoundaryReplayCounts.set(name, next);
|
|
239
|
+
return `workflow:${name}:${next}`;
|
|
240
|
+
};
|
|
241
|
+
const taskRunners = createWorkflowTaskRunners({ runtime });
|
|
242
|
+
const workflow = createChildWorkflowRunner({
|
|
243
|
+
runtime,
|
|
244
|
+
resolveWorkflowCwd,
|
|
245
|
+
nextWorkflowBoundaryReplayKey,
|
|
246
|
+
runWorkflow: run,
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
const ctx: WorkflowRunContext<TInputs> = {
|
|
250
|
+
inputs: resolvedInputs as TInputs,
|
|
251
|
+
get cwd() { return resolveWorkflowCwd(); },
|
|
252
|
+
exit: exit.exit,
|
|
253
|
+
ui: buildExitGatedUiContext({
|
|
254
|
+
opts,
|
|
255
|
+
throwIfWorkflowExitSelected: exit.throwIfWorkflowExitSelected,
|
|
256
|
+
baseFromPromptNodes: () => buildPromptNodeUiAdapter({
|
|
257
|
+
runId,
|
|
258
|
+
activeStore,
|
|
259
|
+
opts,
|
|
260
|
+
tracker,
|
|
261
|
+
replayIndex,
|
|
262
|
+
signal: ownController.signal,
|
|
263
|
+
throwIfWorkflowExitSelected: exit.throwIfWorkflowExitSelected,
|
|
264
|
+
registerWorkflowExitCleanup: exit.registerWorkflowExitCleanup,
|
|
265
|
+
workflowExitSkippedReason: exit.workflowExitSkippedReason,
|
|
266
|
+
preserveWorkflowExitSkippedReason: exit.preserveWorkflowExitSkippedReason,
|
|
267
|
+
classifyExecutorFailure,
|
|
268
|
+
}),
|
|
269
|
+
}),
|
|
270
|
+
stage: runtime.stage,
|
|
271
|
+
task: taskRunners.task,
|
|
272
|
+
chain: taskRunners.chain,
|
|
273
|
+
parallel: taskRunners.parallel,
|
|
274
|
+
workflow,
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
try {
|
|
278
|
+
if (opts.deferWorkflowStart === true) {
|
|
279
|
+
await nextEventLoopTurn();
|
|
280
|
+
if (ownController.signal.aborted) {
|
|
281
|
+
const selectedExit = findWorkflowExitSignal(ownController.signal.reason, exitScope);
|
|
282
|
+
if (selectedExit !== undefined) return await finalizers.finalizeWorkflowExit(selectedExit);
|
|
283
|
+
const parentExit = parentWorkflowExitAbortReason(ownController.signal.reason);
|
|
284
|
+
if (parentExit !== undefined) return await finalizers.finalizeParentWorkflowExitCancellation(parentExit);
|
|
285
|
+
return finalizeKilled(runId, runSnapshot, activeStore, opts.persistence, opts.onRunEnd);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const rawResult = await def.run(ctx);
|
|
290
|
+
if (ownController.signal.aborted) {
|
|
291
|
+
const selectedExit = findWorkflowExitSignal(ownController.signal.reason, exitScope);
|
|
292
|
+
if (selectedExit !== undefined) return await finalizers.finalizeWorkflowExit(selectedExit);
|
|
293
|
+
const parentExit = parentWorkflowExitAbortReason(ownController.signal.reason);
|
|
294
|
+
if (parentExit !== undefined) return await finalizers.finalizeParentWorkflowExitCancellation(parentExit);
|
|
295
|
+
return finalizeKilled(runId, runSnapshot, activeStore, opts.persistence, opts.onRunEnd);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const result = normalizeWorkflowRunOutput(def.name, rawResult);
|
|
299
|
+
assertWorkflowRunOutputs(def.name, result, def.outputs);
|
|
300
|
+
assertWorkflowCreatedStage(runSnapshot);
|
|
301
|
+
const recorded = activeStore.recordRunEnd(runId, "completed", result);
|
|
302
|
+
appendRunEndWhenRecorded(opts.persistence, recorded, { runId, status: "completed", result, ts: Date.now() });
|
|
303
|
+
return reconcileTerminalRunResult(runId, runSnapshot, activeStore, { status: "completed", result }, opts.onRunEnd);
|
|
304
|
+
} catch (err) {
|
|
305
|
+
const selectedExit = findWorkflowExitSignal(err, exitScope) ?? findWorkflowExitSignal(ownController.signal.reason, exitScope);
|
|
306
|
+
if (selectedExit !== undefined) return await finalizers.finalizeWorkflowExit(selectedExit);
|
|
307
|
+
|
|
308
|
+
if (ownController.signal.aborted) {
|
|
309
|
+
const parentExit = parentWorkflowExitAbortReason(ownController.signal.reason);
|
|
310
|
+
if (parentExit !== undefined) return await finalizers.finalizeParentWorkflowExitCancellation(parentExit);
|
|
311
|
+
return finalizeKilled(runId, runSnapshot, activeStore, opts.persistence, opts.onRunEnd);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const failure = classifyExecutorFailure(err);
|
|
315
|
+
const metadata = selectRunFailureDisposition({
|
|
316
|
+
outerFailure: failure,
|
|
317
|
+
thrownError: err,
|
|
318
|
+
stages: runSnapshot.stages,
|
|
319
|
+
classifyFailure: classifyExecutorFailure,
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
if (metadata.failureDisposition === "terminal_killed") {
|
|
323
|
+
for (const failedStageId of metadata.failedStageIds) scheduler.blockKnownNonTerminalDescendants(failedStageId);
|
|
324
|
+
return finalizeKilledByFailure(runId, runSnapshot, activeStore, opts.persistence, opts.onRunEnd, { ...metadata, resumable: false });
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (metadata.failureDisposition === "active_blocked" && metadata.failedStageId !== undefined && metadata.failureRecoverability === "recoverable") {
|
|
328
|
+
for (const failedStageId of metadata.failedStageIds) scheduler.blockKnownNonTerminalDescendants(failedStageId);
|
|
329
|
+
return recordActiveBlockedFailure(runId, runSnapshot, activeStore, opts.persistence, {
|
|
330
|
+
...metadata,
|
|
331
|
+
failureRecoverability: "recoverable",
|
|
332
|
+
failedStageId: metadata.failedStageId,
|
|
333
|
+
resumable: true,
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const recorded = activeStore.recordRunEnd(runId, "failed", undefined, metadata.errorMessage, metadata);
|
|
338
|
+
appendRunEndWhenRecorded(opts.persistence, recorded, {
|
|
339
|
+
runId,
|
|
340
|
+
status: "failed",
|
|
341
|
+
error: metadata.errorMessage,
|
|
342
|
+
failureKind: metadata.failureKind,
|
|
343
|
+
...(metadata.failureCode !== undefined ? { failureCode: metadata.failureCode } : {}),
|
|
344
|
+
...(metadata.failureRecoverability !== undefined ? { failureRecoverability: metadata.failureRecoverability } : {}),
|
|
345
|
+
...(metadata.failureDisposition !== undefined ? { failureDisposition: metadata.failureDisposition } : {}),
|
|
346
|
+
failureMessage: metadata.failureMessage,
|
|
347
|
+
...(metadata.failedStageId !== undefined ? { failedStageId: metadata.failedStageId } : {}),
|
|
348
|
+
resumable: metadata.resumable,
|
|
349
|
+
...(metadata.retryAfterMs !== undefined ? { retryAfterMs: metadata.retryAfterMs } : {}),
|
|
350
|
+
ts: Date.now(),
|
|
351
|
+
});
|
|
352
|
+
return reconcileTerminalRunResult(runId, runSnapshot, activeStore, { status: "failed", error: metadata.errorMessage }, opts.onRunEnd);
|
|
353
|
+
} finally {
|
|
354
|
+
opts.cancellation?.unregister(runId);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import type { RunSnapshot } from "../shared/store-types.js";
|
|
2
|
+
import type { Store } from "../shared/store.js";
|
|
3
|
+
import type { StageOptions } from "../shared/types.js";
|
|
4
|
+
import type { ConcurrencyLimiter } from "../runs/shared/concurrency.js";
|
|
5
|
+
import type { ParallelFailFastScope } from "../runs/foreground/executor-types.js";
|
|
6
|
+
import type { WorkflowExitManager } from "../runs/foreground/executor-exit-manager.js";
|
|
7
|
+
import type { ContinuationReplayIndex } from "../runs/foreground/executor-continuation.js";
|
|
8
|
+
import type { StageScheduler } from "../runs/foreground/executor-scheduler.js";
|
|
9
|
+
import type { StageControlRegistry } from "../runs/foreground/stage-control-registry.js";
|
|
10
|
+
import type { StageAdapters } from "../runs/foreground/stage-runner.js";
|
|
11
|
+
import type { LiveStageRuntime, StageMcpScope, StageContextWithMeta } from "../runs/foreground/executor-stage-types.js";
|
|
12
|
+
import { createWorkflowStageFactory } from "../runs/foreground/executor-stage-factory.js";
|
|
13
|
+
import { createWorkflowBoundaryFactory, type WorkflowBoundaryStage } from "../runs/foreground/executor-child-boundary.js";
|
|
14
|
+
import type { GraphFrontierTracker } from "./graph-inference.js";
|
|
15
|
+
import type { EngineChildRunOptions, EngineStageRuntimeOptions, EngineWorkflowBoundaryOptions } from "./options.js";
|
|
16
|
+
|
|
17
|
+
export interface EngineRuntimeInput {
|
|
18
|
+
readonly runId: string;
|
|
19
|
+
readonly depth: number;
|
|
20
|
+
readonly runSnapshot: RunSnapshot;
|
|
21
|
+
readonly activeStore: Store;
|
|
22
|
+
readonly stageOptions: EngineStageRuntimeOptions;
|
|
23
|
+
readonly workflowBoundaryOptions: EngineWorkflowBoundaryOptions;
|
|
24
|
+
readonly childRunOptions: EngineChildRunOptions;
|
|
25
|
+
readonly parentRootRunId?: string;
|
|
26
|
+
readonly adapters: StageAdapters;
|
|
27
|
+
readonly signal: AbortSignal;
|
|
28
|
+
readonly tracker: GraphFrontierTracker;
|
|
29
|
+
readonly scheduler: StageScheduler;
|
|
30
|
+
readonly replayIndex: ContinuationReplayIndex;
|
|
31
|
+
readonly limiter: ConcurrencyLimiter;
|
|
32
|
+
readonly inputRuntimeDefaults: Partial<StageOptions>;
|
|
33
|
+
readonly workflowInvocationCwd: string;
|
|
34
|
+
readonly stageRegistry: StageControlRegistry;
|
|
35
|
+
readonly exit: WorkflowExitManager;
|
|
36
|
+
readonly classifyExecutorFailure: LiveStageRuntime["classifyExecutorFailure"];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface EngineSpawnAgentStageOptions {
|
|
40
|
+
readonly kind?: "agent";
|
|
41
|
+
readonly options?: StageOptions;
|
|
42
|
+
readonly failFastScope?: ParallelFailFastScope;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface EngineSpawnWorkflowBoundaryOptions {
|
|
46
|
+
readonly kind: "workflow-boundary";
|
|
47
|
+
readonly replayKey: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type EngineSpawnStageOptions = EngineSpawnAgentStageOptions | EngineSpawnWorkflowBoundaryOptions;
|
|
51
|
+
|
|
52
|
+
export interface EngineAgentStageHandle {
|
|
53
|
+
readonly kind: "agent";
|
|
54
|
+
readonly context: StageContextWithMeta;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface EngineWorkflowBoundaryHandle {
|
|
58
|
+
readonly kind: "workflow-boundary";
|
|
59
|
+
readonly boundary: WorkflowBoundaryStage;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type StageHandle = EngineAgentStageHandle | EngineWorkflowBoundaryHandle;
|
|
63
|
+
|
|
64
|
+
export class EngineRuntime {
|
|
65
|
+
readonly runId: string;
|
|
66
|
+
readonly depth: number;
|
|
67
|
+
readonly activeStore: Store;
|
|
68
|
+
readonly childRunOptions: EngineChildRunOptions;
|
|
69
|
+
readonly parentRootRunId?: string;
|
|
70
|
+
readonly adapters: StageAdapters;
|
|
71
|
+
readonly signal: AbortSignal;
|
|
72
|
+
readonly tracker: GraphFrontierTracker;
|
|
73
|
+
readonly exit: WorkflowExitManager;
|
|
74
|
+
readonly inputRuntimeDefaults: Partial<StageOptions>;
|
|
75
|
+
readonly workflowInvocationCwd: string;
|
|
76
|
+
|
|
77
|
+
private readonly spawnAgentStage: (
|
|
78
|
+
name: string,
|
|
79
|
+
options?: StageOptions,
|
|
80
|
+
stageFailFastScope?: ParallelFailFastScope,
|
|
81
|
+
) => StageContextWithMeta;
|
|
82
|
+
private readonly spawnWorkflowBoundary: (name: string, replayKey: string) => WorkflowBoundaryStage;
|
|
83
|
+
|
|
84
|
+
constructor(input: EngineRuntimeInput) {
|
|
85
|
+
this.runId = input.runId;
|
|
86
|
+
this.depth = input.depth;
|
|
87
|
+
this.activeStore = input.activeStore;
|
|
88
|
+
this.childRunOptions = input.childRunOptions;
|
|
89
|
+
this.parentRootRunId = input.parentRootRunId;
|
|
90
|
+
this.adapters = input.adapters;
|
|
91
|
+
this.signal = input.signal;
|
|
92
|
+
this.tracker = input.tracker;
|
|
93
|
+
this.exit = input.exit;
|
|
94
|
+
this.inputRuntimeDefaults = input.inputRuntimeDefaults;
|
|
95
|
+
this.workflowInvocationCwd = input.workflowInvocationCwd;
|
|
96
|
+
|
|
97
|
+
// The runtime only wires host-injected ports; stage sessions are still
|
|
98
|
+
// created lazily by the stage runner through input.adapters.agentSession.
|
|
99
|
+
this.spawnAgentStage = createWorkflowStageFactory({
|
|
100
|
+
runId: input.runId,
|
|
101
|
+
activeStore: input.activeStore,
|
|
102
|
+
opts: input.stageOptions,
|
|
103
|
+
adapters: input.adapters,
|
|
104
|
+
signal: input.signal,
|
|
105
|
+
tracker: input.tracker,
|
|
106
|
+
scheduler: input.scheduler,
|
|
107
|
+
replayIndex: input.replayIndex,
|
|
108
|
+
limiter: input.limiter,
|
|
109
|
+
inputRuntimeDefaults: input.inputRuntimeDefaults,
|
|
110
|
+
workflowInvocationCwd: input.workflowInvocationCwd,
|
|
111
|
+
stageRegistry: input.stageRegistry,
|
|
112
|
+
exit: input.exit,
|
|
113
|
+
classifyExecutorFailure: input.classifyExecutorFailure,
|
|
114
|
+
createMcpScope: (stageId, options) => this.createMcpScope(stageId, options),
|
|
115
|
+
});
|
|
116
|
+
this.spawnWorkflowBoundary = createWorkflowBoundaryFactory({
|
|
117
|
+
runId: input.runId,
|
|
118
|
+
runSnapshot: input.runSnapshot,
|
|
119
|
+
activeStore: input.activeStore,
|
|
120
|
+
opts: input.workflowBoundaryOptions,
|
|
121
|
+
tracker: input.tracker,
|
|
122
|
+
replayIndex: input.replayIndex,
|
|
123
|
+
registerWorkflowExitCleanup: input.exit.registerWorkflowExitCleanup,
|
|
124
|
+
workflowExitSkippedReason: input.exit.workflowExitSkippedReason,
|
|
125
|
+
classifyExecutorFailure: input.classifyExecutorFailure,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
spawnStage(name: string, opts: EngineSpawnWorkflowBoundaryOptions): EngineWorkflowBoundaryHandle;
|
|
130
|
+
spawnStage(name: string, opts?: EngineSpawnAgentStageOptions): EngineAgentStageHandle;
|
|
131
|
+
spawnStage(name: string, opts: EngineSpawnStageOptions = {}): StageHandle {
|
|
132
|
+
if (opts.kind === "workflow-boundary") {
|
|
133
|
+
return { kind: "workflow-boundary", boundary: this.spawnWorkflowBoundary(name, opts.replayKey) };
|
|
134
|
+
}
|
|
135
|
+
return { kind: "agent", context: this.spawnAgentStage(name, opts.options, opts.failFastScope) };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
readonly stage = (name: string, options?: StageOptions, failFastScope?: ParallelFailFastScope): StageContextWithMeta => {
|
|
139
|
+
const handle = this.spawnStage(name, {
|
|
140
|
+
kind: "agent",
|
|
141
|
+
...(options !== undefined ? { options } : {}),
|
|
142
|
+
...(failFastScope !== undefined ? { failFastScope } : {}),
|
|
143
|
+
});
|
|
144
|
+
return handle.context;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
private createMcpScope(stageId: string, options: StageOptions | undefined): StageMcpScope {
|
|
148
|
+
const allow = options?.mcp?.allow ?? null;
|
|
149
|
+
const deny = options?.mcp?.deny ?? null;
|
|
150
|
+
const hasScope = allow !== null || deny !== null;
|
|
151
|
+
return {
|
|
152
|
+
apply: () => {
|
|
153
|
+
if (this.childRunOptions.mcp && hasScope) this.childRunOptions.mcp.setScope(stageId, allow, deny);
|
|
154
|
+
},
|
|
155
|
+
clear: () => {
|
|
156
|
+
if (this.childRunOptions.mcp && hasScope) this.childRunOptions.mcp.clearScope(stageId);
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { createJiti } from "jiti/static";
|
|
10
|
+
import * as typeboxModule from "typebox";
|
|
10
11
|
import * as workflowsSdkSurface from "../sdk-surface.js";
|
|
11
|
-
import { isBrandedWorkflowDefinition } from "../
|
|
12
|
+
import { isBrandedWorkflowDefinition } from "../authoring/workflow.js";
|
|
12
13
|
import deepResearchCodebase from "../../builtin/deep-research-codebase.js";
|
|
13
14
|
import goal from "../../builtin/goal.js";
|
|
14
15
|
import openClaudeDesign from "../../builtin/open-claude-design.js";
|
|
@@ -16,6 +17,7 @@ import ralph from "../../builtin/ralph.js";
|
|
|
16
17
|
|
|
17
18
|
const WORKFLOWS_MODULE_SPECIFIER = "@bastani/workflows";
|
|
18
19
|
const WORKFLOWS_BUILTIN_MODULE_SPECIFIER = `${WORKFLOWS_MODULE_SPECIFIER}/builtin`;
|
|
20
|
+
const TYPEBOX_MODULE_SPECIFIER = "typebox";
|
|
19
21
|
// Keep this in sync with index.ts through sdk-surface.ts.
|
|
20
22
|
const WORKFLOWS_SDK_MODULE: Record<string, unknown> = {
|
|
21
23
|
...workflowsSdkSurface,
|
|
@@ -26,9 +28,13 @@ const WORKFLOWS_BUILTIN_MODULE: Record<string, unknown> = {
|
|
|
26
28
|
openClaudeDesign,
|
|
27
29
|
ralph,
|
|
28
30
|
};
|
|
31
|
+
const TYPEBOX_MODULE: Record<string, unknown> = {
|
|
32
|
+
...typeboxModule,
|
|
33
|
+
};
|
|
29
34
|
const WORKFLOWS_VIRTUAL_MODULES: Record<string, unknown> = {
|
|
30
35
|
[WORKFLOWS_MODULE_SPECIFIER]: WORKFLOWS_SDK_MODULE,
|
|
31
36
|
[WORKFLOWS_BUILTIN_MODULE_SPECIFIER]: WORKFLOWS_BUILTIN_MODULE,
|
|
37
|
+
[TYPEBOX_MODULE_SPECIFIER]: TYPEBOX_MODULE,
|
|
32
38
|
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/deep-research-codebase`]: { default: deepResearchCodebase },
|
|
33
39
|
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/goal`]: { default: goal },
|
|
34
40
|
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/open-claude-design`]: { default: openClaudeDesign },
|
|
@@ -95,10 +101,10 @@ export function validateWorkflowDefinitionShape(value: unknown): string | null {
|
|
|
95
101
|
const d = value as Record<string, unknown>;
|
|
96
102
|
|
|
97
103
|
if (d["__piWorkflow"] !== true) {
|
|
98
|
-
return "missing or incorrect __piWorkflow sentinel (expected true); export a workflow from
|
|
104
|
+
return "missing or incorrect __piWorkflow sentinel (expected true); export a workflow from workflow({...})";
|
|
99
105
|
}
|
|
100
106
|
if (!isBrandedWorkflowDefinition(value)) {
|
|
101
|
-
return "workflow definition is not produced by
|
|
107
|
+
return "workflow definition is not produced by workflow({...}); hand-rolled __piWorkflow objects are not supported";
|
|
102
108
|
}
|
|
103
109
|
if (typeof d["name"] !== "string" || (d["name"] as string).trim().length === 0) {
|
|
104
110
|
return "name must be a non-empty string";
|
|
@@ -43,23 +43,6 @@ const JsonSchemaObject = Type.Unsafe<Record<string, unknown>>({
|
|
|
43
43
|
description: "Plain JSON Schema used as final-answer tool arguments for this workflow item.",
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
const BashCommandRuleSchema = Type.Union([
|
|
47
|
-
Type.String(),
|
|
48
|
-
Type.Object({ prefix: Type.String() }, { additionalProperties: false }),
|
|
49
|
-
Type.Object({ glob: Type.String() }, { additionalProperties: false }),
|
|
50
|
-
Type.Object({
|
|
51
|
-
regex: Type.String(),
|
|
52
|
-
flags: Type.Optional(Type.String()),
|
|
53
|
-
}, { additionalProperties: false }),
|
|
54
|
-
]);
|
|
55
|
-
|
|
56
|
-
const BashCommandPolicySchema = Type.Object({
|
|
57
|
-
default: Type.Optional(Type.Union([Type.Literal("allow"), Type.Literal("deny")])),
|
|
58
|
-
allow: Type.Optional(Type.Array(BashCommandRuleSchema)),
|
|
59
|
-
deny: Type.Optional(Type.Array(BashCommandRuleSchema)),
|
|
60
|
-
match: Type.Optional(Type.Union([Type.Literal("whole"), Type.Literal("segments")])),
|
|
61
|
-
}, { additionalProperties: false });
|
|
62
|
-
|
|
63
46
|
const StageSessionOptionProperties = {
|
|
64
47
|
schema: Type.Optional(JsonSchemaObject),
|
|
65
48
|
cwd: Type.Optional(Type.String()),
|
|
@@ -76,7 +59,6 @@ const StageSessionOptionProperties = {
|
|
|
76
59
|
})),
|
|
77
60
|
tools: Type.Optional(Type.Array(Type.String())),
|
|
78
61
|
customTools: Type.Optional(Type.Array(SdkSessionOptionArrayElementSchema("customTools"))),
|
|
79
|
-
bashPolicy: Type.Optional(BashCommandPolicySchema),
|
|
80
62
|
resourceLoader: Type.Optional(SdkSessionOptionSchema("resourceLoader")),
|
|
81
63
|
sessionManager: Type.Optional(SdkSessionOptionSchema("sessionManager")),
|
|
82
64
|
settingsManager: Type.Optional(SdkSessionOptionSchema("settingsManager")),
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* cross-ref: spec detached-runner
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import type { WorkflowDefinition, WorkflowExecutionMode, WorkflowInputValues } from "../../shared/types.js";
|
|
17
|
+
import type { WorkflowDefinition, WorkflowExecutionMode, WorkflowInputValues, WorkflowOutputValues } from "../../shared/types.js";
|
|
18
18
|
import type { RunOpts, RunResult } from "../foreground/executor.js";
|
|
19
19
|
import type { CancellationRegistry } from "./cancellation-registry.js";
|
|
20
20
|
import type { JobTracker } from "./job-tracker.js";
|
|
@@ -85,8 +85,11 @@ export function buildDetachedAccepted(
|
|
|
85
85
|
* the store remains source of truth for run status. Cancellation is wired
|
|
86
86
|
* through the provided (or default) CancellationRegistry.
|
|
87
87
|
*/
|
|
88
|
-
export function runDetached<
|
|
89
|
-
|
|
88
|
+
export function runDetached<
|
|
89
|
+
TInputs extends WorkflowInputValues,
|
|
90
|
+
TRunInputs extends WorkflowInputValues = TInputs,
|
|
91
|
+
>(
|
|
92
|
+
def: WorkflowDefinition<TInputs, WorkflowOutputValues, TRunInputs>,
|
|
90
93
|
inputs: Readonly<Record<string, unknown>>,
|
|
91
94
|
opts: DetachedRunOpts = {},
|
|
92
95
|
): DetachedAccepted {
|
|
@@ -4,12 +4,12 @@ import type { WorkflowChildResult } from "../../shared/types.js";
|
|
|
4
4
|
import { appendStageEnd, appendStageStart } from "../../shared/persistence-session-entries.js";
|
|
5
5
|
import { elapsedStageMs } from "../../shared/timing.js";
|
|
6
6
|
import type { WorkflowFailure } from "../../shared/workflow-failures.js";
|
|
7
|
-
import type {
|
|
7
|
+
import type { EngineWorkflowBoundaryOptions } from "../../engine/options.js";
|
|
8
8
|
import type { ContinuationReplayIndex } from "./executor-continuation.js";
|
|
9
9
|
import { sameStringSet } from "./executor-continuation.js";
|
|
10
10
|
import { applyFailureToStage, stageReplayFields } from "./executor-lifecycle.js";
|
|
11
11
|
import { cloneWorkflowChildReplaySnapshot, cloneWorkflowChildValue } from "./executor-child-helpers.js";
|
|
12
|
-
import type { GraphFrontierTracker } from "
|
|
12
|
+
import type { GraphFrontierTracker } from "../../engine/graph-inference.js";
|
|
13
13
|
import type { WorkflowExitCleanup } from "./executor-types.js";
|
|
14
14
|
import { makeParentWorkflowExitAbortReason } from "./executor-abort.js";
|
|
15
15
|
|
|
@@ -71,7 +71,7 @@ export function createWorkflowBoundaryFactory(input: {
|
|
|
71
71
|
readonly runId: string;
|
|
72
72
|
readonly runSnapshot: RunSnapshot;
|
|
73
73
|
readonly activeStore: Store;
|
|
74
|
-
readonly opts:
|
|
74
|
+
readonly opts: EngineWorkflowBoundaryOptions;
|
|
75
75
|
readonly tracker: GraphFrontierTracker;
|
|
76
76
|
readonly replayIndex: ContinuationReplayIndex;
|
|
77
77
|
readonly registerWorkflowExitCleanup: (stageId: string, cleanup: WorkflowExitCleanup) => () => void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isBrandedWorkflowDefinition } from "../../
|
|
1
|
+
import { isBrandedWorkflowDefinition } from "../../authoring/workflow.js";
|
|
2
2
|
import type {
|
|
3
3
|
WorkflowChildResult,
|
|
4
4
|
WorkflowDefinition,
|
|
@@ -16,7 +16,7 @@ function workflowChildSerializationMessage(err: unknown): string {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function isWorkflowDefinition(value: unknown): value is WorkflowDefinition {
|
|
19
|
-
if (!isBrandedWorkflowDefinition(value)) return false;
|
|
19
|
+
if (value === null || typeof value !== "object" || !isBrandedWorkflowDefinition(value)) return false;
|
|
20
20
|
const record = value as Partial<WorkflowDefinition>;
|
|
21
21
|
return record.__piWorkflow === true &&
|
|
22
22
|
typeof record.name === "string" && record.name.trim().length > 0 &&
|
|
@@ -27,9 +27,9 @@ export function isWorkflowDefinition(value: unknown): value is WorkflowDefinitio
|
|
|
27
27
|
|
|
28
28
|
export function workflowDefinitionRequirementMessage(callSite: string, value: unknown): string {
|
|
29
29
|
if (value !== null && typeof value === "object" && (value as { __piWorkflow?: unknown }).__piWorkflow === true) {
|
|
30
|
-
return `atomic-workflows: ${callSite} requires a
|
|
30
|
+
return `atomic-workflows: ${callSite} requires a workflow definition produced by workflow({...}); hand-rolled __piWorkflow objects are not supported`;
|
|
31
31
|
}
|
|
32
|
-
return `atomic-workflows: ${callSite} requires a
|
|
32
|
+
return `atomic-workflows: ${callSite} requires a workflow definition`;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export function cloneWorkflowChildReplaySnapshot(snapshot: WorkflowChildReplaySnapshot): WorkflowChildReplaySnapshot {
|