@bastani/atomic 0.9.41-alpha.1 → 0.9.41-alpha.2

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/builtin/intercom/package.json +2 -2
  3. package/dist/builtin/mcp/package.json +1 -1
  4. package/dist/builtin/subagents/package.json +3 -3
  5. package/dist/builtin/web-access/package.json +2 -2
  6. package/dist/builtin/workflows/CHANGELOG.md +8 -0
  7. package/dist/builtin/workflows/builtin/adversarial-verification.js +2 -2
  8. package/dist/builtin/workflows/builtin/{chunk-qjqn389g.js → chunk-2jfst7e4.js} +72 -10
  9. package/dist/builtin/workflows/builtin/{chunk-4bwtzyjq.js → chunk-49kkbdpr.js} +1 -1
  10. package/dist/builtin/workflows/builtin/{chunk-qdd897wm.js → chunk-apagcs4r.js} +1 -1
  11. package/dist/builtin/workflows/builtin/{chunk-454hz1qt.js → chunk-dcxscfnb.js} +1 -1
  12. package/dist/builtin/workflows/builtin/{chunk-bjva9j5k.js → chunk-hx8v4p97.js} +1 -1
  13. package/dist/builtin/workflows/builtin/{chunk-85mx6wcf.js → chunk-k5q3t7je.js} +1 -1
  14. package/dist/builtin/workflows/builtin/{chunk-8kkv04hz.js → chunk-n2gkzkty.js} +1 -1
  15. package/dist/builtin/workflows/builtin/{chunk-y45tkftg.js → chunk-txbc93t6.js} +1 -1
  16. package/dist/builtin/workflows/builtin/{chunk-x0vvjyzg.js → chunk-w4xp1w1f.js} +1 -1
  17. package/dist/builtin/workflows/builtin/{chunk-5eh0brtd.js → chunk-z3pajrfs.js} +1 -1
  18. package/dist/builtin/workflows/builtin/classify-and-act.js +2 -2
  19. package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +2 -2
  20. package/dist/builtin/workflows/builtin/generate-and-filter.js +2 -2
  21. package/dist/builtin/workflows/builtin/goal.js +2 -2
  22. package/dist/builtin/workflows/builtin/index.js +10 -10
  23. package/dist/builtin/workflows/builtin/loop-until-done.js +2 -2
  24. package/dist/builtin/workflows/builtin/open-claude-design.js +2 -2
  25. package/dist/builtin/workflows/builtin/ralph.js +2 -2
  26. package/dist/builtin/workflows/builtin/tournament.js +2 -2
  27. package/dist/builtin/workflows/package.json +2 -2
  28. package/dist/builtin/workflows/src/extension/index.bundle.mjs +511 -28
  29. package/dist/builtin/workflows/src/index.js +582 -99
  30. package/dist/core/model-config.d.ts +28 -0
  31. package/dist/core/model-config.d.ts.map +1 -1
  32. package/dist/core/provider-composer-internal.d.ts +2 -1
  33. package/dist/core/provider-composer-internal.d.ts.map +1 -1
  34. package/dist/core/provider-composer-internal.js +8 -6
  35. package/dist/core/provider-composer-internal.js.map +1 -1
  36. package/dist/core/tools/grep.js +1 -1
  37. package/dist/core/tools/grep.js.map +1 -1
  38. package/docs/models-configuration.md +9 -0
  39. package/docs/models.md +3 -1
  40. package/docs/providers.md +1 -1
  41. package/docs/workflows/authoring.md +1 -1
  42. package/npm-shrinkwrap.json +67 -54
  43. package/package.json +6 -6
  44. package/schemas/models.schema.json +21 -0
