@bastani/atomic 0.9.0-alpha.1 → 0.9.0-alpha.3
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 +29 -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 +19 -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-ledger.ts +2 -0
- package/dist/builtin/workflows/builtin/goal-reports.ts +5 -0
- package/dist/builtin/workflows/builtin/goal-runner.ts +17 -20
- package/dist/builtin/workflows/builtin/goal-types.ts +2 -0
- package/dist/builtin/workflows/builtin/goal.d.ts +1 -0
- package/dist/builtin/workflows/builtin/goal.ts +40 -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/prompt-refinement.ts +102 -0
- package/dist/builtin/workflows/builtin/ralph-core.ts +6 -4
- package/dist/builtin/workflows/builtin/ralph-runner.ts +22 -24
- package/dist/builtin/workflows/builtin/ralph.d.ts +2 -0
- package/dist/builtin/workflows/builtin/ralph.ts +46 -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-prompts.ts +3 -1
- 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/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +0 -1
- package/dist/core/system-prompt.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 +991 -176
- 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,41 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
WorkflowCustomUiFactory,
|
|
3
|
+
WorkflowCustomUiOptions,
|
|
4
|
+
WorkflowUIContext,
|
|
5
|
+
} from "../../shared/types.js";
|
|
6
|
+
import type { RunOpts } from "../../runs/foreground/executor-types.js";
|
|
7
|
+
import { makeHeadlessUnavailableUIContext, normalizeUIContext } from "../../runs/foreground/executor-hil.js";
|
|
8
|
+
|
|
9
|
+
export function buildExitGatedUiContext(input: {
|
|
10
|
+
readonly opts: RunOpts;
|
|
11
|
+
readonly baseFromPromptNodes: () => WorkflowUIContext;
|
|
12
|
+
readonly throwIfWorkflowExitSelected: () => void;
|
|
13
|
+
}): WorkflowUIContext {
|
|
14
|
+
const base = input.opts.usePromptNodesForUi === true
|
|
15
|
+
? input.baseFromPromptNodes()
|
|
16
|
+
: input.opts.executionMode === "non_interactive" && input.opts.ui === undefined
|
|
17
|
+
? makeHeadlessUnavailableUIContext()
|
|
18
|
+
: normalizeUIContext(input.opts.ui);
|
|
19
|
+
return {
|
|
20
|
+
async input(promptText: string): Promise<string> {
|
|
21
|
+
input.throwIfWorkflowExitSelected();
|
|
22
|
+
return await base.input(promptText);
|
|
23
|
+
},
|
|
24
|
+
async confirm(message: string): Promise<boolean> {
|
|
25
|
+
input.throwIfWorkflowExitSelected();
|
|
26
|
+
return await base.confirm(message);
|
|
27
|
+
},
|
|
28
|
+
async select<T extends string>(message: string, options: readonly T[]): Promise<T> {
|
|
29
|
+
input.throwIfWorkflowExitSelected();
|
|
30
|
+
return await base.select(message, options);
|
|
31
|
+
},
|
|
32
|
+
async editor(initial?: string): Promise<string> {
|
|
33
|
+
input.throwIfWorkflowExitSelected();
|
|
34
|
+
return await base.editor(initial);
|
|
35
|
+
},
|
|
36
|
+
async custom<T>(factory: WorkflowCustomUiFactory<T>, options?: WorkflowCustomUiOptions): Promise<T> {
|
|
37
|
+
input.throwIfWorkflowExitSelected();
|
|
38
|
+
return await base.custom(factory, options);
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
WorkflowChildResult,
|
|
3
|
+
WorkflowDefinition,
|
|
4
|
+
WorkflowInputValues,
|
|
5
|
+
WorkflowOutputValues,
|
|
6
|
+
WorkflowRunChildArgs,
|
|
7
|
+
WorkflowRunChildOptions,
|
|
8
|
+
} from "../../shared/types.js";
|
|
9
|
+
import type { WorkflowChildRunRef } from "../../shared/store-types.js";
|
|
10
|
+
import type { ResolvedInputs, RunOpts, RunResult } from "../../runs/foreground/executor-types.js";
|
|
11
|
+
import type { EngineRuntime } from "../runtime.js";
|
|
12
|
+
import { findWorkflowExitSignal, isWorkflowExitStatus, makeParentWorkflowExitAbortReason } from "../../runs/foreground/executor-abort.js";
|
|
13
|
+
import { selectWorkflowOutputs } from "../../runs/foreground/executor-outputs.js";
|
|
14
|
+
import { resolveAndValidateInputs } from "../../runs/foreground/executor-inputs.js";
|
|
15
|
+
import {
|
|
16
|
+
isWorkflowDefinition,
|
|
17
|
+
workflowChildReplaySnapshot,
|
|
18
|
+
workflowDefinitionRequirementMessage,
|
|
19
|
+
} from "../../runs/foreground/executor-child-helpers.js";
|
|
20
|
+
|
|
21
|
+
export function createChildWorkflowRunner(input: {
|
|
22
|
+
readonly runtime: EngineRuntime;
|
|
23
|
+
readonly resolveWorkflowCwd: () => string;
|
|
24
|
+
readonly nextWorkflowBoundaryReplayKey: (name: string) => string;
|
|
25
|
+
readonly runWorkflow: <
|
|
26
|
+
TInputs extends WorkflowInputValues,
|
|
27
|
+
TRunInputs extends WorkflowInputValues = TInputs,
|
|
28
|
+
>(
|
|
29
|
+
def: WorkflowDefinition<TInputs, WorkflowOutputValues, TRunInputs>,
|
|
30
|
+
inputs: ResolvedInputs,
|
|
31
|
+
opts?: RunOpts,
|
|
32
|
+
) => Promise<RunResult>;
|
|
33
|
+
}): <
|
|
34
|
+
TChildInputs extends WorkflowInputValues,
|
|
35
|
+
TChildOutputs extends WorkflowOutputValues,
|
|
36
|
+
TChildRunInputs extends WorkflowInputValues = TChildInputs,
|
|
37
|
+
>(
|
|
38
|
+
child: WorkflowDefinition<TChildInputs, TChildOutputs, TChildRunInputs>,
|
|
39
|
+
...args: WorkflowRunChildArgs<TChildRunInputs>
|
|
40
|
+
) => Promise<WorkflowChildResult<TChildOutputs>> {
|
|
41
|
+
return async <
|
|
42
|
+
TChildInputs extends WorkflowInputValues,
|
|
43
|
+
TChildOutputs extends WorkflowOutputValues,
|
|
44
|
+
TChildRunInputs extends WorkflowInputValues = TChildInputs,
|
|
45
|
+
>(
|
|
46
|
+
child: WorkflowDefinition<TChildInputs, TChildOutputs, TChildRunInputs>,
|
|
47
|
+
...args: WorkflowRunChildArgs<TChildRunInputs>
|
|
48
|
+
): Promise<WorkflowChildResult<TChildOutputs>> => {
|
|
49
|
+
const options: WorkflowRunChildOptions<TChildRunInputs> = args[0] ?? {};
|
|
50
|
+
const { runtime } = input;
|
|
51
|
+
runtime.exit.throwIfWorkflowExitSelected();
|
|
52
|
+
if (!isWorkflowDefinition(child)) throw new Error(workflowDefinitionRequirementMessage("ctx.workflow(definition)", child));
|
|
53
|
+
const childName = child.normalizedName;
|
|
54
|
+
const boundaryName = options.stageName ?? `workflow:${childName}`;
|
|
55
|
+
const boundaryReplayKey = input.nextWorkflowBoundaryReplayKey(boundaryName);
|
|
56
|
+
const boundary = runtime.spawnStage(boundaryName, { kind: "workflow-boundary", replayKey: boundaryReplayKey }).boundary;
|
|
57
|
+
let childRunId: string | undefined;
|
|
58
|
+
let detachParentAbort: (() => void) | undefined;
|
|
59
|
+
try {
|
|
60
|
+
if (boundary.replayedChild !== undefined) {
|
|
61
|
+
await Promise.resolve();
|
|
62
|
+
runtime.exit.throwIfWorkflowExitSelected();
|
|
63
|
+
boundary.finalizeReplay();
|
|
64
|
+
return boundary.replayedChild as WorkflowChildResult<TChildOutputs>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const childInputs = resolveAndValidateInputs(child.inputs, options.inputs ?? {}, `child workflow "${childName}" (${child.name})`);
|
|
68
|
+
runtime.exit.throwIfWorkflowExitSelected();
|
|
69
|
+
|
|
70
|
+
childRunId = crypto.randomUUID();
|
|
71
|
+
const childController = new AbortController();
|
|
72
|
+
const childRef: WorkflowChildRunRef = { alias: childName, workflow: child.normalizedName, runId: childRunId };
|
|
73
|
+
boundary.linkChildRun(childRef, childController);
|
|
74
|
+
|
|
75
|
+
const abortChildFromParent = (): void => {
|
|
76
|
+
const parentExit = findWorkflowExitSignal(runtime.signal.reason, runtime.exit.exitScope);
|
|
77
|
+
childController.abort(parentExit !== undefined ? makeParentWorkflowExitAbortReason(parentExit.reason) : runtime.signal.reason);
|
|
78
|
+
};
|
|
79
|
+
if (runtime.signal.aborted) abortChildFromParent();
|
|
80
|
+
else {
|
|
81
|
+
runtime.signal.addEventListener("abort", abortChildFromParent, { once: true });
|
|
82
|
+
detachParentAbort = () => runtime.signal.removeEventListener("abort", abortChildFromParent);
|
|
83
|
+
}
|
|
84
|
+
runtime.exit.throwIfWorkflowExitSelected();
|
|
85
|
+
runtime.childRunOptions.cancellation?.register(childRunId, childController);
|
|
86
|
+
runtime.exit.throwIfWorkflowExitSelected();
|
|
87
|
+
|
|
88
|
+
// Ordering is intentional: linkChildRun happens before launch so parent
|
|
89
|
+
// cleanup can abort the child; observeChildRun happens immediately after
|
|
90
|
+
// promise creation, with no await in between, so cleanup can await teardown.
|
|
91
|
+
const childRunPromise = input.runWorkflow(child, childInputs, {
|
|
92
|
+
...runtime.childRunOptions,
|
|
93
|
+
runId: childRunId,
|
|
94
|
+
cwd: input.resolveWorkflowCwd(),
|
|
95
|
+
depth: runtime.depth + 1,
|
|
96
|
+
parentRun: {
|
|
97
|
+
runId: runtime.runId,
|
|
98
|
+
stageId: boundary.id,
|
|
99
|
+
rootRunId: runtime.parentRootRunId ?? runtime.runId,
|
|
100
|
+
},
|
|
101
|
+
signal: childController.signal,
|
|
102
|
+
deferWorkflowStart: false,
|
|
103
|
+
});
|
|
104
|
+
boundary.observeChildRun(childRunPromise);
|
|
105
|
+
const childRun = await childRunPromise;
|
|
106
|
+
runtime.exit.throwIfWorkflowExitSelected();
|
|
107
|
+
|
|
108
|
+
if (!isWorkflowExitStatus(childRun.status)) {
|
|
109
|
+
const failedChildStage = childRun.stages.find((stage) => stage.failureKind !== undefined);
|
|
110
|
+
throw new Error(
|
|
111
|
+
`atomic-workflows: child workflow "${childName}" (${child.name}) failed with status ${childRun.status}${childRun.error !== undefined ? `: ${childRun.error}` : ""}`,
|
|
112
|
+
{
|
|
113
|
+
cause: {
|
|
114
|
+
...(failedChildStage?.failureKind !== undefined ? { code: failedChildStage.failureKind } : {}),
|
|
115
|
+
...(failedChildStage?.failureMessage !== undefined ? { message: failedChildStage.failureMessage } : {}),
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const outputs = selectWorkflowOutputs(child, childRun.result);
|
|
122
|
+
const childExited = childRun.exited === true || childRun.status !== "completed";
|
|
123
|
+
const childResult: WorkflowChildResult<TChildOutputs> = childExited
|
|
124
|
+
? {
|
|
125
|
+
workflow: child.normalizedName,
|
|
126
|
+
runId: childRun.runId,
|
|
127
|
+
status: childRun.status,
|
|
128
|
+
exited: true,
|
|
129
|
+
outputs: outputs as Partial<TChildOutputs>,
|
|
130
|
+
...(childRun.exitReason !== undefined ? { exitReason: childRun.exitReason } : {}),
|
|
131
|
+
}
|
|
132
|
+
: {
|
|
133
|
+
workflow: child.normalizedName,
|
|
134
|
+
runId: childRun.runId,
|
|
135
|
+
status: "completed",
|
|
136
|
+
exited: false,
|
|
137
|
+
outputs: outputs as TChildOutputs,
|
|
138
|
+
};
|
|
139
|
+
const workflowChild = workflowChildReplaySnapshot(childName, childResult);
|
|
140
|
+
const outputKeys = Object.keys(outputs);
|
|
141
|
+
boundary.complete(
|
|
142
|
+
`Workflow "${child.name}" ${childRun.status} (runId: ${childRun.runId}; outputs: ${outputKeys.length > 0 ? outputKeys.join(", ") : "(none)"})`,
|
|
143
|
+
workflowChild,
|
|
144
|
+
);
|
|
145
|
+
return childResult;
|
|
146
|
+
} catch (err) {
|
|
147
|
+
const exit = findWorkflowExitSignal(err, runtime.exit.exitScope) ?? findWorkflowExitSignal(runtime.signal.reason, runtime.exit.exitScope);
|
|
148
|
+
if (exit !== undefined) {
|
|
149
|
+
await boundary.skipForWorkflowExit(exit.reason);
|
|
150
|
+
throw exit;
|
|
151
|
+
}
|
|
152
|
+
boundary.fail(err);
|
|
153
|
+
throw err;
|
|
154
|
+
} finally {
|
|
155
|
+
detachParentAbort?.();
|
|
156
|
+
if (childRunId !== undefined) runtime.childRunOptions.cancellation?.unregister(childRunId);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
}
|
|
@@ -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
|
+
}
|