@bastani/atomic 0.9.19-alpha.9 → 0.9.20-alpha.1
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 +97 -0
- package/dist/builtin/intercom/CHANGELOG.md +30 -0
- package/dist/builtin/intercom/index.bundle.mjs +15 -1
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/CHANGELOG.md +8 -0
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +30 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/CHANGELOG.md +14 -0
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +67 -0
- package/dist/builtin/workflows/builtin/{chunk-nkrafh9s.js → chunk-ewkkkbak.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-1jth021m.js → chunk-zqtm1d2c.js} +1 -1
- package/dist/builtin/workflows/builtin/goal.js +2 -2
- package/dist/builtin/workflows/builtin/index.js +3 -3
- package/dist/builtin/workflows/builtin/ralph.js +2 -2
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +546 -133
- package/dist/builtin/workflows/src/index.js +326 -72
- package/dist/core/extensions/api-types.d.ts +2 -0
- package/dist/core/extensions/api-types.d.ts.map +1 -1
- package/dist/core/extensions/api-types.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader-api.d.ts.map +1 -1
- package/dist/core/extensions/loader-api.js.map +1 -1
- package/dist/core/extensions/loader-host-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-host-modules.js +3 -1
- package/dist/core/extensions/loader-host-modules.js.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.js +2 -0
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
- package/dist/core/extensions/reactive-widget.d.ts +6 -0
- package/dist/core/extensions/reactive-widget.d.ts.map +1 -1
- package/dist/core/extensions/reactive-widget.js +7 -1
- package/dist/core/extensions/reactive-widget.js.map +1 -1
- package/dist/core/extensions/runner-shortcuts.d.ts.map +1 -1
- package/dist/core/extensions/runner-shortcuts.js +32 -3
- package/dist/core/extensions/runner-shortcuts.js.map +1 -1
- package/dist/core/extensions/runtime-types.d.ts +4 -0
- package/dist/core/extensions/runtime-types.d.ts.map +1 -1
- package/dist/core/extensions/runtime-types.js.map +1 -1
- package/dist/core/extensions/ui-types.d.ts +20 -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/keybinding-identity.d.ts +4 -0
- package/dist/core/keybinding-identity.d.ts.map +1 -0
- package/dist/core/keybinding-identity.js +10 -0
- package/dist/core/keybinding-identity.js.map +1 -0
- package/dist/core/keybindings.d.ts +10 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +2 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +7 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/index-extensions.d.ts +1 -1
- package/dist/index-extensions.d.ts.map +1 -1
- package/dist/index-extensions.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/scroll-widget.d.ts +23 -0
- package/dist/modes/interactive/components/scroll-widget.d.ts.map +1 -0
- package/dist/modes/interactive/components/scroll-widget.js +61 -0
- package/dist/modes/interactive/components/scroll-widget.js.map +1 -0
- package/dist/modes/interactive/interactive-extension-runtime.js +10 -3
- package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.js +3 -2
- package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
- package/dist/modes/interactive-engine/engine-custom-ui.d.ts +4 -1
- package/dist/modes/interactive-engine/engine-custom-ui.d.ts.map +1 -1
- package/dist/modes/interactive-engine/engine-custom-ui.js +15 -7
- package/dist/modes/interactive-engine/engine-custom-ui.js.map +1 -1
- package/dist/modes/interactive-engine/engine-dialog-host.d.ts.map +1 -1
- package/dist/modes/interactive-engine/engine-dialog-host.js +4 -1
- package/dist/modes/interactive-engine/engine-dialog-host.js.map +1 -1
- package/dist/modes/interactive-engine/extension-ui-bridge.d.ts.map +1 -1
- package/dist/modes/interactive-engine/extension-ui-bridge.js +1 -1
- package/dist/modes/interactive-engine/extension-ui-bridge.js.map +1 -1
- package/dist/modes/interactive-engine/protocol.d.ts +12 -1
- package/dist/modes/interactive-engine/protocol.d.ts.map +1 -1
- package/dist/modes/interactive-engine/protocol.js +45 -2
- package/dist/modes/interactive-engine/protocol.js.map +1 -1
- package/dist/modes/interactive-engine/remote-component.d.ts.map +1 -1
- package/dist/modes/interactive-engine/remote-component.js +18 -8
- package/dist/modes/interactive-engine/remote-component.js.map +1 -1
- package/dist/modes/rpc/rpc-extension-ui.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-extension-ui.js +2 -1
- package/dist/modes/rpc/rpc-extension-ui.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +1 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +4 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/background-tasks.md +2 -0
- package/docs/extensions/api-reference.md +2 -0
- package/docs/extensions/authoring.md +2 -0
- package/docs/keybindings.md +17 -0
- package/docs/tui.md +34 -0
- package/docs/workflows/api-reference.md +2 -0
- package/docs/workflows/operations.md +13 -1
- package/npm-shrinkwrap.json +32 -32
- package/package.json +3 -3
- /package/dist/builtin/workflows/builtin/{chunk-ngkqkzej.js → chunk-m0xfsef8.js} +0 -0
|
@@ -2304,6 +2304,13 @@ function isTopLevelWorkflowRun(run) {
|
|
|
2304
2304
|
}
|
|
2305
2305
|
|
|
2306
2306
|
// dist/builtin/workflows/src/shared/timing.ts
|
|
2307
|
+
function stageTimingFields(stage = {}) {
|
|
2308
|
+
return {
|
|
2309
|
+
...stage.startedAt !== undefined ? { startedAt: stage.startedAt } : {},
|
|
2310
|
+
...stage.endedAt !== undefined ? { endedAt: stage.endedAt } : {},
|
|
2311
|
+
...stage.durationMs !== undefined ? { durationMs: stage.durationMs } : {}
|
|
2312
|
+
};
|
|
2313
|
+
}
|
|
2307
2314
|
function nonNegative(ms) {
|
|
2308
2315
|
return Math.max(0, ms);
|
|
2309
2316
|
}
|
|
@@ -2329,6 +2336,8 @@ function elapsedStageMs(stage, now = Date.now()) {
|
|
|
2329
2336
|
return nonNegative(stage.durationMs);
|
|
2330
2337
|
if (stage.startedAt === undefined)
|
|
2331
2338
|
return;
|
|
2339
|
+
if (stage.replayed && stage.endedAt === undefined)
|
|
2340
|
+
return;
|
|
2332
2341
|
const effectiveNow = stage.endedAt ?? now;
|
|
2333
2342
|
return elapsedFromStart(stage.startedAt, effectiveNow, stage.pausedDurationMs, stage.pausedAt);
|
|
2334
2343
|
}
|
|
@@ -5994,6 +6003,7 @@ function cachedStageId(runId, replayKey) {
|
|
|
5994
6003
|
function stageMetadataCheckpointId(replayKey, stage) {
|
|
5995
6004
|
return `${stableCheckpointId("stage-meta", replayKey)}:${durableHash({
|
|
5996
6005
|
stageId: stage.id,
|
|
6006
|
+
...stage.replayed === true ? { replayed: true } : {},
|
|
5997
6007
|
status: stage.status,
|
|
5998
6008
|
endedAt: stage.endedAt ?? 0,
|
|
5999
6009
|
durationMs: stage.durationMs ?? 0,
|
|
@@ -6001,11 +6011,9 @@ function stageMetadataCheckpointId(replayKey, stage) {
|
|
|
6001
6011
|
})}`;
|
|
6002
6012
|
}
|
|
6003
6013
|
function recordCachedStageIntoStore(store, runId, name, replayKey, output, completedStageReplayKeys, parentIds, checkpoint) {
|
|
6004
|
-
const now = Date.now();
|
|
6005
6014
|
const sourceStageId = checkpoint?.topology?.run?.runId === runId ? checkpoint.topology.stageId : undefined;
|
|
6006
6015
|
const stageId = sourceStageId ?? cachedStageId(runId, replayKey);
|
|
6007
6016
|
const result = checkpoint?.result ?? (typeof output === "string" ? output : JSON.stringify(output));
|
|
6008
|
-
const endedAt = checkpoint?.endedAt ?? checkpoint?.completedAt ?? now;
|
|
6009
6017
|
const hasCurrentIdentity = checkpoint?.topology?.sourceOrder !== undefined || checkpoint?.topology?.status !== undefined || checkpoint?.topology?.occurrenceKey !== undefined || checkpoint?.topology?.boundary !== undefined;
|
|
6010
6018
|
const childResult = parseWorkflowChildResult(output) ?? (hasCurrentIdentity ? undefined : parseLegacyWorkflowChildResult(output));
|
|
6011
6019
|
const workflowChild = childResult === undefined ? undefined : workflowChildSnapshotFromResult(childResult);
|
|
@@ -6015,9 +6023,7 @@ function recordCachedStageIntoStore(store, runId, name, replayKey, output, compl
|
|
|
6015
6023
|
name,
|
|
6016
6024
|
status: "completed",
|
|
6017
6025
|
parentIds: parentIds !== undefined ? Object.freeze([...parentIds]) : [],
|
|
6018
|
-
|
|
6019
|
-
endedAt,
|
|
6020
|
-
durationMs: checkpoint?.durationMs ?? 0,
|
|
6026
|
+
...stageTimingFields(checkpoint),
|
|
6021
6027
|
result,
|
|
6022
6028
|
replayKey,
|
|
6023
6029
|
replayed: true,
|
|
@@ -8908,7 +8914,7 @@ function appendStageStart(api, payload) {
|
|
|
8908
8914
|
...payload.replayKey !== undefined ? { replayKey: payload.replayKey } : {},
|
|
8909
8915
|
...payload.replayedFromStageId !== undefined ? { replayedFromStageId: payload.replayedFromStageId } : {},
|
|
8910
8916
|
...payload.replayed !== undefined ? { replayed: payload.replayed } : {},
|
|
8911
|
-
ts: payload.ts
|
|
8917
|
+
...payload.ts !== undefined ? { ts: payload.ts } : {}
|
|
8912
8918
|
});
|
|
8913
8919
|
}
|
|
8914
8920
|
function appendStageEnd(api, payload, opts) {
|
|
@@ -8919,6 +8925,7 @@ function appendStageEnd(api, payload, opts) {
|
|
|
8919
8925
|
stageId: payload.stageId,
|
|
8920
8926
|
status: payload.status,
|
|
8921
8927
|
...payload.durationMs !== undefined ? { durationMs: payload.durationMs } : {},
|
|
8928
|
+
...payload.endedAt !== undefined ? { endedAt: payload.endedAt } : {},
|
|
8922
8929
|
...payload.summary !== undefined ? { summary: payload.summary } : {},
|
|
8923
8930
|
...payload.error !== undefined ? { error: payload.error } : {},
|
|
8924
8931
|
...payload.failureKind !== undefined ? { failureKind: payload.failureKind } : {},
|
|
@@ -9622,6 +9629,26 @@ function createContinuationReplayIndex(continuation, sourceToContinuationNodeIds
|
|
|
9622
9629
|
}
|
|
9623
9630
|
|
|
9624
9631
|
// dist/builtin/workflows/src/runs/foreground/executor-prompt-nodes.ts
|
|
9632
|
+
function continuationPromptAnswer(store, sourceRun, sourceStage) {
|
|
9633
|
+
let run = sourceRun;
|
|
9634
|
+
let stage = sourceStage;
|
|
9635
|
+
const visited = new Set;
|
|
9636
|
+
while (!visited.has(stage.id)) {
|
|
9637
|
+
visited.add(stage.id);
|
|
9638
|
+
const answer = store.getStagePromptAnswer(run.id, stage.id);
|
|
9639
|
+
if (answer !== undefined)
|
|
9640
|
+
return answer;
|
|
9641
|
+
if (!stage.replayed || stage.replayedFromStageId === undefined || run.resumedFromRunId === undefined)
|
|
9642
|
+
break;
|
|
9643
|
+
const parentRun = store.runs().find((candidate) => candidate.id === run.resumedFromRunId);
|
|
9644
|
+
const parentStage = parentRun?.stages.find((candidate) => candidate.id === stage.replayedFromStageId);
|
|
9645
|
+
if (parentRun === undefined || parentStage === undefined)
|
|
9646
|
+
break;
|
|
9647
|
+
run = parentRun;
|
|
9648
|
+
stage = parentStage;
|
|
9649
|
+
}
|
|
9650
|
+
return;
|
|
9651
|
+
}
|
|
9625
9652
|
function buildPromptNodeUiAdapter(input) {
|
|
9626
9653
|
const ask = async (descriptor, durableReplay) => {
|
|
9627
9654
|
input.throwIfWorkflowExitSelected();
|
|
@@ -9636,6 +9663,9 @@ function buildPromptNodeUiAdapter(input) {
|
|
|
9636
9663
|
const prompt = makePrompt(descriptor);
|
|
9637
9664
|
const replayKey = promptReplayKey(descriptor);
|
|
9638
9665
|
const durableTopology = input.durableTopologyForReplayKey?.(replayKey);
|
|
9666
|
+
if (durableTopology?.status === "completed" && durableReplay === undefined) {
|
|
9667
|
+
throw new Error(`insufficient_state: missing durable UI answer for completed prompt ${durableTopology.stageId}`);
|
|
9668
|
+
}
|
|
9639
9669
|
const stageId = durableTopology?.stageId ?? crypto.randomUUID();
|
|
9640
9670
|
const provisionalParentIds = input.tracker.onSpawn(stageId, descriptor.kind);
|
|
9641
9671
|
const replayDecision = input.replayIndex.decide({
|
|
@@ -9649,7 +9679,7 @@ function buildPromptNodeUiAdapter(input) {
|
|
|
9649
9679
|
if (!sameStringSet(parentIds, provisionalParentIds))
|
|
9650
9680
|
input.tracker.replaceParents(stageId, parentIds);
|
|
9651
9681
|
const replaySource = replayDecision.source;
|
|
9652
|
-
const continuationAnswer = replayDecision.kind === "replay" ? input.activeStore
|
|
9682
|
+
const continuationAnswer = replayDecision.kind === "replay" ? continuationPromptAnswer(input.activeStore, input.opts.continuation.source, replayDecision.source) : undefined;
|
|
9653
9683
|
const replayAnswer = durableReplay === undefined ? continuationAnswer : { value: durableReplay.response };
|
|
9654
9684
|
const shouldReplay = replayAnswer !== undefined;
|
|
9655
9685
|
if (shouldReplay && durableReplay === undefined)
|
|
@@ -9662,13 +9692,11 @@ function buildPromptNodeUiAdapter(input) {
|
|
|
9662
9692
|
replayKey,
|
|
9663
9693
|
status: shouldReplay ? "completed" : "running",
|
|
9664
9694
|
parentIds: Object.freeze(parentIds),
|
|
9665
|
-
startedAt: prompt.createdAt,
|
|
9695
|
+
...shouldReplay ? stageTimingFields(durableReplay === undefined ? replaySource : input.durableTimingForStageId?.(stageId)) : { startedAt: prompt.createdAt },
|
|
9666
9696
|
promptFootprint: { ...prompt },
|
|
9667
9697
|
toolEvents: [],
|
|
9668
9698
|
attachable: !shouldReplay,
|
|
9669
9699
|
...shouldReplay ? {
|
|
9670
|
-
endedAt: prompt.createdAt,
|
|
9671
|
-
durationMs: 0,
|
|
9672
9700
|
promptAnswerState: promptAnswerStatus,
|
|
9673
9701
|
replayedFromStageId: replaySourceId,
|
|
9674
9702
|
replayed: true
|
|
@@ -9698,8 +9726,10 @@ function buildPromptNodeUiAdapter(input) {
|
|
|
9698
9726
|
pauseGate = undefined;
|
|
9699
9727
|
currentPauseGate?.resolve();
|
|
9700
9728
|
stageSnapshot.status = status;
|
|
9701
|
-
|
|
9702
|
-
|
|
9729
|
+
if (!shouldReplay) {
|
|
9730
|
+
stageSnapshot.endedAt = Date.now();
|
|
9731
|
+
stageSnapshot.durationMs = elapsedStageMs(stageSnapshot, stageSnapshot.endedAt);
|
|
9732
|
+
}
|
|
9703
9733
|
input.activeStore.recordStageAttachable(input.runId, stageId, false);
|
|
9704
9734
|
input.activeStore.recordStageEnd(input.runId, stageSnapshot);
|
|
9705
9735
|
await input.opts.onStageEnd?.(input.runId, stageSnapshot);
|
|
@@ -9709,6 +9739,7 @@ function buildPromptNodeUiAdapter(input) {
|
|
|
9709
9739
|
stageId,
|
|
9710
9740
|
status: stageSnapshot.status,
|
|
9711
9741
|
durationMs: stageSnapshot.durationMs,
|
|
9742
|
+
endedAt: stageSnapshot.endedAt,
|
|
9712
9743
|
...stageSnapshot.error !== undefined ? { error: stageSnapshot.error } : {},
|
|
9713
9744
|
...stageSnapshot.failureKind !== undefined ? { failureKind: stageSnapshot.failureKind } : {},
|
|
9714
9745
|
...stageSnapshot.failureCode !== undefined ? { failureCode: stageSnapshot.failureCode } : {},
|
|
@@ -9775,7 +9806,7 @@ function buildPromptNodeUiAdapter(input) {
|
|
|
9775
9806
|
name: stageSnapshot.name,
|
|
9776
9807
|
parentIds: stageSnapshot.parentIds,
|
|
9777
9808
|
...stageReplayFields(stageSnapshot),
|
|
9778
|
-
ts:
|
|
9809
|
+
ts: stageSnapshot.startedAt
|
|
9779
9810
|
});
|
|
9780
9811
|
}
|
|
9781
9812
|
if (shouldReplay) {
|
|
@@ -11312,7 +11343,7 @@ function wrapUiWithDurable(base, deps) {
|
|
|
11312
11343
|
// dist/builtin/workflows/src/engine/primitives/ui.ts
|
|
11313
11344
|
function buildExitGatedUiContext(input) {
|
|
11314
11345
|
const base = input.opts.usePromptNodesForUi === true ? input.baseFromPromptNodes() : input.opts.executionMode === "non_interactive" && input.opts.ui === undefined ? makeHeadlessUnavailableUIContext() : normalizeUIContext(input.opts.ui);
|
|
11315
|
-
const promptNodeReplay = input.opts.usePromptNodesForUi === true && input.opts.continuation !== undefined;
|
|
11346
|
+
const promptNodeReplay = input.opts.usePromptNodesForUi === true && input.opts.continuation !== undefined && input.opts.continuation.source.id !== input.durableUi?.workflowId;
|
|
11316
11347
|
const durableBase = input.durableUi !== undefined && !promptNodeReplay ? wrapUiWithDurable(base, input.durableUi) : base;
|
|
11317
11348
|
const invoke = (call) => {
|
|
11318
11349
|
input.throwIfWorkflowExitSelected();
|
|
@@ -11935,7 +11966,7 @@ function mergeStageDraft(existing, checkpoint, sequence) {
|
|
|
11935
11966
|
...valueOrExisting("thinkingLevel", checkpoint, existing),
|
|
11936
11967
|
...valueOrExisting("attemptedModels", checkpoint, existing),
|
|
11937
11968
|
...valueOrExisting("modelAttempts", checkpoint, existing),
|
|
11938
|
-
...checkpoint.topology !== undefined ? { topology: checkpoint.topology } : existing?.topology !== undefined ? { topology: existing.topology } : {}
|
|
11969
|
+
...existing?.topology?.run !== undefined && checkpoint.topology?.run === undefined ? { topology: existing.topology } : checkpoint.topology !== undefined ? { topology: checkpoint.topology } : existing?.topology !== undefined ? { topology: existing.topology } : {}
|
|
11939
11970
|
};
|
|
11940
11971
|
}
|
|
11941
11972
|
function valueOrExisting(key, checkpoint, existing) {
|
|
@@ -13226,13 +13257,11 @@ function createWorkflowBoundaryFactory(input) {
|
|
|
13226
13257
|
replayKey,
|
|
13227
13258
|
status: replayedChild !== undefined ? "completed" : "running",
|
|
13228
13259
|
parentIds: Object.freeze([...parentIds]),
|
|
13229
|
-
startedAt,
|
|
13260
|
+
...replayedChild === undefined ? { startedAt } : stageTimingFields(replaySource),
|
|
13230
13261
|
toolEvents: [],
|
|
13231
13262
|
attachable: false,
|
|
13232
13263
|
...replaySource !== undefined ? { replayedFromStageId: replaySource.id, replayed: replayedChild !== undefined } : {},
|
|
13233
13264
|
...replayedChild !== undefined && replayChildSnapshot !== undefined ? {
|
|
13234
|
-
endedAt: startedAt,
|
|
13235
|
-
durationMs: 0,
|
|
13236
13265
|
...replayDecision.kind === "replay" && replayDecision.source.result !== undefined ? { result: replayDecision.source.result } : {},
|
|
13237
13266
|
workflowChild: cloneWorkflowChildReplaySnapshot(replayChildSnapshot)
|
|
13238
13267
|
} : {}
|
|
@@ -13249,7 +13278,7 @@ function createWorkflowBoundaryFactory(input) {
|
|
|
13249
13278
|
name,
|
|
13250
13279
|
parentIds: stageSnapshot.parentIds,
|
|
13251
13280
|
...stageReplayFields(stageSnapshot),
|
|
13252
|
-
ts: startedAt
|
|
13281
|
+
ts: stageSnapshot.startedAt
|
|
13253
13282
|
});
|
|
13254
13283
|
};
|
|
13255
13284
|
const appendStageEndForSnapshot = () => {
|
|
@@ -13260,6 +13289,7 @@ function createWorkflowBoundaryFactory(input) {
|
|
|
13260
13289
|
stageId,
|
|
13261
13290
|
status: stageSnapshot.status,
|
|
13262
13291
|
durationMs: stageSnapshot.durationMs,
|
|
13292
|
+
endedAt: stageSnapshot.endedAt,
|
|
13263
13293
|
...stageSnapshot.error !== undefined ? { error: stageSnapshot.error } : {},
|
|
13264
13294
|
...stageSnapshot.failureKind !== undefined ? { failureKind: stageSnapshot.failureKind } : {},
|
|
13265
13295
|
...stageSnapshot.failureCode !== undefined ? { failureCode: stageSnapshot.failureCode } : {},
|
|
@@ -13296,8 +13326,10 @@ function createWorkflowBoundaryFactory(input) {
|
|
|
13296
13326
|
clearBoundaryChildMetadata();
|
|
13297
13327
|
applyFailureToStage(stageSnapshot, input.classifyExecutorFailure(failureError));
|
|
13298
13328
|
}
|
|
13299
|
-
|
|
13300
|
-
|
|
13329
|
+
if (replayedChild === undefined) {
|
|
13330
|
+
stageSnapshot.endedAt = Date.now();
|
|
13331
|
+
stageSnapshot.durationMs = elapsedStageMs(stageSnapshot, stageSnapshot.endedAt);
|
|
13332
|
+
}
|
|
13301
13333
|
input.activeStore.recordStageEnd(input.runId, stageSnapshot);
|
|
13302
13334
|
input.opts.onStageEnd?.(input.runId, stageSnapshot);
|
|
13303
13335
|
appendStageEndForSnapshot();
|
|
@@ -13365,6 +13397,12 @@ function createWorkflowBoundaryFactory(input) {
|
|
|
13365
13397
|
// dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts
|
|
13366
13398
|
import { runCallback as runCallback3, runSynchronousCallback } from "@bastani/atomic";
|
|
13367
13399
|
|
|
13400
|
+
// dist/builtin/workflows/src/shared/pending-stage-route-readiness.ts
|
|
13401
|
+
var owners = new WeakMap;
|
|
13402
|
+
function workflowPendingStageRouteReady(store, runId) {
|
|
13403
|
+
return owners.get(store)?.ready(runId);
|
|
13404
|
+
}
|
|
13405
|
+
|
|
13368
13406
|
// dist/builtin/workflows/src/runs/foreground/executor-queued-user-message.ts
|
|
13369
13407
|
function removedMessages(before, after) {
|
|
13370
13408
|
const remaining = [...after];
|
|
@@ -14259,7 +14297,7 @@ function createReplayStageContext(input) {
|
|
|
14259
14297
|
name,
|
|
14260
14298
|
parentIds: stageSnapshot.parentIds,
|
|
14261
14299
|
...stageReplayFields(stageSnapshot),
|
|
14262
|
-
ts: stageSnapshot.startedAt
|
|
14300
|
+
ts: stageSnapshot.startedAt
|
|
14263
14301
|
});
|
|
14264
14302
|
};
|
|
14265
14303
|
const appendReplayStageEnd = () => {
|
|
@@ -14269,7 +14307,8 @@ function createReplayStageContext(input) {
|
|
|
14269
14307
|
runId,
|
|
14270
14308
|
stageId,
|
|
14271
14309
|
status: stageSnapshot.status,
|
|
14272
|
-
durationMs: stageSnapshot.durationMs
|
|
14310
|
+
durationMs: stageSnapshot.durationMs,
|
|
14311
|
+
endedAt: stageSnapshot.endedAt,
|
|
14273
14312
|
...stageSnapshot.status === "completed" && stageSnapshot.result !== undefined ? { summary: stageSnapshot.result } : {},
|
|
14274
14313
|
...stageSnapshot.skippedReason !== undefined ? { skippedReason: stageSnapshot.skippedReason } : {},
|
|
14275
14314
|
...stageSnapshot.sessionId !== undefined ? { sessionId: stageSnapshot.sessionId } : {},
|
|
@@ -14287,8 +14326,6 @@ function createReplayStageContext(input) {
|
|
|
14287
14326
|
delete stageSnapshot.result;
|
|
14288
14327
|
stageSnapshot.skippedReason = input.workflowExitSkippedReason(reason);
|
|
14289
14328
|
}
|
|
14290
|
-
stageSnapshot.endedAt = Date.now();
|
|
14291
|
-
stageSnapshot.durationMs = elapsedStageMs(stageSnapshot, stageSnapshot.endedAt);
|
|
14292
14329
|
input.activeStore.recordStageEnd(runId, stageSnapshot);
|
|
14293
14330
|
input.opts.onStageEnd?.(runId, stageSnapshot);
|
|
14294
14331
|
appendReplayStageEnd();
|
|
@@ -15649,16 +15686,52 @@ function stageSessionExtensionRunner(current) {
|
|
|
15649
15686
|
}
|
|
15650
15687
|
return;
|
|
15651
15688
|
}
|
|
15689
|
+
var shutdowns = new WeakMap;
|
|
15690
|
+
function shutdownStageSession(current) {
|
|
15691
|
+
if (!current)
|
|
15692
|
+
return Promise.resolve();
|
|
15693
|
+
const existing = shutdowns.get(current);
|
|
15694
|
+
if (existing)
|
|
15695
|
+
return existing;
|
|
15696
|
+
const shutdown = Promise.resolve().then(async () => {
|
|
15697
|
+
const runner = stageSessionExtensionRunner(current);
|
|
15698
|
+
if (runner?.hasHandlers("session_shutdown"))
|
|
15699
|
+
await runner.emit({ type: "session_shutdown", reason: "quit" });
|
|
15700
|
+
});
|
|
15701
|
+
shutdowns.set(current, shutdown);
|
|
15702
|
+
return shutdown;
|
|
15703
|
+
}
|
|
15704
|
+
|
|
15705
|
+
class StageSessionBindingCleanupFailure extends AggregateError {
|
|
15706
|
+
constructor(bindingError, cleanupErrors) {
|
|
15707
|
+
super([bindingError, ...cleanupErrors], "atomic-workflows: failed binding cleanup did not release session ownership", {
|
|
15708
|
+
cause: bindingError
|
|
15709
|
+
});
|
|
15710
|
+
this.name = "StageSessionBindingCleanupFailure";
|
|
15711
|
+
}
|
|
15712
|
+
}
|
|
15713
|
+
async function cleanupFailedStageSessionBinding(current, bindingError) {
|
|
15714
|
+
const cleanupErrors = [];
|
|
15715
|
+
try {
|
|
15716
|
+
await shutdownStageSession(current);
|
|
15717
|
+
} catch (error) {
|
|
15718
|
+
cleanupErrors.push(error);
|
|
15719
|
+
}
|
|
15720
|
+
try {
|
|
15721
|
+
await current.dispose();
|
|
15722
|
+
} catch (error) {
|
|
15723
|
+
cleanupErrors.push(error);
|
|
15724
|
+
}
|
|
15725
|
+
if (cleanupErrors.length > 0)
|
|
15726
|
+
throw new StageSessionBindingCleanupFailure(bindingError, cleanupErrors);
|
|
15727
|
+
}
|
|
15652
15728
|
async function disposeStageSession(current) {
|
|
15653
15729
|
if (!current)
|
|
15654
15730
|
return;
|
|
15655
|
-
|
|
15656
|
-
|
|
15657
|
-
|
|
15658
|
-
|
|
15659
|
-
} catch (error) {
|
|
15660
|
-
console.error("atomic-workflows: stage session_shutdown handler failed", error);
|
|
15661
|
-
}
|
|
15731
|
+
try {
|
|
15732
|
+
await shutdownStageSession(current);
|
|
15733
|
+
} catch (error) {
|
|
15734
|
+
console.error("atomic-workflows: stage session_shutdown handler failed", error);
|
|
15662
15735
|
}
|
|
15663
15736
|
await current.dispose();
|
|
15664
15737
|
}
|
|
@@ -15972,6 +16045,27 @@ function terminatingToolCallId(event) {
|
|
|
15972
16045
|
return typeof callId === "string" && callId.length > 0 ? callId : undefined;
|
|
15973
16046
|
}
|
|
15974
16047
|
|
|
16048
|
+
// dist/builtin/workflows/src/runs/foreground/stage-startup-wait.ts
|
|
16049
|
+
function waitForStageStartup(operation, signal) {
|
|
16050
|
+
return new Promise((resolve, reject) => {
|
|
16051
|
+
const onAbort = () => {
|
|
16052
|
+
signal.removeEventListener("abort", onAbort);
|
|
16053
|
+
reject(signal.reason ?? new DOMException("Stage startup cancelled", "AbortError"));
|
|
16054
|
+
};
|
|
16055
|
+
operation.then((value) => {
|
|
16056
|
+
signal.removeEventListener("abort", onAbort);
|
|
16057
|
+
resolve(value);
|
|
16058
|
+
}, (error) => {
|
|
16059
|
+
signal.removeEventListener("abort", onAbort);
|
|
16060
|
+
reject(error);
|
|
16061
|
+
});
|
|
16062
|
+
if (signal.aborted)
|
|
16063
|
+
onAbort();
|
|
16064
|
+
else
|
|
16065
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
16066
|
+
});
|
|
16067
|
+
}
|
|
16068
|
+
|
|
15975
16069
|
// dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts
|
|
15976
16070
|
function hasMeaningfulUsage(usage) {
|
|
15977
16071
|
if (usage === undefined)
|
|
@@ -16052,9 +16146,14 @@ class StageSessionController {
|
|
|
16052
16146
|
activeCreation;
|
|
16053
16147
|
ownedCreationPromise;
|
|
16054
16148
|
abortGeneration = 0;
|
|
16149
|
+
routeAuthorityWait;
|
|
16150
|
+
startupWait = new AbortController;
|
|
16151
|
+
startup;
|
|
16055
16152
|
abortReason;
|
|
16056
16153
|
abortReasonGeneration = 0;
|
|
16057
16154
|
sessionPromise;
|
|
16155
|
+
sessionShutdownPromise;
|
|
16156
|
+
bindingCleanupFailure;
|
|
16058
16157
|
reattachSessionFile;
|
|
16059
16158
|
lastPromptStartIndex;
|
|
16060
16159
|
attemptUsageStartIndex;
|
|
@@ -16171,8 +16270,7 @@ class StageSessionController {
|
|
|
16171
16270
|
this.pendingFallbackWarnings.push(`[fallback] ${candidateLabel(candidate)} failed: ${error}. Retrying with ${candidateLabel(nextCandidate)}.`);
|
|
16172
16271
|
this.modelWarnings.push(...this.pendingFallbackWarnings);
|
|
16173
16272
|
this.pendingFallbackWarnings.length = 0;
|
|
16174
|
-
await this.disposeCurrentSession();
|
|
16175
|
-
this.activeCandidateIndex = index + 1;
|
|
16273
|
+
await this.disposeCurrentSession(index + 1);
|
|
16176
16274
|
this.notifyModelFallbackMetaChange();
|
|
16177
16275
|
return true;
|
|
16178
16276
|
}
|
|
@@ -16200,28 +16298,41 @@ class StageSessionController {
|
|
|
16200
16298
|
this.session?.setThinkingLevel(level);
|
|
16201
16299
|
}
|
|
16202
16300
|
async ensureSession(consumer = "prompt") {
|
|
16301
|
+
if (this.bindingCleanupFailure !== undefined)
|
|
16302
|
+
throw this.bindingCleanupFailure;
|
|
16303
|
+
if (this.sessionShutdownPromise !== undefined) {
|
|
16304
|
+
const generation = this.abortGeneration;
|
|
16305
|
+
await this.sessionShutdownPromise;
|
|
16306
|
+
if (this.disposed || this.opts.signal?.aborted || this.abortGeneration !== generation)
|
|
16307
|
+
throw this.staleCreationReason(generation);
|
|
16308
|
+
}
|
|
16203
16309
|
if (this.disposed)
|
|
16204
16310
|
throw new Error(`atomic-workflows: stage "${this.opts.stageName}" session has been disposed`);
|
|
16205
|
-
|
|
16311
|
+
this.opts.signal?.throwIfAborted();
|
|
16312
|
+
if (this.session !== undefined && this.activeCreation === undefined)
|
|
16206
16313
|
return this.session;
|
|
16207
16314
|
if (!this.sessionPromise) {
|
|
16315
|
+
this.beginStartup();
|
|
16208
16316
|
const pending = this.createInitialSession(consumer);
|
|
16209
16317
|
this.sessionPromise = pending;
|
|
16210
16318
|
this.ownedCreationPromise = pending;
|
|
16211
|
-
const release = () => {
|
|
16319
|
+
const release = (failed = false) => {
|
|
16212
16320
|
if (this.ownedCreationPromise === pending)
|
|
16213
16321
|
this.ownedCreationPromise = undefined;
|
|
16322
|
+
this.settleStartup(failed);
|
|
16214
16323
|
};
|
|
16215
|
-
pending.then(release, () => {
|
|
16216
|
-
release();
|
|
16217
|
-
if (this.sessionPromise === pending)
|
|
16324
|
+
pending.then(() => release(), () => {
|
|
16325
|
+
release(true);
|
|
16326
|
+
if (this.sessionPromise === pending) {
|
|
16218
16327
|
this.sessionPromise = undefined;
|
|
16328
|
+
this.activeCandidateIndex = undefined;
|
|
16329
|
+
}
|
|
16219
16330
|
});
|
|
16220
16331
|
}
|
|
16221
|
-
return this.sessionPromise;
|
|
16332
|
+
return waitForStageStartup(this.sessionPromise, this.startupWait.signal);
|
|
16222
16333
|
}
|
|
16223
16334
|
async ensureSessionFromFile(sessionFile, consumer = "prompt") {
|
|
16224
|
-
if (!this.sessionPromise && !this.session)
|
|
16335
|
+
if (!this.sessionShutdownPromise && !this.sessionPromise && !this.session)
|
|
16225
16336
|
this.reattachSessionFile = sessionFile;
|
|
16226
16337
|
const session = await this.ensureSession(consumer);
|
|
16227
16338
|
await session.closeWorkflowStageGeneration?.();
|
|
@@ -16266,6 +16377,10 @@ class StageSessionController {
|
|
|
16266
16377
|
this.artifactCapture.close();
|
|
16267
16378
|
}
|
|
16268
16379
|
async promptWithFallback(text, sdkOptions, consumer = "prompt") {
|
|
16380
|
+
if (this.session !== undefined && this.activeCreation === undefined && this.ownedCreationPromise === undefined && this.startupWait.signal.aborted) {
|
|
16381
|
+
this.opts.signal?.throwIfAborted();
|
|
16382
|
+
this.startupWait = new AbortController;
|
|
16383
|
+
}
|
|
16269
16384
|
if (!this.hasExplicitModelFallbackConfig) {
|
|
16270
16385
|
try {
|
|
16271
16386
|
const activeSession = await this.ensureSession(consumer);
|
|
@@ -16288,7 +16403,13 @@ class StageSessionController {
|
|
|
16288
16403
|
}
|
|
16289
16404
|
return;
|
|
16290
16405
|
}
|
|
16291
|
-
const
|
|
16406
|
+
const readinessOwner = this.ownedCreationPromise ?? this.activeCreation;
|
|
16407
|
+
if (readinessOwner !== undefined)
|
|
16408
|
+
await waitForStageStartup(readinessOwner, this.startupWait.signal);
|
|
16409
|
+
if (this.session === undefined)
|
|
16410
|
+
this.beginStartup();
|
|
16411
|
+
const startupSignal = this.startupWait.signal;
|
|
16412
|
+
const candidates = await waitForStageStartup(this.modelCandidates(), startupSignal);
|
|
16292
16413
|
if (candidates.length === 0) {
|
|
16293
16414
|
try {
|
|
16294
16415
|
const activeSession = await this.ensureSession(consumer);
|
|
@@ -16304,14 +16425,9 @@ class StageSessionController {
|
|
|
16304
16425
|
}
|
|
16305
16426
|
return;
|
|
16306
16427
|
}
|
|
16307
|
-
|
|
16308
|
-
|
|
16309
|
-
|
|
16310
|
-
} catch (error) {
|
|
16311
|
-
if (error instanceof StageSessionCreationCancelled)
|
|
16312
|
-
return;
|
|
16313
|
-
}
|
|
16314
|
-
}
|
|
16428
|
+
const creationOwner = this.ownedCreationPromise ?? this.activeCreation;
|
|
16429
|
+
if (creationOwner !== undefined)
|
|
16430
|
+
await waitForStageStartup(creationOwner, startupSignal);
|
|
16315
16431
|
const resumedText = this.pendingCreationResumeMessage;
|
|
16316
16432
|
this.pendingCreationResumeMessage = undefined;
|
|
16317
16433
|
let promptText = resumedText ?? text;
|
|
@@ -16319,9 +16435,21 @@ class StageSessionController {
|
|
|
16319
16435
|
return;
|
|
16320
16436
|
let index = this.activeCandidateIndex ?? 0;
|
|
16321
16437
|
while (index < candidates.length) {
|
|
16438
|
+
if (this.ownedCreationPromise !== undefined || this.activeCreation !== undefined) {
|
|
16439
|
+
try {
|
|
16440
|
+
await waitForStageStartup(this.ownedCreationPromise ?? this.activeCreation, startupSignal);
|
|
16441
|
+
} catch (error) {
|
|
16442
|
+
if (error instanceof StageSessionCreationCancelled)
|
|
16443
|
+
return;
|
|
16444
|
+
throw error;
|
|
16445
|
+
}
|
|
16446
|
+
index = this.activeCandidateIndex ?? index;
|
|
16447
|
+
promptText = this.pendingCreationResumeMessage ?? promptText;
|
|
16448
|
+
this.pendingCreationResumeMessage = undefined;
|
|
16449
|
+
}
|
|
16322
16450
|
const candidate = candidates[index];
|
|
16323
16451
|
try {
|
|
16324
|
-
const created = this.session && this.activeCandidateIndex === index ? this.session : await this.createSessionWithThrownErrorRetry(candidate, consumer);
|
|
16452
|
+
const created = this.session && this.activeCandidateIndex === index ? this.session : await waitForStageStartup(this.createSessionWithThrownErrorRetry(candidate, consumer), startupSignal);
|
|
16325
16453
|
if (isSessionCreationPauseResult(created)) {
|
|
16326
16454
|
if (created.resumeMessage === undefined)
|
|
16327
16455
|
return;
|
|
@@ -16348,8 +16476,10 @@ class StageSessionController {
|
|
|
16348
16476
|
const failure = await this.handleCandidateFailure(err, candidate, candidates, index);
|
|
16349
16477
|
if (failure === "handled")
|
|
16350
16478
|
return;
|
|
16351
|
-
if (failure === "throw")
|
|
16479
|
+
if (failure === "throw") {
|
|
16480
|
+
this.settleStartup(true);
|
|
16352
16481
|
throw err;
|
|
16482
|
+
}
|
|
16353
16483
|
index += 1;
|
|
16354
16484
|
}
|
|
16355
16485
|
}
|
|
@@ -16392,7 +16522,8 @@ class StageSessionController {
|
|
|
16392
16522
|
this.messageAdmission.dispose();
|
|
16393
16523
|
this.deliveryActivity.dispose();
|
|
16394
16524
|
await this.replacement.dispose();
|
|
16395
|
-
|
|
16525
|
+
if (this.activeCreation === undefined)
|
|
16526
|
+
await disposeStageSession(this.session);
|
|
16396
16527
|
}
|
|
16397
16528
|
async drainPendingDisposal() {
|
|
16398
16529
|
if (!this.pendingDisposal)
|
|
@@ -16466,6 +16597,12 @@ class StageSessionController {
|
|
|
16466
16597
|
this.abortGeneration += 1;
|
|
16467
16598
|
this.abortReason = reason;
|
|
16468
16599
|
this.abortReasonGeneration = this.abortGeneration;
|
|
16600
|
+
this.routeAuthorityWait?.abort(reason);
|
|
16601
|
+
this.startupWait.abort(reason);
|
|
16602
|
+
if (this.startup?.state === "active") {
|
|
16603
|
+
this.startup = { ...this.startup, state: "cancelled" };
|
|
16604
|
+
this.opts.onStartupChange?.(this.startup);
|
|
16605
|
+
}
|
|
16469
16606
|
this.abortThrownErrorRetries(reason);
|
|
16470
16607
|
}
|
|
16471
16608
|
pauseThrownErrorRetries(resume) {
|
|
@@ -16706,11 +16843,15 @@ class StageSessionController {
|
|
|
16706
16843
|
return this.candidatesPromise;
|
|
16707
16844
|
}
|
|
16708
16845
|
async createInitialSession(consumer) {
|
|
16846
|
+
const generation = this.abortGeneration;
|
|
16709
16847
|
if (!this.hasExplicitModelFallbackConfig) {
|
|
16710
16848
|
return this.createSessionObservingPause(undefined, consumer).catch((error) => this.createInitialSessionWithRetry(undefined, consumer, { error }));
|
|
16711
16849
|
}
|
|
16712
16850
|
const candidates = await this.modelCandidates();
|
|
16713
|
-
|
|
16851
|
+
if (this.abortGeneration !== generation || this.opts.signal?.aborted || this.disposed)
|
|
16852
|
+
throw this.staleCreationReason(generation);
|
|
16853
|
+
const initialIndex = this.activeCandidateIndex ?? 0;
|
|
16854
|
+
const first = candidates[initialIndex];
|
|
16714
16855
|
if (first === undefined) {
|
|
16715
16856
|
return this.createSessionObservingPause(undefined, consumer).catch((error) => this.createInitialSessionWithRetry(undefined, consumer, { error }));
|
|
16716
16857
|
}
|
|
@@ -16723,9 +16864,9 @@ class StageSessionController {
|
|
|
16723
16864
|
this.resumeCurrentSession = true;
|
|
16724
16865
|
return resumed;
|
|
16725
16866
|
}
|
|
16726
|
-
this.activeCandidateIndex =
|
|
16867
|
+
this.activeCandidateIndex = initialIndex;
|
|
16727
16868
|
this.selectedModel = first.id;
|
|
16728
|
-
return this.createSessionObservingPause(first, consumer).catch((error) => this.createInitialSessionCandidateWalk(candidates, consumer,
|
|
16869
|
+
return this.createSessionObservingPause(first, consumer).catch((error) => this.createInitialSessionCandidateWalk(candidates, consumer, initialIndex, { error }));
|
|
16729
16870
|
}
|
|
16730
16871
|
async createInitialSessionCandidateWalk(candidates, consumer, startIndex, initialFailure) {
|
|
16731
16872
|
let index = startIndex;
|
|
@@ -16807,11 +16948,13 @@ class StageSessionController {
|
|
|
16807
16948
|
}
|
|
16808
16949
|
return await this.createSessionObservingPause(candidate, consumer);
|
|
16809
16950
|
} catch (error) {
|
|
16951
|
+
if (error instanceof StageSessionBindingCleanupFailure)
|
|
16952
|
+
throw error;
|
|
16810
16953
|
const errorSettingsManager = retrySettingsManagerFromError(error);
|
|
16811
16954
|
if (errorSettingsManager !== undefined)
|
|
16812
16955
|
this.sessionSettingsManager = errorSettingsManager;
|
|
16813
16956
|
const decision = isWorkflowPendingStageDeliveryFailure(error) ? undefined : nextRetryDecision(this.retrySettings(), retryAttempt, isRetryableSameModelFailure(error));
|
|
16814
|
-
if (decision === undefined || this.disposed || this.opts.signal?.aborted === true || this.capturedStructuredOutputForAttempt()) {
|
|
16957
|
+
if (decision === undefined || this.disposed || this.opts.signal?.aborted === true || this.startupWait.signal.aborted || this.capturedStructuredOutputForAttempt()) {
|
|
16815
16958
|
throw error;
|
|
16816
16959
|
}
|
|
16817
16960
|
retryAttempt = decision.attempt;
|
|
@@ -16840,16 +16983,86 @@ class StageSessionController {
|
|
|
16840
16983
|
}
|
|
16841
16984
|
}
|
|
16842
16985
|
createSession(candidate, consumer, resumeOptions) {
|
|
16986
|
+
if (this.bindingCleanupFailure !== undefined)
|
|
16987
|
+
return Promise.reject(this.bindingCleanupFailure);
|
|
16988
|
+
if (this.sessionShutdownPromise !== undefined) {
|
|
16989
|
+
const generation = this.abortGeneration;
|
|
16990
|
+
return this.sessionShutdownPromise.then(() => {
|
|
16991
|
+
if (this.disposed || this.opts.signal?.aborted || this.abortGeneration !== generation)
|
|
16992
|
+
throw this.staleCreationReason(generation);
|
|
16993
|
+
return this.createSession(candidate, consumer, resumeOptions);
|
|
16994
|
+
});
|
|
16995
|
+
}
|
|
16996
|
+
if (this.activeCreation !== undefined)
|
|
16997
|
+
return this.activeCreation;
|
|
16998
|
+
if (this.session !== undefined)
|
|
16999
|
+
return Promise.resolve(this.session);
|
|
17000
|
+
this.startupWait.signal.throwIfAborted();
|
|
16843
17001
|
const creation = this.createSessionAttempt(candidate, consumer, resumeOptions);
|
|
16844
17002
|
this.activeCreation = creation;
|
|
16845
17003
|
creation.finally(() => {
|
|
16846
17004
|
if (this.activeCreation === creation)
|
|
16847
17005
|
this.activeCreation = undefined;
|
|
17006
|
+
this.settleStartup();
|
|
16848
17007
|
}).catch(() => {});
|
|
16849
17008
|
return creation;
|
|
16850
17009
|
}
|
|
17010
|
+
settleStartup(failed = false) {
|
|
17011
|
+
if (this.activeCreation !== undefined || this.ownedCreationPromise !== undefined || this.startup === undefined)
|
|
17012
|
+
return;
|
|
17013
|
+
if (this.startup.state === "dispatched" || this.startup.phase === "ready")
|
|
17014
|
+
return;
|
|
17015
|
+
if (this.startup.state === "active" && !failed && this.bindingCleanupFailure === undefined)
|
|
17016
|
+
return;
|
|
17017
|
+
this.startup = {
|
|
17018
|
+
...this.startup,
|
|
17019
|
+
state: this.startup.state === "active" ? "failed" : this.startup.state,
|
|
17020
|
+
ownershipPending: this.bindingCleanupFailure !== undefined,
|
|
17021
|
+
...this.bindingCleanupFailure === undefined ? { settledAt: Date.now() } : {}
|
|
17022
|
+
};
|
|
17023
|
+
this.opts.onStartupChange?.(this.startup);
|
|
17024
|
+
}
|
|
17025
|
+
beginStartup() {
|
|
17026
|
+
if (this.activeCreation !== undefined || this.ownedCreationPromise !== undefined || this.sessionPromise !== undefined)
|
|
17027
|
+
return;
|
|
17028
|
+
this.opts.signal?.throwIfAborted();
|
|
17029
|
+
if (this.startupWait.signal.aborted)
|
|
17030
|
+
this.startupWait = new AbortController;
|
|
17031
|
+
this.reportStartupPhase("model-resolution", true);
|
|
17032
|
+
}
|
|
17033
|
+
reportStartupPhase(phase, reset = false) {
|
|
17034
|
+
if (!reset && this.startup !== undefined && this.startup.state !== "active")
|
|
17035
|
+
return;
|
|
17036
|
+
const now = Date.now();
|
|
17037
|
+
this.startup = {
|
|
17038
|
+
phase,
|
|
17039
|
+
startedAt: reset ? now : this.startup?.startedAt ?? now,
|
|
17040
|
+
phaseStartedAt: now,
|
|
17041
|
+
state: phase === "first-dispatch" ? "dispatched" : "active",
|
|
17042
|
+
ownershipPending: phase !== "first-dispatch" && phase !== "ready"
|
|
17043
|
+
};
|
|
17044
|
+
this.opts.onStartupChange?.(this.startup);
|
|
17045
|
+
}
|
|
16851
17046
|
async createSessionAttempt(candidate, consumer, resumeOptions) {
|
|
16852
17047
|
const startGeneration = this.abortGeneration;
|
|
17048
|
+
if (this.disposed || this.opts.signal?.aborted)
|
|
17049
|
+
throw this.staleCreationReason(startGeneration);
|
|
17050
|
+
this.reportStartupPhase("route-authority");
|
|
17051
|
+
const authority = this.opts.routeAuthorityReady?.();
|
|
17052
|
+
if (authority !== undefined) {
|
|
17053
|
+
const wait = new AbortController;
|
|
17054
|
+
this.routeAuthorityWait = wait;
|
|
17055
|
+
try {
|
|
17056
|
+
await raceAbort2(authority.completion, wait.signal);
|
|
17057
|
+
authority.assertCurrent();
|
|
17058
|
+
if (this.disposed || this.opts.signal?.aborted || this.abortGeneration !== startGeneration)
|
|
17059
|
+
throw this.staleCreationReason(startGeneration);
|
|
17060
|
+
} finally {
|
|
17061
|
+
if (this.routeAuthorityWait === wait)
|
|
17062
|
+
this.routeAuthorityWait = undefined;
|
|
17063
|
+
}
|
|
17064
|
+
}
|
|
17065
|
+
this.reportStartupPhase("resource-preparation");
|
|
16853
17066
|
this.applyCandidateThinking(candidate);
|
|
16854
17067
|
const stageOptions = buildStageSessionOptions({
|
|
16855
17068
|
effectiveStageOptions: this.effectiveStageOptions,
|
|
@@ -16862,10 +17075,19 @@ class StageSessionController {
|
|
|
16862
17075
|
try {
|
|
16863
17076
|
created = this.opts.adapters.agentSession ? await this.opts.adapters.agentSession.create(stripWorkflowOnlyOptions(stageOptions, this.opts.defaultSessionDir, this.meta, this.opts.pendingStageDelivery), {
|
|
16864
17077
|
...this.meta,
|
|
17078
|
+
startupSignal: this.startupWait.signal,
|
|
17079
|
+
onStartupPhase: (phase) => {
|
|
17080
|
+
if (this.abortGeneration === startGeneration)
|
|
17081
|
+
this.reportStartupPhase(phase);
|
|
17082
|
+
},
|
|
16865
17083
|
stageOptions,
|
|
16866
17084
|
...this.sharedOrchestrationContext !== undefined ? { orchestrationContext: this.sharedOrchestrationContext } : {}
|
|
16867
17085
|
}) : missingAdapter(consumer);
|
|
16868
17086
|
} catch (error) {
|
|
17087
|
+
if (error instanceof StageSessionBindingCleanupFailure) {
|
|
17088
|
+
this.bindingCleanupFailure = error;
|
|
17089
|
+
throw error;
|
|
17090
|
+
}
|
|
16869
17091
|
if (this.disposed || this.opts.signal?.aborted === true || this.abortGeneration !== startGeneration)
|
|
16870
17092
|
throw this.disposed ? new Error(`atomic-workflows: stage "${this.opts.stageName}" session has been disposed`) : this.staleCreationReason(startGeneration);
|
|
16871
17093
|
throw error;
|
|
@@ -16876,20 +17098,28 @@ class StageSessionController {
|
|
|
16876
17098
|
throw new Error(`atomic-workflows: stage "${this.opts.stageName}" session has been disposed`);
|
|
16877
17099
|
throw this.staleCreationReason(startGeneration);
|
|
16878
17100
|
}
|
|
17101
|
+
this.reportStartupPhase("session-attachment");
|
|
16879
17102
|
const session = attachCreatedStageSession(created, this.disposed, this.opts.stageName, (result) => this.attachSession(result));
|
|
16880
17103
|
const attachedSession = session instanceof Promise ? await session : session;
|
|
16881
|
-
|
|
16882
|
-
|
|
17104
|
+
this.reportStartupPhase("delivery-readiness");
|
|
17105
|
+
try {
|
|
17106
|
+
await this.sharedOrchestrationContext?.pendingStageDelivery?.ready();
|
|
17107
|
+
await this.opts.onSessionReady?.();
|
|
17108
|
+
if (this.disposed || this.opts.signal?.aborted || this.abortGeneration !== startGeneration)
|
|
17109
|
+
throw this.staleCreationReason(startGeneration);
|
|
17110
|
+
} catch (reason) {
|
|
17111
|
+
if (this.session === attachedSession)
|
|
17112
|
+
this.session = undefined;
|
|
16883
17113
|
try {
|
|
16884
|
-
await
|
|
17114
|
+
await cleanupFailedStageSessionBinding(attachedSession, reason);
|
|
16885
17115
|
} catch (error) {
|
|
16886
|
-
if (
|
|
16887
|
-
this.
|
|
16888
|
-
await disposeStageSession(attachedSession).catch(() => {});
|
|
17116
|
+
if (error instanceof StageSessionBindingCleanupFailure)
|
|
17117
|
+
this.bindingCleanupFailure = error;
|
|
16889
17118
|
throw error;
|
|
16890
17119
|
}
|
|
17120
|
+
throw reason;
|
|
16891
17121
|
}
|
|
16892
|
-
|
|
17122
|
+
this.reportStartupPhase("ready");
|
|
16893
17123
|
return attachedSession;
|
|
16894
17124
|
}
|
|
16895
17125
|
attachSession(created) {
|
|
@@ -16929,12 +17159,16 @@ class StageSessionController {
|
|
|
16929
17159
|
});
|
|
16930
17160
|
return result.session;
|
|
16931
17161
|
}
|
|
16932
|
-
async disposeCurrentSession() {
|
|
17162
|
+
async disposeCurrentSession(nextCandidateIndex) {
|
|
17163
|
+
if (this.sessionShutdownPromise !== undefined)
|
|
17164
|
+
await this.sessionShutdownPromise;
|
|
17165
|
+
const startGeneration = this.abortGeneration;
|
|
16933
17166
|
this.abortThrownErrorRetries(new Error(`atomic-workflows: stage "${this.opts.stageName}" session was replaced`));
|
|
16934
17167
|
const current = this.session;
|
|
16935
17168
|
this.messageAdmission.reset();
|
|
16936
17169
|
this.replacement.retire(current);
|
|
16937
17170
|
this.session = undefined;
|
|
17171
|
+
this.activeCandidateIndex = nextCandidateIndex;
|
|
16938
17172
|
if (this.sessionPromise !== this.ownedCreationPromise)
|
|
16939
17173
|
this.sessionPromise = undefined;
|
|
16940
17174
|
this.sessionSettingsManager = undefined;
|
|
@@ -16945,6 +17179,15 @@ class StageSessionController {
|
|
|
16945
17179
|
this.unsubscribeTerminateWatcher?.();
|
|
16946
17180
|
this.unsubscribeTerminateWatcher = undefined;
|
|
16947
17181
|
this.terminatingToolCallIds.clear();
|
|
17182
|
+
const shutdown = Promise.resolve().then(() => shutdownStageSession(current));
|
|
17183
|
+
this.sessionShutdownPromise = shutdown;
|
|
17184
|
+
shutdown.then(() => {
|
|
17185
|
+
if (this.sessionShutdownPromise === shutdown)
|
|
17186
|
+
this.sessionShutdownPromise = undefined;
|
|
17187
|
+
}, () => {});
|
|
17188
|
+
await shutdown;
|
|
17189
|
+
if (this.disposed || this.opts.signal?.aborted === true || this.abortGeneration !== startGeneration)
|
|
17190
|
+
throw this.staleCreationReason(startGeneration);
|
|
16948
17191
|
}
|
|
16949
17192
|
async promptWithPauseResume(activeSession, initialText, sdkOptions) {
|
|
16950
17193
|
let nextText = initialText;
|
|
@@ -16962,6 +17205,7 @@ class StageSessionController {
|
|
|
16962
17205
|
this.lastPromptStartIndex = promptStartIndex;
|
|
16963
17206
|
this.unresolvedContextOverflowMessage = undefined;
|
|
16964
17207
|
try {
|
|
17208
|
+
this.reportStartupPhase("first-dispatch");
|
|
16965
17209
|
await activeSession.prompt(nextText, sdkOptions);
|
|
16966
17210
|
const pendingPauseAfterPrompt = this.pauseControl.currentResume();
|
|
16967
17211
|
if (pendingPauseAfterPrompt) {
|
|
@@ -17054,12 +17298,13 @@ class StageSessionController {
|
|
|
17054
17298
|
throw err;
|
|
17055
17299
|
}
|
|
17056
17300
|
this.pendingFallbackWarnings.push(resumedOverflowNextIndex === undefined ? `[fallback] resume on ${resumedLabel} failed: ${message}. Restarting fallback from ${candidateLabel(candidates[0])}.` : `[fallback] resume on ${resumedLabel} failed: ${message}. Retrying with ${candidateLabel(candidates[resumedOverflowNextIndex])}.`);
|
|
17057
|
-
await this.disposeCurrentSession();
|
|
17058
|
-
this.activeCandidateIndex = resumedOverflowNextIndex;
|
|
17301
|
+
await this.disposeCurrentSession(resumedOverflowNextIndex);
|
|
17059
17302
|
return false;
|
|
17060
17303
|
}
|
|
17061
17304
|
}
|
|
17062
17305
|
async handleCandidateFailure(err, candidate, candidates, index) {
|
|
17306
|
+
if (err instanceof StageSessionBindingCleanupFailure)
|
|
17307
|
+
throw err;
|
|
17063
17308
|
const message = errorMessage2(err);
|
|
17064
17309
|
const terminalStageDelivery = isWorkflowPendingStageDeliveryFailure(err);
|
|
17065
17310
|
if (!terminalStageDelivery && this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err)) {
|
|
@@ -17075,7 +17320,7 @@ class StageSessionController {
|
|
|
17075
17320
|
...usage === undefined ? {} : { usage },
|
|
17076
17321
|
error: message
|
|
17077
17322
|
});
|
|
17078
|
-
if (this.opts.signal?.aborted || terminalStageDelivery || !isRetryableModelFailure(err) || index === candidates.length - 1) {
|
|
17323
|
+
if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !isRetryableModelFailure(err) || index === candidates.length - 1) {
|
|
17079
17324
|
this.modelWarnings.push(...this.pendingFallbackWarnings);
|
|
17080
17325
|
this.pendingFallbackWarnings.length = 0;
|
|
17081
17326
|
this.notifyModelFallbackMetaChange();
|
|
@@ -17083,7 +17328,7 @@ class StageSessionController {
|
|
|
17083
17328
|
}
|
|
17084
17329
|
const nextCandidate = candidates[index + 1];
|
|
17085
17330
|
this.pendingFallbackWarnings.push(`[fallback] ${candidateLabel(candidate)} failed: ${message}. Retrying with ${candidateLabel(nextCandidate)}.`);
|
|
17086
|
-
await this.disposeCurrentSession();
|
|
17331
|
+
await this.disposeCurrentSession(index + 1);
|
|
17087
17332
|
return "retry";
|
|
17088
17333
|
}
|
|
17089
17334
|
capturedStructuredOutputForAttempt() {
|
|
@@ -17724,9 +17969,7 @@ function createWorkflowStageFactory(input) {
|
|
|
17724
17969
|
toolEvents: [],
|
|
17725
17970
|
pendingStageDeliveryAvailable,
|
|
17726
17971
|
...shouldReplay ? {
|
|
17727
|
-
|
|
17728
|
-
endedAt: Date.now(),
|
|
17729
|
-
durationMs: 0,
|
|
17972
|
+
...stageTimingFields(replaySource),
|
|
17730
17973
|
...replaySource.result !== undefined ? { result: replaySource.result } : {},
|
|
17731
17974
|
...replaySource.sessionId !== undefined ? { sessionId: replaySource.sessionId } : {},
|
|
17732
17975
|
...replaySource.sessionFile !== undefined ? { sessionFile: replaySource.sessionFile } : {},
|
|
@@ -17789,11 +18032,19 @@ function createWorkflowStageFactory(input) {
|
|
|
17789
18032
|
signal: input.signal,
|
|
17790
18033
|
stageOptions: stageOptionsForContext,
|
|
17791
18034
|
...pendingStageDeliveryAvailable ? {
|
|
18035
|
+
routeAuthorityReady: () => workflowPendingStageRouteReady(input.activeStore, input.runId),
|
|
17792
18036
|
pendingStageDelivery: createWorkflowPendingStageDelivery(input.activeStore, input.runId, stageId, name)
|
|
17793
18037
|
} : {},
|
|
17794
18038
|
models: input.opts.models,
|
|
17795
18039
|
executionMode: input.opts.executionMode,
|
|
17796
18040
|
defaultSessionDir: input.opts.defaultSessionDir,
|
|
18041
|
+
onStartupChange(startup) {
|
|
18042
|
+
const current = input.activeStore.runs().find((run) => run.id === input.runId);
|
|
18043
|
+
if (!current?.stages.includes(stageSnapshot))
|
|
18044
|
+
return;
|
|
18045
|
+
stageSnapshot.startup = startup;
|
|
18046
|
+
input.activeStore.recordStageStart(input.runId, stageSnapshot);
|
|
18047
|
+
},
|
|
17797
18048
|
onModelFallbackMetaChange(meta) {
|
|
17798
18049
|
applyModelFallbackMeta(meta);
|
|
17799
18050
|
if (stageSnapshot.status === "running")
|
|
@@ -17956,6 +18207,7 @@ function createWorkflowStageFactory(input) {
|
|
|
17956
18207
|
stageId,
|
|
17957
18208
|
status: stageSnapshot.status,
|
|
17958
18209
|
durationMs: stageSnapshot.durationMs,
|
|
18210
|
+
endedAt: stageSnapshot.endedAt,
|
|
17959
18211
|
...stageSnapshot.error !== undefined ? { error: stageSnapshot.error } : {},
|
|
17960
18212
|
...stageSnapshot.failureKind !== undefined ? { failureKind: stageSnapshot.failureKind } : {},
|
|
17961
18213
|
...stageSnapshot.failureCode !== undefined ? { failureCode: stageSnapshot.failureCode } : {},
|
|
@@ -18561,6 +18813,7 @@ async function run(def, inputs, opts = {}) {
|
|
|
18561
18813
|
};
|
|
18562
18814
|
};
|
|
18563
18815
|
const resolvePromptNodeTopology = createDurableStageTopologyResolver(durableBackend, runId);
|
|
18816
|
+
const priorPromptStageCheckpoints = durableBackend.listCheckpoints(runId).filter((checkpoint) => checkpoint.kind === "stage");
|
|
18564
18817
|
let promptNodeUi;
|
|
18565
18818
|
const getPromptNodeUi = () => {
|
|
18566
18819
|
promptNodeUi ??= buildPromptNodeUiAdapter({
|
|
@@ -18577,6 +18830,7 @@ async function run(def, inputs, opts = {}) {
|
|
|
18577
18830
|
workflowExitSkippedReason: exit.workflowExitSkippedReason,
|
|
18578
18831
|
preserveWorkflowExitSkippedReason: exit.preserveWorkflowExitSkippedReason,
|
|
18579
18832
|
durableTopologyForReplayKey: resolvePromptNodeTopology,
|
|
18833
|
+
durableTimingForStageId: (stageId) => priorPromptStageCheckpoints.find((checkpoint) => checkpoint.topology?.stageId === stageId && checkpoint.topology.status === "completed" && (checkpoint.topology.run === undefined || checkpoint.topology.run.runId === runId)),
|
|
18580
18834
|
onPendingStage: async (pendingRunId, snapshot) => pendingRunId === runId ? void await recordDurableActiveStage(durableStageDeps, snapshot) : undefined
|
|
18581
18835
|
});
|
|
18582
18836
|
return promptNodeUi;
|