@bastani/atomic 0.9.19 → 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.
@@ -67164,6 +67164,13 @@ function topLevelWorkflowRuns(runs) {
67164
67164
  }
67165
67165
 
67166
67166
  // dist/builtin/workflows/src/shared/timing.ts
67167
+ function stageTimingFields(stage = {}) {
67168
+ return {
67169
+ ...stage.startedAt !== undefined ? { startedAt: stage.startedAt } : {},
67170
+ ...stage.endedAt !== undefined ? { endedAt: stage.endedAt } : {},
67171
+ ...stage.durationMs !== undefined ? { durationMs: stage.durationMs } : {}
67172
+ };
67173
+ }
67167
67174
  function nonNegative(ms) {
67168
67175
  return Math.max(0, ms);
67169
67176
  }
@@ -67189,6 +67196,8 @@ function elapsedStageMs(stage, now = Date.now()) {
67189
67196
  return nonNegative(stage.durationMs);
67190
67197
  if (stage.startedAt === undefined)
67191
67198
  return;
67199
+ if (stage.replayed && stage.endedAt === undefined)
67200
+ return;
67192
67201
  const effectiveNow = stage.endedAt ?? now;
67193
67202
  return elapsedFromStart(stage.startedAt, effectiveNow, stage.pausedDurationMs, stage.pausedAt);
67194
67203
  }
@@ -68631,6 +68640,15 @@ function pendingWorkflowStageStatuses(run, resolveOwningRunStatus, resolveBounda
68631
68640
  });
68632
68641
  }
68633
68642
 
68643
+ // dist/builtin/workflows/src/shared/stage-startup.ts
68644
+ function formatStageStartup(startup, now = Date.now()) {
68645
+ const observedAt = startup.state === "dispatched" ? startup.phaseStartedAt : startup.settledAt ?? now;
68646
+ const age = Math.max(0, Math.floor((observedAt - startup.phaseStartedAt) / 1000));
68647
+ const total = Math.max(0, Math.floor((observedAt - startup.startedAt) / 1000));
68648
+ const recovery = startup.state === "cancelled" && startup.ownershipPending ? "; cleanup pending — do not retry in-process; stop the owning Atomic process before fresh execution" : "";
68649
+ return `startup ${startup.phase} (${total}s total, ${age}s on current step; ${startup.state})${recovery}`;
68650
+ }
68651
+
68634
68652
  // dist/builtin/workflows/src/tui/status-helpers.ts
