@bastani/atomic 0.9.13-alpha.2 → 0.9.13-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 +14 -0
- package/README.md +1 -1
- package/dist/builtin/i-have-adhd/package.json +1 -1
- package/dist/builtin/intercom/CHANGELOG.md +14 -0
- package/dist/builtin/intercom/README.md +12 -12
- package/dist/builtin/intercom/incoming-message-delivery.ts +1 -1
- package/dist/builtin/intercom/index.ts +1 -1
- package/dist/builtin/intercom/intercom-tool.ts +1 -1
- package/dist/builtin/intercom/intercom-utils.ts +3 -6
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/result-renderers.ts +1 -1
- package/dist/builtin/intercom/session-target.ts +1 -15
- package/dist/builtin/intercom/skills/intercom/SKILL.md +6 -6
- package/dist/builtin/intercom/terminal-ordering-barrier.ts +2 -2
- package/dist/builtin/intercom/ui/inline-message.ts +7 -5
- package/dist/builtin/intercom/ui/session-list.ts +23 -10
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +19 -0
- package/dist/builtin/subagents/README.md +29 -73
- package/dist/builtin/subagents/package.json +2 -2
- package/dist/builtin/subagents/prompts/parallel-cleanup.md +1 -1
- package/dist/builtin/subagents/prompts/parallel-review.md +1 -1
- package/dist/builtin/subagents/prompts/review-loop.md +2 -2
- package/dist/builtin/subagents/skills/subagent/SKILL.md +23 -59
- package/dist/builtin/subagents/skills/tmux/SKILL.md +1 -1
- package/dist/builtin/subagents/src/extension/control-notices.ts +2 -3
- package/dist/builtin/subagents/src/extension/doctor.ts +2 -14
- package/dist/builtin/subagents/src/extension/fanout-child.ts +1 -17
- package/dist/builtin/subagents/src/extension/index.ts +9 -70
- package/dist/builtin/subagents/src/extension/notification-content.ts +1 -1
- package/dist/builtin/subagents/src/extension/prompt-guidance.ts +2 -2
- package/dist/builtin/subagents/src/extension/schemas.ts +2 -8
- package/dist/builtin/subagents/src/extension/tool-description.ts +2 -3
- package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +1 -1
- package/dist/builtin/subagents/src/intercom/result-intercom.ts +5 -46
- package/dist/builtin/subagents/src/runs/{background → foreground}/completion-notification.ts +2 -2
- package/dist/builtin/subagents/src/runs/foreground/inprocess-run-sync.ts +25 -88
- package/dist/builtin/subagents/src/runs/{background → foreground}/notify.ts +5 -5
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +11 -28
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +3 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +2 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-runtime.ts +0 -5
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +30 -20
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +4 -4
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +0 -13
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +104 -48
- package/dist/builtin/subagents/src/runs/inprocess/index.ts +1 -1
- package/dist/builtin/subagents/src/runs/inprocess/runner.ts +5 -5
- package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-api.ts +0 -7
- package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-core.ts +0 -10
- package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-projection.ts +3 -108
- package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-sanitize.ts +0 -4
- package/dist/builtin/subagents/src/runs/shared/subagent-control.ts +1 -1
- package/dist/builtin/subagents/src/shared/formatters.ts +3 -5
- package/dist/builtin/subagents/src/shared/model-resolution.ts +78 -0
- package/dist/builtin/subagents/src/shared/status-format.ts +4 -11
- package/dist/builtin/subagents/src/shared/types-config.ts +10 -9
- package/dist/builtin/subagents/src/shared/types-nested.ts +127 -0
- package/dist/builtin/subagents/src/shared/types-results.ts +2 -8
- package/dist/builtin/subagents/src/shared/types-runtime.ts +0 -9
- package/dist/builtin/subagents/src/shared/types.ts +1 -1
- package/dist/builtin/subagents/src/shared/utils.ts +1 -109
- package/dist/builtin/subagents/src/slash/slash-commands.ts +7 -17
- package/dist/builtin/subagents/src/tui/render-event-formatting.ts +2 -252
- package/dist/builtin/subagents/src/tui/render-layout.ts +4 -4
- package/dist/builtin/subagents/src/tui/render-result.ts +0 -9
- package/dist/builtin/subagents/src/tui/render-stable-output.ts +1 -34
- package/dist/builtin/subagents/src/tui/render.ts +0 -2
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +12 -0
- package/dist/builtin/workflows/README.md +3 -3
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/durable/backend.ts +11 -0
- package/dist/builtin/workflows/src/durable/completed-catalog-stage-groups.ts +63 -25
- package/dist/builtin/workflows/src/durable/completed-catalog.ts +166 -25
- package/dist/builtin/workflows/src/durable/dbos-backend.ts +42 -24
- package/dist/builtin/workflows/src/durable/dbos-envelope.ts +2 -1
- package/dist/builtin/workflows/src/durable/run-timing.ts +28 -7
- package/dist/builtin/workflows/src/durable/scoped-backend.ts +4 -0
- package/dist/builtin/workflows/src/durable/targeted-inspection.ts +110 -0
- package/dist/builtin/workflows/src/engine/run-durable-stage-session.ts +2 -2
- package/dist/builtin/workflows/src/engine/runtime.ts +19 -2
- package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +3 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +680 -152
- package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +6 -0
- package/dist/builtin/workflows/src/extension/ui-surface.ts +2 -0
- package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +6 -1
- package/dist/builtin/workflows/src/extension/workflow-targets.ts +18 -10
- package/dist/builtin/workflows/src/extension/workflow-tool-inspection.ts +31 -16
- package/dist/builtin/workflows/src/extension/workflow-tool-send.ts +75 -3
- package/dist/builtin/workflows/src/extension/workflow-tool.ts +53 -6
- package/dist/builtin/workflows/src/runs/background/run-inspect.ts +5 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +94 -60
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-context.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-control.ts +7 -7
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +25 -4
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-types.ts +4 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-types.ts +2 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +142 -4
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +2 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-session-heartbeat.ts +88 -0
- package/dist/builtin/workflows/src/tui/run-detail.ts +25 -12
- package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +1 -0
- package/dist/core/agent-session-events.d.ts.map +1 -1
- package/dist/core/agent-session-events.js +16 -5
- package/dist/core/agent-session-events.js.map +1 -1
- package/dist/core/agent-session-export.d.ts.map +1 -1
- package/dist/core/agent-session-export.js +2 -1
- package/dist/core/agent-session-export.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +8 -4
- 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-prompt.d.ts.map +1 -1
- package/dist/core/agent-session-prompt.js +5 -0
- package/dist/core/agent-session-prompt.js.map +1 -1
- package/dist/core/agent-session-summary.d.ts +21 -0
- package/dist/core/agent-session-summary.d.ts.map +1 -0
- package/dist/core/agent-session-summary.js +156 -0
- package/dist/core/agent-session-summary.js.map +1 -0
- package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
- package/dist/core/agent-session-tool-registry.js +0 -4
- package/dist/core/agent-session-tool-registry.js.map +1 -1
- package/dist/core/agent-session-transfer.d.ts.map +1 -1
- package/dist/core/agent-session-transfer.js +0 -2
- package/dist/core/agent-session-transfer.js.map +1 -1
- package/dist/core/agent-session-tree.d.ts.map +1 -1
- package/dist/core/agent-session-tree.js +6 -0
- package/dist/core/agent-session-tree.js.map +1 -1
- package/dist/core/agent-session.d.ts +7 -3
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +8 -5
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/atomic-guide-command.js +2 -2
- package/dist/core/atomic-guide-command.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +1 -0
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/index.d.ts +1 -0
- package/dist/core/compaction/index.d.ts.map +1 -1
- package/dist/core/compaction/index.js +1 -0
- package/dist/core/compaction/index.js.map +1 -1
- package/dist/core/compaction/session-summarization.d.ts +41 -0
- package/dist/core/compaction/session-summarization.d.ts.map +1 -0
- package/dist/core/compaction/session-summarization.js +97 -0
- package/dist/core/compaction/session-summarization.js.map +1 -0
- package/dist/core/extensions/ui-types.d.ts +2 -0
- package/dist/core/extensions/ui-types.d.ts.map +1 -1
- package/dist/core/extensions/ui-types.js.map +1 -1
- package/dist/core/session-manager-core.d.ts +3 -1
- package/dist/core/session-manager-core.d.ts.map +1 -1
- package/dist/core/session-manager-core.js +9 -1
- package/dist/core/session-manager-core.js.map +1 -1
- package/dist/core/session-manager-entries.d.ts +24 -1
- package/dist/core/session-manager-entries.d.ts.map +1 -1
- package/dist/core/session-manager-entries.js +48 -0
- package/dist/core/session-manager-entries.js.map +1 -1
- package/dist/core/session-manager-list.d.ts.map +1 -1
- package/dist/core/session-manager-list.js +10 -0
- package/dist/core/session-manager-list.js.map +1 -1
- package/dist/core/session-manager-types.d.ts +10 -1
- package/dist/core/session-manager-types.d.ts.map +1 -1
- package/dist/core/session-manager-types.js.map +1 -1
- package/dist/core/settings-manager-basic-accessors.d.ts +3 -0
- package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-basic-accessors.js +5 -0
- package/dist/core/settings-manager-basic-accessors.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/settings-types.d.ts +4 -0
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/slash-commands.js +2 -2
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/tools/bash.d.ts +0 -15
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +3 -81
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/fetch-url.d.ts +12 -0
- package/dist/core/tools/fetch-url.d.ts.map +1 -1
- package/dist/core/tools/fetch-url.js +76 -10
- package/dist/core/tools/fetch-url.js.map +1 -1
- package/dist/core/tools/index.js +4 -4
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/session-temp-dir.d.ts +2 -2
- package/dist/core/tools/session-temp-dir.d.ts.map +1 -1
- package/dist/core/tools/session-temp-dir.js +6 -7
- package/dist/core/tools/session-temp-dir.js.map +1 -1
- package/dist/core/usage-totals.js +1 -1
- package/dist/core/usage-totals.js.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/host-session-picker.d.ts.map +1 -1
- package/dist/modes/interactive/components/host-session-picker.js +1 -0
- package/dist/modes/interactive/components/host-session-picker.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-list.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-list.js +29 -4
- package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.js +1 -1
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector-content.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector-content.js +6 -0
- package/dist/modes/interactive/components/tree-selector-content.js.map +1 -1
- package/dist/modes/interactive-engine/protocol.d.ts.map +1 -1
- package/dist/modes/interactive-engine/protocol.js +4 -1
- package/dist/modes/interactive-engine/protocol.js.map +1 -1
- package/docs/environment-variables.md +1 -1
- package/docs/intercom.md +20 -21
- package/docs/quickstart.md +5 -1
- package/docs/sdk.md +1 -1
- package/docs/session-format.md +15 -0
- package/docs/sessions.md +8 -0
- package/docs/settings.md +6 -0
- package/docs/subagents.md +19 -31
- package/docs/tools.md +3 -5
- package/docs/usage.md +1 -1
- package/docs/windows.md +1 -1
- package/docs/workflows.md +60 -32
- package/npm-shrinkwrap.json +29 -29
- package/package.json +2 -2
- package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +0 -331
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +0 -161
- package/dist/builtin/subagents/src/runs/inprocess/background-single.ts +0 -195
- package/dist/builtin/subagents/src/runs/inprocess/background.ts +0 -90
- package/dist/builtin/subagents/src/shared/types-async.ts +0 -247
- package/dist/builtin/subagents/src/tui/render-widget-graph.ts +0 -217
- package/dist/builtin/subagents/src/tui/render-widget.ts +0 -366
- package/dist/core/async/format.d.ts +0 -3
- package/dist/core/async/format.d.ts.map +0 -1
- package/dist/core/async/format.js +0 -52
- package/dist/core/async/format.js.map +0 -1
- package/dist/core/async/job-manager.d.ts +0 -40
- package/dist/core/async/job-manager.d.ts.map +0 -1
- package/dist/core/async/job-manager.js +0 -293
- package/dist/core/async/job-manager.js.map +0 -1
- package/dist/core/async/session-manager.d.ts +0 -16
- package/dist/core/async/session-manager.d.ts.map +0 -1
- package/dist/core/async/session-manager.js +0 -34
- package/dist/core/async/session-manager.js.map +0 -1
- package/dist/core/async/types.d.ts +0 -23
- package/dist/core/async/types.d.ts.map +0 -1
- package/dist/core/async/types.js +0 -2
- package/dist/core/async/types.js.map +0 -1
- package/dist/core/tools/bash-async-execution.d.ts +0 -27
- package/dist/core/tools/bash-async-execution.d.ts.map +0 -1
- package/dist/core/tools/bash-async-execution.js +0 -81
- package/dist/core/tools/bash-async-execution.js.map +0 -1
- package/dist/core/tools/bash-async-jobs.d.ts +0 -30
- package/dist/core/tools/bash-async-jobs.d.ts.map +0 -1
- package/dist/core/tools/bash-async-jobs.js +0 -87
- package/dist/core/tools/bash-async-jobs.js.map +0 -1
- package/dist/core/tools/bash-async-output.d.ts +0 -13
- package/dist/core/tools/bash-async-output.d.ts.map +0 -1
- package/dist/core/tools/bash-async-output.js +0 -122
- package/dist/core/tools/bash-async-output.js.map +0 -1
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
type ResumeDurableResult,
|
|
14
14
|
resumeDurableWorkflow as resumeDurableWorkflowAdapter,
|
|
15
15
|
} from "../durable/resume-runtime.js";
|
|
16
|
+
import { inspectTargetedDurableWorkflow, type TargetedDurableInspection } from "../durable/targeted-inspection.js";
|
|
16
17
|
import type { ResumableWorkflowEntry } from "../durable/types.js";
|
|
17
18
|
import type { JobTracker } from "../runs/background/job-tracker.js";
|
|
18
19
|
import type { RunOpts } from "../runs/foreground/executor.js";
|
|
@@ -28,6 +29,7 @@ export interface DurableResumeRuntime {
|
|
|
28
29
|
workflowId: string,
|
|
29
30
|
options?: { readonly policy?: WorkflowExecutionPolicy; readonly actor?: WorkflowActor },
|
|
30
31
|
): Promise<ResumeDurableResult>;
|
|
32
|
+
inspectDurableWorkflow(workflowId: string): Promise<TargetedDurableInspection>;
|
|
31
33
|
listDurableResumable(): readonly ResumableWorkflowEntry[];
|
|
32
34
|
prepareDurableResumable(workflowId?: string): Promise<readonly ResumableWorkflowEntry[]>;
|
|
33
35
|
prepareDurableCatalog?(): Promise<DurableWorkflowCatalogEntries>;
|
|
@@ -65,6 +67,10 @@ export function createDurableResumeRuntime(deps: DurableResumeRuntimeDeps): Dura
|
|
|
65
67
|
};
|
|
66
68
|
let preparedCatalog: readonly ResumableWorkflowEntry[] = [];
|
|
67
69
|
return {
|
|
70
|
+
async inspectDurableWorkflow(workflowId) {
|
|
71
|
+
await deps.ensureReady();
|
|
72
|
+
return await inspectTargetedDurableWorkflow(getDurableBackend(), workflowId);
|
|
73
|
+
},
|
|
68
74
|
async resumeDurableWorkflow(workflowId, options): Promise<ResumeDurableResult> {
|
|
69
75
|
await deps.ensureReady();
|
|
70
76
|
const backend = getDurableBackend();
|
|
@@ -209,6 +209,8 @@ export interface PiHostSessionPickerRow {
|
|
|
209
209
|
modifiedAt: number;
|
|
210
210
|
messageCount: number;
|
|
211
211
|
firstMessage: string;
|
|
212
|
+
/** Generated resume summary. Absent when never generated, or stale against the latest message. */
|
|
213
|
+
summary?: string;
|
|
212
214
|
allMessagesText?: string;
|
|
213
215
|
name?: string;
|
|
214
216
|
/** Optional semantic color for synthetic selector rows. */
|
|
@@ -153,7 +153,12 @@ async function workflowSlashHandler(
|
|
|
153
153
|
if (target && !target.startsWith("--")) {
|
|
154
154
|
const resolved = resolveRunId(target);
|
|
155
155
|
if (resolved.kind === "malformed") return fail(resolved.message);
|
|
156
|
-
if (resolved.kind === "not_found")
|
|
156
|
+
if (resolved.kind === "not_found") {
|
|
157
|
+
const durable = await deps.runtimeForContext(ctx).inspectDurableWorkflow(target);
|
|
158
|
+
if (durable.kind !== "found") return fail(durable.message);
|
|
159
|
+
emitChatSurface(pi, { kind: "detail", detail: durable.detail });
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
157
162
|
const inspected = inspectRun(resolved.runId);
|
|
158
163
|
if (!inspected.ok) return fail(`Run not found: ${target}`);
|
|
159
164
|
emitChatSurface(pi, { kind: "detail", detail: inspected.detail });
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "../shared/expanded-workflow-graph.js";
|
|
8
8
|
import { isFullRunId, malformedRunIdMessage, RUN_ID_LENGTH } from "../shared/run-id.js";
|
|
9
9
|
import { topLevelWorkflowRuns } from "../shared/run-visibility.js";
|
|
10
|
-
import { store } from "../shared/store.js";
|
|
10
|
+
import { type Store, store } from "../shared/store.js";
|
|
11
11
|
import { readGraphStoreSnapshot } from "../shared/store-observation.js";
|
|
12
12
|
import type { RunStatus } from "../shared/store-types.js";
|
|
13
13
|
import type { OverlayPiSurface } from "../tui/overlay-adapter.js";
|
|
@@ -87,9 +87,9 @@ export type RunIdResolution =
|
|
|
87
87
|
| { kind: "malformed"; message: string }
|
|
88
88
|
| { kind: "not_found" };
|
|
89
89
|
|
|
90
|
-
export function resolveRunId(target: string): RunIdResolution {
|
|
90
|
+
export function resolveRunId(target: string, activeStore: Store = store): RunIdResolution {
|
|
91
91
|
if (!isFullRunId(target)) return { kind: "malformed", message: malformedRunIdMessage(target) };
|
|
92
|
-
const exact =
|
|
92
|
+
const exact = activeStore.runs().find((r) => r.id === target);
|
|
93
93
|
if (exact) return { kind: "exact", runId: exact.id };
|
|
94
94
|
return { kind: "not_found" };
|
|
95
95
|
}
|
|
@@ -100,12 +100,16 @@ export type ToolRunTarget =
|
|
|
100
100
|
| { kind: "malformed"; target: string; message: string }
|
|
101
101
|
| { kind: "not_found"; target: string; message: string };
|
|
102
102
|
|
|
103
|
-
export function resolveToolRunTarget(
|
|
103
|
+
export function resolveToolRunTarget(
|
|
104
|
+
args: WorkflowToolArgs,
|
|
105
|
+
emptyMessage: string,
|
|
106
|
+
activeStore: Store = store,
|
|
107
|
+
): ToolRunTarget {
|
|
104
108
|
const rawTarget = args.runId?.trim() ?? "";
|
|
105
109
|
if (args.all === true || rawTarget === "--all") return { kind: "all" };
|
|
106
|
-
const target = rawTarget ||
|
|
110
|
+
const target = rawTarget || activeStore.activeRunId() || "";
|
|
107
111
|
if (!target) return { kind: "not_found", target: rawTarget, message: emptyMessage };
|
|
108
|
-
const resolved = resolveRunId(target);
|
|
112
|
+
const resolved = resolveRunId(target, activeStore);
|
|
109
113
|
if (resolved.kind === "exact") return { kind: "run", runId: resolved.runId };
|
|
110
114
|
if (resolved.kind === "malformed") return { kind: "malformed", target, message: resolved.message };
|
|
111
115
|
return { kind: "not_found", target, message: `Run not found: ${target}` };
|
|
@@ -113,10 +117,10 @@ export function resolveToolRunTarget(args: WorkflowToolArgs, emptyMessage: strin
|
|
|
113
117
|
|
|
114
118
|
export type ToolStageTarget = { ok: true; runId?: string; stageId?: string } | { ok: false; message: string };
|
|
115
119
|
|
|
116
|
-
export function resolveStageTarget(runId: string, stageTarget?: string): ToolStageTarget {
|
|
120
|
+
export function resolveStageTarget(runId: string, stageTarget?: string, activeStore: Store = store): ToolStageTarget {
|
|
117
121
|
const target = stageTarget?.trim();
|
|
118
122
|
if (!target) return { ok: true, runId };
|
|
119
|
-
const graph = expandWorkflowGraph(readGraphStoreSnapshot(
|
|
123
|
+
const graph = expandWorkflowGraph(readGraphStoreSnapshot(activeStore), runId);
|
|
120
124
|
const exactVirtualIds = graph.stages.filter((stage) => stage.id === target);
|
|
121
125
|
if (exactVirtualIds.length === 1) return resolvedStageTarget(exactVirtualIds[0]!);
|
|
122
126
|
if (exactVirtualIds.length > 1) return ambiguousStageTarget(target, exactVirtualIds);
|
|
@@ -147,8 +151,12 @@ function ambiguousStageTarget(target: string, stages: readonly ExpandedWorkflowS
|
|
|
147
151
|
};
|
|
148
152
|
}
|
|
149
153
|
|
|
150
|
-
export function resolveToolStageTarget(
|
|
151
|
-
|
|
154
|
+
export function resolveToolStageTarget(
|
|
155
|
+
runId: string,
|
|
156
|
+
stageTarget?: string,
|
|
157
|
+
activeStore: Store = store,
|
|
158
|
+
): ToolStageTarget {
|
|
159
|
+
return resolveStageTarget(runId, stageTarget, activeStore);
|
|
152
160
|
}
|
|
153
161
|
|
|
154
162
|
/**
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { stageControlRegistry } from "../runs/foreground/stage-control-registry.js";
|
|
2
|
-
import {
|
|
2
|
+
import { expandWorkflowGraph } from "../shared/expanded-workflow-graph.js";
|
|
3
|
+
import { type Store, store } from "../shared/store.js";
|
|
4
|
+
import { readGraphStoreSnapshot } from "../shared/store-observation.js";
|
|
3
5
|
import type { WorkflowToolArgs } from "./public-types.js";
|
|
4
6
|
import type { WorkflowToolResult } from "./render-result.js";
|
|
5
7
|
import {
|
|
@@ -14,8 +16,14 @@ import {
|
|
|
14
16
|
} from "./workflow-stage-results.js";
|
|
15
17
|
import { resolveToolRunTarget, resolveToolStageTarget } from "./workflow-targets.js";
|
|
16
18
|
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
+
export interface WorkflowInspectionSource {
|
|
20
|
+
readonly store?: Store;
|
|
21
|
+
readonly allowLiveHandles?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function workflowStagesResult(args: WorkflowToolArgs, source?: WorkflowInspectionSource): WorkflowToolResult {
|
|
25
|
+
const activeStore = source?.store ?? store;
|
|
26
|
+
const target = resolveToolRunTarget(args, "No active run to inspect.", activeStore);
|
|
19
27
|
const filter = args.statusFilter ?? "all";
|
|
20
28
|
if (target.kind === "all") {
|
|
21
29
|
return {
|
|
@@ -35,22 +43,24 @@ export function workflowStagesResult(args: WorkflowToolArgs): WorkflowToolResult
|
|
|
35
43
|
error: target.message,
|
|
36
44
|
};
|
|
37
45
|
}
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
const stageSnapshots =
|
|
47
|
+
source?.store === undefined
|
|
48
|
+
? (activeStore.runs().find((run) => run.id === target.runId)?.stages ?? [])
|
|
49
|
+
: expandWorkflowGraph(readGraphStoreSnapshot(activeStore), target.runId).stages;
|
|
50
|
+
const stages = stageSnapshots.filter((stage) => filter === "all" || stage.status === filter).map(summarizeStage);
|
|
42
51
|
return { action: "stages", runId: target.runId, filter, stages };
|
|
43
52
|
}
|
|
44
53
|
|
|
45
|
-
export function workflowStageResult(args: WorkflowToolArgs): WorkflowToolResult {
|
|
46
|
-
const
|
|
54
|
+
export function workflowStageResult(args: WorkflowToolArgs, source?: WorkflowInspectionSource): WorkflowToolResult {
|
|
55
|
+
const activeStore = source?.store ?? store;
|
|
56
|
+
const target = resolveToolRunTarget(args, "No active run to inspect.", activeStore);
|
|
47
57
|
if (target.kind === "all") {
|
|
48
58
|
return { action: "stage", runId: "--all", error: "Stage inspection requires a single run." };
|
|
49
59
|
}
|
|
50
60
|
if (target.kind === "malformed" || target.kind === "not_found") {
|
|
51
61
|
return { action: "stage", runId: target.target, error: target.message };
|
|
52
62
|
}
|
|
53
|
-
const stage = resolveToolStageTarget(target.runId, args.stageId);
|
|
63
|
+
const stage = resolveToolStageTarget(target.runId, args.stageId, activeStore);
|
|
54
64
|
if (!stage.ok || stage.stageId === undefined) {
|
|
55
65
|
return {
|
|
56
66
|
action: "stage",
|
|
@@ -59,7 +69,7 @@ export function workflowStageResult(args: WorkflowToolArgs): WorkflowToolResult
|
|
|
59
69
|
};
|
|
60
70
|
}
|
|
61
71
|
const stageRunId = stage.runId ?? target.runId;
|
|
62
|
-
const run =
|
|
72
|
+
const run = activeStore.runs().find((r) => r.id === stageRunId);
|
|
63
73
|
const snapshot = run?.stages.find((s) => s.id === stage.stageId);
|
|
64
74
|
return snapshot
|
|
65
75
|
? { action: "stage", runId: stageRunId, stage: cloneStage(snapshot) }
|
|
@@ -70,8 +80,12 @@ export function workflowStageResult(args: WorkflowToolArgs): WorkflowToolResult
|
|
|
70
80
|
};
|
|
71
81
|
}
|
|
72
82
|
|
|
73
|
-
export function workflowTranscriptResult(
|
|
74
|
-
|
|
83
|
+
export function workflowTranscriptResult(
|
|
84
|
+
args: WorkflowToolArgs,
|
|
85
|
+
source?: WorkflowInspectionSource,
|
|
86
|
+
): WorkflowToolResult {
|
|
87
|
+
const activeStore = source?.store ?? store;
|
|
88
|
+
const target = resolveToolRunTarget(args, "No active run to inspect.", activeStore);
|
|
75
89
|
if (target.kind === "all") {
|
|
76
90
|
return {
|
|
77
91
|
action: "transcript",
|
|
@@ -92,7 +106,7 @@ export function workflowTranscriptResult(args: WorkflowToolArgs): WorkflowToolRe
|
|
|
92
106
|
truncated: false,
|
|
93
107
|
};
|
|
94
108
|
}
|
|
95
|
-
const stage = resolveToolStageTarget(target.runId, args.stageId);
|
|
109
|
+
const stage = resolveToolStageTarget(target.runId, args.stageId, activeStore);
|
|
96
110
|
if (!stage.ok || stage.stageId === undefined) {
|
|
97
111
|
return {
|
|
98
112
|
action: "transcript",
|
|
@@ -104,9 +118,10 @@ export function workflowTranscriptResult(args: WorkflowToolArgs): WorkflowToolRe
|
|
|
104
118
|
};
|
|
105
119
|
}
|
|
106
120
|
const stageRunId = stage.runId ?? target.runId;
|
|
107
|
-
const run =
|
|
121
|
+
const run = activeStore.runs().find((r) => r.id === stageRunId);
|
|
108
122
|
const snapshot = run?.stages.find((s) => s.id === stage.stageId);
|
|
109
|
-
const liveHandle =
|
|
123
|
+
const liveHandle =
|
|
124
|
+
source?.allowLiveHandles === false ? undefined : stageControlRegistry.get(stageRunId, stage.stageId);
|
|
110
125
|
if (liveHandle !== undefined) {
|
|
111
126
|
const sessionFile = liveHandle.sessionFile ?? snapshot?.sessionFile;
|
|
112
127
|
const sessionId = liveHandle.sessionId ?? snapshot?.sessionId;
|
|
@@ -5,15 +5,20 @@ import {
|
|
|
5
5
|
import type { DetachedStageHandleLease, StageControlHandle } from "../runs/foreground/stage-control-registry.js";
|
|
6
6
|
import { stageControlRegistry } from "../runs/foreground/stage-control-registry.js";
|
|
7
7
|
import type { StageUserMessageDeliveryAction } from "../runs/foreground/stage-runner-types.js";
|
|
8
|
+
import {
|
|
9
|
+
type ExpandedWorkflowStage,
|
|
10
|
+
expandedStageLabel,
|
|
11
|
+
expandWorkflowGraph,
|
|
12
|
+
} from "../shared/expanded-workflow-graph.js";
|
|
8
13
|
import { coerceStageInputAnswer, hasStageInputAnswerContent, type StageInputAnswer } from "../shared/stage-prompt.js";
|
|
9
14
|
import { stageUiBroker } from "../shared/stage-ui-broker.js";
|
|
10
15
|
import { store } from "../shared/store.js";
|
|
11
16
|
import { isTerminalRunStatus } from "../shared/store-internal.js";
|
|
12
|
-
import { subscribeStoreInvalidation } from "../shared/store-observation.js";
|
|
17
|
+
import { readGraphStoreSnapshot, subscribeStoreInvalidation } from "../shared/store-observation.js";
|
|
13
18
|
import { reciprocalWorkflowRootRunId } from "../shared/workflow-run-ownership.js";
|
|
14
19
|
import type { WorkflowToolArgs } from "./public-types.js";
|
|
15
20
|
import type { WorkflowToolResult } from "./render-result.js";
|
|
16
|
-
import { resolveToolRunTarget, resolveToolStageTarget } from "./workflow-targets.js";
|
|
21
|
+
import { resolveToolRunTarget, resolveToolStageTarget, type ToolStageTarget } from "./workflow-targets.js";
|
|
17
22
|
|
|
18
23
|
/**
|
|
19
24
|
* Optional dependencies enabling `workflow send` to revive an eligible
|
|
@@ -49,6 +54,69 @@ function brokerAnswerFromArgs(args: WorkflowToolArgs): StageInputAnswer {
|
|
|
49
54
|
return text !== undefined ? { text } : {};
|
|
50
55
|
}
|
|
51
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Whether this delivery is one whose destination a pending prompt determines.
|
|
59
|
+
*
|
|
60
|
+
* `answer` and `auto` are both documented as answering pending prompts first,
|
|
61
|
+
* and an explicit `promptId` names a prompt without naming its stage. Steering
|
|
62
|
+
* deliveries are excluded: a live stage is a destination in its own right, so
|
|
63
|
+
* there is nothing for a prompt to disambiguate.
|
|
64
|
+
*/
|
|
65
|
+
function answersPendingPrompt(delivery: string, promptId: string | undefined): boolean {
|
|
66
|
+
return delivery === "answer" || delivery === "auto" || promptId !== undefined;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Ids of the prompts an `answer` delivery could resolve on this stage.
|
|
71
|
+
*
|
|
72
|
+
* Covers the same three prompt kinds the delivery path dispatches on —
|
|
73
|
+
* brokered, custom-footprint, and plain pending prompts — so a stage counted
|
|
74
|
+
* here is one the send would actually act on rather than merely mention.
|
|
75
|
+
*/
|
|
76
|
+
function answerablePromptIds(stage: ExpandedWorkflowStage): string[] {
|
|
77
|
+
const target = stage.workflowGraphTarget;
|
|
78
|
+
const ids: string[] = [];
|
|
79
|
+
const brokered = stageUiBroker.peekStagePrompt(target.runId, target.stageId);
|
|
80
|
+
if (brokered !== undefined) ids.push(brokered.id);
|
|
81
|
+
if (stage.pendingPrompt !== undefined) ids.push(stage.pendingPrompt.id);
|
|
82
|
+
if (stage.status === "awaiting_input" && stage.promptFootprint?.kind === "custom") {
|
|
83
|
+
ids.push(stage.promptFootprint.id);
|
|
84
|
+
}
|
|
85
|
+
return ids;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Resolve the stage an answer is for when the caller named a prompt but no stage.
|
|
90
|
+
*
|
|
91
|
+
* A named `promptId` already identifies its stage, so it narrows the candidates
|
|
92
|
+
* before uniqueness is decided — otherwise naming one of two pending prompts
|
|
93
|
+
* would be rejected as ambiguous, and naming an unknown one would target the
|
|
94
|
+
* unrelated stage that happened to be the only one waiting.
|
|
95
|
+
*
|
|
96
|
+
* Returns the target unchanged when nothing is pending, so a run with no prompt
|
|
97
|
+
* still reports that a stage is required rather than inventing a destination.
|
|
98
|
+
*/
|
|
99
|
+
function inferPromptStageTarget(runId: string, delivery: string, promptId: string | undefined): ToolStageTarget {
|
|
100
|
+
if (!answersPendingPrompt(delivery, promptId)) return { ok: true, runId };
|
|
101
|
+
const pending = expandWorkflowGraph(readGraphStoreSnapshot(store), runId).stages.filter((stage) => {
|
|
102
|
+
const ids = answerablePromptIds(stage);
|
|
103
|
+
return promptId === undefined ? ids.length > 0 : ids.includes(promptId);
|
|
104
|
+
});
|
|
105
|
+
const only = pending[0];
|
|
106
|
+
if (pending.length === 1 && only !== undefined) {
|
|
107
|
+
return { ok: true, runId: only.workflowGraphTarget.runId, stageId: only.workflowGraphTarget.stageId };
|
|
108
|
+
}
|
|
109
|
+
if (pending.length === 0) {
|
|
110
|
+
return promptId === undefined
|
|
111
|
+
? { ok: true, runId }
|
|
112
|
+
: { ok: false, message: `No pending prompt ${promptId} in run ${runId}.` };
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
ok: false,
|
|
116
|
+
message: `${pending.length} prompts pending; pass stageId: ${pending.map(expandedStageLabel).join(", ")}`,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
52
120
|
type WorkflowSendToolResult = Extract<WorkflowToolResult, { action: "send" }>;
|
|
53
121
|
|
|
54
122
|
function workflowSendResult(
|
|
@@ -131,7 +199,11 @@ export async function workflowSendAction(
|
|
|
131
199
|
if (rootRun !== undefined && isTerminalRunStatus(rootRun.status)) {
|
|
132
200
|
return terminalWorkflowSendResult(rootRun.id, args.stageId?.trim() ?? "", rootRun.status);
|
|
133
201
|
}
|
|
134
|
-
const
|
|
202
|
+
const requested = resolveToolStageTarget(target.runId, args.stageId);
|
|
203
|
+
const stage =
|
|
204
|
+
requested.ok && requested.stageId === undefined
|
|
205
|
+
? inferPromptStageTarget(target.runId, requestedDelivery, args.promptId)
|
|
206
|
+
: requested;
|
|
135
207
|
if (!stage.ok || stage.stageId === undefined) {
|
|
136
208
|
return workflowSendResult(
|
|
137
209
|
target.runId,
|
|
@@ -18,9 +18,49 @@ import {
|
|
|
18
18
|
workflowReloadAction,
|
|
19
19
|
workflowResumeAction,
|
|
20
20
|
} from "./workflow-tool-control.js";
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
type WorkflowInspectionSource,
|
|
23
|
+
workflowStageResult,
|
|
24
|
+
workflowStagesResult,
|
|
25
|
+
workflowTranscriptResult,
|
|
26
|
+
} from "./workflow-tool-inspection.js";
|
|
22
27
|
import { type WorkflowSendDeps, workflowSendAction } from "./workflow-tool-send.js";
|
|
23
28
|
|
|
29
|
+
type DurableInspectionSourceResolution =
|
|
30
|
+
| { readonly kind: "local" }
|
|
31
|
+
| { readonly kind: "durable"; readonly source: WorkflowInspectionSource }
|
|
32
|
+
| { readonly kind: "error"; readonly message: string };
|
|
33
|
+
|
|
34
|
+
async function resolveDurableInspectionSource(
|
|
35
|
+
args: WorkflowToolArgs,
|
|
36
|
+
runtime: ExtensionRuntime,
|
|
37
|
+
): Promise<DurableInspectionSourceResolution> {
|
|
38
|
+
const target = args.runId?.trim();
|
|
39
|
+
if (args.all === true || target === undefined || target.length === 0 || target === "--all") return { kind: "local" };
|
|
40
|
+
const local = resolveRunId(target);
|
|
41
|
+
if (local.kind !== "not_found") return { kind: "local" };
|
|
42
|
+
const durable = await runtime.inspectDurableWorkflow(target);
|
|
43
|
+
if (durable.kind !== "found") return { kind: "error", message: durable.message };
|
|
44
|
+
return { kind: "durable", source: { store: durable.store, allowLiveHandles: false } };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function durableInspectionError(
|
|
48
|
+
action: "stages" | "stage" | "transcript",
|
|
49
|
+
runId: string,
|
|
50
|
+
message: string,
|
|
51
|
+
): WorkflowToolResult {
|
|
52
|
+
if (action === "stages") return { action, runId, filter: "all", stages: [], error: message };
|
|
53
|
+
if (action === "stage") return { action, runId, error: message };
|
|
54
|
+
return {
|
|
55
|
+
action,
|
|
56
|
+
runId,
|
|
57
|
+
stageId: "",
|
|
58
|
+
source: "error",
|
|
59
|
+
entries: [{ role: "notice", text: message }],
|
|
60
|
+
truncated: false,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
24
64
|
export function makeExecuteWorkflowTool(
|
|
25
65
|
runtime: ExtensionRuntime | ((ctx: PiExecuteContext) => ExtensionRuntime),
|
|
26
66
|
reloadWorkflowResources: () => Promise<WorkflowReloadReport | undefined> | undefined,
|
|
@@ -87,7 +127,10 @@ export function makeExecuteWorkflowTool(
|
|
|
87
127
|
return { action: "statusDetail", runId: target, error: resolved.message };
|
|
88
128
|
}
|
|
89
129
|
if (resolved.kind === "not_found") {
|
|
90
|
-
|
|
130
|
+
const durable = await getRuntime().inspectDurableWorkflow(target);
|
|
131
|
+
return durable.kind === "found"
|
|
132
|
+
? { action: "statusDetail", runId: target, detail: durable.detail }
|
|
133
|
+
: { action: "statusDetail", runId: target, error: durable.message };
|
|
91
134
|
}
|
|
92
135
|
const result = inspectRun(resolved.runId);
|
|
93
136
|
return result.ok
|
|
@@ -105,11 +148,15 @@ export function makeExecuteWorkflowTool(
|
|
|
105
148
|
return result;
|
|
106
149
|
}
|
|
107
150
|
case "stages":
|
|
108
|
-
return workflowStagesResult(args);
|
|
109
151
|
case "stage":
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return
|
|
152
|
+
case "transcript": {
|
|
153
|
+
const resolved = await resolveDurableInspectionSource(args, getRuntime());
|
|
154
|
+
if (resolved.kind === "error") return durableInspectionError(action, args.runId ?? "", resolved.message);
|
|
155
|
+
const source = resolved.kind === "durable" ? resolved.source : undefined;
|
|
156
|
+
if (action === "stages") return workflowStagesResult(args, source);
|
|
157
|
+
if (action === "stage") return workflowStageResult(args, source);
|
|
158
|
+
return workflowTranscriptResult(args, source);
|
|
159
|
+
}
|
|
113
160
|
case "send":
|
|
114
161
|
return workflowSendAction(args, sendDeps);
|
|
115
162
|
case "pause":
|
|
@@ -28,7 +28,7 @@ import type { WorkflowInputValues, WorkflowOutputValues } from "../../shared/typ
|
|
|
28
28
|
export interface RunDetail {
|
|
29
29
|
readonly runId: string;
|
|
30
30
|
readonly name: string;
|
|
31
|
-
readonly status: RunStatus;
|
|
31
|
+
readonly status: RunStatus | "crashed";
|
|
32
32
|
readonly mode: "single" | "chain";
|
|
33
33
|
readonly startedAt: number;
|
|
34
34
|
readonly endedAt?: number;
|
|
@@ -54,6 +54,10 @@ export interface RunDetail {
|
|
|
54
54
|
readonly failedToolNodeId?: string;
|
|
55
55
|
readonly resumable?: boolean;
|
|
56
56
|
readonly retryAfterMs?: number;
|
|
57
|
+
/** Actionable guidance for a snapshot hydrated from durable storage. */
|
|
58
|
+
readonly resumeGuidance?: string;
|
|
59
|
+
/** True when a fresh durable owner is active in another Atomic process. */
|
|
60
|
+
readonly ownerActiveElsewhere?: boolean;
|
|
57
61
|
readonly blockedAt?: number;
|
|
58
62
|
}
|
|
59
63
|
|
|
@@ -107,7 +107,9 @@ export function createTrackedStageCaller(input: {
|
|
|
107
107
|
const suppressQueuedContinuation = reason === "paused-queued-user-message";
|
|
108
108
|
if (suppressQueuedContinuation) runtime.state.suppressQueuedUserMessageContinuation = true;
|
|
109
109
|
try {
|
|
110
|
-
result = (await
|
|
110
|
+
result = (await runtime.raceStageSessionHeartbeat(
|
|
111
|
+
raceAbort(runtime.innerCtx.prompt(RESUME_CONTINUATION_PROMPT), runtime.signal),
|
|
112
|
+
)) as T;
|
|
111
113
|
} finally {
|
|
112
114
|
if (suppressQueuedContinuation) runtime.state.suppressQueuedUserMessageContinuation = false;
|
|
113
115
|
}
|
|
@@ -134,61 +136,69 @@ export function createTrackedStageCaller(input: {
|
|
|
134
136
|
}
|
|
135
137
|
|
|
136
138
|
const trackStageLifecycle = !runtime.state.stageFinalized;
|
|
137
|
-
let
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const actualParentIds = runtime.scheduler.tracker.currentParents();
|
|
145
|
-
const sameParents =
|
|
146
|
-
actualParentIds.length === runtime.stageSnapshot.parentIds.length &&
|
|
147
|
-
actualParentIds.every((value) => runtime.stageSnapshot.parentIds.includes(value));
|
|
148
|
-
if (!sameParents) {
|
|
149
|
-
runtime.scheduler.tracker.replaceParents(runtime.stageId, actualParentIds);
|
|
150
|
-
refreshedParentIds = actualParentIds;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
if (trackStageLifecycle) {
|
|
154
|
-
const now = Date.now();
|
|
155
|
-
const hasNoExplicitModelConfig =
|
|
156
|
-
input.options?.model === undefined && input.options?.fallbackModels === undefined;
|
|
157
|
-
const promptAdapterHandlesInitialPrompt = input.adapters.prompt !== undefined;
|
|
139
|
+
let applyTerminalStageState: (() => void) | undefined;
|
|
140
|
+
// Set only alongside the successful "completed" terminal state, so a failed
|
|
141
|
+
// final durable checkpoint can replace it without touching a real
|
|
142
|
+
// failure/skip classification recorded by the catch block.
|
|
143
|
+
let terminalStateIsSuccess = false;
|
|
144
|
+
try {
|
|
145
|
+
let refreshedParentIds: readonly string[] | undefined;
|
|
158
146
|
if (
|
|
159
|
-
|
|
160
|
-
!
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
model: input.options?.model,
|
|
164
|
-
fallbackModels: input.options?.fallbackModels,
|
|
165
|
-
models: runtime.opts.models,
|
|
166
|
-
})))
|
|
147
|
+
trackStageLifecycle &&
|
|
148
|
+
!input.hasContinuation &&
|
|
149
|
+
runtime.stageSnapshot.startedAt === undefined &&
|
|
150
|
+
!input.hasScopedParents
|
|
167
151
|
) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
runtime.
|
|
171
|
-
|
|
172
|
-
|
|
152
|
+
const actualParentIds = runtime.scheduler.tracker.currentParents();
|
|
153
|
+
const sameParents =
|
|
154
|
+
actualParentIds.length === runtime.stageSnapshot.parentIds.length &&
|
|
155
|
+
actualParentIds.every((value) => runtime.stageSnapshot.parentIds.includes(value));
|
|
156
|
+
if (!sameParents) {
|
|
157
|
+
runtime.scheduler.tracker.replaceParents(runtime.stageId, actualParentIds);
|
|
158
|
+
refreshedParentIds = actualParentIds;
|
|
173
159
|
}
|
|
174
160
|
}
|
|
175
|
-
if (
|
|
176
|
-
|
|
161
|
+
if (trackStageLifecycle) {
|
|
162
|
+
const now = Date.now();
|
|
163
|
+
const hasNoExplicitModelConfig =
|
|
164
|
+
input.options?.model === undefined && input.options?.fallbackModels === undefined;
|
|
165
|
+
const promptAdapterHandlesInitialPrompt = input.adapters.prompt !== undefined;
|
|
166
|
+
if (
|
|
167
|
+
callOptions.eagerSession &&
|
|
168
|
+
!promptAdapterHandlesInitialPrompt &&
|
|
169
|
+
(hasNoExplicitModelConfig ||
|
|
170
|
+
(await hasExplicitFastModeCandidate({
|
|
171
|
+
model: input.options?.model,
|
|
172
|
+
fallbackModels: input.options?.fallbackModels,
|
|
173
|
+
models: runtime.opts.models,
|
|
174
|
+
})))
|
|
175
|
+
) {
|
|
176
|
+
try {
|
|
177
|
+
await runtime.innerCtx.__ensureSession();
|
|
178
|
+
} catch (err) {
|
|
179
|
+
if (!(err instanceof Error && err.message.includes("prompt adapter not configured"))) throw err;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (refreshedParentIds !== undefined) {
|
|
183
|
+
runtime.scheduler.setStageParentIds(runtime.stageSnapshot, refreshedParentIds);
|
|
184
|
+
}
|
|
185
|
+
runtime.stageSnapshot.status = "running";
|
|
186
|
+
runtime.stageSnapshot.startedAt ??= rebasedStageStartedAt(input.options?.durableAccumulatedDurationMs, now);
|
|
187
|
+
runtime.applyModelFallbackMeta(runtime.innerCtx.__modelFallbackMeta());
|
|
188
|
+
// Publish every graph-visible live write before this task can yield.
|
|
189
|
+
runtime.activeStore.recordStageStart(runtime.runId, runtime.stageSnapshot);
|
|
190
|
+
runtime.appendStageStartOnce();
|
|
191
|
+
const sessionMeta = runtime.innerCtx.__sessionMeta();
|
|
192
|
+
if (sessionMeta.sessionId !== undefined || sessionMeta.sessionFile !== undefined) {
|
|
193
|
+
await runtime.captureStageSessionMeta({ awaitDurable: true });
|
|
194
|
+
}
|
|
195
|
+
runtime.startStageSessionHeartbeat();
|
|
196
|
+
} else {
|
|
197
|
+
runtime.applyModelFallbackMeta(runtime.innerCtx.__modelFallbackMeta());
|
|
177
198
|
}
|
|
178
|
-
runtime.stageSnapshot.status = "running";
|
|
179
|
-
runtime.stageSnapshot.startedAt ??= rebasedStageStartedAt(input.options?.durableAccumulatedDurationMs, now);
|
|
180
|
-
runtime.applyModelFallbackMeta(runtime.innerCtx.__modelFallbackMeta());
|
|
181
|
-
// Publish every graph-visible live write before this task can yield.
|
|
182
|
-
runtime.activeStore.recordStageStart(runtime.runId, runtime.stageSnapshot);
|
|
183
|
-
runtime.appendStageStartOnce();
|
|
184
|
-
} else {
|
|
185
|
-
runtime.applyModelFallbackMeta(runtime.innerCtx.__modelFallbackMeta());
|
|
186
|
-
}
|
|
187
199
|
|
|
188
|
-
|
|
200
|
+
runtime.mcpScope.apply();
|
|
189
201
|
|
|
190
|
-
let applyTerminalStageState: (() => void) | undefined;
|
|
191
|
-
try {
|
|
192
202
|
const abortSession = (): void => {
|
|
193
203
|
void runtime.innerCtx.abort().catch(() => {});
|
|
194
204
|
};
|
|
@@ -198,7 +208,7 @@ export function createTrackedStageCaller(input: {
|
|
|
198
208
|
try {
|
|
199
209
|
runtime.state.askUserQuestionObservedThisTurn = false;
|
|
200
210
|
runtime.state.chatAnswerObservedThisTurn = false;
|
|
201
|
-
result = await raceAbort(call(), runtime.signal);
|
|
211
|
+
result = await runtime.raceStageSessionHeartbeat(raceAbort(call(), runtime.signal));
|
|
202
212
|
const initialDrain = await drainResumeContinuations(result);
|
|
203
213
|
result = initialDrain.result;
|
|
204
214
|
let repeatReadinessAfterChatTurn = initialDrain.chatAnswerObserved;
|
|
@@ -226,12 +236,14 @@ export function createTrackedStageCaller(input: {
|
|
|
226
236
|
runtime.state.chatAnswerObservedThisTurn = false;
|
|
227
237
|
runtime.state.waitingForStageChatTurn = true;
|
|
228
238
|
try {
|
|
229
|
-
await
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
239
|
+
await runtime.raceStageSessionHeartbeat(
|
|
240
|
+
raceAbort(
|
|
241
|
+
new Promise<void>((resolve) => {
|
|
242
|
+
resolveNextTurnEnd = resolve;
|
|
243
|
+
runtime.state.wakeWaitingForStageChatTurn = resolve;
|
|
244
|
+
}),
|
|
245
|
+
runtime.signal,
|
|
246
|
+
),
|
|
235
247
|
);
|
|
236
248
|
} finally {
|
|
237
249
|
runtime.state.wakeWaitingForStageChatTurn = undefined;
|
|
@@ -254,7 +266,7 @@ export function createTrackedStageCaller(input: {
|
|
|
254
266
|
runtime.signal.removeEventListener("abort", abortSession);
|
|
255
267
|
}
|
|
256
268
|
await runtime.innerCtx.__closeGeneration();
|
|
257
|
-
runtime.captureStageSessionMeta();
|
|
269
|
+
await runtime.captureStageSessionMeta({ awaitDurable: true });
|
|
258
270
|
runtime.applyModelFallbackMeta(runtime.innerCtx.__modelFallbackMeta());
|
|
259
271
|
if (
|
|
260
272
|
trackStageLifecycle &&
|
|
@@ -267,6 +279,7 @@ export function createTrackedStageCaller(input: {
|
|
|
267
279
|
if (trackStageLifecycle && runtime.state.stageFinalized) throw runtime.parallelFailFastError();
|
|
268
280
|
if (trackStageLifecycle) {
|
|
269
281
|
const assistantText = runtime.innerCtx.__getLastAssistantText();
|
|
282
|
+
terminalStateIsSuccess = true;
|
|
270
283
|
applyTerminalStageState = () => {
|
|
271
284
|
runtime.stageSnapshot.status = "completed";
|
|
272
285
|
if (assistantText !== undefined) runtime.stageSnapshot.result = assistantText;
|
|
@@ -294,15 +307,36 @@ export function createTrackedStageCaller(input: {
|
|
|
294
307
|
// If finalizeStageSnapshot() throws, the limiter must still be released
|
|
295
308
|
// so the concurrency semaphore is not leaked.
|
|
296
309
|
// cross-ref: issue #1498 — durable finalization failures must not leak the stage limiter.
|
|
297
|
-
runtime.mcpScope.clear();
|
|
298
310
|
let finalizationError: { readonly thrown: true; readonly error: unknown } | undefined;
|
|
311
|
+
// Tracked separately from `finalizationError`: only a failed final durable
|
|
312
|
+
// checkpoint may rewrite an otherwise-successful terminal stage state.
|
|
313
|
+
let durableCheckpointError: { readonly thrown: true; readonly error: unknown } | undefined;
|
|
299
314
|
try {
|
|
300
|
-
|
|
301
|
-
runtime.captureStageSessionMeta();
|
|
315
|
+
runtime.mcpScope.clear();
|
|
302
316
|
} catch (err) {
|
|
303
317
|
finalizationError = { thrown: true, error: err };
|
|
304
318
|
}
|
|
319
|
+
try {
|
|
320
|
+
// Drain rather than stop: a checkpoint still in flight must be awaited
|
|
321
|
+
// here, or its late rejection is discarded with the cancelled timer.
|
|
322
|
+
await runtime.drainStageSessionHeartbeat();
|
|
323
|
+
} catch (err) {
|
|
324
|
+
durableCheckpointError = { thrown: true, error: err };
|
|
325
|
+
}
|
|
326
|
+
try {
|
|
327
|
+
await runtime.innerCtx.__closeGeneration();
|
|
328
|
+
await runtime.captureStageSessionMeta({ awaitDurable: true });
|
|
329
|
+
} catch (err) {
|
|
330
|
+
durableCheckpointError ??= { thrown: true, error: err };
|
|
331
|
+
}
|
|
332
|
+
finalizationError ??= durableCheckpointError;
|
|
305
333
|
if (trackStageLifecycle) {
|
|
334
|
+
// A stage whose final durability checkpoint failed must never be
|
|
335
|
+
// persisted as `completed` while its caller receives that rejection.
|
|
336
|
+
if (durableCheckpointError !== undefined && terminalStateIsSuccess) {
|
|
337
|
+
const failure = runtime.classifyExecutorFailure(durableCheckpointError.error);
|
|
338
|
+
applyTerminalStageState = () => applyFailureToStage(runtime.stageSnapshot, failure);
|
|
339
|
+
}
|
|
306
340
|
if (!runtime.state.stageFinalized) applyTerminalStageState?.();
|
|
307
341
|
// `finalizeStageSnapshot` calls the version-bumping `recordStageEnd`
|
|
308
342
|
// before its first yield, so the live write cannot outpace the cache.
|