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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +39 -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/compaction/compaction-runner.d.ts.map +1 -1
  31. package/dist/core/compaction/compaction-runner.js +1 -0
  32. package/dist/core/compaction/compaction-runner.js.map +1 -1
  33. package/dist/core/model-config.d.ts +28 -0
  34. package/dist/core/model-config.d.ts.map +1 -1
  35. package/dist/core/provider-composer-internal.d.ts +2 -1
  36. package/dist/core/provider-composer-internal.d.ts.map +1 -1
  37. package/dist/core/provider-composer-internal.js +8 -6
  38. package/dist/core/provider-composer-internal.js.map +1 -1
  39. package/dist/core/tools/grep.js +1 -1
  40. package/dist/core/tools/grep.js.map +1 -1
  41. package/dist/core/usage-totals.d.ts.map +1 -1
  42. package/dist/core/usage-totals.js +2 -0
  43. package/dist/core/usage-totals.js.map +1 -1
  44. package/docs/getting-started/installation.md +19 -1
  45. package/docs/models-configuration.md +9 -0
  46. package/docs/models.md +3 -1
  47. package/docs/providers.md +1 -1
  48. package/docs/quickstart.md +1 -1
  49. package/docs/windows.md +1 -1
  50. package/docs/workflows/authoring.md +1 -1
  51. package/npm-shrinkwrap.json +67 -54
  52. package/package.json +6 -6
  53. package/schemas/models.schema.json +21 -0
@@ -11,7 +11,7 @@ ${KEEP_CONTEXT_CLOSE_TAG}`;
11
11
  }
12
12
  // dist/builtin/workflows/src/authoring/workflow.ts
13
13
  import { basename } from "node:path";
14
- import { fileURLToPath } from "node:url";
14
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
15
15
 
16
16
  // dist/builtin/workflows/src/shared/budget.ts
17
17
  function enforceDurationBudget(reading, budget, options = {}) {
@@ -87,6 +87,89 @@ function resolve_budget(layers) {
87
87
  var DEFAULT_WORKFLOW_HEARTBEAT_INTERVAL_MINUTES = 15;
88
88
  var WORKFLOW_HEARTBEAT_CUSTOM_TYPE = "workflows:workflow-heartbeat";
89
89
 
90
+ // dist/builtin/workflows/src/runs/shared/prompt-callsite.ts
91
+ import { fileURLToPath } from "node:url";
92
+ var PACKAGED_WORKFLOW_RUNTIME_ROOTS = ["/dist/builtin/workflows/src/"];
93
+ function normalizeSlashes(path) {
94
+ return path.replace(/\\/g, "/");
95
+ }
96
+ function normalizeStackPath(framePath) {
97
+ let normalized = framePath;
98
+ if (normalized.startsWith("file://")) {
99
+ try {
100
+ normalized = fileURLToPath(normalized);
101
+ } catch {
102
+ try {
103
+ normalized = decodeURIComponent(new URL(normalized).pathname);
104
+ } catch {}
105
+ }
106
+ }
107
+ normalized = normalizeSlashes(normalized).replace(/^\/([A-Za-z]:\/)/, "$1");
108
+ return normalized;
109
+ }
110
+ function currentModuleRuntimeRoot() {
111
+ const modulePath = normalizeStackPath(fileURLToPath(import.meta.url));
112
+ const markers = ["packages/workflows/src/", ...PACKAGED_WORKFLOW_RUNTIME_ROOTS.map((root) => root.slice(1))];
113
+ for (const marker of markers) {
114
+ const index = modulePath.indexOf(marker);
115
+ if (index >= 0)
116
+ return modulePath.slice(0, index + marker.length);
117
+ }
118
+ return;
119
+ }
120
+ var CURRENT_WORKFLOW_RUNTIME_ROOT = currentModuleRuntimeRoot();
121
+ function isWorkflowRuntimeFrame(normalizedPath) {
122
+ const path = normalizeSlashes(normalizedPath);
123
+ if (path.startsWith("packages/workflows/src/"))
124
+ return true;
125
+ if (CURRENT_WORKFLOW_RUNTIME_ROOT !== undefined && path.startsWith(CURRENT_WORKFLOW_RUNTIME_ROOT)) {
126
+ return true;
127
+ }
128
+ const comparable = path.startsWith("/") ? path : `/${path}`;
129
+ return PACKAGED_WORKFLOW_RUNTIME_ROOTS.some((runtimeRoot) => comparable.includes(runtimeRoot));
130
+ }
131
+ function parsePromptStackFrame(stackLine) {
132
+ const line = stackLine.trim();
133
+ if (line.length === 0)
134
+ return;
135
+ if (line.includes("node:internal") || line.includes("bun:") || line.includes("(native:"))
136
+ return;
137
+ const match = line.match(/(\S+):(\d+):(\d+)\)?$/);
138
+ if (!match)
139
+ return;
140
+ const [, rawFramePath, lineNumber, columnNumber] = match;
141
+ if (rawFramePath === undefined || lineNumber === undefined || columnNumber === undefined)
142
+ return;
143
+ const normalizedPath = normalizeStackPath(rawFramePath.replace(/^\(/, ""));
144
+ return { normalizedPath, lineNumber, columnNumber };
145
+ }
146
+ function normalizedPromptCallsiteFrame(stackLine) {
147
+ const frame = parsePromptStackFrame(stackLine);
148
+ if (frame === undefined)
149
+ return;
150
+ if (isWorkflowRuntimeFrame(frame.normalizedPath))
151
+ return;
152
+ return `${frame.normalizedPath}:${frame.lineNumber}:${frame.columnNumber}`;
153
+ }
154
+ function selectPromptCallsiteFrame(stack) {
155
+ return stack.split(`
156
+ `).slice(1).map(normalizedPromptCallsiteFrame).find((candidate) => candidate !== undefined);
157
+ }
158
+
159
+ // dist/builtin/workflows/src/shared/workflow-source.ts
160
+ var WORKFLOW_SOURCES = new WeakMap;
161
+ var OWN_MODULE_PATH = normalizeStackPath(import.meta.url);
162
+ function isWorkflowRuntimeModule(path) {
163
+ const normalized = normalizeStackPath(path);
164
+ return normalized === OWN_MODULE_PATH || isWorkflowRuntimeFrame(normalized);
165
+ }
166
+ function recordWorkflowSource(definition, path) {
167
+ WORKFLOW_SOURCES.set(definition, path);
168
+ }
169
+ function workflowSource(definition) {
170
+ return WORKFLOW_SOURCES.get(definition);
171
+ }
172
+
90
173
  // dist/builtin/workflows/src/workflows/identity.ts
91
174
  function normalizeWorkflowName(name) {
92
175
  if (!name || typeof name !== "string") {
@@ -123,7 +206,7 @@ function stackFilePath(line) {
123
206
  if (!rawPath.startsWith("file://"))
124
207
  return rawPath;
125
208
  try {
126
- return fileURLToPath(rawPath);
209
+ return fileURLToPath2(rawPath);
127
210
  } catch {
128
211
  return;
129
212
  }
@@ -134,8 +217,10 @@ function isWorkflowAuthoringImplementationFrame(filePath) {
134
217
  return false;
135
218
  return normalized.includes("/packages/workflows/") || normalized.includes("/dist/builtin/workflows/") || normalized.includes("/.atomic/agent/extensions/workflows/");
136
219
  }
137
- function workflowNameFromCaller() {
138
- const stack = new Error().stack;
220
+ function callerSourcePath(entry) {
221
+ const capture = new Error;
222
+ Error.captureStackTrace(capture, entry);
223
+ const stack = capture.stack;
139
224
  if (stack === undefined)
140
225
  return;
141
226
  for (const line of stack.split(`