68635
68653
  function statusColor(status, theme) {
68636
68654
  switch (status) {
@@ -68886,9 +68904,15 @@ function pendingStageRows(runId, rootRunId, runStatus, stage, width, theme, reso
68886
68904
  const text = hexToAnsi(theme.text);
68887
68905
  return wrapped.map(({ prefix, chunk }, index) => index === 0 ? ` ${muted}${pad(label, 16)}${RESET}${text}${chunk}${RESET} ` : `${prefix}${text}${chunk}${RESET} `);
68888
68906
  }
68907
+ function startupRows(stage, now, width, theme) {
68908
+ if (stage.startup === undefined)
68909
+ return [];
68910
+ return wrapIdentifierLines(formatStageStartup(stage.startup, now), Math.max(1, width - 2), " ", " ").map(({ prefix, chunk }) => theme === undefined ? `${prefix}${chunk}` : `${prefix}${hexToAnsi(theme.textMuted)}${chunk}${RESET}`);
68911
+ }
68889
68912
  function renderStageRowsPlain(runId, rootRunId, runStatus, stage, now, width, resolveOwningRunStatus, resolveBoundarySegments) {
68890
68913
  const rows = [
68891
68914
  ` ${stageLinePlain(stage, now, Math.max(1, width - 2))} `,
68915
+ ...startupRows(stage, now, width),
68892
68916
  ...pendingStageRows(runId, rootRunId, runStatus, stage, width, undefined, resolveOwningRunStatus, resolveBoundarySegments)
68893
68917
  ];
68894
68918
  if (stage.error) {
@@ -68900,6 +68924,7 @@ function renderStageRowsPlain(runId, rootRunId, runStatus, stage, now, width, re
68900
68924
  function renderStageRowsThemed(runId, rootRunId, runStatus, stage, now, theme, width, resolveOwningRunStatus, resolveBoundarySegments) {
68901
68925
  const rows = [
68902
68926
  ` ${stageLineThemed(stage, now, theme, Math.max(1, width - 2))} `,
68927
+ ...startupRows(stage, now, width, theme),
68903
68928
  ...pendingStageRows(runId, rootRunId, runStatus, stage, width, theme, resolveOwningRunStatus, resolveBoundarySegments)
68904
68929
  ];
68905
68930
  if (stage.error) {
@@ -87873,6 +87898,7 @@ function cachedStageId(runId, replayKey) {
87873
87898
  function stageMetadataCheckpointId(replayKey, stage) {
87874
87899
  return `${stableCheckpointId("stage-meta", replayKey)}:${durableHash({
87875
87900
  stageId: stage.id,
87901
+ ...stage.replayed === true ? { replayed: true } : {},
87876
87902
  status: stage.status,
87877
87903
  endedAt: stage.endedAt ?? 0,
87878
87904
  durationMs: stage.durationMs ?? 0,
@@ -87880,11 +87906,9 @@ function stageMetadataCheckpointId(replayKey, stage) {
87880
87906
  })}`;
87881
87907
  }
87882
87908
  function recordCachedStageIntoStore(store, runId, name, replayKey, output, completedStageReplayKeys, parentIds, checkpoint) {
87883
- const now = Date.now();
87884
87909
  const sourceStageId = checkpoint?.topology?.run?.runId === runId ? checkpoint.topology.stageId : undefined;
87885
87910
  const stageId = sourceStageId ?? cachedStageId(runId, replayKey);
87886
87911
  const result = checkpoint?.result ?? (typeof output === "string" ? output : JSON.stringify(output));
87887
- const endedAt = checkpoint?.endedAt ?? checkpoint?.completedAt ?? now;
87888
87912
  const hasCurrentIdentity = checkpoint?.topology?.sourceOrder !== undefined || checkpoint?.topology?.status !== undefined || checkpoint?.topology?.occurrenceKey !== undefined || checkpoint?.topology?.boundary !== undefined;
87889
87913
  const childResult = parseWorkflowChildResult(output) ?? (hasCurrentIdentity ? undefined : parseLegacyWorkflowChildResult(output));
87890
87914
  const workflowChild = childResult === undefined ? undefined : workflowChildSnapshotFromResult(childResult);
@@ -87894,9 +87918,7 @@ function recordCachedStageIntoStore(store, runId, name, replayKey, output, compl
87894
87918
  name,
87895
87919
  status: "completed",
87896
87920
  parentIds: parentIds !== undefined ? Object.freeze([...parentIds]) : [],
87897
- startedAt: checkpoint?.startedAt ?? endedAt,
87898
- endedAt,
87899
- durationMs: checkpoint?.durationMs ?? 0,
87921
+ ...stageTimingFields(checkpoint),
87900
87922
  result,
87901
87923
  replayKey,
87902
87924
  replayed: true,
@@ -88260,7 +88282,7 @@ function appendStageStart(api, payload) {
88260
88282
  ...payload.replayKey !== undefined ? { replayKey: payload.replayKey } : {},
88261
88283
  ...payload.replayedFromStageId !== undefined ? { replayedFromStageId: payload.replayedFromStageId } : {},
88262
88284
  ...payload.replayed !== undefined ? { replayed: payload.replayed } : {},
88263
- ts: payload.ts
88285
+ ...payload.ts !== undefined ? { ts: payload.ts } : {}
88264
88286
  });
88265
88287
  }
88266
88288
  function appendStageEnd(api, payload, opts) {
@@ -88271,6 +88293,7 @@ function appendStageEnd(api, payload, opts) {
88271
88293
  stageId: payload.stageId,
88272
88294
  status: payload.status,
88273
88295
  ...payload.durationMs !== undefined ? { durationMs: payload.durationMs } : {},
88296
+ ...payload.endedAt !== undefined ? { endedAt: payload.endedAt } : {},
88274
88297
  ...payload.summary !== undefined ? { summary: payload.summary } : {},
88275
88298
  ...payload.error !== undefined ? { error: payload.error } : {},
88276
88299
  ...payload.failureKind !== undefined ? { failureKind: payload.failureKind } : {},
@@ -100921,6 +100944,26 @@ function createContinuationReplayIndex(continuation, sourceToContinuationNodeIds
100921
100944
  }
100922
100945
 
100923
100946
  // dist/builtin/workflows/src/runs/foreground/executor-prompt-nodes.ts
100947
+ function continuationPromptAnswer(store, sourceRun, sourceStage) {
100948
+ let run = sourceRun;
100949
+ let stage = sourceStage;
100950
+ const visited = new Set;
100951
+ while (!visited.has(stage.id)) {
100952
+ visited.add(stage.id);
100953
+ const answer = store.getStagePromptAnswer(run.id, stage.id);
100954
+ if (answer !== undefined)
100955
+ return answer;
100956
+ if (!stage.replayed || stage.replayedFromStageId === undefined || run.resumedFromRunId === undefined)
100957
+ break;
100958
+ const parentRun = store.runs().find((candidate) => candidate.id === run.resumedFromRunId);
100959
+ const parentStage = parentRun?.stages.find((candidate) => candidate.id === stage.replayedFromStageId);
100960
+ if (parentRun === undefined || parentStage === undefined)
100961
+ break;
100962
+ run = parentRun;
100963
+ stage = parentStage;
100964
+ }
100965
+ return;
100966
+ }
100924
100967
  function buildPromptNodeUiAdapter(input) {
100925
100968
  const ask = async (descriptor, durableReplay) => {
100926
100969
  input.throwIfWorkflowExitSelected();
@@ -100935,6 +100978,9 @@ function buildPromptNodeUiAdapter(input) {
100935
100978
  const prompt = makePrompt(descriptor);
100936
100979
  const replayKey = promptReplayKey(descriptor);
100937
100980
  const durableTopology = input.durableTopologyForReplayKey?.(replayKey);
100981
+ if (durableTopology?.status === "completed" && durableReplay === undefined) {
100982
+ throw new Error(`insufficient_state: missing durable UI answer for completed prompt ${durableTopology.stageId}`);
100983
+ }
100938
100984
  const stageId = durableTopology?.stageId ?? crypto.randomUUID();
100939
100985
  const provisionalParentIds = input.tracker.onSpawn(stageId, descriptor.kind);
100940
100986
  const replayDecision = input.replayIndex.decide({
@@ -100948,7 +100994,7 @@ function buildPromptNodeUiAdapter(input) {
100948
100994
  if (!sameStringSet(parentIds, provisionalParentIds))
100949
100995
  input.tracker.replaceParents(stageId, parentIds);
100950
100996
  const replaySource = replayDecision.source;
100951
- const continuationAnswer = replayDecision.kind === "replay" ? input.activeStore.getStagePromptAnswer(input.opts.continuation.source.id, replayDecision.source.id) : undefined;
100997
+ const continuationAnswer = replayDecision.kind === "replay" ? continuationPromptAnswer(input.activeStore, input.opts.continuation.source, replayDecision.source) : undefined;
100952
100998
  const replayAnswer = durableReplay === undefined ? continuationAnswer : { value: durableReplay.response };
100953
100999
  const shouldReplay = replayAnswer !== undefined;
100954
101000
  if (shouldReplay && durableReplay === undefined)
@@ -100961,13 +101007,11 @@ function buildPromptNodeUiAdapter(input) {
100961
101007
  replayKey,
100962
101008
  status: shouldReplay ? "completed" : "running",
100963
101009
  parentIds: Object.freeze(parentIds),
100964
- startedAt: prompt.createdAt,
101010
+ ...shouldReplay ? stageTimingFields(durableReplay === undefined ? replaySource : input.durableTimingForStageId?.(stageId)) : { startedAt: prompt.createdAt },
100965
101011
  promptFootprint: { ...prompt },
100966
101012
  toolEvents: [],
100967
101013
  attachable: !shouldReplay,
100968
101014
  ...shouldReplay ? {
100969
- endedAt: prompt.createdAt,
100970
- durationMs: 0,
100971
101015
  promptAnswerState: promptAnswerStatus,
100972
101016
  replayedFromStageId: replaySourceId,
100973
101017
  replayed: true
@@ -100997,8 +101041,10 @@ function buildPromptNodeUiAdapter(input) {
100997
101041
  pauseGate = undefined;
100998
101042
  currentPauseGate?.resolve();
100999
101043
  stageSnapshot.status = status;
101000
- stageSnapshot.endedAt = Date.now();
101001
- stageSnapshot.durationMs = elapsedStageMs(stageSnapshot, stageSnapshot.endedAt);
101044
+ if (!shouldReplay) {
101045
+ stageSnapshot.endedAt = Date.now();
101046
+ stageSnapshot.durationMs = elapsedStageMs(stageSnapshot, stageSnapshot.endedAt);
101047
+ }
101002
101048
  input.activeStore.recordStageAttachable(input.runId, stageId, false);
101003
101049
  input.activeStore.recordStageEnd(input.runId, stageSnapshot);
101004
101050
  await input.opts.onStageEnd?.(input.runId, stageSnapshot);
@@ -101008,6 +101054,7 @@ function buildPromptNodeUiAdapter(input) {
101008
101054
  stageId,
101009
101055
  status: stageSnapshot.status,
101010
101056
  durationMs: stageSnapshot.durationMs,
101057
+ endedAt: stageSnapshot.endedAt,
101011
101058
  ...stageSnapshot.error !== undefined ? { error: stageSnapshot.error } : {},
101012
101059
  ...stageSnapshot.failureKind !== undefined ? { failureKind: stageSnapshot.failureKind } : {},
101013
101060
  ...stageSnapshot.failureCode !== undefined ? { failureCode: stageSnapshot.failureCode } : {},
@@ -101074,7 +101121,7 @@ function buildPromptNodeUiAdapter(input) {
101074
101121
  name: stageSnapshot.name,
101075
101122
  parentIds: stageSnapshot.parentIds,
101076
101123
  ...stageReplayFields(stageSnapshot),
101077
- ts: prompt.createdAt
101124
+ ts: stageSnapshot.startedAt
101078
101125
  });
101079
101126
  }
101080
101127
  if (shouldReplay) {
@@ -102345,7 +102392,7 @@ function wrapUiWithDurable(base, deps) {
102345
102392
  // dist/builtin/workflows/src/engine/primitives/ui.ts
102346
102393
  function buildExitGatedUiContext(input) {
102347
102394
  const base = input.opts.usePromptNodesForUi === true ? input.baseFromPromptNodes() : input.opts.executionMode === "non_interactive" && input.opts.ui === undefined ? makeHeadlessUnavailableUIContext() : normalizeUIContext(input.opts.ui);
102348
- const promptNodeReplay = input.opts.usePromptNodesForUi === true && input.opts.continuation !== undefined;
102395
+ const promptNodeReplay = input.opts.usePromptNodesForUi === true && input.opts.continuation !== undefined && input.opts.continuation.source.id !== input.durableUi?.workflowId;
102349
102396
  const durableBase = input.durableUi !== undefined && !promptNodeReplay ? wrapUiWithDurable(base, input.durableUi) : base;
102350
102397
  const invoke = (call) => {
102351
102398
  input.throwIfWorkflowExitSelected();
@@ -102869,7 +102916,7 @@ function mergeStageDraft(existing, checkpoint, sequence) {
102869
102916
  ...valueOrExisting("thinkingLevel", checkpoint, existing),
102870
102917
  ...valueOrExisting("attemptedModels", checkpoint, existing),
102871
102918
  ...valueOrExisting("modelAttempts", checkpoint, existing),
102872
- ...checkpoint.topology !== undefined ? { topology: checkpoint.topology } : existing?.topology !== undefined ? { topology: existing.topology } : {}
102919
+ ...existing?.topology?.run !== undefined && checkpoint.topology?.run === undefined ? { topology: existing.topology } : checkpoint.topology !== undefined ? { topology: checkpoint.topology } : existing?.topology !== undefined ? { topology: existing.topology } : {}
102873
102920
  };
102874
102921
  }
102875
102922
  function valueOrExisting(key, checkpoint, existing) {
@@ -103090,7 +103137,7 @@ function resolveToolResumeFrontier(source, backend) {
103090
103137
  if (source.failedToolNodeId === undefined && !checkpoints.some((checkpoint) => checkpoint.kind === "tool" && checkpoint.throwingFailureError === source.error && checkpoint.argsHash === frontier.argsHash && checkpoint.topology?.nodeId === frontier.id && checkpoint.topology.ordinal === frontier.ordinal))
103091
103138
  return fail("missing typed tool failure checkpoint for legacy frontier");
103092
103139
  for (const stage of source.stages) {
103093
- if (stage.status !== "completed" || !checkpoints.some((checkpoint) => checkpoint.kind === "stage" && checkpoint.replayKey === stage.replayKey && checkpoint.output !== undefined))
103140
+ if (stage.status !== "completed" || !checkpoints.some((checkpoint) => checkpoint.kind === "stage" && checkpoint.replayKey === stage.replayKey && (checkpoint.output !== undefined || ["input", "confirm", "select", "editor", "custom"].includes(stage.name) && stage.replayKey?.startsWith(`prompt:${stage.name}:`) === true && checkpoint.name === stage.name && checkpoint.topology?.stageId === stage.id && checkpoint.topology.status === "completed" && checkpoint.topology.run?.runId === source.id)))
103094
103141
  return fail(`unfinished or missing completed stage checkpoint ${stage.id}`);
103095
103142
  }
103096
103143
  for (const tool of tools) {
@@ -104510,13 +104557,11 @@ function createWorkflowBoundaryFactory(input) {
104510
104557
  replayKey,
104511
104558
  status: replayedChild !== undefined ? "completed" : "running",
104512
104559
  parentIds: Object.freeze([...parentIds]),
104513
- startedAt,
104560
+ ...replayedChild === undefined ? { startedAt } : stageTimingFields(replaySource),
104514
104561
  toolEvents: [],
104515
104562
  attachable: false,
104516
104563
  ...replaySource !== undefined ? { replayedFromStageId: replaySource.id, replayed: replayedChild !== undefined } : {},
104517
104564
  ...replayedChild !== undefined && replayChildSnapshot !== undefined ? {
104518
- endedAt: startedAt,
104519
- durationMs: 0,
104520
104565
  ...replayDecision.kind === "replay" && replayDecision.source.result !== undefined ? { result: replayDecision.source.result } : {},
104521
104566
  workflowChild: cloneWorkflowChildReplaySnapshot(replayChildSnapshot)
104522
104567
  } : {}
@@ -104533,7 +104578,7 @@ function createWorkflowBoundaryFactory(input) {
104533
104578
  name,
104534
104579
  parentIds: stageSnapshot.parentIds,
104535
104580
  ...stageReplayFields(stageSnapshot),
104536
- ts: startedAt
104581
+ ts: stageSnapshot.startedAt
104537
104582
  });
104538
104583
  };
104539
104584
  const appendStageEndForSnapshot = () => {
@@ -104544,6 +104589,7 @@ function createWorkflowBoundaryFactory(input) {
104544
104589
  stageId,
104545
104590
  status: stageSnapshot.status,
104546
104591
  durationMs: stageSnapshot.durationMs,
104592
+ endedAt: stageSnapshot.endedAt,
104547
104593
  ...stageSnapshot.error !== undefined ? { error: stageSnapshot.error } : {},
104548
104594
  ...stageSnapshot.failureKind !== undefined ? { failureKind: stageSnapshot.failureKind } : {},
104549
104595
  ...stageSnapshot.failureCode !== undefined ? { failureCode: stageSnapshot.failureCode } : {},
@@ -104580,8 +104626,10 @@ function createWorkflowBoundaryFactory(input) {
104580
104626
  clearBoundaryChildMetadata();
104581
104627
  applyFailureToStage(stageSnapshot, input.classifyExecutorFailure(failureError));
104582
104628
  }
104583
- stageSnapshot.endedAt = Date.now();
104584
- stageSnapshot.durationMs = elapsedStageMs(stageSnapshot, stageSnapshot.endedAt);
104629
+ if (replayedChild === undefined) {
104630
+ stageSnapshot.endedAt = Date.now();
104631
+ stageSnapshot.durationMs = elapsedStageMs(stageSnapshot, stageSnapshot.endedAt);
104632
+ }
104585
104633
  input.activeStore.recordStageEnd(input.runId, stageSnapshot);
104586
104634
  input.opts.onStageEnd?.(input.runId, stageSnapshot);
104587
104635
  appendStageEndForSnapshot();
@@ -104649,6 +104697,34 @@ function createWorkflowBoundaryFactory(input) {
104649
104697
  // dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts
104650
104698
  import { runCallback as runCallback3, runSynchronousCallback } from "@bastani/atomic";
104651
104699
 
104700
+ // dist/builtin/workflows/src/shared/pending-stage-route-readiness.ts
104701
+ var owners = new WeakMap;
104702
+ function registerWorkflowPendingStageRouteReadiness(store, ready) {
104703
+ owners.get(store)?.retire();
104704
+ const controller = new AbortController;
104705
+ const owner = {
104706
+ ready(runId) {
104707
+ const completion = ready(runId);
104708
+ return completion === undefined ? undefined : {
104709
+ completion: raceAbort2(completion, controller.signal),
104710
+ assertCurrent: () => controller.signal.throwIfAborted()
104711
+ };
104712
+ },
104713
+ retire() {
104714
+ controller.abort(new Error("atomic-workflows: Intercom route authority owner retired before stage startup"));
104715
+ }
104716
+ };
104717
+ owners.set(store, owner);
104718
+ return () => {
104719
+ owner.retire();
104720
+ if (owners.get(store) === owner)
104721
+ owners.delete(store);
104722
+ };
104723
+ }
104724
+ function workflowPendingStageRouteReady(store, runId) {
104725
+ return owners.get(store)?.ready(runId);
104726
+ }
104727
+
104652
104728
  // dist/builtin/workflows/src/runs/foreground/executor-queued-user-message.ts
104653
104729
  function removedMessages(before, after) {
104654
104730
  const remaining = [...after];
@@ -105503,7 +105579,7 @@ function createReplayStageContext(input) {
105503
105579
  name,
105504
105580
  parentIds: stageSnapshot.parentIds,
105505
105581
  ...stageReplayFields(stageSnapshot),
105506
- ts: stageSnapshot.startedAt ?? Date.now()
105582
+ ts: stageSnapshot.startedAt
105507
105583
  });
105508
105584
  };
105509
105585
  const appendReplayStageEnd = () => {
@@ -105513,7 +105589,8 @@ function createReplayStageContext(input) {
105513
105589
  runId,
105514
105590
  stageId,
105515
105591
  status: stageSnapshot.status,
105516
- durationMs: stageSnapshot.durationMs ?? 0,
105592
+ durationMs: stageSnapshot.durationMs,
105593
+ endedAt: stageSnapshot.endedAt,
105517
105594
  ...stageSnapshot.status === "completed" && stageSnapshot.result !== undefined ? { summary: stageSnapshot.result } : {},
105518
105595
  ...stageSnapshot.skippedReason !== undefined ? { skippedReason: stageSnapshot.skippedReason } : {},
105519
105596
  ...stageSnapshot.sessionId !== undefined ? { sessionId: stageSnapshot.sessionId } : {},
@@ -105531,8 +105608,6 @@ function createReplayStageContext(input) {
105531
105608
  delete stageSnapshot.result;
105532
105609
  stageSnapshot.skippedReason = input.workflowExitSkippedReason(reason);
105533
105610
  }
105534
- stageSnapshot.endedAt = Date.now();
105535
- stageSnapshot.durationMs = elapsedStageMs(stageSnapshot, stageSnapshot.endedAt);
105536
105611
  input.activeStore.recordStageEnd(runId, stageSnapshot);
105537
105612
  input.opts.onStageEnd?.(runId, stageSnapshot);
105538
105613
  appendReplayStageEnd();
@@ -107147,6 +107222,27 @@ function terminatingToolCallId(event) {
107147
107222
  return typeof callId === "string" && callId.length > 0 ? callId : undefined;
107148
107223
  }
107149
107224
 
107225
+ // dist/builtin/workflows/src/runs/foreground/stage-startup-wait.ts
107226
+ function waitForStageStartup(operation, signal) {
107227
+ return new Promise((resolve, reject) => {
107228
+ const onAbort = () => {
107229
+ signal.removeEventListener("abort", onAbort);
107230
+ reject(signal.reason ?? new DOMException("Stage startup cancelled", "AbortError"));
107231
+ };
107232
+ operation.then((value2) => {
107233
+ signal.removeEventListener("abort", onAbort);
107234
+ resolve(value2);
107235
+ }, (error) => {
107236
+ signal.removeEventListener("abort", onAbort);
107237
+ reject(error);
107238
+ });
107239
+ if (signal.aborted)
107240
+ onAbort();
107241
+ else
107242
+ signal.addEventListener("abort", onAbort, { once: true });
107243
+ });
107244
+ }
107245
+
107150
107246
  // dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts
107151
107247
  function hasMeaningfulUsage(usage) {
107152
107248
  if (usage === undefined)
@@ -107227,6 +107323,9 @@ class StageSessionController {
107227
107323
  activeCreation;
107228
107324
  ownedCreationPromise;
107229
107325
  abortGeneration = 0;
107326
+ routeAuthorityWait;
107327
+ startupWait = new AbortController;
107328
+ startup;
107230
107329
  abortReason;
107231
107330
  abortReasonGeneration = 0;
107232
107331
  sessionPromise;
@@ -107386,25 +107485,28 @@ class StageSessionController {
107386
107485
  }
107387
107486
  if (this.disposed)
107388
107487
  throw new Error(`atomic-workflows: stage "${this.opts.stageName}" session has been disposed`);
107389
- if (this.session !== undefined)
107488
+ this.opts.signal?.throwIfAborted();
107489
+ if (this.session !== undefined && this.activeCreation === undefined)
107390
107490
  return this.session;
107391
107491
  if (!this.sessionPromise) {
107492
+ this.beginStartup();
107392
107493
  const pending = this.createInitialSession(consumer);
107393
107494
  this.sessionPromise = pending;
107394
107495
  this.ownedCreationPromise = pending;
107395
- const release = () => {
107496
+ const release = (failed = false) => {
107396
107497
  if (this.ownedCreationPromise === pending)
107397
107498
  this.ownedCreationPromise = undefined;
107499
+ this.settleStartup(failed);
107398
107500
  };
107399
- pending.then(release, () => {
107400
- release();
107501
+ pending.then(() => release(), () => {
107502
+ release(true);
107401
107503
  if (this.sessionPromise === pending) {
107402
107504
  this.sessionPromise = undefined;
107403
107505
  this.activeCandidateIndex = undefined;
107404
107506
  }
107405
107507
  });
107406
107508
  }
107407
- return this.sessionPromise;
107509
+ return waitForStageStartup(this.sessionPromise, this.startupWait.signal);
107408
107510
  }
107409
107511
  async ensureSessionFromFile(sessionFile, consumer = "prompt") {
107410
107512
  if (!this.sessionShutdownPromise && !this.sessionPromise && !this.session)
@@ -107452,6 +107554,10 @@ class StageSessionController {
107452
107554
  this.artifactCapture.close();
107453
107555
  }
107454
107556
  async promptWithFallback(text, sdkOptions, consumer = "prompt") {
107557
+ if (this.session !== undefined && this.activeCreation === undefined && this.ownedCreationPromise === undefined && this.startupWait.signal.aborted) {
107558
+ this.opts.signal?.throwIfAborted();
107559
+ this.startupWait = new AbortController;
107560
+ }
107455
107561
  if (!this.hasExplicitModelFallbackConfig) {
107456
107562
  try {
107457
107563
  const activeSession = await this.ensureSession(consumer);
@@ -107474,7 +107580,13 @@ class StageSessionController {
107474
107580
  }
107475
107581
  return;
107476
107582
  }
107477
- const candidates = await this.modelCandidates();
107583
+ const readinessOwner = this.ownedCreationPromise ?? this.activeCreation;
107584
+ if (readinessOwner !== undefined)
107585
+ await waitForStageStartup(readinessOwner, this.startupWait.signal);
107586
+ if (this.session === undefined)
107587
+ this.beginStartup();
107588
+ const startupSignal = this.startupWait.signal;
107589
+ const candidates = await waitForStageStartup(this.modelCandidates(), startupSignal);
107478
107590
  if (candidates.length === 0) {
107479
107591
  try {
107480
107592
  const activeSession = await this.ensureSession(consumer);
@@ -107490,14 +107602,9 @@ class StageSessionController {
107490
107602
  }
107491
107603
  return;
107492
107604
  }
107493
- if (this.session === undefined && this.sessionPromise !== undefined) {
107494
- try {
107495
- await this.sessionPromise;
107496
- } catch (error) {
107497
- if (error instanceof StageSessionCreationCancelled)
107498
- return;
107499
- }
107500
- }
107605
+ const creationOwner = this.ownedCreationPromise ?? this.activeCreation;
107606
+ if (creationOwner !== undefined)
107607
+ await waitForStageStartup(creationOwner, startupSignal);
107501
107608
  const resumedText = this.pendingCreationResumeMessage;
107502
107609
  this.pendingCreationResumeMessage = undefined;
107503
107610
  let promptText = resumedText ?? text;
@@ -107505,9 +107612,9 @@ class StageSessionController {
107505
107612
  return;
107506
107613
  let index = this.activeCandidateIndex ?? 0;
107507
107614
  while (index < candidates.length) {
107508
- if (this.session === undefined && this.ownedCreationPromise !== undefined) {
107615
+ if (this.ownedCreationPromise !== undefined || this.activeCreation !== undefined) {
107509
107616
  try {
107510
- await this.ownedCreationPromise;
107617
+ await waitForStageStartup(this.ownedCreationPromise ?? this.activeCreation, startupSignal);
107511
107618
  } catch (error) {
107512
107619
  if (error instanceof StageSessionCreationCancelled)
107513
107620
  return;
@@ -107519,7 +107626,7 @@ class StageSessionController {
107519
107626
  }
107520
107627
  const candidate = candidates[index];
107521
107628
  try {
107522
- const created = this.session && this.activeCandidateIndex === index ? this.session : await this.createSessionWithThrownErrorRetry(candidate, consumer);
107629
+ const created = this.session && this.activeCandidateIndex === index ? this.session : await waitForStageStartup(this.createSessionWithThrownErrorRetry(candidate, consumer), startupSignal);
107523
107630
  if (isSessionCreationPauseResult(created)) {
107524
107631
  if (created.resumeMessage === undefined)
107525
107632
  return;
@@ -107546,8 +107653,10 @@ class StageSessionController {
107546
107653
  const failure = await this.handleCandidateFailure(err, candidate, candidates, index);
107547
107654
  if (failure === "handled")
107548
107655
  return;
107549
- if (failure === "throw")
107656
+ if (failure === "throw") {
107657
+ this.settleStartup(true);
107550
107658
  throw err;
107659
+ }
107551
107660
  index += 1;
107552
107661
  }
107553
107662
  }
@@ -107590,7 +107699,8 @@ class StageSessionController {
107590
107699
  this.messageAdmission.dispose();
107591
107700
  this.deliveryActivity.dispose();
107592
107701
  await this.replacement.dispose();
107593
- await disposeStageSession(this.session);
107702
+ if (this.activeCreation === undefined)
107703
+ await disposeStageSession(this.session);
107594
107704
  }
107595
107705
  async drainPendingDisposal() {
107596
107706
  if (!this.pendingDisposal)
@@ -107664,6 +107774,12 @@ class StageSessionController {
107664
107774
  this.abortGeneration += 1;
107665
107775
  this.abortReason = reason;
107666
107776
  this.abortReasonGeneration = this.abortGeneration;
107777
+ this.routeAuthorityWait?.abort(reason);
107778
+ this.startupWait.abort(reason);
107779
+ if (this.startup?.state === "active") {
107780
+ this.startup = { ...this.startup, state: "cancelled" };
107781
+ this.opts.onStartupChange?.(this.startup);
107782
+ }
107667
107783
  this.abortThrownErrorRetries(reason);
107668
107784
  }
107669
107785
  pauseThrownErrorRetries(resume) {
@@ -107904,10 +108020,13 @@ class StageSessionController {
107904
108020
  return this.candidatesPromise;
107905
108021
  }
107906
108022
  async createInitialSession(consumer) {
108023
+ const generation = this.abortGeneration;
107907
108024
  if (!this.hasExplicitModelFallbackConfig) {
107908
108025
  return this.createSessionObservingPause(undefined, consumer).catch((error) => this.createInitialSessionWithRetry(undefined, consumer, { error }));
107909
108026
  }
107910
108027
  const candidates = await this.modelCandidates();
108028
+ if (this.abortGeneration !== generation || this.opts.signal?.aborted || this.disposed)
108029
+ throw this.staleCreationReason(generation);
107911
108030
  const initialIndex = this.activeCandidateIndex ?? 0;
107912
108031
  const first = candidates[initialIndex];
107913
108032
  if (first === undefined) {
@@ -108012,7 +108131,7 @@ class StageSessionController {
108012
108131
  if (errorSettingsManager !== undefined)
108013
108132
  this.sessionSettingsManager = errorSettingsManager;
108014
108133
  const decision = isWorkflowPendingStageDeliveryFailure(error) ? undefined : nextRetryDecision(this.retrySettings(), retryAttempt, isRetryableSameModelFailure(error));
108015
- if (decision === undefined || this.disposed || this.opts.signal?.aborted === true || this.capturedStructuredOutputForAttempt()) {
108134
+ if (decision === undefined || this.disposed || this.opts.signal?.aborted === true || this.startupWait.signal.aborted || this.capturedStructuredOutputForAttempt()) {
108016
108135
  throw error;
108017
108136
  }
108018
108137
  retryAttempt = decision.attempt;
@@ -108055,16 +108174,72 @@ class StageSessionController {
108055
108174
  return this.activeCreation;
108056
108175
  if (this.session !== undefined)
108057
108176
  return Promise.resolve(this.session);
108177
+ this.startupWait.signal.throwIfAborted();
108058
108178
  const creation = this.createSessionAttempt(candidate, consumer, resumeOptions);
108059
108179
  this.activeCreation = creation;
108060
108180
  creation.finally(() => {
108061
108181
  if (this.activeCreation === creation)
108062
108182
  this.activeCreation = undefined;
108183
+ this.settleStartup();
108063
108184
  }).catch(() => {});
108064
108185
  return creation;
108065
108186
  }
108187
+ settleStartup(failed = false) {
108188
+ if (this.activeCreation !== undefined || this.ownedCreationPromise !== undefined || this.startup === undefined)
108189
+ return;
108190
+ if (this.startup.state === "dispatched" || this.startup.phase === "ready")
108191
+ return;
108192
+ if (this.startup.state === "active" && !failed && this.bindingCleanupFailure === undefined)
108193
+ return;
108194
+ this.startup = {
108195
+ ...this.startup,
108196
+ state: this.startup.state === "active" ? "failed" : this.startup.state,
108197
+ ownershipPending: this.bindingCleanupFailure !== undefined,
108198
+ ...this.bindingCleanupFailure === undefined ? { settledAt: Date.now() } : {}
108199
+ };
108200
+ this.opts.onStartupChange?.(this.startup);
108201
+ }
108202
+ beginStartup() {
108203
+ if (this.activeCreation !== undefined || this.ownedCreationPromise !== undefined || this.sessionPromise !== undefined)
108204
+ return;
108205
+ this.opts.signal?.throwIfAborted();
108206
+ if (this.startupWait.signal.aborted)
108207
+ this.startupWait = new AbortController;
108208
+ this.reportStartupPhase("model-resolution", true);
108209
+ }
108210
+ reportStartupPhase(phase, reset = false) {
108211
+ if (!reset && this.startup !== undefined && this.startup.state !== "active")
108212
+ return;
108213
+ const now = Date.now();
108214
+ this.startup = {
108215
+ phase,
108216
+ startedAt: reset ? now : this.startup?.startedAt ?? now,
108217
+ phaseStartedAt: now,
108218
+ state: phase === "first-dispatch" ? "dispatched" : "active",
108219
+ ownershipPending: phase !== "first-dispatch" && phase !== "ready"
108220
+ };
108221
+ this.opts.onStartupChange?.(this.startup);
108222
+ }
108066
108223
  async createSessionAttempt(candidate, consumer, resumeOptions) {
108067
108224
  const startGeneration = this.abortGeneration;
108225
+ if (this.disposed || this.opts.signal?.aborted)
108226
+ throw this.staleCreationReason(startGeneration);
108227
+ this.reportStartupPhase("route-authority");
108228
+ const authority = this.opts.routeAuthorityReady?.();
108229
+ if (authority !== undefined) {
108230
+ const wait = new AbortController;
108231
+ this.routeAuthorityWait = wait;
108232
+ try {
108233
+ await raceAbort2(authority.completion, wait.signal);
108234
+ authority.assertCurrent();
108235
+ if (this.disposed || this.opts.signal?.aborted || this.abortGeneration !== startGeneration)
108236
+ throw this.staleCreationReason(startGeneration);
108237
+ } finally {
108238
+ if (this.routeAuthorityWait === wait)
108239
+ this.routeAuthorityWait = undefined;
108240
+ }
108241
+ }
108242
+ this.reportStartupPhase("resource-preparation");
108068
108243
  this.applyCandidateThinking(candidate);
108069
108244
  const stageOptions = buildStageSessionOptions({
108070
108245
  effectiveStageOptions: this.effectiveStageOptions,
@@ -108077,6 +108252,11 @@ class StageSessionController {
108077
108252
  try {
108078
108253
  created = this.opts.adapters.agentSession ? await this.opts.adapters.agentSession.create(stripWorkflowOnlyOptions(stageOptions, this.opts.defaultSessionDir, this.meta, this.opts.pendingStageDelivery), {
108079
108254
  ...this.meta,
108255
+ startupSignal: this.startupWait.signal,
108256
+ onStartupPhase: (phase) => {
108257
+ if (this.abortGeneration === startGeneration)
108258
+ this.reportStartupPhase(phase);
108259
+ },
108080
108260
  stageOptions,
108081
108261
  ...this.sharedOrchestrationContext !== undefined ? { orchestrationContext: this.sharedOrchestrationContext } : {}
108082
108262
  }) : missingAdapter(consumer);
@@ -108095,20 +108275,28 @@ class StageSessionController {
108095
108275
  throw new Error(`atomic-workflows: stage "${this.opts.stageName}" session has been disposed`);
108096
108276
  throw this.staleCreationReason(startGeneration);
108097
108277
  }
108278
+ this.reportStartupPhase("session-attachment");
108098
108279
  const session = attachCreatedStageSession(created, this.disposed, this.opts.stageName, (result) => this.attachSession(result));
108099
108280
  const attachedSession = session instanceof Promise ? await session : session;
108100
- const pendingStageDeliveryReady = this.sharedOrchestrationContext?.pendingStageDelivery?.ready();
108101
- if (pendingStageDeliveryReady !== undefined) {
108281
+ this.reportStartupPhase("delivery-readiness");
108282
+ try {
108283
+ await this.sharedOrchestrationContext?.pendingStageDelivery?.ready();
108284
+ await this.opts.onSessionReady?.();
108285
+ if (this.disposed || this.opts.signal?.aborted || this.abortGeneration !== startGeneration)
108286
+ throw this.staleCreationReason(startGeneration);
108287
+ } catch (reason) {
108288
+ if (this.session === attachedSession)
108289
+ this.session = undefined;
108102
108290
  try {
108103
- await pendingStageDeliveryReady;
108291
+ await cleanupFailedStageSessionBinding(attachedSession, reason);
108104
108292
  } catch (error) {
108105
- if (this.session === attachedSession)
108106
- this.session = undefined;
108107
- await disposeStageSession(attachedSession).catch(() => {});
108293
+ if (error instanceof StageSessionBindingCleanupFailure)
108294
+ this.bindingCleanupFailure = error;
108108
108295
  throw error;
108109
108296
  }
108297
+ throw reason;
108110
108298
  }
108111
- await this.opts.onSessionReady?.();
108299
+ this.reportStartupPhase("ready");
108112
108300
  return attachedSession;
108113
108301
  }
108114
108302
  attachSession(created) {
@@ -108194,6 +108382,7 @@ class StageSessionController {
108194
108382
  this.lastPromptStartIndex = promptStartIndex;
108195
108383
  this.unresolvedContextOverflowMessage = undefined;
108196
108384
  try {
108385
+ this.reportStartupPhase("first-dispatch");
108197
108386
  await activeSession.prompt(nextText, sdkOptions);
108198
108387
  const pendingPauseAfterPrompt = this.pauseControl.currentResume();
108199
108388
  if (pendingPauseAfterPrompt) {
@@ -108308,7 +108497,7 @@ class StageSessionController {
108308
108497
  ...usage === undefined ? {} : { usage },
108309
108498
  error: message
108310
108499
  });
108311
- if (this.opts.signal?.aborted || terminalStageDelivery || !isRetryableModelFailure(err) || index === candidates.length - 1) {
108500
+ if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !isRetryableModelFailure(err) || index === candidates.length - 1) {
108312
108501
  this.modelWarnings.push(...this.pendingFallbackWarnings);
108313
108502
  this.pendingFallbackWarnings.length = 0;
108314
108503
  this.notifyModelFallbackMetaChange();
@@ -108957,9 +109146,7 @@ function createWorkflowStageFactory(input) {
108957
109146
  toolEvents: [],
108958
109147
  pendingStageDeliveryAvailable,
108959
109148
  ...shouldReplay ? {
108960
- startedAt: Date.now(),
108961
- endedAt: Date.now(),
108962
- durationMs: 0,
109149
+ ...stageTimingFields(replaySource),
108963
109150
  ...replaySource.result !== undefined ? { result: replaySource.result } : {},
108964
109151
  ...replaySource.sessionId !== undefined ? { sessionId: replaySource.sessionId } : {},
108965
109152
  ...replaySource.sessionFile !== undefined ? { sessionFile: replaySource.sessionFile } : {},
@@ -109022,11 +109209,19 @@ function createWorkflowStageFactory(input) {
109022
109209
  signal: input.signal,
109023
109210
  stageOptions: stageOptionsForContext,
109024
109211
  ...pendingStageDeliveryAvailable ? {
109212
+ routeAuthorityReady: () => workflowPendingStageRouteReady(input.activeStore, input.runId),
109025
109213
  pendingStageDelivery: createWorkflowPendingStageDelivery(input.activeStore, input.runId, stageId, name)
109026
109214
  } : {},
109027
109215
  models: input.opts.models,
109028
109216
  executionMode: input.opts.executionMode,
109029
109217
  defaultSessionDir: input.opts.defaultSessionDir,
109218
+ onStartupChange(startup) {
109219
+ const current = input.activeStore.runs().find((run) => run.id === input.runId);
109220
+ if (!current?.stages.includes(stageSnapshot))
109221
+ return;
109222
+ stageSnapshot.startup = startup;
109223
+ input.activeStore.recordStageStart(input.runId, stageSnapshot);
109224
+ },
109030
109225
  onModelFallbackMetaChange(meta) {
109031
109226
  applyModelFallbackMeta(meta);
109032
109227
  if (stageSnapshot.status === "running")
@@ -109189,6 +109384,7 @@ function createWorkflowStageFactory(input) {
109189
109384
  stageId,
109190
109385
  status: stageSnapshot.status,
109191
109386
  durationMs: stageSnapshot.durationMs,
109387
+ endedAt: stageSnapshot.endedAt,
109192
109388
  ...stageSnapshot.error !== undefined ? { error: stageSnapshot.error } : {},
109193
109389
  ...stageSnapshot.failureKind !== undefined ? { failureKind: stageSnapshot.failureKind } : {},
109194
109390
  ...stageSnapshot.failureCode !== undefined ? { failureCode: stageSnapshot.failureCode } : {},
@@ -109794,6 +109990,7 @@ async function run(def, inputs, opts = {}) {
109794
109990
  };
109795
109991
  };
109796
109992
  const resolvePromptNodeTopology = createDurableStageTopologyResolver(durableBackend, runId);
109993
+ const priorPromptStageCheckpoints = durableBackend.listCheckpoints(runId).filter((checkpoint) => checkpoint.kind === "stage");
109797
109994
  let promptNodeUi;
109798
109995
  const getPromptNodeUi = () => {
109799
109996
  promptNodeUi ??= buildPromptNodeUiAdapter({
@@ -109810,6 +110007,7 @@ async function run(def, inputs, opts = {}) {
109810
110007
  workflowExitSkippedReason: exit.workflowExitSkippedReason,
109811
110008
  preserveWorkflowExitSkippedReason: exit.preserveWorkflowExitSkippedReason,
109812
110009
  durableTopologyForReplayKey: resolvePromptNodeTopology,
110010
+ durableTimingForStageId: (stageId) => priorPromptStageCheckpoints.find((checkpoint) => checkpoint.topology?.stageId === stageId && checkpoint.topology.status === "completed" && (checkpoint.topology.run === undefined || checkpoint.topology.run.runId === runId)),
109813
110011
  onPendingStage: async (pendingRunId, snapshot) => pendingRunId === runId ? void await recordDurableActiveStage(durableStageDeps, snapshot) : undefined
109814
110012
  });
109815
110013
  return promptNodeUi;
@@ -113063,6 +113261,8 @@ function registerPendingStageIntercomBridge(pi, activeStore) {
113063
113261
  return payload.handled && await payload.completion === true;
113064
113262
  };
113065
113263
  const announcedRoutes = new Map;
113264
+ const routeCompletions = new Map;
113265
+ const disposeReadiness = registerWorkflowPendingStageRouteReadiness(activeStore, (runId) => routeCompletions.get(runId));
113066
113266
  const announceRoutes = () => {
113067
113267
  if (disposed)
113068
113268
  return;
@@ -113116,12 +113316,17 @@ function registerPendingStageIntercomBridge(pi, activeStore) {
113116
113316
  } catch (error) {
113117
113317
  if (announcedRoutes.get(run.id) === entry)
113118
113318
  announcedRoutes.delete(run.id);
113319
+ const failure = Promise.reject(error);
113320
+ failure.catch(() => {});
113321
+ routeCompletions.set(run.id, failure);
113119
113322
  throw error;
113120
113323
  }
113121
113324
  const completion = announcement.completion;
113122
113325
  if (completion === undefined) {
113123
113326
  announcedRoutes.delete(run.id);
113327
+ routeCompletions.delete(run.id);
113124
113328
  } else {
113329
+ routeCompletions.set(run.id, completion);
113125
113330
  completion.catch(() => {
113126
113331
  if (announcedRoutes.get(run.id) === entry)
113127
113332
  announcedRoutes.delete(run.id);
@@ -113132,6 +113337,10 @@ function registerPendingStageIntercomBridge(pi, activeStore) {
113132
113337
  if (!ownedRunIds.has(runId))
113133
113338
  announcedRoutes.delete(runId);
113134
113339
  }
113340
+ for (const runId of routeCompletions.keys()) {
113341
+ if (!ownedRunIds.has(runId))
113342
+ routeCompletions.delete(runId);
113343
+ }
113135
113344
  sweepPromise = sweepPromise.then(() => settleUndeliverablePendingStageMessages(activeStore, notifyUndeliverable)).then(() => {
113136
113345
  return;
113137
113346
  }).catch((error) => reportWarning(`atomic-workflows: pending stage delivery sweep failed: ${error.message}`));
@@ -113210,6 +113419,8 @@ function registerPendingStageIntercomBridge(pi, activeStore) {
113210
113419
  });
113211
113420
  const dispose = () => {
113212
113421
  disposed = true;
113422
+ disposeReadiness();
113423
+ routeCompletions.clear();
113213
113424
  unsubscribeStore();
113214
113425
  if (typeof subscription === "function")
113215
113426
  subscription();
@@ -113696,6 +113907,8 @@ function resolveSessionCwd(options) {
113696
113907
  return options?.cwd ?? options?.sessionManager?.getCwd() ?? process.cwd();
113697
113908
  }
113698
113909
  async function prepareAtomicStageSessionOptions(options, sdk, prepareOptions = {}) {
113910
+ prepareOptions.signal?.throwIfAborted();
113911
+ prepareOptions.onStartupPhase?.("resource-preparation");
113699
113912
  const atomicOptions = options;
113700
113913
  if (atomicOptions?.resourceLoader !== undefined)
113701
113914
  return atomicOptions;
@@ -113714,7 +113927,8 @@ async function prepareAtomicStageSessionOptions(options, sdk, prepareOptions = {
113714
113927
  resourceLoaderInheritanceSnapshot: inheritanceSnapshot,
113715
113928
  builtinPackagePaths: stageBuiltinPackagePaths(builtinPackagePaths)
113716
113929
  });
113717
- await reloadWorkflowStageResources(resourceLoader);
113930
+ await reloadWorkflowStageResources(resourceLoader, prepareOptions);
113931
+ prepareOptions.signal?.throwIfAborted();
113718
113932
  return {
113719
113933
  ...atomicOptions,
113720
113934
  cwd,
@@ -113751,8 +113965,13 @@ function stageBuiltinPackagePaths(paths) {
113751
113965
  });
113752
113966
  }
113753
113967
  var workflowStageResourceReloadQueue = Promise.resolve();
113754
- async function reloadWorkflowStageResources(resourceLoader) {
113755
- const queuedReload = workflowStageResourceReloadQueue.then(() => resourceLoader.reload());
113968
+ async function reloadWorkflowStageResources(resourceLoader, options) {
113969
+ options.onStartupPhase?.("reload-queued");
113970
+ const queuedReload = workflowStageResourceReloadQueue.then(() => {
113971
+ options.signal?.throwIfAborted();
113972
+ options.onStartupPhase?.("reload-active");
113973
+ return resourceLoader.reload();
113974
+ });
113756
113975
  workflowStageResourceReloadQueue = queuedReload.catch(() => {
113757
113976
  return;
113758
113977
  });
@@ -113787,8 +114006,8 @@ function attachSettingsManager(error, settingsManager) {
113787
114006
  });
113788
114007
  return wrapped;
113789
114008
  }
113790
- async function createPiSdkAgentSession(options, prepareOptions) {
113791
- const sdk = await import("@bastani/atomic");
114009
+ async function createPiSdkAgentSession(options, prepareOptions, injectedSdk) {
114010
+ const sdk = injectedSdk ?? await import("@bastani/atomic");
113792
114011
  let settingsManager;
113793
114012
  try {
113794
114013
  const sessionOptions = await prepareAtomicStageSessionOptions(options, sdk, {
@@ -113799,6 +114018,8 @@ async function createPiSdkAgentSession(options, prepareOptions) {
113799
114018
  }
113800
114019
  });
113801
114020
  settingsManager = sessionOptions?.settingsManager ?? settingsManager;
114021
+ prepareOptions?.signal?.throwIfAborted();
114022
+ prepareOptions?.onStartupPhase?.("sdk-creation");
113802
114023
  const result = await sdk.createAgentSession(sessionOptions);
113803
114024
  const resultSettingsManager = result.session.settingsManager;
113804
114025
  settingsManager = sessionOptions?.settingsManager ?? resultSettingsManager ?? settingsManager;
@@ -114058,20 +114279,25 @@ function makeStageExtensionUiContext(ui, meta, broker) {
114058
114279
  };
114059
114280
  }
114060
114281
  function buildRuntimeAdapters(pi, options = {}) {
114061
- const createSession = options.createAgentSession ?? pi.createAgentSession ?? (isTestContext() ? createTestAgentSession : (sessionOptions) => createPiSdkAgentSession(sessionOptions, {
114062
- resourceLoaderInheritanceSnapshot: pi.getResourceLoaderInheritanceSnapshot?.()
114063
- }));
114282
+ const createSession = options.createAgentSession ?? pi.createAgentSession ?? (isTestContext() && options.sdk === undefined ? createTestAgentSession : (sessionOptions, prepareOptions) => createPiSdkAgentSession(sessionOptions, {
114283
+ resourceLoaderInheritanceSnapshot: pi.getResourceLoaderInheritanceSnapshot?.(),
114284
+ ...prepareOptions
114285
+ }, options.sdk));
114064
114286
  const broker = options.stageUiBroker ?? stageUiBroker;
114065
114287
  const adapters = {
114066
114288
  agentSession: {
114067
114289
  async create(stageOptions, meta) {
114068
114290
  const sessionOptions = withWorkflowStageSessionOptions(stripWorkflowOnlyOptions2(stageOptions) ?? {}, meta, pi);
114069
- const result = await createSession(sessionOptions);
114291
+ const signal = meta?.startupSignal ?? meta?.signal;
114292
+ const result = await createSession(sessionOptions, { signal, onStartupPhase: meta?.onStartupPhase });
114070
114293
  const bindable = result.session;
114071
114294
  try {
114295
+ signal?.throwIfAborted();
114296
+ meta?.onStartupPhase?.("extension-binding");
114072
114297
  if (typeof bindable.bindExtensions === "function") {
114073
114298
  await bindable.bindExtensions(shouldBindStageUiContext(pi, meta) ? { uiContext: makeStageExtensionUiContext(pi.ui ?? {}, meta, broker) } : {});
114074
114299
  }
114300
+ signal?.throwIfAborted();
114075
114301
  } catch (error) {
114076
114302
  await cleanupFailedStageSessionBinding(result.session, error);
114077
114303
  throw error;
@@ -115639,7 +115865,21 @@ Picker requires an interactive UI surface. Pass a runId: /workflow attach <id> [
115639
115865
  return true;
115640
115866
  runId = picked.runId;
115641
115867
  } else if (action === "resume") {
115642
- const backend = getDurableBackend();
115868
+ let backend;
115869
+ try {
115870
+ try {
115871
+ backend = getDurableBackend();
115872
+ } catch (error) {
115873
+ if (!(error instanceof DbosNotReadyError))
115874
+ throw error;
115875
+ await ensureWorkflowResourcesVisible();
115876
+ await deps.runtimeForContext(ctx).prepareDurableResumable(target);
115877
+ backend = getDurableBackend();
115878
+ }
115879
+ } catch (error) {
115880
+ fail(`Failed to resolve workflow resume target: ${error instanceof Error ? error.message : String(error)}`);
115881
+ return true;
115882
+ }
115643
115883
  const localResolution = resolveRunId(target);
115644
115884
  const localBeforePreparation = localResolution.kind === "exact" ? store.runs().find((run) => run.id === localResolution.runId) : undefined;
115645
115885
  const exactBeforePreparation = localBeforePreparation?.id === target ? localBeforePreparation : undefined;
@@ -116493,6 +116733,8 @@ function renderStagesToolContent(result) {
116493
116733
  lines.push("stages:");
116494
116734
  result.stages.forEach((stage, index) => {
116495
116735
  lines.push(`[${index + 1}] ${stage.name} (${stage.id}) ${stage.status}`);
116736
+ if (stage.startup)
116737
+ lines.push(formatStageStartup(stage.startup));
116496
116738
  if (stage.sessionId)
116497
116739
  lines.push(`sessionId: ${stage.sessionId}`);
116498
116740
  if (stage.sessionFile)
@@ -116533,6 +116775,8 @@ function renderStageToolContent(result) {
116533
116775
  `);
116534
116776
  }
116535
116777
  lines.push("stage:");
116778
+ if (result.stage.startup)
116779
+ lines.push(formatStageStartup(result.stage.startup));
116536
116780
  lines.push(JSON.stringify(result.stage, null, 2));
116537
116781
  if (result.stage.sessionFile) {
116538
116782
  lines.push(`transcriptPath: ${result.stage.sessionFile}`);
@@ -117011,6 +117255,7 @@ function summarizeStage(stage) {
117011
117255
  id: stage.id,
117012
117256
  name: stage.name,
117013
117257
  status: stage.status,
117258
+ ...stage.startup === undefined ? {} : { startup: { ...stage.startup } },
117014
117259
  sessionId: stage.sessionId,
117015
117260
  sessionFile: stage.sessionFile,
117016
117261
  transcriptPath: stage.sessionFile,