@bastani/atomic 0.9.11-alpha.9 → 0.9.11
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 +134 -0
- package/README.md +1 -1
- package/dist/builtin/intercom/CHANGELOG.md +6 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/subagent-relay.ts +8 -5
- package/dist/builtin/mcp/CHANGELOG.md +10 -0
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +20 -0
- package/dist/builtin/subagents/agents/code-simplifier.md +2 -2
- package/dist/builtin/subagents/agents/codebase-analyzer.md +2 -2
- package/dist/builtin/subagents/agents/codebase-locator.md +2 -2
- package/dist/builtin/subagents/agents/codebase-online-researcher.md +2 -2
- package/dist/builtin/subagents/agents/codebase-pattern-finder.md +2 -2
- package/dist/builtin/subagents/agents/codebase-research-analyzer.md +2 -2
- package/dist/builtin/subagents/agents/codebase-research-locator.md +2 -2
- package/dist/builtin/subagents/agents/worker.md +2 -2
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/notification-content.ts +14 -9
- package/dist/builtin/subagents/src/runs/background/notify.ts +20 -4
- package/dist/builtin/web-access/CHANGELOG.md +20 -0
- package/dist/builtin/web-access/content-tools.ts +1 -0
- package/dist/builtin/web-access/flat-string.ts +37 -0
- package/dist/builtin/web-access/github-api.ts +2 -1
- package/dist/builtin/web-access/github-extract.ts +3 -2
- package/dist/builtin/web-access/package.json +2 -2
- package/dist/builtin/workflows/CHANGELOG.md +57 -0
- package/dist/builtin/workflows/builtin/goal-ledger.ts +6 -4
- package/dist/builtin/workflows/builtin/goal-runner.ts +2 -1
- package/dist/builtin/workflows/builtin/goal.ts +1 -1
- package/dist/builtin/workflows/builtin/ralph-core.ts +8 -9
- package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +2 -4
- package/dist/builtin/workflows/builtin/ralph-models.ts +4 -4
- package/dist/builtin/workflows/builtin/ralph-runner.ts +5 -8
- package/dist/builtin/workflows/builtin/ralph.ts +2 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/durable/completed-catalog.ts +14 -8
- package/dist/builtin/workflows/src/durable/completed-inspection.ts +10 -11
- package/dist/builtin/workflows/src/durable/resume-catalog.ts +1 -1
- package/dist/builtin/workflows/src/durable/resume-eligibility.ts +42 -0
- package/dist/builtin/workflows/src/durable/resume-runtime.ts +36 -37
- package/dist/builtin/workflows/src/durable/tool-primitive.ts +10 -2
- package/dist/builtin/workflows/src/engine/run.ts +1 -0
- package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +12 -8
- package/dist/builtin/workflows/src/extension/hil-answer-notifications.ts +5 -2
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +1966 -880
- package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +6 -3
- package/dist/builtin/workflows/src/extension/postmortem-deps.ts +3 -2
- package/dist/builtin/workflows/src/extension/render-result.ts +4 -11
- package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +17 -20
- package/dist/builtin/workflows/src/extension/runtime.ts +3 -3
- package/dist/builtin/workflows/src/extension/workflow-command-completions.ts +1 -1
- package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +3 -7
- package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +21 -24
- package/dist/builtin/workflows/src/extension/workflow-resume-picker-rows.ts +38 -26
- package/dist/builtin/workflows/src/extension/workflow-resume-shadow.ts +2 -1
- package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +56 -64
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +2 -2
- package/dist/builtin/workflows/src/extension/workflow-status-summary.ts +0 -5
- package/dist/builtin/workflows/src/extension/workflow-targets.ts +17 -20
- package/dist/builtin/workflows/src/extension/workflow-tool-content.ts +1 -1
- package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +24 -51
- package/dist/builtin/workflows/src/extension/workflow-tool-inspection.ts +7 -29
- package/dist/builtin/workflows/src/extension/workflow-tool-send.ts +5 -13
- package/dist/builtin/workflows/src/extension/workflow-tool.ts +4 -13
- package/dist/builtin/workflows/src/runs/background/quit.ts +4 -3
- package/dist/builtin/workflows/src/runs/background/run-inspect.ts +8 -8
- package/dist/builtin/workflows/src/runs/background/status.ts +2 -1
- package/dist/builtin/workflows/src/runs/background/workflow-lifecycle-aggregate.ts +2 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +5 -5
- package/dist/builtin/workflows/src/runs/foreground/executor-lifecycle.ts +4 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-scheduler.ts +2 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +23 -8
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +6 -2
- package/dist/builtin/workflows/src/runs/foreground/executor-task-prompts.ts +5 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +56 -10
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +6 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts +137 -6
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +2 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +2 -0
- package/dist/builtin/workflows/src/shared/expanded-workflow-graph.ts +159 -10
- package/dist/builtin/workflows/src/shared/flat-string.ts +33 -0
- package/dist/builtin/workflows/src/shared/graph-store-snapshot.ts +144 -0
- package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +2 -3
- package/dist/builtin/workflows/src/shared/run-id.ts +36 -0
- package/dist/builtin/workflows/src/shared/store-internal.ts +32 -3
- package/dist/builtin/workflows/src/shared/store-observation.ts +10 -0
- package/dist/builtin/workflows/src/shared/store-public-types.ts +8 -0
- package/dist/builtin/workflows/src/shared/store-run-methods.ts +14 -0
- package/dist/builtin/workflows/src/shared/store-types.ts +4 -0
- package/dist/builtin/workflows/src/shared/types.ts +2 -0
- package/dist/builtin/workflows/src/shared/workflow-artifacts.ts +261 -0
- package/dist/builtin/workflows/src/tui/dispatch-confirm.ts +39 -23
- package/dist/builtin/workflows/src/tui/graph-canvas.ts +26 -9
- package/dist/builtin/workflows/src/tui/graph-view-constants.ts +3 -0
- package/dist/builtin/workflows/src/tui/graph-view-graph-render.ts +95 -98
- package/dist/builtin/workflows/src/tui/graph-view-render.ts +7 -20
- package/dist/builtin/workflows/src/tui/graph-view-state.ts +160 -13
- package/dist/builtin/workflows/src/tui/layout.ts +8 -2
- package/dist/builtin/workflows/src/tui/node-card.ts +57 -45
- package/dist/builtin/workflows/src/tui/overlay-adapter.ts +4 -2
- package/dist/builtin/workflows/src/tui/prompt-card-render.ts +291 -21
- package/dist/builtin/workflows/src/tui/prompt-card.ts +1 -1
- package/dist/builtin/workflows/src/tui/renderers.ts +0 -1
- package/dist/builtin/workflows/src/tui/run-detail.ts +52 -35
- package/dist/builtin/workflows/src/tui/run-identity-rows.ts +97 -0
- package/dist/builtin/workflows/src/tui/session-overlays.ts +24 -3
- package/dist/builtin/workflows/src/tui/session-picker.ts +94 -41
- package/dist/builtin/workflows/src/tui/stage-chat-view-archive-history.ts +190 -26
- package/dist/builtin/workflows/src/tui/stage-chat-view-footer-status.ts +52 -18
- package/dist/builtin/workflows/src/tui/stage-chat-view-input.ts +9 -5
- package/dist/builtin/workflows/src/tui/stage-chat-view-state.ts +44 -4
- package/dist/builtin/workflows/src/tui/stage-chat-view-types.ts +3 -1
- package/dist/builtin/workflows/src/tui/stage-chat-view.ts +3 -2
- package/dist/builtin/workflows/src/tui/status-list.ts +67 -45
- package/dist/builtin/workflows/src/tui/store-widget-installer.ts +7 -6
- package/dist/builtin/workflows/src/tui/widget.ts +49 -40
- package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +15 -10
- package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +21 -8
- package/dist/core/agent-session-accessors.d.ts.map +1 -1
- package/dist/core/agent-session-accessors.js +5 -0
- package/dist/core/agent-session-accessors.js.map +1 -1
- package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-auto-compaction.js +5 -0
- package/dist/core/agent-session-auto-compaction.js.map +1 -1
- package/dist/core/agent-session-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-compaction.js +3 -0
- package/dist/core/agent-session-compaction.js.map +1 -1
- package/dist/core/agent-session-events.d.ts.map +1 -1
- package/dist/core/agent-session-events.js +2 -1
- package/dist/core/agent-session-events.js.map +1 -1
- package/dist/core/agent-session-message-queue.d.ts +3 -7
- package/dist/core/agent-session-message-queue.d.ts.map +1 -1
- package/dist/core/agent-session-message-queue.js +27 -13
- package/dist/core/agent-session-message-queue.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +5 -3
- 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-persistent-custom-messages.d.ts.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.js +6 -3
- package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
- package/dist/core/agent-session-post-tool-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-post-tool-compaction.js +11 -2
- package/dist/core/agent-session-post-tool-compaction.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +5 -3
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-tree.d.ts.map +1 -1
- package/dist/core/agent-session-tree.js +4 -0
- package/dist/core/agent-session-tree.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +4 -0
- 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 +2 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage-backends.d.ts.map +1 -1
- package/dist/core/auth-storage-backends.js +12 -1
- package/dist/core/auth-storage-backends.js.map +1 -1
- package/dist/core/bounded-model-refresh.d.ts +14 -0
- package/dist/core/bounded-model-refresh.d.ts.map +1 -0
- package/dist/core/bounded-model-refresh.js +38 -0
- package/dist/core/bounded-model-refresh.js.map +1 -0
- package/dist/core/context-tool-pairing.d.ts +4 -4
- package/dist/core/context-tool-pairing.js +4 -4
- package/dist/core/context-tool-pairing.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +26 -1
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/messages.d.ts +18 -6
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +46 -18
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-refresh-timeout.d.ts +9 -0
- package/dist/core/model-refresh-timeout.d.ts.map +1 -0
- package/dist/core/model-refresh-timeout.js +9 -0
- package/dist/core/model-refresh-timeout.js.map +1 -0
- package/dist/core/model-runtime-snapshot.d.ts +3 -0
- package/dist/core/model-runtime-snapshot.d.ts.map +1 -1
- package/dist/core/model-runtime-snapshot.js +59 -0
- package/dist/core/model-runtime-snapshot.js.map +1 -1
- package/dist/core/model-runtime.d.ts +7 -1
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +72 -17
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +4 -3
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager-core.d.ts +1 -1
- package/dist/core/session-manager-core.d.ts.map +1 -1
- package/dist/core/session-manager-core.js +2 -2
- package/dist/core/session-manager-core.js.map +1 -1
- package/dist/core/session-manager-entries.d.ts +1 -1
- package/dist/core/session-manager-entries.d.ts.map +1 -1
- package/dist/core/session-manager-entries.js +2 -1
- package/dist/core/session-manager-entries.js.map +1 -1
- package/dist/core/session-manager-history.d.ts.map +1 -1
- package/dist/core/session-manager-history.js +2 -2
- package/dist/core/session-manager-history.js.map +1 -1
- package/dist/core/session-manager-types.d.ts +3 -0
- package/dist/core/session-manager-types.d.ts.map +1 -1
- package/dist/core/session-manager-types.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main-app-mode.d.ts +1 -0
- package/dist/main-app-mode.d.ts.map +1 -1
- package/dist/main-app-mode.js +3 -0
- package/dist/main-app-mode.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +8 -3
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-actions.d.ts +7 -2
- package/dist/modes/interactive/components/chat-session-host-actions.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-actions.js +13 -4
- package/dist/modes/interactive/components/chat-session-host-actions.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-editor.d.ts +3 -1
- package/dist/modes/interactive/components/chat-session-host-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-editor.js +2 -2
- package/dist/modes/interactive/components/chat-session-host-editor.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.d.ts +3 -0
- package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.js +5 -4
- package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.d.ts +16 -2
- package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.js +35 -5
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts +0 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +25 -35
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-editor-actions.js +2 -1
- package/dist/modes/interactive/interactive-editor-actions.js.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.js +1 -1
- package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +4 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
- package/dist/modes/interactive/interactive-model-routing.js +4 -1
- package/dist/modes/interactive/interactive-model-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-pause.d.ts +3 -1
- package/dist/modes/interactive/interactive-pause.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-pause.js +5 -1
- package/dist/modes/interactive/interactive-pause.js.map +1 -1
- package/dist/modes/interactive/interactive-queueing.js +3 -3
- package/dist/modes/interactive/interactive-queueing.js.map +1 -1
- package/dist/modes/interactive-engine/engine-health.d.ts +6 -0
- package/dist/modes/interactive-engine/engine-health.d.ts.map +1 -1
- package/dist/modes/interactive-engine/engine-health.js +15 -1
- package/dist/modes/interactive-engine/engine-health.js.map +1 -1
- package/dist/modes/interactive-engine/isolated-auth.js +1 -1
- package/dist/modes/interactive-engine/isolated-auth.js.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.d.ts +1 -0
- package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.js +7 -1
- package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
- package/dist/modes/interactive-engine/remote-model-catalog.d.ts.map +1 -1
- package/dist/modes/interactive-engine/remote-model-catalog.js +5 -1
- package/dist/modes/interactive-engine/remote-model-catalog.js.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.js +23 -7
- package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
- package/dist/modes/rpc/rpc-input-scheduler.js +1 -1
- package/dist/modes/rpc/rpc-input-scheduler.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +2 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/custom-provider.md +3 -3
- package/docs/extensions.md +3 -1
- package/docs/index.md +10 -0
- package/docs/keybindings.md +1 -1
- package/docs/models.md +2 -0
- package/docs/providers.md +7 -3
- package/docs/quickstart.md +7 -1
- package/docs/session-format.md +2 -0
- package/docs/termux.md +3 -1
- package/docs/usage.md +3 -2
- package/docs/workflows.md +82 -46
- package/npm-shrinkwrap.json +59 -27
- package/package.json +3 -3
- package/dist/builtin/workflows/src/tui/toast.ts +0 -107
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getDurableBackend } from "../durable/factory.js";
|
|
2
|
+
import { isWorkflowRunResumable } from "../durable/resume-eligibility.js";
|
|
2
3
|
import type { ResumableWorkflowEntry } from "../durable/types.js";
|
|
3
4
|
import { quitAllRuns, quitRun } from "../runs/background/quit.js";
|
|
4
5
|
import { abortToolNode } from "../runs/background/quit-tool-node.js";
|
|
@@ -7,6 +8,7 @@ import { workflowHasPausedStages, workflowHasPausedState } from "../runs/backgro
|
|
|
7
8
|
import { store } from "../shared/store.js";
|
|
8
9
|
import type { RunSnapshot } from "../shared/store-types.js";
|
|
9
10
|
import type { WorkflowExecutionPolicy, WorkflowToolNodeIdentity } from "../shared/types.js";
|
|
11
|
+
import { workflowRunResumeCandidate } from "../shared/workflow-artifacts.js";
|
|
10
12
|
import type { WorkflowToolArgs } from "./public-types.js";
|
|
11
13
|
import type { WorkflowToolResult } from "./render-result.js";
|
|
12
14
|
import type { ExtensionRuntime } from "./runtime.js";
|
|
@@ -16,7 +18,6 @@ import { normalizeWorkflowReloadReport, type WorkflowReloadReport } from "./work
|
|
|
16
18
|
import { classifyDurableResumeShadow } from "./workflow-resume-shadow.js";
|
|
17
19
|
import {
|
|
18
20
|
allStageConflictMessage,
|
|
19
|
-
ambiguousRunMessage,
|
|
20
21
|
reloadFailureMessage,
|
|
21
22
|
resolveControlNodeTarget,
|
|
22
23
|
resolveToolRunTarget,
|
|
@@ -81,14 +82,8 @@ export async function workflowPauseAction(args: WorkflowToolArgs): Promise<Workf
|
|
|
81
82
|
return controlFailure(action, "--all", error);
|
|
82
83
|
}
|
|
83
84
|
}
|
|
84
|
-
if (target.kind === "
|
|
85
|
-
return {
|
|
86
|
-
action,
|
|
87
|
-
runId: target.target,
|
|
88
|
-
status: "noop",
|
|
89
|
-
message: ambiguousRunMessage(target.target, target.matches),
|
|
90
|
-
};
|
|
91
|
-
if (target.kind === "not_found") return { action, runId: target.target, status: "noop", message: target.message };
|
|
85
|
+
if (target.kind === "malformed" || target.kind === "not_found")
|
|
86
|
+
return { action, runId: target.target, status: "noop", message: target.message };
|
|
92
87
|
const controlNode = resolveControlNodeTarget(target.runId, args.stageId);
|
|
93
88
|
// Tool nodes have no turn boundary to stop at, so pause rejects them loudly
|
|
94
89
|
// instead of silently resolving to nothing.
|
|
@@ -111,7 +106,7 @@ export async function workflowPauseAction(args: WorkflowToolArgs): Promise<Workf
|
|
|
111
106
|
action,
|
|
112
107
|
runId: result.runId,
|
|
113
108
|
status: "paused",
|
|
114
|
-
message: `Paused ${result.paused.length} stage(s) on run ${result.runId
|
|
109
|
+
message: `Paused ${result.paused.length} stage(s) on run ${result.runId}.`,
|
|
115
110
|
}
|
|
116
111
|
: {
|
|
117
112
|
action,
|
|
@@ -214,7 +209,7 @@ async function quitToolNodeAction(
|
|
|
214
209
|
action,
|
|
215
210
|
runId,
|
|
216
211
|
status: "noop",
|
|
217
|
-
message: `Tool node ${nodeId} is not running on run ${runId
|
|
212
|
+
message: `Tool node ${nodeId} is not running on run ${runId}.`,
|
|
218
213
|
};
|
|
219
214
|
}
|
|
220
215
|
// Let the rejected tool promise reach workflow code before the run status is
|
|
@@ -232,7 +227,7 @@ async function quitToolNodeAction(
|
|
|
232
227
|
workflowStatus,
|
|
233
228
|
abandoned: aborted.abandoned,
|
|
234
229
|
message:
|
|
235
|
-
`Cancelled ctx.tool ${aborted.name} (${nodeId}) on run ${runId
|
|
230
|
+
`Cancelled ctx.tool ${aborted.name} (${nodeId}) on run ${runId}.${abandonedNote}` +
|
|
236
231
|
` Sibling work was not aborted. Current workflow status: ${workflowStatus}.` +
|
|
237
232
|
" If workflow code awaited this call without catching cancellation, the workflow may fail." +
|
|
238
233
|
" A later resume re-runs this call.",
|
|
@@ -262,15 +257,9 @@ export async function workflowQuitAction(args: WorkflowToolArgs): Promise<Workfl
|
|
|
262
257
|
: "No in-flight runs to quit.",
|
|
263
258
|
};
|
|
264
259
|
}
|
|
265
|
-
if (target.kind === "
|
|
266
|
-
return {
|
|
267
|
-
action,
|
|
268
|
-
runId: target.target,
|
|
269
|
-
status: "noop",
|
|
270
|
-
message: ambiguousRunMessage(target.target, target.matches),
|
|
271
|
-
};
|
|
260
|
+
if (target.kind === "malformed" || target.kind === "not_found") {
|
|
261
|
+
return { action, runId: target.target, status: "noop", message: target.message };
|
|
272
262
|
}
|
|
273
|
-
if (target.kind === "not_found") return { action, runId: target.target, status: "noop", message: target.message };
|
|
274
263
|
const controlNode = resolveControlNodeTarget(target.runId, args.stageId);
|
|
275
264
|
if (!controlNode.ok) return { action, runId: target.runId, status: "noop", message: controlNode.message };
|
|
276
265
|
if (controlNode.kind === "tool") return quitToolNodeAction(controlNode.runId, controlNode.nodeId, action);
|
|
@@ -290,9 +279,9 @@ export async function workflowQuitAction(args: WorkflowToolArgs): Promise<Workfl
|
|
|
290
279
|
status: "noop",
|
|
291
280
|
message:
|
|
292
281
|
result.reason === "already_ended"
|
|
293
|
-
? `Run ${target.runId
|
|
282
|
+
? `Run ${target.runId} already ended.`
|
|
294
283
|
: result.reason === "no_active_stages"
|
|
295
|
-
? `No controllable stages on run ${target.runId
|
|
284
|
+
? `No controllable stages on run ${target.runId}; the run remains active.`
|
|
296
285
|
: `Run not found: ${target.runId}`,
|
|
297
286
|
};
|
|
298
287
|
} catch (error) {
|
|
@@ -320,14 +309,8 @@ export async function workflowInterruptAction(args: WorkflowToolArgs): Promise<W
|
|
|
320
309
|
return controlFailure(action, "--all", error);
|
|
321
310
|
}
|
|
322
311
|
}
|
|
323
|
-
if (target.kind === "
|
|
324
|
-
return {
|
|
325
|
-
action,
|
|
326
|
-
runId: target.target,
|
|
327
|
-
status: "noop",
|
|
328
|
-
message: ambiguousRunMessage(target.target, target.matches),
|
|
329
|
-
};
|
|
330
|
-
if (target.kind === "not_found") return { action, runId: target.target, status: "noop", message: target.message };
|
|
312
|
+
if (target.kind === "malformed" || target.kind === "not_found")
|
|
313
|
+
return { action, runId: target.target, status: "noop", message: target.message };
|
|
331
314
|
const controlNode = resolveControlNodeTarget(target.runId, args.stageId);
|
|
332
315
|
if (!controlNode.ok) return { action, runId: target.runId, status: "noop", message: controlNode.message };
|
|
333
316
|
if (controlNode.kind === "tool") return quitToolNodeAction(controlNode.runId, controlNode.nodeId, action);
|
|
@@ -412,14 +395,8 @@ async function resolveExplicitDurableTarget(
|
|
|
412
395
|
return controlFailure("resume", target, error);
|
|
413
396
|
}
|
|
414
397
|
const resolved = resolveWorkflowResumeTarget(target, liveRuns, durable, []);
|
|
415
|
-
if (resolved.kind === "
|
|
416
|
-
|
|
417
|
-
return {
|
|
418
|
-
action: "resume",
|
|
419
|
-
runId: target,
|
|
420
|
-
status: "noop",
|
|
421
|
-
message: `Ambiguous run prefix "${target}" matches: ${matches.join(", ")}`,
|
|
422
|
-
};
|
|
398
|
+
if (resolved.kind === "malformed") {
|
|
399
|
+
return { action: "resume", runId: target, status: "noop", message: resolved.message };
|
|
423
400
|
}
|
|
424
401
|
if (resolved.kind === "durable") return resumePreparedDurableTarget(resolved.workflowId, deps);
|
|
425
402
|
if (resolved.kind === "live") {
|
|
@@ -458,9 +435,8 @@ export async function workflowResumeAction(
|
|
|
458
435
|
const target = resolveToolRunTarget(args, "No active run to resume.");
|
|
459
436
|
if (target.kind === "all")
|
|
460
437
|
return { action: "resume", runId: "--all", status: "noop", message: "Resume does not support --all." };
|
|
461
|
-
if (target.kind === "
|
|
462
|
-
|
|
463
|
-
return resolveExplicitDurableTarget(target.target, args, deps, liveMatches);
|
|
438
|
+
if (target.kind === "malformed") {
|
|
439
|
+
return { action: "resume", runId: target.target, status: "noop", message: target.message };
|
|
464
440
|
}
|
|
465
441
|
if (target.kind === "not_found") {
|
|
466
442
|
const explicitTarget = args.runId?.trim();
|
|
@@ -469,11 +445,8 @@ export async function workflowResumeAction(
|
|
|
469
445
|
}
|
|
470
446
|
return { action: "resume", runId: target.target, status: "noop", message: target.message };
|
|
471
447
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
const liveMatches = store.runs().filter((run) => run.id.startsWith(explicitTarget));
|
|
475
|
-
return resolveExplicitDurableTarget(explicitTarget, args, deps, liveMatches);
|
|
476
|
-
}
|
|
448
|
+
// An explicit target now resolves only by exact id, so it can never disagree
|
|
449
|
+
// with the resolved run; the old re-resolution branch here is unreachable.
|
|
477
450
|
const backend = getDurableBackend();
|
|
478
451
|
const exact = store.runs().find((run) => run.id === target.runId);
|
|
479
452
|
const shadow = exact === undefined ? "not_shadow" : classifyDurableResumeShadow(exact, store, { backend });
|
|
@@ -512,8 +485,8 @@ export async function workflowResumeAction(
|
|
|
512
485
|
const isResumableContinuation =
|
|
513
486
|
run !== undefined &&
|
|
514
487
|
!isPaused &&
|
|
515
|
-
|
|
516
|
-
|
|
488
|
+
run.exitReason !== "quit" &&
|
|
489
|
+
isWorkflowRunResumable(workflowRunResumeCandidate(run));
|
|
517
490
|
if (isResumableContinuation) {
|
|
518
491
|
try {
|
|
519
492
|
await deps.ensureWorkflowResourcesLoaded();
|
|
@@ -544,9 +517,9 @@ export async function workflowResumeAction(
|
|
|
544
517
|
(isPaused
|
|
545
518
|
? result.resumed.length === 0
|
|
546
519
|
? runLevelResumed
|
|
547
|
-
? `Resumed run ${result.runId
|
|
548
|
-
: `No paused stages on run ${result.runId
|
|
549
|
-
: `Resumed ${result.resumed.length} stage(s) on run ${result.runId
|
|
520
|
+
? `Resumed run ${result.runId}.`
|
|
521
|
+
: `No paused stages on run ${result.runId}.`
|
|
522
|
+
: `Resumed ${result.resumed.length} stage(s) on run ${result.runId}${args.message ? ` with message: "${args.message}"` : ""}.`
|
|
550
523
|
: `Snapshot available: run ${result.runId} (${result.snapshot.name}) — status: ${result.snapshot.status}, stages: ${result.snapshot.stages.length}`);
|
|
551
524
|
const status = result.mode === "partial" ? "partial" : noPausedProgress ? "noop" : "ok";
|
|
552
525
|
return { action: "resume", runId: result.runId, status, message };
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
summarizeStage,
|
|
13
13
|
transcriptEntryFromMessage,
|
|
14
14
|
} from "./workflow-stage-results.js";
|
|
15
|
-
import {
|
|
15
|
+
import { resolveToolRunTarget, resolveToolStageTarget } from "./workflow-targets.js";
|
|
16
16
|
|
|
17
17
|
export function workflowStagesResult(args: WorkflowToolArgs): WorkflowToolResult {
|
|
18
18
|
const target = resolveToolRunTarget(args, "No active run to inspect.");
|
|
@@ -26,16 +26,7 @@ export function workflowStagesResult(args: WorkflowToolArgs): WorkflowToolResult
|
|
|
26
26
|
error: "Stage listing requires a single run.",
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
|
-
if (target.kind === "
|
|
30
|
-
return {
|
|
31
|
-
action: "stages",
|
|
32
|
-
runId: target.target,
|
|
33
|
-
filter,
|
|
34
|
-
stages: [],
|
|
35
|
-
error: ambiguousRunMessage(target.target, target.matches),
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
if (target.kind === "not_found") {
|
|
29
|
+
if (target.kind === "malformed" || target.kind === "not_found") {
|
|
39
30
|
return {
|
|
40
31
|
action: "stages",
|
|
41
32
|
runId: target.target,
|
|
@@ -56,10 +47,7 @@ export function workflowStageResult(args: WorkflowToolArgs): WorkflowToolResult
|
|
|
56
47
|
if (target.kind === "all") {
|
|
57
48
|
return { action: "stage", runId: "--all", error: "Stage inspection requires a single run." };
|
|
58
49
|
}
|
|
59
|
-
if (target.kind === "
|
|
60
|
-
return { action: "stage", runId: target.target, error: ambiguousRunMessage(target.target, target.matches) };
|
|
61
|
-
}
|
|
62
|
-
if (target.kind === "not_found") {
|
|
50
|
+
if (target.kind === "malformed" || target.kind === "not_found") {
|
|
63
51
|
return { action: "stage", runId: target.target, error: target.message };
|
|
64
52
|
}
|
|
65
53
|
const stage = resolveToolStageTarget(target.runId, args.stageId);
|
|
@@ -67,7 +55,7 @@ export function workflowStageResult(args: WorkflowToolArgs): WorkflowToolResult
|
|
|
67
55
|
return {
|
|
68
56
|
action: "stage",
|
|
69
57
|
runId: target.runId,
|
|
70
|
-
error: stage.ok ? "Stage id
|
|
58
|
+
error: stage.ok ? "Stage id or name is required." : stage.message,
|
|
71
59
|
};
|
|
72
60
|
}
|
|
73
61
|
const stageRunId = stage.runId ?? target.runId;
|
|
@@ -78,7 +66,7 @@ export function workflowStageResult(args: WorkflowToolArgs): WorkflowToolResult
|
|
|
78
66
|
: {
|
|
79
67
|
action: "stage",
|
|
80
68
|
runId: stageRunId,
|
|
81
|
-
error: `Stage not found in run ${stageRunId
|
|
69
|
+
error: `Stage not found in run ${stageRunId}: ${stage.stageId}`,
|
|
82
70
|
};
|
|
83
71
|
}
|
|
84
72
|
|
|
@@ -94,17 +82,7 @@ export function workflowTranscriptResult(args: WorkflowToolArgs): WorkflowToolRe
|
|
|
94
82
|
truncated: false,
|
|
95
83
|
};
|
|
96
84
|
}
|
|
97
|
-
if (target.kind === "
|
|
98
|
-
return {
|
|
99
|
-
action: "transcript",
|
|
100
|
-
runId: target.target,
|
|
101
|
-
stageId: "",
|
|
102
|
-
source: "error",
|
|
103
|
-
entries: [{ role: "notice", text: ambiguousRunMessage(target.target, target.matches) }],
|
|
104
|
-
truncated: false,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
if (target.kind === "not_found") {
|
|
85
|
+
if (target.kind === "malformed" || target.kind === "not_found") {
|
|
108
86
|
return {
|
|
109
87
|
action: "transcript",
|
|
110
88
|
runId: target.target,
|
|
@@ -121,7 +99,7 @@ export function workflowTranscriptResult(args: WorkflowToolArgs): WorkflowToolRe
|
|
|
121
99
|
runId: target.runId,
|
|
122
100
|
stageId: "",
|
|
123
101
|
source: "error",
|
|
124
|
-
entries: [{ role: "notice", text: stage.ok ? "Stage id
|
|
102
|
+
entries: [{ role: "notice", text: stage.ok ? "Stage id or name is required." : stage.message }],
|
|
125
103
|
truncated: false,
|
|
126
104
|
};
|
|
127
105
|
}
|
|
@@ -9,10 +9,11 @@ import { coerceStageInputAnswer, hasStageInputAnswerContent, type StageInputAnsw
|
|
|
9
9
|
import { stageUiBroker } from "../shared/stage-ui-broker.js";
|
|
10
10
|
import { store } from "../shared/store.js";
|
|
11
11
|
import { isTerminalRunStatus } from "../shared/store-internal.js";
|
|
12
|
+
import { subscribeStoreInvalidation } from "../shared/store-observation.js";
|
|
12
13
|
import { reciprocalWorkflowRootRunId } from "../shared/workflow-run-ownership.js";
|
|
13
14
|
import type { WorkflowToolArgs } from "./public-types.js";
|
|
14
15
|
import type { WorkflowToolResult } from "./render-result.js";
|
|
15
|
-
import {
|
|
16
|
+
import { resolveToolRunTarget, resolveToolStageTarget } from "./workflow-targets.js";
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Optional dependencies enabling `workflow send` to revive an eligible
|
|
@@ -120,16 +121,7 @@ export async function workflowSendAction(
|
|
|
120
121
|
if (target.kind === "all") {
|
|
121
122
|
return workflowSendResult("--all", "", requestedDelivery, "noop", "Send requires a single run.");
|
|
122
123
|
}
|
|
123
|
-
if (target.kind === "
|
|
124
|
-
return workflowSendResult(
|
|
125
|
-
target.target,
|
|
126
|
-
"",
|
|
127
|
-
requestedDelivery,
|
|
128
|
-
"noop",
|
|
129
|
-
ambiguousRunMessage(target.target, target.matches),
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
if (target.kind === "not_found") {
|
|
124
|
+
if (target.kind === "malformed" || target.kind === "not_found") {
|
|
133
125
|
return workflowSendResult(target.target, "", requestedDelivery, "noop", target.message);
|
|
134
126
|
}
|
|
135
127
|
const runs = store.runs();
|
|
@@ -146,7 +138,7 @@ export async function workflowSendAction(
|
|
|
146
138
|
"",
|
|
147
139
|
requestedDelivery,
|
|
148
140
|
"noop",
|
|
149
|
-
stage.ok ? "Stage id
|
|
141
|
+
stage.ok ? "Stage id or name is required." : stage.message,
|
|
150
142
|
);
|
|
151
143
|
}
|
|
152
144
|
const resolvedStageId = stage.stageId;
|
|
@@ -280,7 +272,7 @@ export async function workflowSendAction(
|
|
|
280
272
|
admitted = true;
|
|
281
273
|
};
|
|
282
274
|
const terminalPending = Promise.withResolvers<never>();
|
|
283
|
-
const unsubscribeTerminal = store
|
|
275
|
+
const unsubscribeTerminal = subscribeStoreInvalidation(store, () => {
|
|
284
276
|
if (admitted) return;
|
|
285
277
|
const terminal = terminalWorkflowSendResultForRoot(rootRunId, args.stageId?.trim() ?? resolvedStageId);
|
|
286
278
|
if (terminal !== undefined) terminalPending.reject(new WorkflowSendAdmissionError(terminal));
|
|
@@ -8,12 +8,7 @@ import { formatWorkflowResourceLoadWarning } from "./workflow-command-surfaces.j
|
|
|
8
8
|
import { workflowPolicyFromContext } from "./workflow-policy.js";
|
|
9
9
|
import type { WorkflowReloadReport } from "./workflow-reload-report.js";
|
|
10
10
|
import { buildWorkflowStatusListing } from "./workflow-status-summary.js";
|
|
11
|
-
import {
|
|
12
|
-
ambiguousRunMessage,
|
|
13
|
-
isWorkflowStageToolContext,
|
|
14
|
-
resolveRunIdPrefix,
|
|
15
|
-
topLevelExpandedSnapshots,
|
|
16
|
-
} from "./workflow-targets.js";
|
|
11
|
+
import { isWorkflowStageToolContext, resolveRunId, topLevelExpandedSnapshots } from "./workflow-targets.js";
|
|
17
12
|
import { workflowGetResult } from "./workflow-tool-content.js";
|
|
18
13
|
import {
|
|
19
14
|
workflowInterruptAction,
|
|
@@ -84,13 +79,9 @@ export function makeExecuteWorkflowTool(
|
|
|
84
79
|
case "status": {
|
|
85
80
|
const target = args.runId;
|
|
86
81
|
if (target !== undefined) {
|
|
87
|
-
const resolved =
|
|
88
|
-
if (resolved.kind === "
|
|
89
|
-
return {
|
|
90
|
-
action: "statusDetail",
|
|
91
|
-
runId: target,
|
|
92
|
-
error: ambiguousRunMessage(target, resolved.matches),
|
|
93
|
-
};
|
|
82
|
+
const resolved = resolveRunId(target);
|
|
83
|
+
if (resolved.kind === "malformed") {
|
|
84
|
+
return { action: "statusDetail", runId: target, error: resolved.message };
|
|
94
85
|
}
|
|
95
86
|
if (resolved.kind === "not_found") {
|
|
96
87
|
return { action: "statusDetail", runId: target, error: `run not found: ${target}` };
|
|
@@ -18,6 +18,7 @@ import { WorkflowGracefulQuitError } from "../../engine/workflow-tool-abort.js";
|
|
|
18
18
|
import { expandWorkflowGraph } from "../../shared/expanded-workflow-graph.js";
|
|
19
19
|
import { topLevelWorkflowRuns } from "../../shared/run-visibility.js";
|
|
20
20
|
import { store as defaultStore } from "../../shared/store.js";
|
|
21
|
+
import { readGraphStoreSnapshot } from "../../shared/store-observation.js";
|
|
21
22
|
import type { Store } from "../../shared/store-public-types.js";
|
|
22
23
|
import type { RunSnapshot, StageSnapshot } from "../../shared/store-types.js";
|
|
23
24
|
import type { WorkflowCancelledToolNode, WorkflowToolNodeIdentity } from "../../shared/types.js";
|
|
@@ -100,7 +101,7 @@ export async function quitRun(
|
|
|
100
101
|
if (!run) return { ok: false, runId, reason: "not_found" };
|
|
101
102
|
if (run.endedAt !== undefined) return { ok: false, runId, reason: "already_ended" };
|
|
102
103
|
|
|
103
|
-
const graph = expandWorkflowGraph(activeStore
|
|
104
|
+
const graph = expandWorkflowGraph(readGraphStoreSnapshot(activeStore), runId);
|
|
104
105
|
const handles = controllableHandles(activeStore, registry, runId);
|
|
105
106
|
const admissionBoundaries = controllableAdmissionBoundaries(activeStore, toolControls, runId);
|
|
106
107
|
const promptStages = graph.stages.filter(
|
|
@@ -247,7 +248,7 @@ function controllableAdmissionBoundaries(
|
|
|
247
248
|
*/
|
|
248
249
|
async function closeToolAdmission(boundaries: readonly ToolAdmissionBoundary[], runId: string): Promise<void> {
|
|
249
250
|
if (boundaries.length === 0) return;
|
|
250
|
-
const reason = new WorkflowGracefulQuitError(runId, `run ${runId
|
|
251
|
+
const reason = new WorkflowGracefulQuitError(runId, `run ${runId}`);
|
|
251
252
|
await Promise.all(boundaries.map((boundary) => boundary.closeForQuit(reason)));
|
|
252
253
|
}
|
|
253
254
|
|
|
@@ -303,7 +304,7 @@ function controllableHandles(
|
|
|
303
304
|
registry: StageControlRegistry,
|
|
304
305
|
runId: string,
|
|
305
306
|
): Array<{ controlRunId: string; handle: StageControlHandle }> {
|
|
306
|
-
const graph = expandWorkflowGraph(activeStore
|
|
307
|
+
const graph = expandWorkflowGraph(readGraphStoreSnapshot(activeStore), runId);
|
|
307
308
|
const controlRunIds = new Set<string>([runId]);
|
|
308
309
|
for (const stage of graph.stages) controlRunIds.add(stage.workflowGraphTarget.runId);
|
|
309
310
|
return [...controlRunIds].flatMap((controlRunId) =>
|
|
@@ -62,18 +62,18 @@ export type InspectRunResult =
|
|
|
62
62
|
| { ok: false; runId: string; reason: "not_found" };
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
|
-
* Look up a single run by
|
|
66
|
-
*
|
|
65
|
+
* Look up a single run by its exact id and return a normalised
|
|
66
|
+
* {@link RunDetail} for the per-run text/TUI surfaces.
|
|
67
67
|
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
68
|
+
* Exact match only. Callers reach this with an id already resolved at the input
|
|
69
|
+
* boundary, where shape is validated; a second, looser prefix match here would
|
|
70
|
+
* only reintroduce the truncated targeting the resolvers now reject.
|
|
71
|
+
*
|
|
72
|
+
* Read-only: does not mutate the store.
|
|
70
73
|
*/
|
|
71
74
|
export function inspectRun(runId: string, opts?: { store?: Store }): InspectRunResult {
|
|
72
75
|
const activeStore = opts?.store ?? defaultStore;
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
const exact = runs.find((r) => r.id === runId);
|
|
76
|
-
const candidate = exact ?? (runs.length > 0 ? runs.find((r) => r.id.startsWith(runId)) : undefined);
|
|
76
|
+
const candidate = activeStore.runs().find((r) => r.id === runId);
|
|
77
77
|
|
|
78
78
|
if (!candidate) {
|
|
79
79
|
return { ok: false, runId, reason: "not_found" };
|
|
@@ -15,6 +15,7 @@ import { effectiveRunStatus } from "../../shared/returned-run-status.js";
|
|
|
15
15
|
import { topLevelWorkflowRuns } from "../../shared/run-visibility.js";
|
|
16
16
|
import type { Store } from "../../shared/store.js";
|
|
17
17
|
import { store as defaultStore } from "../../shared/store.js";
|
|
18
|
+
import { readGraphStoreSnapshot } from "../../shared/store-observation.js";
|
|
18
19
|
import type { RunSnapshot, RunStatus, StageSnapshot } from "../../shared/store-types.js";
|
|
19
20
|
import type { WorkflowPersistencePort } from "../../shared/types.js";
|
|
20
21
|
import type { StageControlRegistry } from "../foreground/stage-control-registry.js";
|
|
@@ -89,7 +90,7 @@ export { type InspectRunResult, inspectRun, type RunDetail } from "./run-inspect
|
|
|
89
90
|
export function statusRuns(opts?: { all?: boolean; store?: Store }): RunStatusEntry[] {
|
|
90
91
|
const activeStore = opts?.store ?? defaultStore;
|
|
91
92
|
|
|
92
|
-
const snapshot = activeStore
|
|
93
|
+
const snapshot = readGraphStoreSnapshot(activeStore);
|
|
93
94
|
return topLevelWorkflowRuns(snapshot.runs).map((run) => {
|
|
94
95
|
const graph = expandWorkflowGraph(snapshot, run.id);
|
|
95
96
|
return {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { expandWorkflowGraph } from "../../shared/expanded-workflow-graph.js";
|
|
2
|
+
import { readGraphStoreSnapshot } from "../../shared/store-observation.js";
|
|
2
3
|
import type { Store } from "../../shared/store-public-types.js";
|
|
3
4
|
import { reciprocalWorkflowRootRunId } from "../../shared/workflow-run-ownership.js";
|
|
4
5
|
|
|
5
6
|
/** Control-run ids visible below one workflow boundary, in graph order. */
|
|
6
7
|
export function expandedControlRunIds(store: Store, runId: string): string[] {
|
|
7
|
-
const graph = expandWorkflowGraph(store
|
|
8
|
+
const graph = expandWorkflowGraph(readGraphStoreSnapshot(store), runId);
|
|
8
9
|
const ids = new Set<string>([runId]);
|
|
9
10
|
for (const stage of graph.stages) ids.add(stage.workflowGraphTarget.runId);
|
|
10
11
|
// Tool-only nested runs own no stage, yet their in-flight ctx.tool nodes are
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { tmpdir } from "node:os";
|
|
2
1
|
import { isAbsolute, join, resolve } from "node:path";
|
|
3
|
-
import {
|
|
2
|
+
import { CONFIG_DIR_NAME, isCodexFastModeCandidateModelId } from "@bastani/atomic";
|
|
4
3
|
import type { StageOptions, WorkflowArtifact, WorkflowTaskOptions, WorkflowTaskStep } from "../../shared/types.js";
|
|
4
|
+
import { workflowArtifactRunPath } from "../../shared/workflow-artifacts.js";
|
|
5
5
|
import { buildModelCandidatesFromCatalog, workflowModelId } from "../shared/model-fallback.js";
|
|
6
6
|
import {
|
|
7
7
|
cleanupWorktrees,
|
|
@@ -211,8 +211,8 @@ function resolvedTaskCwd(cwd: string | undefined, workflowInvocationCwd: string)
|
|
|
211
211
|
return isAbsolute(cwd) ? cwd : resolve(workflowInvocationCwd, cwd);
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
-
function taskWorktreeOutputsRoot(): string {
|
|
215
|
-
return join(
|
|
214
|
+
function taskWorktreeOutputsRoot(runId: string): string {
|
|
215
|
+
return join(workflowArtifactRunPath(runId), "task-outputs");
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
export function prepareTaskWorktrees(
|
|
@@ -250,7 +250,7 @@ export function prepareTaskWorktrees(
|
|
|
250
250
|
baseBranch: options.baseBranch,
|
|
251
251
|
symlinkDirectories,
|
|
252
252
|
});
|
|
253
|
-
const trustedRoot = taskWorktreeOutputsRoot();
|
|
253
|
+
const trustedRoot = taskWorktreeOutputsRoot(runId);
|
|
254
254
|
return {
|
|
255
255
|
tasks: tasks.map((task, index) => ({ ...task, cwd: setup.worktrees[index]!.agentCwd })),
|
|
256
256
|
setup,
|
|
@@ -103,6 +103,10 @@ export interface RunFailureMetadata {
|
|
|
103
103
|
readonly retryAfterMs?: number;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Apply failure fields to a live stage. Executor callers invoke this next to
|
|
108
|
+
* a version-bumping stage store method, with no intervening asynchronous work.
|
|
109
|
+
*/
|
|
106
110
|
export function applyFailureToStage(stage: StageSnapshot, failure: WorkflowFailure): void {
|
|
107
111
|
stage.status = "failed";
|
|
108
112
|
stage.error = failure.userMessage;
|
|
@@ -52,6 +52,8 @@ export function createStageScheduler(input: {
|
|
|
52
52
|
input.runSnapshot.stages.find((stage) => stage.id === stageId);
|
|
53
53
|
|
|
54
54
|
const setStageParentIds = (stage: StageSnapshot, parentIds: readonly string[]): void => {
|
|
55
|
+
// The tracked-stage caller invokes this next to the version-bumping
|
|
56
|
+
// `recordStageStart` method, with no intervening asynchronous work.
|
|
55
57
|
stage.parentIds = Object.freeze([...parentIds]);
|
|
56
58
|
};
|
|
57
59
|
|
|
@@ -134,6 +134,7 @@ export function createTrackedStageCaller(input: {
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
const trackStageLifecycle = !runtime.state.stageFinalized;
|
|
137
|
+
let refreshedParentIds: readonly string[] | undefined;
|
|
137
138
|
if (
|
|
138
139
|
trackStageLifecycle &&
|
|
139
140
|
!input.hasContinuation &&
|
|
@@ -146,13 +147,11 @@ export function createTrackedStageCaller(input: {
|
|
|
146
147
|
actualParentIds.every((value) => runtime.stageSnapshot.parentIds.includes(value));
|
|
147
148
|
if (!sameParents) {
|
|
148
149
|
runtime.scheduler.tracker.replaceParents(runtime.stageId, actualParentIds);
|
|
149
|
-
|
|
150
|
+
refreshedParentIds = actualParentIds;
|
|
150
151
|
}
|
|
151
152
|
}
|
|
152
153
|
if (trackStageLifecycle) {
|
|
153
154
|
const now = Date.now();
|
|
154
|
-
runtime.stageSnapshot.status = "running";
|
|
155
|
-
runtime.stageSnapshot.startedAt ??= rebasedStageStartedAt(input.options?.durableAccumulatedDurationMs, now);
|
|
156
155
|
const hasNoExplicitModelConfig =
|
|
157
156
|
input.options?.model === undefined && input.options?.fallbackModels === undefined;
|
|
158
157
|
const promptAdapterHandlesInitialPrompt = input.adapters.prompt !== undefined;
|
|
@@ -173,7 +172,13 @@ export function createTrackedStageCaller(input: {
|
|
|
173
172
|
if (!(err instanceof Error && err.message.includes("prompt adapter not configured"))) throw err;
|
|
174
173
|
}
|
|
175
174
|
}
|
|
175
|
+
if (refreshedParentIds !== undefined) {
|
|
176
|
+
runtime.scheduler.setStageParentIds(runtime.stageSnapshot, refreshedParentIds);
|
|
177
|
+
}
|
|
178
|
+
runtime.stageSnapshot.status = "running";
|
|
179
|
+
runtime.stageSnapshot.startedAt ??= rebasedStageStartedAt(input.options?.durableAccumulatedDurationMs, now);
|
|
176
180
|
runtime.applyModelFallbackMeta(runtime.innerCtx.__modelFallbackMeta());
|
|
181
|
+
// Publish every graph-visible live write before this task can yield.
|
|
177
182
|
runtime.activeStore.recordStageStart(runtime.runId, runtime.stageSnapshot);
|
|
178
183
|
runtime.appendStageStartOnce();
|
|
179
184
|
} else {
|
|
@@ -182,6 +187,7 @@ export function createTrackedStageCaller(input: {
|
|
|
182
187
|
|
|
183
188
|
runtime.mcpScope.apply();
|
|
184
189
|
|
|
190
|
+
let applyTerminalStageState: (() => void) | undefined;
|
|
185
191
|
try {
|
|
186
192
|
const abortSession = (): void => {
|
|
187
193
|
void runtime.innerCtx.abort().catch(() => {});
|
|
@@ -260,9 +266,11 @@ export function createTrackedStageCaller(input: {
|
|
|
260
266
|
}
|
|
261
267
|
if (trackStageLifecycle && runtime.state.stageFinalized) throw runtime.parallelFailFastError();
|
|
262
268
|
if (trackStageLifecycle) {
|
|
263
|
-
runtime.stageSnapshot.status = "completed";
|
|
264
269
|
const assistantText = runtime.innerCtx.__getLastAssistantText();
|
|
265
|
-
|
|
270
|
+
applyTerminalStageState = () => {
|
|
271
|
+
runtime.stageSnapshot.status = "completed";
|
|
272
|
+
if (assistantText !== undefined) runtime.stageSnapshot.result = assistantText;
|
|
273
|
+
};
|
|
266
274
|
}
|
|
267
275
|
return result;
|
|
268
276
|
} catch (err) {
|
|
@@ -270,11 +278,15 @@ export function createTrackedStageCaller(input: {
|
|
|
270
278
|
if (workflowExitAbort !== undefined && !runtime.state.skippedForParallelFailFast) {
|
|
271
279
|
runtime.state.stageClosedByWorkflowExit = true;
|
|
272
280
|
if (trackStageLifecycle && !isTerminalStage(runtime.stageSnapshot)) {
|
|
273
|
-
runtime.
|
|
274
|
-
|
|
281
|
+
const skippedReason = runtime.exit.workflowExitSkippedReason(workflowExitAbort.reason);
|
|
282
|
+
applyTerminalStageState = () => {
|
|
283
|
+
runtime.stageSnapshot.status = "skipped";
|
|
284
|
+
runtime.stageSnapshot.skippedReason = skippedReason;
|
|
285
|
+
};
|
|
275
286
|
}
|
|
276
287
|
} else if (trackStageLifecycle && !runtime.signal.aborted && !runtime.state.skippedForParallelFailFast) {
|
|
277
|
-
|
|
288
|
+
const failure = runtime.classifyExecutorFailure(err);
|
|
289
|
+
applyTerminalStageState = () => applyFailureToStage(runtime.stageSnapshot, failure);
|
|
278
290
|
}
|
|
279
291
|
throw err;
|
|
280
292
|
} finally {
|
|
@@ -291,6 +303,9 @@ export function createTrackedStageCaller(input: {
|
|
|
291
303
|
finalizationError = { thrown: true, error: err };
|
|
292
304
|
}
|
|
293
305
|
if (trackStageLifecycle) {
|
|
306
|
+
if (!runtime.state.stageFinalized) applyTerminalStageState?.();
|
|
307
|
+
// `finalizeStageSnapshot` calls the version-bumping `recordStageEnd`
|
|
308
|
+
// before its first yield, so the live write cannot outpace the cache.
|
|
294
309
|
try {
|
|
295
310
|
await runtime.finalizeStageSnapshot();
|
|
296
311
|
} catch (err) {
|
|
@@ -290,6 +290,10 @@ export function createWorkflowStageFactory(input: {
|
|
|
290
290
|
input.tracker.onSettle(stageId);
|
|
291
291
|
return false;
|
|
292
292
|
}
|
|
293
|
+
if (state.skippedForParallelFailFast) {
|
|
294
|
+
stageSnapshot.status = "skipped";
|
|
295
|
+
stageSnapshot.skippedReason = "fail-fast";
|
|
296
|
+
}
|
|
293
297
|
state.stageFinalized = true;
|
|
294
298
|
runtime.unregisterWorkflowExitCleanup();
|
|
295
299
|
stageSnapshot.endedAt = Date.now();
|
|
@@ -340,9 +344,9 @@ export function createWorkflowStageFactory(input: {
|
|
|
340
344
|
};
|
|
341
345
|
|
|
342
346
|
const markSkippedForParallelFailFast = (): void => {
|
|
347
|
+
// Defer graph-visible fields until `finalizeStageSnapshot`, directly
|
|
348
|
+
// before its version-bumping `recordStageEnd` call.
|
|
343
349
|
state.skippedForParallelFailFast = true;
|
|
344
|
-
stageSnapshot.status = "skipped";
|
|
345
|
-
stageSnapshot.skippedReason = "fail-fast";
|
|
346
350
|
};
|
|
347
351
|
const parallelFailFastError = (): unknown =>
|
|
348
352
|
stageFailFastScope?.firstFailure ?? new Error("atomic-workflows: skipped after parallel fail-fast");
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
1
2
|
import { isAbsolute, resolve } from "node:path";
|
|
2
3
|
import type {
|
|
3
4
|
StageOptions,
|
|
@@ -80,6 +81,10 @@ export function taskReadInstruction(options: WorkflowTaskExecutionOptions): stri
|
|
|
80
81
|
if (options.reads === false || options.reads === undefined || options.reads.length === 0) return "";
|
|
81
82
|
const baseDir = taskBaseDir(options);
|
|
82
83
|
const files = options.reads.map((file) => resolveWorkflowPath(file, baseDir));
|
|
84
|
+
const missing = files.find((file) => !existsSync(file));
|
|
85
|
+
if (missing !== undefined) {
|
|
86
|
+
throw new Error(`atomic-workflows: referenced artifact does not exist: ${missing}`);
|
|
87
|
+
}
|
|
83
88
|
return `[Read from: ${files.join(", ")}]\n\n`;
|
|
84
89
|
}
|
|
85
90
|
|