@@ -145,14 +230,18 @@ function workflowNameFromCaller() {
145
230
  continue;
146
231
  if (isWorkflowAuthoringImplementationFrame(filePath))
147
232
  continue;
148
- const base = basename(filePath.replace(/\\/g, "/")).replace(/\.[cm]?[jt]sx?$/, "");
149
- if (base.length > 0)
150
- return base;
233
+ return isWorkflowRuntimeModule(filePath) ? undefined : filePath;
151
234
  }
152
235
  return;
153
236
  }
154
- function resolveWorkflowName(name) {
155
- const resolved = name ?? workflowNameFromCaller();
237
+ function workflowNameFromSourcePath(filePath) {
238
+ if (filePath === undefined)
239
+ return;
240
+ const base = basename(filePath.replace(/\\/g, "/")).replace(/\.[cm]?[jt]sx?$/, "");
241
+ return base.length > 0 ? base : undefined;
242
+ }
243
+ function resolveWorkflowName(name, sourcePath) {
244
+ const resolved = name ?? workflowNameFromSourcePath(sourcePath);
156
245
  if (resolved === undefined) {
157
246
  throw new TypeError("workflow: name must be provided when caller filename cannot be inferred");
158
247
  }
@@ -188,7 +277,8 @@ function workflow(spec) {
188
277
  throw new TypeError("workflow: heartbeatIntervalMinutes must be a non-negative finite number");
189
278
  }
190
279
  assertWorkflowBudget(spec.budget, "workflow: budget");
191
- const name = resolveWorkflowName(spec.name);
280
+ const source = callerSourcePath(workflow);
281
+ const name = resolveWorkflowName(spec.name, source);
192
282
  const normalizedName = normalizeWorkflowName(name);
193
283
  requireNonEmptyString(normalizedName, "normalized name");
194
284
  const frozenInputs = freezeSchemaMap(spec.inputs ?? {});
@@ -210,6 +300,8 @@ function workflow(spec) {
210
300
  run
211
301
  };
212
302
  const branded = stampWorkflowDefinition(definition);
303
+ if (source !== undefined)
304
+ recordWorkflowSource(branded, source);
213
305
  return Object.freeze(branded);
214
306
  }
215
307
  // dist/builtin/workflows/src/durable/journal/conformance.ts
@@ -5956,75 +6048,6 @@ function buildStagePromptAdapter(id, kind, args, createdAt) {
5956
6048
  };
5957
6049
  }
5958
6050
 