@@ -52451,7 +52451,7 @@ function compareDraftSourceOrder(left, right) {
52451
52451
  function runTopologyFor(drafts, tools) {
52452
52452
  return drafts.find((draft) => draft.topology?.run !== undefined)?.topology?.run ?? tools.find((checkpoint) => checkpoint.topology?.run !== undefined)?.topology?.run;
52453
52453
  }
52454
- function validateRunGroups(grouped, rootRunId, tools, checkpoints) {
52454
+ function validateRunGroups(grouped, rootRunId, tools, checkpoints, allowPendingChildren = false) {
52455
52455
  const toolsFor = (runId) => tools.filter((checkpoint) => (checkpoint.topology?.run?.runId ?? rootRunId) === runId);
52456
52456
  const owners = new Map;
52457
52457
  const syntheticChildIds = new Set;
@@ -52463,6 +52463,11 @@ function validateRunGroups(grouped, rootRunId, tools, checkpoints) {
52463
52463
  if (childRunId === parentRunId || owners.has(childRunId))
52464
52464
  return false;
52465
52465
  if (!grouped.has(childRunId)) {
52466
+ if (allowPendingChildren && isPendingChildBoundary(draft, parentRunId, childRunId, rootRunId) && !childScopedEvidenceExists(checkpoints, draft.replayKey, childRunId)) {
52467
+ syntheticChildIds.add(childRunId);
52468
+ owners.set(childRunId, draft);
52469
+ continue;
52470
+ }
52466
52471
  if (!isSyntheticExitedChild(draft, parentRunId, childRunId, rootRunId) || childScopedEvidenceExists(checkpoints, draft.replayKey, childRunId))
52467
52472
  return false;
52468
52473
  syntheticChildIds.add(childRunId);
@@ -52495,6 +52500,10 @@ function validateRunGroups(grouped, rootRunId, tools, checkpoints) {
52495
52500
  }
52496
52501
  return true;
52497
52502
  }
52503
+ function isPendingChildBoundary(draft, parentRunId, childRunId, rootRunId) {
52504
+ const boundary = draft.topology?.boundary;
52505
+ return workflowChildFromDraft(draft) === undefined && boundary?.event === "start" && boundary.status === "running" && boundary.child.runId === childRunId && boundary.child.parentRunId === parentRunId && boundary.child.parentStageId === draft.topology?.stageId && boundary.child.rootRunId === rootRunId;
52506
+ }
52498
52507
  function isSyntheticExitedChild(draft, parentRunId, childRunId, rootRunId) {
52499
52508
  const child = workflowChildFromDraft(draft);
52500
52509
  const boundary = draft.topology?.boundary;
@@ -56014,6 +56023,20 @@ function resolve_budget(layers) {
56014
56023
  var DEFAULT_WORKFLOW_HEARTBEAT_INTERVAL_MINUTES = 15;
56015
56024
  var WORKFLOW_HEARTBEAT_CUSTOM_TYPE = "workflows:workflow-heartbeat";
56016
56025
 
56026
+ // dist/builtin/workflows/src/shared/workflow-source.ts
56027
+ var WORKFLOW_SOURCES = new WeakMap;
56028
+ var OWN_MODULE_PATH = normalizeStackPath(import.meta.url);
56029
+ function isWorkflowRuntimeModule(path) {
56030
+ const normalized = normalizeStackPath(path);
56031
+ return normalized === OWN_MODULE_PATH || isWorkflowRuntimeFrame(normalized);
56032
+ }
56033
+ function recordWorkflowSource(definition, path) {
56034
+ WORKFLOW_SOURCES.set(definition, path);
56035
+ }
56036
+ function workflowSource(definition) {
56037
+ return WORKFLOW_SOURCES.get(definition);
56038
+ }
56039
+
56017
56040
  // dist/builtin/workflows/src/workflows/identity.ts
56018
56041
  function normalizeWorkflowName(name) {
56019
56042
  if (!name || typeof name !== "string") {
@@ -56061,8 +56084,10 @@ function isWorkflowAuthoringImplementationFrame(filePath) {
56061
56084
  return false;
56062
56085
  return normalized.includes("/packages/workflows/") || normalized.includes("/dist/builtin/workflows/") || normalized.includes("/.atomic/agent/extensions/workflows/");
56063
56086
  }
56064
- function workflowNameFromCaller() {
56065
- const stack = new Error().stack;
56087
+ function callerSourcePath(entry) {
56088
+ const capture = new Error;
56089
+ Error.captureStackTrace(capture, entry);
56090
+ const stack = capture.stack;
56066
56091
  if (stack === undefined)
56067
56092
  return;
56068
56093
  for (const line of stack.split(`
@@ -56072,14 +56097,18 @@ function workflowNameFromCaller() {
56072
56097
  continue;
56073
56098
  if (isWorkflowAuthoringImplementationFrame(filePath))
56074
56099
  continue;
56075
- const base = basename(filePath.replace(/\\/g, "/")).replace(/\.[cm]?[jt]sx?$/, "");
56076
- if (base.length > 0)
56077
- return base;
56100
+ return isWorkflowRuntimeModule(filePath) ? undefined : filePath;
56078
56101
  }
56079
56102
  return;
56080
56103
  }
56081
- function resolveWorkflowName(name) {
56082
- const resolved = name ?? workflowNameFromCaller();
56104
+ function workflowNameFromSourcePath(filePath) {
56105
+ if (filePath === undefined)
56106
+ return;
56107
+ const base = basename(filePath.replace(/\\/g, "/")).replace(/\.[cm]?[jt]sx?$/, "");
56108
+ return base.length > 0 ? base : undefined;
56109
+ }
56110
+ function resolveWorkflowName(name, sourcePath) {
56111
+ const resolved = name ?? workflowNameFromSourcePath(sourcePath);
56083
56112
  if (resolved === undefined) {
56084
56113
  throw new TypeError("workflow: name must be provided when caller filename cannot be inferred");
56085
56114
  }
@@ -56115,7 +56144,8 @@ function workflow(spec) {
56115
56144
  throw new TypeError("workflow: heartbeatIntervalMinutes must be a non-negative finite number");
56116
56145
  }
56117
56146
  assertWorkflowBudget(spec.budget, "workflow: budget");
56118
- const name = resolveWorkflowName(spec.name);
56147
+ const source = callerSourcePath(workflow);
56148
+ const name = resolveWorkflowName(spec.name, source);
56119
56149
  const normalizedName = normalizeWorkflowName(name);
56120
56150
  requireNonEmptyString(normalizedName, "normalized name");
56121
56151
  const frozenInputs = freezeSchemaMap(spec.inputs ?? {});
@@ -56137,6 +56167,8 @@ function workflow(spec) {
56137
56167
  run
56138
56168
  };
56139
56169
  const branded = stampWorkflowDefinition(definition);
56170
+ if (source !== undefined)
56171
+ recordWorkflowSource(branded, source);
56140
56172
  return Object.freeze(branded);
56141
56173
  }
56142
56174
 
@@ -63585,6 +63617,7 @@ function createWorkflowExitManager(input) {
63585
63617
  ...outputSnapshot !== undefined ? { outputSnapshot } : {},
63586
63618
  ...validationError !== undefined ? { validationError } : {}
63587
63619
  }));
63620
+ input.onExitSelected?.(selectedExit);
63588
63621
  input.controller.abort(selectedExit);
63589
63622
  runWorkflowExitCleanups(reason);
63590
63623
  throw selectedExit;
@@ -64854,6 +64887,402 @@ function deferStageUntilRunRelease(input) {
64854
64887
  };
64855
64888
  }
64856
64889
 
64890
+ // dist/builtin/workflows/src/engine/run-rejection-boundary.ts
64891
+ import { AsyncLocalStorage as AsyncLocalStorage3 } from "node:async_hooks";
64892
+ import { inspect } from "node:util";
64893
+ var EVENT = "unhandledRejection";
64894
+ var BOUNDARY_KEY = Symbol.for("atomic-workflows/run-rejection-boundary@5");
64895
+ var FLAG = "--unhandled-rejections";
64896
+ var MAX_CAUSE_DEPTH2 = 8;
64897
+ var MAX_PRIMITIVES_PER_RUN = 64;
64898
+ var MAX_STOP_STRINGS = 64;
64899
+ var ENDED_RUN_GRACE_MS = 30000;
64900
+ var NATIVE_REPORTING_MODES = new Set(["throw", "warn-with-error-code"]);
64901
+ function boundaryBag() {
64902
+ return globalThis;
64903
+ }
64904
+ function sharedBoundary() {
64905
+ const bag = boundaryBag();
64906
+ const existing = bag[BOUNDARY_KEY];
64907
+ if (existing !== undefined && existing.version === 5)
64908
+ return existing;
64909
+ const created = {
64910
+ version: 5,
64911
+ store: new AsyncLocalStorage3,
64912
+ owners: new WeakMap,
64913
+ promises: new WeakMap,
64914
+ scopes: new Set,
64915
+ runs: new Map,
64916
+ ended: new Map,
64917
+ stops: new Set,
64918
+ listener: undefined
64919
+ };
64920
+ bag[BOUNDARY_KEY] = created;
64921
+ return created;
64922
+ }
64923
+ function isObject(value2) {
64924
+ return typeof value2 === "object" && value2 !== null || typeof value2 === "function";
64925
+ }
64926
+ function isPrimitive(value2) {
64927
+ return !isObject(value2);
64928
+ }
64929
+ function safeField3(value2, key) {
64930
+ try {
64931
+ return value2[key];
64932
+ } catch {
64933
+ return;
64934
+ }
64935
+ }
64936
+ function strongerEffect(left, right) {
64937
+ return left === "fail-run" || right === "fail-run" ? "fail-run" : "ignore";
64938
+ }
64939
+ function addAttribution(into, scope, effect) {
64940
+ into.set(scope, strongerEffect(into.get(scope), effect));
64941
+ }
64942
+ function recordedOwners(boundary, reason) {
64943
+ const owners = new Map;
64944
+ let stopped = false;
64945
+ const seen = new Set;
64946
+ const pending = [{ value: reason, depth: 0 }];
64947
+ while (pending.length > 0) {
64948
+ const { value: value2, depth } = pending.pop();
64949
+ if (depth > MAX_CAUSE_DEPTH2)
64950
+ continue;
64951
+ if (isPrimitive(value2)) {
64952
+ if (depth === 0 || value2 !== undefined && value2 !== null) {
64953
+ for (const scope of boundary.scopes) {
64954
+ const entry = scope.primitives.get(value2);
64955
+ if (entry !== undefined)
64956
+ addAttribution(owners, scope, entry.effect);
64957
+ }
64958
+ if (typeof value2 === "string" && boundary.stops.has(value2))
64959
+ stopped = true;
64960
+ }
64961
+ continue;
64962
+ }
64963
+ if (seen.has(value2))
64964
+ continue;
64965
+ seen.add(value2);
64966
+ for (const [scope, effect] of boundary.owners.get(value2) ?? [])
64967
+ addAttribution(owners, scope, effect);
64968
+ pending.push({ value: safeField3(value2, "cause"), depth: depth + 1 });
64969
+ const errors = safeField3(value2, "errors");
64970
+ if (Array.isArray(errors))
64971
+ for (const entry of errors)
64972
+ pending.push({ value: entry, depth: depth + 1 });
64973
+ }
64974
+ return { owners, stopped };
64975
+ }
64976
+ function pruneEndedSources(boundary) {
64977
+ const now = Date.now();
64978
+ for (const [source, trees] of boundary.ended) {
64979
+ for (const [rootRunId, endedAt] of trees)
64980
+ if (now - endedAt > ENDED_RUN_GRACE_MS)
64981
+ trees.delete(rootRunId);
64982
+ if (trees.size === 0)
64983
+ boundary.ended.delete(source);
64984
+ }
64985
+ }
64986
+ function recordEndedRun(boundary, scope) {
64987
+ if (scope.source === undefined)
64988
+ return;
64989
+ const trees = boundary.ended.get(scope.source) ?? new Map;
64990
+ trees.set(scope.rootRunId, Date.now());
64991
+ boundary.ended.set(scope.source, trees);
64992
+ }
64993
+ function endedInAnotherRunTree(boundary, source, live) {
64994
+ for (const endedRoot of boundary.ended.get(source)?.keys() ?? [])
64995
+ if (endedRoot !== live.rootRunId)
64996
+ return true;
64997
+ return false;
64998
+ }
64999
+ function recognizedSources(boundary) {
65000
+ pruneEndedSources(boundary);
65001
+ const sources = new Set(boundary.ended.keys());
65002
+ for (const scope of boundary.scopes)
65003
+ if (scope.live && scope.source !== undefined)
65004
+ sources.add(scope.source);
65005
+ return sources;
65006
+ }
65007
+ function authoringSource(reason, sources) {
65008
+ if (sources.size === 0 || !isObject(reason))
65009
+ return;
65010
+ const stack = safeField3(reason, "stack");
65011
+ if (typeof stack !== "string")
65012
+ return;
65013
+ for (const line of stack.split(`
65014
+ `)) {
65015
+ if (!line.trimStart().startsWith("at "))
65016
+ continue;
65017
+ const path = parsePromptStackFrame(line)?.normalizedPath;
65018
+ if (path === undefined)
65019
+ continue;
65020
+ if (isWorkflowRuntimeModule(path))
65021
+ return;
65022
+ if (/\/node_modules\//.test(path))
65023
+ continue;
65024
+ if (sources.has(path))
65025
+ return path;
65026
+ }
65027
+ return;
65028
+ }
65029
+ function hasAncestorIn(scope, candidates) {
65030
+ for (let ancestor = scope.parent;ancestor !== undefined; ancestor = ancestor.parent) {
65031
+ if (candidates.has(ancestor))
65032
+ return true;
65033
+ }
65034
+ return false;
65035
+ }
65036
+ function outermostLiveRuns(boundary, source) {
65037
+ const matching = new Set;
65038
+ for (const scope of boundary.scopes)
65039
+ if (scope.live && scope.source === source)
65040
+ matching.add(scope);
65041
+ const outermost = new Set;
65042
+ for (const scope of matching)
65043
+ if (!hasAncestorIn(scope, matching))
65044
+ outermost.add(scope);
65045
+ return outermost;
65046
+ }
65047
+ function runOfSource(boundary, source) {
65048
+ const [only, ...others] = outermostLiveRuns(boundary, source);
65049
+ if (only === undefined)
65050
+ return new Map;
65051
+ if (others.length > 0 || only.sharedSource)
65052
+ return;
65053
+ if (endedInAnotherRunTree(boundary, source, only))
65054
+ return;
65055
+ return new Map([[only, "fail-run"]]);
65056
+ }
65057
+ function markSharedSource(boundary, source) {
65058
+ const runs = outermostLiveRuns(boundary, source);
65059
+ if (runs.size > 1)
65060
+ for (const run of runs)
65061
+ run.sharedSource = true;
65062
+ }
65063
+ function rejectingRun(boundary, recorded, promise, scoped) {
65064
+ const tracked = promise === undefined ? undefined : boundary.promises.get(promise);
65065
+ if (tracked !== undefined && recorded.has(tracked))
65066
+ return tracked;
65067
+ if (scoped !== undefined && recorded.has(scoped))
65068
+ return scoped;
65069
+ return;
65070
+ }
65071
+ function attribute(boundary, reason, promise) {
65072
+ const { owners: recorded, stopped } = recordedOwners(boundary, reason);
65073
+ const scoped = boundary.store.getStore();
65074
+ if (recorded.size > 1) {
65075
+ const rejecting = rejectingRun(boundary, recorded, promise, scoped);
65076
+ if (rejecting !== undefined)
65077
+ return new Map([[rejecting, recorded.get(rejecting) ?? "fail-run"]]);
65078
+ }
65079
+ if (recorded.size > 0)
65080
+ return recorded;
65081
+ if (stopped)
65082
+ return new Map;
65083
+ if (scoped !== undefined && boundary.scopes.has(scoped))
65084
+ return new Map([[scoped, "fail-run"]]);
65085
+ const origin = authoringSource(reason, recognizedSources(boundary));
65086
+ if (origin === undefined)
65087
+ return;
65088
+ if (scoped !== undefined)
65089
+ return new Map([[scoped, "ignore"]]);
65090
+ return runOfSource(boundary, origin);
65091
+ }
65092
+ function unhandledRejectionError(reason) {
65093
+ return Object.assign(new Error("This error originated either by throwing inside of an async function without a catch block, " + `or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "${inspect(reason)}".`), { code: "ERR_UNHANDLED_REJECTION" });
65094
+ }
65095
+ function unhandledRejectionsMode() {
65096
+ const args = [...(process.env.NODE_OPTIONS ?? "").split(/\s+/), ...process.execArgv];
65097
+ let mode = "throw";
65098
+ for (let index = 0;index < args.length; index += 1) {
65099
+ const arg = args[index] ?? "";
65100
+ if (arg.startsWith(`${FLAG}=`))
65101
+ mode = arg.slice(FLAG.length + 1);
65102
+ else if (arg === FLAG && args[index + 1] !== undefined)
65103
+ mode = args[index + 1] ?? mode;
65104
+ }
65105
+ return mode;
65106
+ }
65107
+ function surfaceNatively(boundary, reason) {
65108
+ const listener = boundary.listener;
65109
+ if (listener === undefined || process.listenerCount(EVENT) > 1)
65110
+ return;
65111
+ if (!NATIVE_REPORTING_MODES.has(unhandledRejectionsMode()))
65112
+ return;
65113
+ process.nextTick(() => {
65114
+ process.removeListener(EVENT, listener);
65115
+ Promise.reject(reason);
65116
+ setImmediate(() => {
65117
+ if (!process.listeners(EVENT).includes(listener))
65118
+ process.on(EVENT, listener);
65119
+ });
65120
+ });
65121
+ }
65122
+ function onUnhandledRejection(reason, promise) {
65123
+ const boundary = sharedBoundary();
65124
+ const owners = attribute(boundary, reason, promise);
65125
+ if (owners === undefined) {
65126
+ surfaceNatively(boundary, reason);
65127
+ return;
65128
+ }
65129
+ const error = isObject(reason) ? reason : unhandledRejectionError(reason);
65130
+ for (const [scope, effect] of owners) {
65131
+ if (effect !== "fail-run" || !scope.live)
65132
+ continue;
65133
+ try {
65134
+ scope.fail(error);
65135
+ } catch {}
65136
+ }
65137
+ }
65138
+ function ensureInstalled(boundary) {
65139
+ if (boundary.listener !== undefined)
65140
+ return;
65141
+ boundary.listener = onUnhandledRejection;
65142
+ process.on(EVENT, onUnhandledRejection);
65143
+ }
65144
+ function record(boundary, scope, reason, effect) {
65145
+ if (isPrimitive(reason)) {
65146
+ recordPrimitive(scope, reason, effect);
65147
+ return;
65148
+ }
65149
+ const owners = boundary.owners.get(reason);
65150
+ if (owners === undefined)
65151
+ boundary.owners.set(reason, new Map([[scope, effect]]));
65152
+ else
65153
+ addAttribution(owners, scope, effect);
65154
+ }
65155
+ function recordStop(boundary, reason) {
65156
+ boundary.stops.delete(reason);
65157
+ boundary.stops.add(reason);
65158
+ if (boundary.stops.size <= MAX_STOP_STRINGS)
65159
+ return;
65160
+ const oldest = boundary.stops.values().next();
65161
+ if (!oldest.done)
65162
+ boundary.stops.delete(oldest.value);
65163
+ }
65164
+ function recordPrimitive(scope, reason, effect) {
65165
+ if (!scope.live)
65166
+ return;
65167
+ if (scope.primitives.size >= MAX_PRIMITIVES_PER_RUN && !scope.primitives.has(reason)) {
65168
+ const oldest = scope.primitives.keys().next();
65169
+ if (!oldest.done)
65170
+ scope.primitives.delete(oldest.value);
65171
+ }
65172
+ scope.generation += 1;
65173
+ const generation = scope.generation;
65174
+ scope.primitives.set(reason, { effect: strongerEffect(scope.primitives.get(reason)?.effect, effect), generation });
65175
+ afterPendingRejectionReports().then(() => {
65176
+ if (scope.primitives.get(reason)?.generation === generation)
65177
+ scope.primitives.delete(reason);
65178
+ });
65179
+ }
65180
+ function discardFailure() {}
65181
+ function afterPendingRejectionReports() {
65182
+ return new Promise((resolve) => {
65183
+ const { port1, port2 } = new MessageChannel;
65184
+ port1.onmessage = () => {
65185
+ port1.close();
65186
+ port2.close();
65187
+ resolve();
65188
+ };
65189
+ port2.postMessage(undefined);
65190
+ });
65191
+ }
65192
+ function openRunRejectionScope(options) {
65193
+ const boundary = sharedBoundary();
65194
+ ensureInstalled(boundary);
65195
+ pruneEndedSources(boundary);
65196
+ const parent = options.parentRunId === undefined ? undefined : boundary.runs.get(options.parentRunId);
65197
+ const scope = {
65198
+ runId: options.runId,
65199
+ rootRunId: parent?.rootRunId ?? options.runId,
65200
+ source: options.source === undefined ? undefined : normalizeStackPath(options.source),
65201
+ parent,
65202
+ fail: options.fail,
65203
+ primitives: new Map,
65204
+ generation: 0,
65205
+ live: true,
65206
+ sharedSource: false
65207
+ };
65208
+ boundary.scopes.add(scope);
65209
+ boundary.runs.set(scope.runId, scope);
65210
+ if (scope.source !== undefined)
65211
+ markSharedSource(boundary, scope.source);
65212
+ return {
65213
+ run: (callback) => boundary.store.run(scope, callback),
65214
+ contain: (promise, effect = "fail-run") => {
65215
+ boundary.promises.set(promise, scope);
65216
+ promise.then(undefined, (reason) => record(boundary, scope, reason, effect));
65217
+ return promise;
65218
+ },
65219
+ watch: (promise) => {
65220
+ const watched = promise.then(undefined, (reason) => {
65221
+ record(boundary, scope, reason, "fail-run");
65222
+ throw reason;
65223
+ });
65224
+ boundary.promises.set(watched, scope);
65225
+ return watched;
65226
+ },
65227
+ ignore: (reason) => {
65228
+ if (typeof reason === "string")
65229
+ recordStop(boundary, reason);
65230
+ else
65231
+ record(boundary, scope, reason, "ignore");
65232
+ },
65233
+ settle: afterPendingRejectionReports,
65234
+ close: () => {
65235
+ scope.live = false;
65236
+ scope.fail = discardFailure;
65237
+ recordEndedRun(boundary, scope);
65238
+ afterPendingRejectionReports().then(() => {
65239
+ scope.primitives.clear();
65240
+ scope.parent = undefined;
65241
+ boundary.scopes.delete(scope);
65242
+ if (boundary.runs.get(scope.runId) === scope)
65243
+ boundary.runs.delete(scope.runId);
65244
+ });
65245
+ }
65246
+ };
65247
+ }
65248
+ var WATCHED_STAGE_METHODS = [
65249
+ "prompt",
65250
+ "complete",
65251
+ "sendUserMessage",
65252
+ "steer",
65253
+ "followUp",
65254
+ "setModel",
65255
+ "setThinkingLevel",
65256
+ "cycleModel",
65257
+ "cycleThinkingLevel",
65258
+ "navigateTree",
65259
+ "compact",
65260
+ "abort"
65261
+ ];
65262
+ function containStageRejections(stage, scope) {
65263
+ const contained = Object.create(stage);
65264
+ const descriptors = {};
65265
+ for (const name of WATCHED_STAGE_METHODS) {
65266
+ descriptors[name] = {
65267
+ value: (...args) => {
65268
+ const result = Reflect.apply(stage[name], stage, args);
65269
+ return result instanceof Promise ? scope.watch(result) : result;
65270
+ }
65271
+ };
65272
+ }
65273
+ Object.defineProperties(contained, descriptors);
65274
+ return contained;
65275
+ }
65276
+ function containUiRejections(ui, scope) {
65277
+ return {
65278
+ input: (prompt) => scope.watch(ui.input(prompt)),
65279
+ confirm: (message) => scope.watch(ui.confirm(message)),
65280
+ select: (message, options) => scope.watch(ui.select(message, options)),
65281
+ editor: (initial) => scope.watch(ui.editor(initial)),
65282
+ custom: (factory, options) => scope.watch(ui.custom(factory, options))
65283
+ };
65284
+ }
65285
+
64857
65286
  // dist/builtin/workflows/src/engine/run-returned-status.ts
64858
65287
  function classifyReturnedRunStatus(result, runSnapshot) {
64859
65288
  const structuredFailure = runSnapshot !== undefined ? structuredRecoverableWorkflowFailure(runSnapshot) : undefined;
@@ -70870,13 +71299,13 @@ class EngineRuntime {
70870
71299
 
70871
71300
  // dist/builtin/workflows/src/engine/session-closed-error.ts
70872
71301
  import { isStaleExtensionContextError as isStaleExtensionContextError5 } from "@bastani/atomic";
70873
- var MAX_CAUSE_DEPTH2 = 8;
71302
+ var MAX_CAUSE_DEPTH3 = 8;
70874
71303
  function reportsClosedSession(error) {
70875
71304
  return "code" in error && error.code === "SessionClosed" || isStaleExtensionContextError5(error);
70876
71305
  }
70877
71306
  function isSessionClosedError(error) {
70878
71307
  let current = error;
70879
- for (let depth = 0;depth < MAX_CAUSE_DEPTH2 && current !== undefined; depth++) {
71308
+ for (let depth = 0;depth < MAX_CAUSE_DEPTH3 && current !== undefined; depth++) {
70880
71309
  try {
70881
71310
  if (reportsClosedSession(current))
70882
71311
  return true;
@@ -70948,7 +71377,12 @@ async function executeRun(def, resolvedInputs, opts) {
70948
71377
  workflowObservationRuntime(activeStore).control(runId, "kill");
70949
71378
  ownController.abort(callerSignal?.reason);
70950
71379
  };
70951
- const exit = createWorkflowExitManager({ runId, exitScope, controller: ownController });
71380
+ const exit = createWorkflowExitManager({
71381
+ runId,
71382
+ exitScope,
71383
+ controller: ownController,
71384
+ onExitSelected: (signal) => rejectionScope.ignore(signal)
71385
+ });
70952
71386
  const sourceBackend = opts.durableBackend;
70953
71387
  const backendView = sourceBackend;
70954
71388
  const rootBackend = opts.durableRootBackend ?? backendView;
@@ -71462,6 +71896,22 @@ async function executeRun(def, resolvedInputs, opts) {
71462
71896
  baseFromPromptNodes: getPromptNodeUi
71463
71897
  });
71464
71898
  let pausedExit;
71899
+ const authoredIn = workflowSource(def);
71900
+ const rejectionScope = openRunRejectionScope({
71901
+ runId,
71902
+ ...opts.parentRun !== undefined ? { parentRunId: opts.parentRun.runId } : {},
71903
+ ...authoredIn !== undefined ? { source: authoredIn } : {},
71904
+ fail: (error) => {
71905
+ if (findWorkflowGracefulQuit(error) !== undefined)
71906
+ return;
71907
+ const selected = terminalEvents.selectFailure(error);
71908
+ if (selected.kind === "failure" && !ownController.signal.aborted)
71909
+ ownController.abort(selected.error);
71910
+ }
71911
+ });
71912
+ ownController.signal.addEventListener("abort", () => rejectionScope.ignore(ownController.signal.reason), {
71913
+ once: true
71914
+ });
71465
71915
  const ctx = {
71466
71916
  inputs: resolvedInputs,
71467
71917
  runId,
@@ -71472,28 +71922,30 @@ async function executeRun(def, resolvedInputs, opts) {
71472
71922
  if (scheduler.isRunPaused()) {
71473
71923
  pausedExit ??= whenRunning(async () => exit.exit(options));
71474
71924
  pausedExit.catch(() => {});
71475
- throw new Error("Workflow exit is waiting for explicit resume");
71925
+ const waiting = new Error("Workflow exit is waiting for explicit resume");
71926
+ rejectionScope.ignore(waiting);
71927
+ throw waiting;
71476
71928
  }
71477
71929
  return exit.exit(options);
71478
71930
  },
71479
- ui,
71931
+ ui: containUiRejections(ui, rejectionScope),
71480
71932
  stage: (name, options) => {
71481
71933
  ownController.signal.throwIfAborted();
71482
71934
  if (!scheduler.isRunPaused())
71483
- return durableStage(name, options);
71935
+ return containStageRejections(durableStage(name, options), rejectionScope);
71484
71936
  const replayKey = stageReplayKeyGenerator(name);
71485
- return deferStageUntilRunRelease({
71937
+ return containStageRejections(deferStageUntilRunRelease({
71486
71938
  name,
71487
71939
  create: () => durableStage(name, options, replayKey),
71488
71940
  isPaused: scheduler.isRunPaused,
71489
71941
  waitForRelease: waitForRunRelease,
71490
71942
  signal: ownController.signal
71491
- });
71943
+ }), rejectionScope);
71492
71944
  },
71493
- task: gatedTask,
71494
- chain: (...args) => whenRunning(() => chain(...args)),
71495
- parallel: (...args) => whenRunning(() => parallel(...args)),
71496
- workflow: (...args) => whenRunning(() => {
71945
+ task: (...args) => rejectionScope.watch(gatedTask(...args)),
71946
+ chain: (...args) => rejectionScope.watch(whenRunning(() => chain(...args))),
71947
+ parallel: (...args) => rejectionScope.watch(whenRunning(() => parallel(...args))),
71948
+ workflow: (...args) => rejectionScope.watch(whenRunning(() => {
71497
71949
  const pending = durableWorkflow(...args);
71498
71950
  pendingChildWorkflows.add(pending);
71499
71951
  const settled = () => {
@@ -71501,13 +71953,11 @@ async function executeRun(def, resolvedInputs, opts) {
71501
71953
  };
71502
71954
  pending.then(settled, settled);
71503
71955
  return pending;
71504
- }),
71956
+ })),
71505
71957
  tool: (...args) => {
71506
71958
  if (admittedTools.closed)
71507
- return tool(...args);
71508
- const pending = whenRunning(() => tool(...args));
71509
- pending.catch(() => {});
71510
- return pending;
71959
+ return rejectionScope.contain(tool(...args), "ignore");
71960
+ return rejectionScope.contain(whenRunning(() => tool(...args)));
71511
71961
  },
71512
71962
  ...opts.models !== undefined ? { models: opts.models } : {}
71513
71963
  };
@@ -71659,7 +72109,7 @@ async function executeRun(def, resolvedInputs, opts) {
71659
72109
  while (scheduler.isRunPaused())
71660
72110
  await waitForRunRelease();
71661
72111
  ownController.signal.throwIfAborted();
71662
- const rawResult = await raceAbort(runWorkflowDefinitionCallback(def.name, runId, () => def.run(ctx)), ownController.signal);
72112
+ const rawResult = await raceAbort(runWorkflowDefinitionCallback(def.name, runId, () => rejectionScope.run(() => def.run(ctx))), ownController.signal);
71663
72113
  await drainCachedStagePersistence();
71664
72114
  while (scheduler.isRunPaused())
71665
72115
  await waitForRunRelease();
@@ -71669,6 +72119,7 @@ async function executeRun(def, resolvedInputs, opts) {
71669
72119
  if (pausedExit !== undefined)
71670
72120
  await pausedExit;
71671
72121
  budget.rethrowIfSystemOwnedStop(runSnapshot.stages.at(-1)?.name ?? startupFrontierStage);
72122
+ await rejectionScope.settle();
71672
72123
  const normalTerminalEvent = terminalEvents.winner();
71673
72124
  if (normalTerminalEvent?.kind === "cancellation") {
71674
72125
  const gracefulQuit = findWorkflowGracefulQuit(normalTerminalEvent.reason);
@@ -71738,6 +72189,9 @@ async function executeRun(def, resolvedInputs, opts) {
71738
72189
  }
71739
72190
  if (ownerClosing && err instanceof Error && isSessionClosedError(err))
71740
72191
  return await suspendForClosedSession(err);
72192
+ if (selectedTerminalEvent.kind === "failure" && pendingChildWorkflows.size > 0 && !ownController.signal.aborted) {
72193
+ ownController.abort(err);
72194
+ }
71741
72195
  await admittedTools.closeAndDrain();
71742
72196
  if (ownController.signal.aborted)
71743
72197
  await Promise.allSettled([...pendingChildWorkflows]);
@@ -71812,6 +72266,7 @@ async function executeRun(def, resolvedInputs, opts) {
71812
72266
  });
71813
72267
  return failed;
71814
72268
  } finally {
72269
+ rejectionScope.close();
71815
72270
  callerSignal?.removeEventListener("abort", onCallerAbort);
71816
72271
  workflowObservationRuntime(activeStore).finishRun(runId);
71817
72272
  runtimeSettled.resolve();
@@ -72926,11 +73381,17 @@ function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallba
72926
73381
  retainReachableRunGroups(grouped, rootRunId);
72927
73382
  if (policy.failOnUnreachable && grouped.size !== groupedCount)
72928
73383
  return [];
72929
- if (!validateRunGroups(grouped, rootRunId, toolCheckpoints, checkpoints))
73384
+ if (!validateRunGroups(grouped, rootRunId, toolCheckpoints, checkpoints, policy.retainActive))
72930
73385
  return [];
72931
73386
  const syntheticChildren = [];
73387
+ const pendingChildren = [];
72932
73388
  for (const [parentRunId, runDrafts] of grouped) {
72933
73389
  for (const draft of runDrafts) {
73390
+ const pendingChildRunId = childRunIdFromDraft(draft);
73391
+ if (policy.retainActive && pendingChildRunId !== undefined && !grouped.has(pendingChildRunId) && isPendingChildBoundary(draft, parentRunId, pendingChildRunId, rootRunId)) {
73392
+ pendingChildren.push({ parentRunId, owner: draft });
73393
+ continue;
73394
+ }
72934
73395
  const child = workflowChildFromDraft(draft);
72935
73396
  if (child?.exited !== true || grouped.has(child.runId))
72936
73397
  continue;
@@ -73039,6 +73500,28 @@ function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallba
73039
73500
  resumable: false
73040
73501
  });
73041
73502
  }
73503
+ for (const { parentRunId, owner } of pendingChildren) {
73504
+ if (!emittedRunIds.has(parentRunId))
73505
+ return [];
73506
+ const topology = owner.topology;
73507
+ const boundary = topology.boundary;
73508
+ const parentStageId = idMaps.get(parentRunId)?.get(topology.stageId);
73509
+ if (parentStageId === undefined)
73510
+ return [];
73511
+ runs.push({
73512
+ id: boundary.child.runId,
73513
+ name: boundary.child.runName,
73514
+ inputs: {},
73515
+ status: "running",
73516
+ stages: [],
73517
+ toolNodes: [],
73518
+ startedAt: owner.startedAt ?? owner.firstCompletedAt,
73519
+ parentRunId,
73520
+ parentStageId,
73521
+ rootRunId: boundary.child.rootRunId,
73522
+ resumable: false
73523
+ });
73524
+ }
73042
73525
  return runs;
73043
73526
  }
73044
73527
  function stageSnapshotFromDraft(draft, id, parentIds) {