5959
- // dist/builtin/workflows/src/runs/shared/prompt-callsite.ts
5960
- import { fileURLToPath as fileURLToPath2 } from "node:url";
5961
- var PACKAGED_WORKFLOW_RUNTIME_ROOTS = ["/dist/builtin/workflows/src/"];
5962
- function normalizeSlashes(path) {
5963
- return path.replace(/\\/g, "/");
5964
- }
5965
- function normalizeStackPath(framePath) {
5966
- let normalized = framePath;
5967
- if (normalized.startsWith("file://")) {
5968
- try {
5969
- normalized = fileURLToPath2(normalized);
5970
- } catch {
5971
- try {
5972
- normalized = decodeURIComponent(new URL(normalized).pathname);
5973
- } catch {}
5974
- }
5975
- }
5976
- normalized = normalizeSlashes(normalized).replace(/^\/([A-Za-z]:\/)/, "$1");
5977
- return normalized;
5978
- }
5979
- function currentModuleRuntimeRoot() {
5980
- const modulePath = normalizeStackPath(fileURLToPath2(import.meta.url));
5981
- const markers = ["packages/workflows/src/", ...PACKAGED_WORKFLOW_RUNTIME_ROOTS.map((root) => root.slice(1))];
5982
- for (const marker of markers) {
5983
- const index = modulePath.indexOf(marker);
5984
- if (index >= 0)
5985
- return modulePath.slice(0, index + marker.length);
5986
- }
5987
- return;
5988
- }
5989
- var CURRENT_WORKFLOW_RUNTIME_ROOT = currentModuleRuntimeRoot();
5990
- function isWorkflowRuntimeFrame(normalizedPath) {
5991
- const path = normalizeSlashes(normalizedPath);
5992
- if (path.startsWith("packages/workflows/src/"))
5993
- return true;
5994
- if (CURRENT_WORKFLOW_RUNTIME_ROOT !== undefined && path.startsWith(CURRENT_WORKFLOW_RUNTIME_ROOT)) {
5995
- return true;
5996
- }
5997
- const comparable = path.startsWith("/") ? path : `/${path}`;
5998
- return PACKAGED_WORKFLOW_RUNTIME_ROOTS.some((runtimeRoot) => comparable.includes(runtimeRoot));
5999
- }
6000
- function parsePromptStackFrame(stackLine) {
6001
- const line = stackLine.trim();
6002
- if (line.length === 0)
6003
- return;
6004
- if (line.includes("node:internal") || line.includes("bun:") || line.includes("(native:"))
6005
- return;
6006
- const match = line.match(/(\S+):(\d+):(\d+)\)?$/);
6007
- if (!match)
6008
- return;
6009
- const [, rawFramePath, lineNumber, columnNumber] = match;
6010
- if (rawFramePath === undefined || lineNumber === undefined || columnNumber === undefined)
6011
- return;
6012
- const normalizedPath = normalizeStackPath(rawFramePath.replace(/^\(/, ""));
6013
- return { normalizedPath, lineNumber, columnNumber };
6014
- }
6015
- function normalizedPromptCallsiteFrame(stackLine) {
6016
- const frame = parsePromptStackFrame(stackLine);
6017
- if (frame === undefined)
6018
- return;
6019
- if (isWorkflowRuntimeFrame(frame.normalizedPath))
6020
- return;
6021
- return `${frame.normalizedPath}:${frame.lineNumber}:${frame.columnNumber}`;
6022
- }
6023
- function selectPromptCallsiteFrame(stack) {
6024
- return stack.split(`
6025
- `).slice(1).map(normalizedPromptCallsiteFrame).find((candidate) => candidate !== undefined);
6026
- }
6027
-
6028
6051
  // dist/builtin/workflows/src/shared/resume-continuation.ts
6029
6052
  var RESUME_CONTINUATION_PROMPT = "Continue where you left off. If you believe you are finished with your original task (or a redefined task if the user told you), stop.";
6030
6053
 
@@ -14693,6 +14716,7 @@ function createWorkflowExitManager(input) {
14693
14716
  ...outputSnapshot !== undefined ? { outputSnapshot } : {},
14694
14717
  ...validationError !== undefined ? { validationError } : {}
14695
14718
  }));
14719
+ input.onExitSelected?.(selectedExit);
14696
14720
  input.controller.abort(selectedExit);
14697
14721
  runWorkflowExitCleanups(reason);
14698
14722
  throw selectedExit;
@@ -15914,7 +15938,7 @@ function compareDraftSourceOrder(left, right) {
15914
15938
  function runTopologyFor(drafts, tools) {
15915
15939
  return drafts.find((draft) => draft.topology?.run !== undefined)?.topology?.run ?? tools.find((checkpoint) => checkpoint.topology?.run !== undefined)?.topology?.run;
15916
15940
  }
15917
- function validateRunGroups(grouped, rootRunId, tools, checkpoints) {
15941
+ function validateRunGroups(grouped, rootRunId, tools, checkpoints, allowPendingChildren = false) {
15918
15942
  const toolsFor = (runId) => tools.filter((checkpoint) => (checkpoint.topology?.run?.runId ?? rootRunId) === runId);
15919
15943
  const owners = new Map;
15920
15944
  const syntheticChildIds = new Set;
@@ -15926,6 +15950,11 @@ function validateRunGroups(grouped, rootRunId, tools, checkpoints) {
15926
15950
  if (childRunId === parentRunId || owners.has(childRunId))
15927
15951
  return false;
15928
15952
  if (!grouped.has(childRunId)) {
15953
+ if (allowPendingChildren && isPendingChildBoundary(draft, parentRunId, childRunId, rootRunId) && !childScopedEvidenceExists(checkpoints, draft.replayKey, childRunId)) {
15954
+ syntheticChildIds.add(childRunId);
15955
+ owners.set(childRunId, draft);
15956
+ continue;
15957
+ }
15929
15958
  if (!isSyntheticExitedChild(draft, parentRunId, childRunId, rootRunId) || childScopedEvidenceExists(checkpoints, draft.replayKey, childRunId))
15930
15959
  return false;
15931
15960
  syntheticChildIds.add(childRunId);
@@ -15958,6 +15987,10 @@ function validateRunGroups(grouped, rootRunId, tools, checkpoints) {
15958
15987
  }
15959
15988
  return true;
15960
15989
  }
15990
+ function isPendingChildBoundary(draft, parentRunId, childRunId, rootRunId) {
15991
+ const boundary = draft.topology?.boundary;
15992
+ 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;
15993
+ }
15961
15994
  function isSyntheticExitedChild(draft, parentRunId, childRunId, rootRunId) {
15962
15995
  const child = workflowChildFromDraft(draft);
15963
15996
  const boundary = draft.topology?.boundary;
@@ -16373,11 +16406,17 @@ function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallba
16373
16406
  retainReachableRunGroups(grouped, rootRunId);
16374
16407
  if (policy.failOnUnreachable && grouped.size !== groupedCount)
16375
16408
  return [];
16376
- if (!validateRunGroups(grouped, rootRunId, toolCheckpoints, checkpoints))
16409
+ if (!validateRunGroups(grouped, rootRunId, toolCheckpoints, checkpoints, policy.retainActive))
16377
16410
  return [];
16378
16411
  const syntheticChildren = [];
16412
+ const pendingChildren = [];
16379
16413
  for (const [parentRunId, runDrafts] of grouped) {
16380
16414
  for (const draft of runDrafts) {
16415
+ const pendingChildRunId = childRunIdFromDraft(draft);
16416
+ if (policy.retainActive && pendingChildRunId !== undefined && !grouped.has(pendingChildRunId) && isPendingChildBoundary(draft, parentRunId, pendingChildRunId, rootRunId)) {
16417
+ pendingChildren.push({ parentRunId, owner: draft });
16418
+ continue;
16419
+ }
16381
16420
  const child = workflowChildFromDraft(draft);
16382
16421
  if (child?.exited !== true || grouped.has(child.runId))
16383
16422
  continue;
@@ -16486,6 +16525,28 @@ function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallba
16486
16525
  resumable: false
16487
16526
  });
16488
16527
  }
16528
+ for (const { parentRunId, owner } of pendingChildren) {
16529
+ if (!emittedRunIds.has(parentRunId))
16530
+ return [];
16531
+ const topology = owner.topology;
16532
+ const boundary = topology.boundary;
16533
+ const parentStageId = idMaps.get(parentRunId)?.get(topology.stageId);
16534
+ if (parentStageId === undefined)
16535
+ return [];
16536
+ runs.push({
16537
+ id: boundary.child.runId,
16538
+ name: boundary.child.runName,
16539
+ inputs: {},
16540
+ status: "running",
16541
+ stages: [],
16542
+ toolNodes: [],
16543
+ startedAt: owner.startedAt ?? owner.firstCompletedAt,
16544
+ parentRunId,
16545
+ parentStageId,
16546
+ rootRunId: boundary.child.rootRunId,
16547
+ resumable: false
16548
+ });
16549
+ }
16489
16550
  return runs;
16490
16551
  }
16491
16552
  function stageSnapshotFromDraft(draft, id, parentIds) {
@@ -16801,6 +16862,402 @@ function deferStageUntilRunRelease(input) {
16801
16862
  };
16802
16863
  }
16803
16864
 
16865
+ // dist/builtin/workflows/src/engine/run-rejection-boundary.ts
16866
+ import { AsyncLocalStorage as AsyncLocalStorage3 } from "node:async_hooks";
16867
+ import { inspect } from "node:util";
16868
+ var EVENT = "unhandledRejection";
16869
+ var BOUNDARY_KEY = Symbol.for("atomic-workflows/run-rejection-boundary@5");
16870
+ var FLAG = "--unhandled-rejections";
16871
+ var MAX_CAUSE_DEPTH2 = 8;
16872
+ var MAX_PRIMITIVES_PER_RUN = 64;
16873
+ var MAX_STOP_STRINGS = 64;
16874
+ var ENDED_RUN_GRACE_MS = 30000;
16875
+ var NATIVE_REPORTING_MODES = new Set(["throw", "warn-with-error-code"]);
16876
+ function boundaryBag() {
16877
+ return globalThis;
16878
+ }
16879
+ function sharedBoundary() {
16880
+ const bag = boundaryBag();
16881
+ const existing = bag[BOUNDARY_KEY];
16882
+ if (existing !== undefined && existing.version === 5)
16883
+ return existing;
16884
+ const created = {
16885
+ version: 5,
16886
+ store: new AsyncLocalStorage3,
16887
+ owners: new WeakMap,
16888
+ promises: new WeakMap,
16889
+ scopes: new Set,
16890
+ runs: new Map,
16891
+ ended: new Map,
16892
+ stops: new Set,
16893
+ listener: undefined
16894
+ };
16895
+ bag[BOUNDARY_KEY] = created;
16896
+ return created;
16897
+ }
16898
+ function isObject(value) {
16899
+ return typeof value === "object" && value !== null || typeof value === "function";
16900
+ }
16901
+ function isPrimitive(value) {
16902
+ return !isObject(value);
16903
+ }
16904
+ function safeField3(value, key) {
16905
+ try {
16906
+ return value[key];
16907
+ } catch {
16908
+ return;
16909
+ }
16910
+ }
16911
+ function strongerEffect(left, right) {
16912
+ return left === "fail-run" || right === "fail-run" ? "fail-run" : "ignore";
16913
+ }
16914
+ function addAttribution(into, scope, effect) {
16915
+ into.set(scope, strongerEffect(into.get(scope), effect));
16916
+ }
16917
+ function recordedOwners(boundary, reason) {
16918
+ const owners = new Map;
16919
+ let stopped = false;
16920
+ const seen = new Set;
16921
+ const pending = [{ value: reason, depth: 0 }];
16922
+ while (pending.length > 0) {
16923
+ const { value, depth } = pending.pop();
16924
+ if (depth > MAX_CAUSE_DEPTH2)
16925
+ continue;
16926
+ if (isPrimitive(value)) {
16927
+ if (depth === 0 || value !== undefined && value !== null) {
16928
+ for (const scope of boundary.scopes) {
16929
+ const entry = scope.primitives.get(value);
16930
+ if (entry !== undefined)
16931
+ addAttribution(owners, scope, entry.effect);
16932
+ }
16933
+ if (typeof value === "string" && boundary.stops.has(value))
16934
+ stopped = true;
16935
+ }
16936
+ continue;
16937
+ }
16938
+ if (seen.has(value))
16939
+ continue;
16940
+ seen.add(value);
16941
+ for (const [scope, effect] of boundary.owners.get(value) ?? [])
16942
+ addAttribution(owners, scope, effect);
16943
+ pending.push({ value: safeField3(value, "cause"), depth: depth + 1 });
16944
+ const errors = safeField3(value, "errors");
16945
+ if (Array.isArray(errors))
16946
+ for (const entry of errors)
16947
+ pending.push({ value: entry, depth: depth + 1 });
16948
+ }
16949
+ return { owners, stopped };
16950
+ }
16951
+ function pruneEndedSources(boundary) {
16952
+ const now = Date.now();
16953
+ for (const [source, trees] of boundary.ended) {
16954
+ for (const [rootRunId, endedAt] of trees)
16955
+ if (now - endedAt > ENDED_RUN_GRACE_MS)
16956
+ trees.delete(rootRunId);
16957
+ if (trees.size === 0)
16958
+ boundary.ended.delete(source);
16959
+ }
16960
+ }
16961
+ function recordEndedRun(boundary, scope) {
16962
+ if (scope.source === undefined)
16963
+ return;
16964
+ const trees = boundary.ended.get(scope.source) ?? new Map;
16965
+ trees.set(scope.rootRunId, Date.now());
16966
+ boundary.ended.set(scope.source, trees);
16967
+ }
16968
+ function endedInAnotherRunTree(boundary, source, live) {
16969
+ for (const endedRoot of boundary.ended.get(source)?.keys() ?? [])
16970
+ if (endedRoot !== live.rootRunId)
16971
+ return true;
16972
+ return false;
16973
+ }
16974
+ function recognizedSources(boundary) {
16975
+ pruneEndedSources(boundary);
16976
+ const sources = new Set(boundary.ended.keys());
16977
+ for (const scope of boundary.scopes)
16978
+ if (scope.live && scope.source !== undefined)
16979
+ sources.add(scope.source);
16980
+ return sources;
16981
+ }
16982
+ function authoringSource(reason, sources) {
16983
+ if (sources.size === 0 || !isObject(reason))
16984
+ return;
16985
+ const stack = safeField3(reason, "stack");
16986
+ if (typeof stack !== "string")
16987
+ return;
16988
+ for (const line of stack.split(`
16989
+ `)) {
16990
+ if (!line.trimStart().startsWith("at "))
16991
+ continue;
16992
+ const path = parsePromptStackFrame(line)?.normalizedPath;
16993
+ if (path === undefined)
16994
+ continue;
16995
+ if (isWorkflowRuntimeModule(path))
16996
+ return;
16997
+ if (/\/node_modules\//.test(path))
16998
+ continue;
16999
+ if (sources.has(path))
17000
+ return path;
17001
+ }
17002
+ return;
17003
+ }
17004
+ function hasAncestorIn(scope, candidates) {
17005
+ for (let ancestor = scope.parent;ancestor !== undefined; ancestor = ancestor.parent) {
17006
+ if (candidates.has(ancestor))
17007
+ return true;
17008
+ }
17009
+ return false;
17010
+ }
17011
+ function outermostLiveRuns(boundary, source) {
17012
+ const matching = new Set;
17013
+ for (const scope of boundary.scopes)
17014
+ if (scope.live && scope.source === source)
17015
+ matching.add(scope);
17016
+ const outermost = new Set;
17017
+ for (const scope of matching)
17018
+ if (!hasAncestorIn(scope, matching))
17019
+ outermost.add(scope);
17020
+ return outermost;
17021
+ }
17022
+ function runOfSource(boundary, source) {
17023
+ const [only, ...others] = outermostLiveRuns(boundary, source);
17024
+ if (only === undefined)
17025
+ return new Map;
17026
+ if (others.length > 0 || only.sharedSource)
17027
+ return;
17028
+ if (endedInAnotherRunTree(boundary, source, only))
17029
+ return;
17030
+ return new Map([[only, "fail-run"]]);
17031
+ }
17032
+ function markSharedSource(boundary, source) {
17033
+ const runs = outermostLiveRuns(boundary, source);
17034
+ if (runs.size > 1)
17035
+ for (const run of runs)
17036
+ run.sharedSource = true;
17037
+ }
17038
+ function rejectingRun(boundary, recorded, promise, scoped) {
17039
+ const tracked = promise === undefined ? undefined : boundary.promises.get(promise);
17040
+ if (tracked !== undefined && recorded.has(tracked))
17041
+ return tracked;
17042
+ if (scoped !== undefined && recorded.has(scoped))
17043
+ return scoped;
17044
+ return;
17045
+ }
17046
+ function attribute(boundary, reason, promise) {
17047
+ const { owners: recorded, stopped } = recordedOwners(boundary, reason);
17048
+ const scoped = boundary.store.getStore();
17049
+ if (recorded.size > 1) {
17050
+ const rejecting = rejectingRun(boundary, recorded, promise, scoped);
17051
+ if (rejecting !== undefined)
17052
+ return new Map([[rejecting, recorded.get(rejecting) ?? "fail-run"]]);
17053
+ }
17054
+ if (recorded.size > 0)
17055
+ return recorded;
17056
+ if (stopped)
17057
+ return new Map;
17058
+ if (scoped !== undefined && boundary.scopes.has(scoped))
17059
+ return new Map([[scoped, "fail-run"]]);
17060
+ const origin = authoringSource(reason, recognizedSources(boundary));
17061
+ if (origin === undefined)
17062
+ return;
17063
+ if (scoped !== undefined)
17064
+ return new Map([[scoped, "ignore"]]);
17065
+ return runOfSource(boundary, origin);
17066
+ }
17067
+ function unhandledRejectionError(reason) {
17068
+ 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" });
17069
+ }
17070
+ function unhandledRejectionsMode() {
17071
+ const args = [...(process.env.NODE_OPTIONS ?? "").split(/\s+/), ...process.execArgv];
17072
+ let mode = "throw";
17073
+ for (let index = 0;index < args.length; index += 1) {
17074
+ const arg = args[index] ?? "";
17075
+ if (arg.startsWith(`${FLAG}=`))
17076
+ mode = arg.slice(FLAG.length + 1);
17077
+ else if (arg === FLAG && args[index + 1] !== undefined)
17078
+ mode = args[index + 1] ?? mode;
17079
+ }
17080
+ return mode;
17081
+ }
17082
+ function surfaceNatively(boundary, reason) {
17083
+ const listener = boundary.listener;
17084
+ if (listener === undefined || process.listenerCount(EVENT) > 1)
17085
+ return;
17086
+ if (!NATIVE_REPORTING_MODES.has(unhandledRejectionsMode()))
17087
+ return;
17088
+ process.nextTick(() => {
17089
+ process.removeListener(EVENT, listener);
17090
+ Promise.reject(reason);
17091
+ setImmediate(() => {
17092
+ if (!process.listeners(EVENT).includes(listener))
17093
+ process.on(EVENT, listener);
17094
+ });
17095
+ });
17096
+ }
17097
+ function onUnhandledRejection(reason, promise) {
17098
+ const boundary = sharedBoundary();
17099
+ const owners = attribute(boundary, reason, promise);
17100
+ if (owners === undefined) {
17101
+ surfaceNatively(boundary, reason);
17102
+ return;
17103
+ }
17104
+ const error = isObject(reason) ? reason : unhandledRejectionError(reason);
17105
+ for (const [scope, effect] of owners) {
17106
+ if (effect !== "fail-run" || !scope.live)
17107
+ continue;
17108
+ try {
17109
+ scope.fail(error);
17110
+ } catch {}
17111
+ }
17112
+ }
17113
+ function ensureInstalled(boundary) {
17114
+ if (boundary.listener !== undefined)
17115
+ return;
17116
+ boundary.listener = onUnhandledRejection;
17117
+ process.on(EVENT, onUnhandledRejection);
17118
+ }
17119
+ function record(boundary, scope, reason, effect) {
17120
+ if (isPrimitive(reason)) {
17121
+ recordPrimitive(scope, reason, effect);
17122
+ return;
17123
+ }
17124
+ const owners = boundary.owners.get(reason);
17125
+ if (owners === undefined)
17126
+ boundary.owners.set(reason, new Map([[scope, effect]]));
17127
+ else
17128
+ addAttribution(owners, scope, effect);
17129
+ }
17130
+ function recordStop(boundary, reason) {
17131
+ boundary.stops.delete(reason);
17132
+ boundary.stops.add(reason);
17133
+ if (boundary.stops.size <= MAX_STOP_STRINGS)
17134
+ return;
17135
+ const oldest = boundary.stops.values().next();
17136
+ if (!oldest.done)
17137
+ boundary.stops.delete(oldest.value);
17138
+ }
17139
+ function recordPrimitive(scope, reason, effect) {
17140
+ if (!scope.live)
17141
+ return;
17142
+ if (scope.primitives.size >= MAX_PRIMITIVES_PER_RUN && !scope.primitives.has(reason)) {
17143
+ const oldest = scope.primitives.keys().next();
17144
+ if (!oldest.done)
17145
+ scope.primitives.delete(oldest.value);
17146
+ }
17147
+ scope.generation += 1;
17148
+ const generation = scope.generation;
17149
+ scope.primitives.set(reason, { effect: strongerEffect(scope.primitives.get(reason)?.effect, effect), generation });
17150
+ afterPendingRejectionReports().then(() => {
17151
+ if (scope.primitives.get(reason)?.generation === generation)
17152
+ scope.primitives.delete(reason);
17153
+ });
17154
+ }
17155
+ function discardFailure() {}
17156
+ function afterPendingRejectionReports() {
17157
+ return new Promise((resolve) => {
17158
+ const { port1, port2 } = new MessageChannel;
17159
+ port1.onmessage = () => {
17160
+ port1.close();
17161
+ port2.close();
17162
+ resolve();
17163
+ };
17164
+ port2.postMessage(undefined);
17165
+ });
17166
+ }
17167
+ function openRunRejectionScope(options) {
17168
+ const boundary = sharedBoundary();
17169
+ ensureInstalled(boundary);
17170
+ pruneEndedSources(boundary);
17171
+ const parent = options.parentRunId === undefined ? undefined : boundary.runs.get(options.parentRunId);
17172
+ const scope = {
17173
+ runId: options.runId,
17174
+ rootRunId: parent?.rootRunId ?? options.runId,
17175
+ source: options.source === undefined ? undefined : normalizeStackPath(options.source),
17176
+ parent,
17177
+ fail: options.fail,
17178
+ primitives: new Map,
17179
+ generation: 0,
17180
+ live: true,
17181
+ sharedSource: false
17182
+ };
17183
+ boundary.scopes.add(scope);
17184
+ boundary.runs.set(scope.runId, scope);
17185
+ if (scope.source !== undefined)
17186
+ markSharedSource(boundary, scope.source);
17187
+ return {
17188
+ run: (callback) => boundary.store.run(scope, callback),
17189
+ contain: (promise, effect = "fail-run") => {
17190
+ boundary.promises.set(promise, scope);
17191
+ promise.then(undefined, (reason) => record(boundary, scope, reason, effect));
17192
+ return promise;
17193
+ },
17194
+ watch: (promise) => {
17195
+ const watched = promise.then(undefined, (reason) => {
17196
+ record(boundary, scope, reason, "fail-run");
17197
+ throw reason;
17198
+ });
17199
+ boundary.promises.set(watched, scope);
17200
+ return watched;
17201
+ },
17202
+ ignore: (reason) => {
17203
+ if (typeof reason === "string")
17204
+ recordStop(boundary, reason);
17205
+ else
17206
+ record(boundary, scope, reason, "ignore");
17207
+ },
17208
+ settle: afterPendingRejectionReports,
17209
+ close: () => {
17210
+ scope.live = false;
17211
+ scope.fail = discardFailure;
17212
+ recordEndedRun(boundary, scope);
17213
+ afterPendingRejectionReports().then(() => {
17214
+ scope.primitives.clear();
17215
+ scope.parent = undefined;
17216
+ boundary.scopes.delete(scope);
17217
+ if (boundary.runs.get(scope.runId) === scope)
17218
+ boundary.runs.delete(scope.runId);
17219
+ });
17220
+ }
17221
+ };
17222
+ }
17223
+ var WATCHED_STAGE_METHODS = [
17224
+ "prompt",
17225
+ "complete",
17226
+ "sendUserMessage",
17227
+ "steer",
17228
+ "followUp",
17229
+ "setModel",
17230
+ "setThinkingLevel",
17231
+ "cycleModel",
17232
+ "cycleThinkingLevel",
17233
+ "navigateTree",
17234
+ "compact",
17235
+ "abort"
17236
+ ];
17237
+ function containStageRejections(stage, scope) {
17238
+ const contained = Object.create(stage);
17239
+ const descriptors = {};
17240
+ for (const name of WATCHED_STAGE_METHODS) {
17241
+ descriptors[name] = {
17242
+ value: (...args) => {
17243
+ const result = Reflect.apply(stage[name], stage, args);
17244
+ return result instanceof Promise ? scope.watch(result) : result;
17245
+ }
17246
+ };
17247
+ }
17248
+ Object.defineProperties(contained, descriptors);
17249
+ return contained;
17250
+ }
17251
+ function containUiRejections(ui, scope) {
17252
+ return {
17253
+ input: (prompt) => scope.watch(ui.input(prompt)),
17254
+ confirm: (message) => scope.watch(ui.confirm(message)),
17255
+ select: (message, options) => scope.watch(ui.select(message, options)),
17256
+ editor: (initial) => scope.watch(ui.editor(initial)),
17257
+ custom: (factory, options) => scope.watch(ui.custom(factory, options))
17258
+ };
17259
+ }
17260
+
16804
17261
  // dist/builtin/workflows/src/engine/run-returned-status.ts
16805
17262
  function classifyReturnedRunStatus(result, runSnapshot) {
16806
17263
  const structuredFailure = runSnapshot !== undefined ? structuredRecoverableWorkflowFailure(runSnapshot) : undefined;
@@ -22800,13 +23257,13 @@ class EngineRuntime {
22800
23257
 
22801
23258
  // dist/builtin/workflows/src/engine/session-closed-error.ts
22802
23259
  import { isStaleExtensionContextError as isStaleExtensionContextError2 } from "@bastani/atomic";
22803
- var MAX_CAUSE_DEPTH2 = 8;
23260
+ var MAX_CAUSE_DEPTH3 = 8;
22804
23261
  function reportsClosedSession(error) {
22805
23262
  return "code" in error && error.code === "SessionClosed" || isStaleExtensionContextError2(error);
22806
23263
  }
22807
23264
  function isSessionClosedError(error) {
22808
23265
  let current = error;
22809
- for (let depth = 0;depth < MAX_CAUSE_DEPTH2 && current !== undefined; depth++) {
23266
+ for (let depth = 0;depth < MAX_CAUSE_DEPTH3 && current !== undefined; depth++) {
22810
23267
  try {
22811
23268
  if (reportsClosedSession(current))
22812
23269
  return true;
@@ -22878,7 +23335,12 @@ async function executeRun(def, resolvedInputs, opts) {
22878
23335
  workflowObservationRuntime(activeStore).control(runId, "kill");
22879
23336
  ownController.abort(callerSignal?.reason);
22880
23337
  };
22881
- const exit = createWorkflowExitManager({ runId, exitScope, controller: ownController });
23338
+ const exit = createWorkflowExitManager({
23339
+ runId,
23340
+ exitScope,
23341
+ controller: ownController,
23342
+ onExitSelected: (signal) => rejectionScope.ignore(signal)
23343
+ });
22882
23344
  const sourceBackend = opts.durableBackend;
22883
23345
  const backendView = sourceBackend;
22884
23346
  const rootBackend = opts.durableRootBackend ?? backendView;
@@ -23392,6 +23854,22 @@ async function executeRun(def, resolvedInputs, opts) {
23392
23854
  baseFromPromptNodes: getPromptNodeUi
23393
23855
  });
23394
23856
  let pausedExit;
23857
+ const authoredIn = workflowSource(def);
23858
+ const rejectionScope = openRunRejectionScope({
23859
+ runId,
23860
+ ...opts.parentRun !== undefined ? { parentRunId: opts.parentRun.runId } : {},
23861
+ ...authoredIn !== undefined ? { source: authoredIn } : {},
23862
+ fail: (error) => {
23863
+ if (findWorkflowGracefulQuit(error) !== undefined)
23864
+ return;
23865
+ const selected = terminalEvents.selectFailure(error);
23866
+ if (selected.kind === "failure" && !ownController.signal.aborted)
23867
+ ownController.abort(selected.error);
23868
+ }
23869
+ });
23870
+ ownController.signal.addEventListener("abort", () => rejectionScope.ignore(ownController.signal.reason), {
23871
+ once: true
23872
+ });
23395
23873
  const ctx = {
23396
23874
  inputs: resolvedInputs,
23397
23875
  runId,
@@ -23402,28 +23880,30 @@ async function executeRun(def, resolvedInputs, opts) {
23402
23880
  if (scheduler.isRunPaused()) {
23403
23881
  pausedExit ??= whenRunning(async () => exit.exit(options));
23404
23882
  pausedExit.catch(() => {});
23405
- throw new Error("Workflow exit is waiting for explicit resume");
23883
+ const waiting = new Error("Workflow exit is waiting for explicit resume");
23884
+ rejectionScope.ignore(waiting);
23885
+ throw waiting;
23406
23886
  }
23407
23887
  return exit.exit(options);
23408
23888
  },
23409
- ui,
23889
+ ui: containUiRejections(ui, rejectionScope),
23410
23890
  stage: (name, options) => {
23411
23891
  ownController.signal.throwIfAborted();
23412
23892
  if (!scheduler.isRunPaused())
23413
- return durableStage(name, options);
23893
+ return containStageRejections(durableStage(name, options), rejectionScope);
23414
23894
  const replayKey = stageReplayKeyGenerator(name);
23415
- return deferStageUntilRunRelease({
23895
+ return containStageRejections(deferStageUntilRunRelease({
23416
23896
  name,
23417
23897
  create: () => durableStage(name, options, replayKey),
23418
23898
  isPaused: scheduler.isRunPaused,
23419
23899
  waitForRelease: waitForRunRelease,
23420
23900
  signal: ownController.signal
23421
- });
23901
+ }), rejectionScope);
23422
23902
  },
23423
- task: gatedTask,
23424
- chain: (...args) => whenRunning(() => chain(...args)),
23425
- parallel: (...args) => whenRunning(() => parallel(...args)),
23426
- workflow: (...args) => whenRunning(() => {
23903
+ task: (...args) => rejectionScope.watch(gatedTask(...args)),
23904
+ chain: (...args) => rejectionScope.watch(whenRunning(() => chain(...args))),
23905
+ parallel: (...args) => rejectionScope.watch(whenRunning(() => parallel(...args))),
23906
+ workflow: (...args) => rejectionScope.watch(whenRunning(() => {
23427
23907
  const pending = durableWorkflow(...args);
23428
23908
  pendingChildWorkflows.add(pending);
23429
23909
  const settled = () => {
@@ -23431,13 +23911,11 @@ async function executeRun(def, resolvedInputs, opts) {
23431
23911
  };
23432
23912
  pending.then(settled, settled);
23433
23913
  return pending;
23434
- }),
23914
+ })),
23435
23915
  tool: (...args) => {
23436
23916
  if (admittedTools.closed)
23437
- return tool(...args);
23438
- const pending = whenRunning(() => tool(...args));
23439
- pending.catch(() => {});
23440
- return pending;
23917
+ return rejectionScope.contain(tool(...args), "ignore");
23918
+ return rejectionScope.contain(whenRunning(() => tool(...args)));
23441
23919
  },
23442
23920
  ...opts.models !== undefined ? { models: opts.models } : {}
23443
23921
  };
@@ -23589,7 +24067,7 @@ async function executeRun(def, resolvedInputs, opts) {
23589
24067
  while (scheduler.isRunPaused())
23590
24068
  await waitForRunRelease();
23591
24069
  ownController.signal.throwIfAborted();
23592
- const rawResult = await raceAbort2(runWorkflowDefinitionCallback(def.name, runId, () => def.run(ctx)), ownController.signal);
24070
+ const rawResult = await raceAbort2(runWorkflowDefinitionCallback(def.name, runId, () => rejectionScope.run(() => def.run(ctx))), ownController.signal);
23593
24071
  await drainCachedStagePersistence();
23594
24072
  while (scheduler.isRunPaused())
23595
24073
  await waitForRunRelease();
@@ -23599,6 +24077,7 @@ async function executeRun(def, resolvedInputs, opts) {
23599
24077
  if (pausedExit !== undefined)
23600
24078
  await pausedExit;
23601
24079
  budget.rethrowIfSystemOwnedStop(runSnapshot.stages.at(-1)?.name ?? startupFrontierStage);
24080
+ await rejectionScope.settle();
23602
24081
  const normalTerminalEvent = terminalEvents.winner();
23603
24082
  if (normalTerminalEvent?.kind === "cancellation") {
23604
24083
  const gracefulQuit = findWorkflowGracefulQuit(normalTerminalEvent.reason);
@@ -23668,6 +24147,9 @@ async function executeRun(def, resolvedInputs, opts) {
23668
24147
  }
23669
24148
  if (ownerClosing && err instanceof Error && isSessionClosedError(err))
23670
24149
  return await suspendForClosedSession(err);
24150
+ if (selectedTerminalEvent.kind === "failure" && pendingChildWorkflows.size > 0 && !ownController.signal.aborted) {
24151
+ ownController.abort(err);
24152
+ }
23671
24153
  await admittedTools.closeAndDrain();
23672
24154
  if (ownController.signal.aborted)
23673
24155
  await Promise.allSettled([...pendingChildWorkflows]);
@@ -23742,6 +24224,7 @@ async function executeRun(def, resolvedInputs, opts) {
23742
24224
  });
23743
24225
  return failed;
23744
24226
  } finally {
24227
+ rejectionScope.close();
23745
24228
  callerSignal?.removeEventListener("abort", onCallerAbort);
23746
24229
  workflowObservationRuntime(activeStore).finishRun(runId);
23747
24230
  runtimeSettled.resolve();