@tangle-network/agent-runtime 0.300.0 → 0.306.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.
Files changed (88) hide show
  1. package/dist/{activation-DqWmWTyB.js → activation-C5wesfzd.js} +3 -3
  2. package/dist/{activation-DqWmWTyB.js.map → activation-C5wesfzd.js.map} +1 -1
  3. package/dist/{activation-Bhp8dYV5.d.ts → activation-wZ-8vOjV.d.ts} +88 -13
  4. package/dist/agent.d.ts +2 -2
  5. package/dist/agent.js +2 -2
  6. package/dist/{bundle-C9v5TH_H.js → bundle-C8EO05u3.js} +2 -2
  7. package/dist/{bundle-C9v5TH_H.js.map → bundle-C8EO05u3.js.map} +1 -1
  8. package/dist/candidate-execution/index.d.ts +3 -26
  9. package/dist/candidate-execution/index.js +6 -6
  10. package/dist/{coordination-driver-DzTvehd6.js → coordination-driver-yj9HPXef.js} +322 -223
  11. package/dist/coordination-driver-yj9HPXef.js.map +1 -0
  12. package/dist/{delegate-vJ2g76r6.js → delegate-KtrL9HWq.js} +5 -5
  13. package/dist/delegate-KtrL9HWq.js.map +1 -0
  14. package/dist/durable.d.ts +3 -15
  15. package/dist/durable.js +158 -124
  16. package/dist/durable.js.map +1 -1
  17. package/dist/{graph-BDQh3qry.js → graph-DcdyHbgf.js} +5 -6
  18. package/dist/graph-DcdyHbgf.js.map +1 -0
  19. package/dist/{improvement-cycle-D6cPLi6k.js → improvement-cycle-DsN-TVXR.js} +1129 -10
  20. package/dist/improvement-cycle-DsN-TVXR.js.map +1 -0
  21. package/dist/{index-sC6sl88d.d.ts → index-DflDZq_I.d.ts} +188 -748
  22. package/dist/index.d.ts +378 -12
  23. package/dist/index.js +223 -320
  24. package/dist/index.js.map +1 -1
  25. package/dist/intelligence.d.ts +5 -5
  26. package/dist/intelligence.js +7 -8
  27. package/dist/intelligence.js.map +1 -1
  28. package/dist/kernel.d.ts +4 -4
  29. package/dist/kernel.js +9 -9
  30. package/dist/{loop-runner-bin-DZglq4Cf.d.ts → loop-runner-bin-DZfRUVWy.d.ts} +3 -3
  31. package/dist/{loop-runner-bin-DQIHnCL0.js → loop-runner-bin-rVrSX5l1.js} +3 -3
  32. package/dist/{loop-runner-bin-DQIHnCL0.js.map → loop-runner-bin-rVrSX5l1.js.map} +1 -1
  33. package/dist/loop-runner-bin.d.ts +1 -1
  34. package/dist/loop-runner-bin.js +1 -1
  35. package/dist/mcp/bin.js +3 -3
  36. package/dist/mcp/index.d.ts +6 -35
  37. package/dist/mcp/index.js +311 -364
  38. package/dist/mcp/index.js.map +1 -1
  39. package/dist/model-policy-DydyWTQg.js.map +1 -1
  40. package/dist/{openai-tools-DvR82zEo.d.ts → openai-tools-YO30D2s3.d.ts} +2 -2
  41. package/dist/{prepare-CGVNMb1o.js → prepare--nWcazPr.js} +7 -13
  42. package/dist/prepare--nWcazPr.js.map +1 -0
  43. package/dist/{profile-BetOB4_Q.js → profile-h04LDjV6.js} +2 -2
  44. package/dist/{profile-BetOB4_Q.js.map → profile-h04LDjV6.js.map} +1 -1
  45. package/dist/profiles.d.ts +2 -94
  46. package/dist/profiles.js +2 -451
  47. package/dist/profiles.js.map +1 -1
  48. package/dist/{protected-model-port-CAa0t1MT.d.ts → protected-model-port-C9QtEf3y.d.ts} +2 -2
  49. package/dist/{protected-model-port-CuVHkhti.js → protected-model-port-wwalbyXM.js} +4 -4
  50. package/dist/{protected-model-port-CuVHkhti.js.map → protected-model-port-wwalbyXM.js.map} +1 -1
  51. package/dist/{provision-supervisor-IXBlLHE0.js → provision-supervisor-WxFEFQeJ.js} +14 -24
  52. package/dist/provision-supervisor-WxFEFQeJ.js.map +1 -0
  53. package/dist/{runtime-DpEt5v42.js → runtime-B9eBIyws.js} +86 -496
  54. package/dist/runtime-B9eBIyws.js.map +1 -0
  55. package/dist/{search-method-DvU-fc-f.js → search-executor-2tWr38Qw.js} +239 -1132
  56. package/dist/search-executor-2tWr38Qw.js.map +1 -0
  57. package/dist/{server-CIE8s4AN.js → server-CpKcrOPj.js} +5 -12
  58. package/dist/server-CpKcrOPj.js.map +1 -0
  59. package/dist/{stream-agent-turn-I3bb0eqF.d.ts → stream-agent-turn-B1giFgOg.d.ts} +4 -2
  60. package/dist/{substrate-UjsxukjZ.d.ts → substrate-L_sC7jCD.d.ts} +2 -2
  61. package/dist/{supervise-C5mktzrh.js → supervise-DllOHM4M.js} +206 -80
  62. package/dist/supervise-DllOHM4M.js.map +1 -0
  63. package/dist/{supervisor-CQSu5XGl.js → supervisor-gCfG6K1-.js} +1130 -1667
  64. package/dist/supervisor-gCfG6K1-.js.map +1 -0
  65. package/dist/testing.d.ts +2 -2
  66. package/dist/testing.js +14 -14
  67. package/dist/tui/index.d.ts +1 -1
  68. package/dist/tui/index.js +1 -1
  69. package/dist/{types-C73caP0U.d.ts → types-DeuEkBhI.d.ts} +167 -261
  70. package/dist/{workspace-archive-pz8YJ1fr.d.ts → workspace-streams-CpSmt3zx.d.ts} +67 -3
  71. package/dist/{workspace-streams-D5gHJdTb.js → workspace-streams-ILw0eWZ0.js} +694 -2
  72. package/dist/workspace-streams-ILw0eWZ0.js.map +1 -0
  73. package/package.json +8 -8
  74. package/skills/generate-eval/SKILL.md +1 -1
  75. package/skills/profile-authoring/SKILL.md +5 -5
  76. package/skills/supervise/SKILL.md +2 -2
  77. package/dist/coordination-driver-DzTvehd6.js.map +0 -1
  78. package/dist/delegate-vJ2g76r6.js.map +0 -1
  79. package/dist/graph-BDQh3qry.js.map +0 -1
  80. package/dist/improvement-cycle-D6cPLi6k.js.map +0 -1
  81. package/dist/prepare-CGVNMb1o.js.map +0 -1
  82. package/dist/provision-supervisor-IXBlLHE0.js.map +0 -1
  83. package/dist/runtime-DpEt5v42.js.map +0 -1
  84. package/dist/search-method-DvU-fc-f.js.map +0 -1
  85. package/dist/server-CIE8s4AN.js.map +0 -1
  86. package/dist/supervise-C5mktzrh.js.map +0 -1
  87. package/dist/supervisor-CQSu5XGl.js.map +0 -1
  88. package/dist/workspace-streams-D5gHJdTb.js.map +0 -1
@@ -1,10 +1,10 @@
1
1
  import { c as RetainedInteractiveAdmissionError, d as RetainedRunDispatchBindingError, f as RuntimeRunStateError, i as ConfigError, l as RetainedInteractiveBindingError, m as ValidationError$1, r as BackendTransportError, t as AgentEvalError$1, u as RetainedRunAdmissionError } from "./errors-DodWX-cb.js";
2
+ import { $ as randomUuid, B as addTokenUsage, G as errorMessage, H as cloneSpend, K as fnv1a32Hex, N as deepFreezeCandidate, O as verifyWorkspaceSnapshotArtifacts, Q as randomSuffix, U as cloneTokenUsage, V as chargedTokens, W as deleteBoxSafe, X as mapWithConcurrency, Y as isAsyncIterable$1, Z as promptCacheTokenClasses, _t as armDeadlineTimer, a as verifyAgentCandidateWorkspaceArtifacts, at as unmeteredSpend, bt as singleFlightTeardown, ct as zeroTokenUsage, dt as resourceTelemetry, et as roundBoxMinutes, ft as withBudgetResources, gt as ROOT_DEADLINE_REASON, i as readAgentCandidateWorkspaceArtifactFiles, it as throwIfAborted, k as verifiedArtifactChunks, lt as addResourceSpend, mt as CHILD_DEADLINE_REASON, nt as stringifySafe, o as verifyAgentCandidateWorkspaceTree, ot as withTimeout, pt as ACCEPTED_RESULT_GRACE_MS, q as hasCompleteCacheBreakdown, rt as throwAbort, st as zeroSpend, tt as sleep, u as verifyAgentCandidateWorkspaceArchive, ut as assertResources, vt as boundedChildDeadlineAt, xt as teardownExecutor, yt as isDeadlineAbortReason, z as addSpend } from "./workspace-streams-ILw0eWZ0.js";
2
3
  import { runTaskQueue } from "./task-queue.js";
3
4
  import { _ as agentHarness, a as concreteProfileModel, c as profileModelExecutionSettings, d as assertRouterAutoDeclaration, f as assertRouterAutoResponse, g as observedModelMatchesDeclared, h as observedModelHasSnapshot, l as profileProviderModel, m as mergeObservedModelIdentity, o as enforceTokenLimits, s as profileBridgeWireModel, t as assertExecutableAgentProfile, u as resolveRouterRetryPolicy } from "./model-policy-DydyWTQg.js";
4
- import { D as verifiedArtifactChunks, E as verifyWorkspaceSnapshotArtifacts, c as verifyAgentCandidateWorkspaceArchive, i as verifyAgentCandidateWorkspaceArtifacts, j as deepFreezeCandidate, r as readAgentCandidateWorkspaceArtifactFiles } from "./workspace-streams-D5gHJdTb.js";
5
5
  import { n as assertNoSymlinkDescendant, r as publishExclusiveDurableFile } from "./durable-file-DWQA4ooo.js";
6
6
  import { i as notifyRuntimeHookEvent } from "./runtime-hooks-tXpAarhW.js";
7
- import { AGENT_PROFILE_MATERIALIZATION_AXES, AgentEnvironmentCapabilitiesSchema, AgentExactRunControlRefSchema, AgentInteractiveSessionControlClaimAcknowledgementSchema, AgentInteractiveSessionControlClaimSchema, AgentInteractiveSessionPromptAcknowledgementSchema, AgentInteractiveSessionRefSchema, AgentInteractiveSessionStatusSchema, AgentInteractiveSessionStopAcknowledgementSchema, AgentNativeContextContinuationResultSchema, AgentRunCancellationAcknowledgementSchema, AgentRunCancellationRequestSchema, AgentTurnInputSchema, AgentTurnResultSchema, CanonicalStreamEventSchema, ContextTransferRequestSchema, InteractionAcknowledgementSchema, InteractionResponseCommandSchema, NativeContextBoundaryProofSchema, NativeContextContinuationRequestSchema, REASONING_EFFORTS, RuntimeEventEnvelopeSchema, TerminalReplayWindowSchema, TerminalSessionRefSchema, agentCandidateArtifactRefSchema, agentCandidateWorkspaceManifestMaterialSchema, agentCandidateWorkspaceSnapshotEvidenceSchema, agentInteractiveSessionControlClaimAcknowledgementMatchesRequest, agentInteractiveSessionControlClaimMatchesRef, agentInteractiveSessionPromptAcknowledgementMatchesCommand, agentInteractiveSessionRefMatchesStart, agentInteractiveSessionRunRef, agentInteractiveSessionStatusMatchesRef, agentInteractiveSessionStopAcknowledgementMatchesCommand, agentNativeContextContinuationResultMatchesRequest, agentProfileSchema, agentRunCancellationAcknowledgementMatchesRequest, agentRunCancellationRequestDigest, canonicalAgentProfileDigest, canonicalCandidateDigest, canonicalWorkspaceCwd, exactAgentInteractiveSessionStart, harnessTypeSchema, nativeContextContinuationTurnDigest, nativeReasoningControl, profileMaterializationAxes, profileMaterializationAxes as profileMaterializationAxes$1, renderInputPartsAsText, sha256DigestSchema, workspaceCheckpointRequestDigest, workspaceCheckpointResultMatchesRequest, workspaceCleanupAcknowledgementMatches, workspaceCleanupRequestDigest } from "@tangle-network/agent-interface";
7
+ import { AGENT_PROFILE_MATERIALIZATION_AXES, AgentEnvironmentCapabilitiesSchema, AgentExactRunControlRefSchema, AgentInteractiveSessionControlClaimAcknowledgementSchema, AgentInteractiveSessionControlClaimSchema, AgentInteractiveSessionPromptAcknowledgementSchema, AgentInteractiveSessionRefSchema, AgentInteractiveSessionStatusSchema, AgentInteractiveSessionStopAcknowledgementSchema, AgentNativeContextContinuationResultSchema, AgentRunCancellationAcknowledgementSchema, AgentRunCancellationRequestSchema, AgentTurnInputSchema, AgentTurnResultSchema, CanonicalStreamEventSchema, ContextTransferRequestSchema, InteractionAcknowledgementSchema, InteractionResponseCommandSchema, NativeContextBoundaryProofSchema, NativeContextContinuationRequestSchema, REASONING_EFFORTS, RuntimeEventEnvelopeSchema, TerminalReplayWindowSchema, TerminalSessionRefSchema, agentCandidateArtifactRefSchema, agentCandidateWorkspaceManifestMaterialSchema, agentCandidateWorkspaceSnapshotEvidenceSchema, agentInteractiveSessionControlClaimAcknowledgementMatchesRequest, agentInteractiveSessionControlClaimMatchesRef, agentInteractiveSessionPromptAcknowledgementMatchesCommand, agentInteractiveSessionRefMatchesStart, agentInteractiveSessionRunRef, agentInteractiveSessionStatusMatchesRef, agentInteractiveSessionStopAcknowledgementMatchesCommand, agentNativeContextContinuationResultMatchesRequest, agentProfileSchema, agentRunCancellationAcknowledgementMatchesRequest, agentRunCancellationRequestDigest, canonicalAgentProfileDigest, canonicalCandidateDigest, canonicalWorkspaceCwd, exactAgentInteractiveSessionStart, harnessTypeSchema, nativeContextContinuationTurnDigest, nativeReasoningControl, profileMaterializationAxes, profileMaterializationAxes as profileMaterializationAxes$1, renderInputPartsAsText, sha256DigestSchema, workspaceCheckpointRequestDigest, workspaceCheckpointResultMatchesRequest, workspaceCleanupAcknowledgementMatches, workspaceCleanupRequestDigest, workspaceForkRequestDigest, workspaceForkResultMatchesRequest } from "@tangle-network/agent-interface";
8
8
  import { estimateCost, isModelPriced, isToolSpan, toolSpansToTraceAnalysisStore } from "@tangle-network/agent-eval";
9
9
  import { createAgentRunOutcomeTracker } from "@tangle-network/sandbox/runtime";
10
10
  import { createHash, randomBytes, randomUUID } from "node:crypto";
@@ -102,123 +102,6 @@ function promptPartFromInputPart(part) {
102
102
  };
103
103
  }
104
104
  //#endregion
105
- //#region src/runtime/supervise/deadline.ts
106
- const MAX_TIMER_DELAY_MS = 2147483647;
107
- const DEFAULT_SUCCESSFUL_SHUTDOWN_MS = 5e3;
108
- /** The abort reason a child's own deadline carries. */
109
- const CHILD_DEADLINE_REASON = "child deadline exceeded";
110
- /** The abort reason the root's budget deadline cascades to every node. */
111
- const ROOT_DEADLINE_REASON = "root budget deadline exceeded";
112
- /** Whether an abort reason is a deadline: the child's own or the root budget's. */
113
- function isDeadlineAbortReason(reason) {
114
- return reason === "child deadline exceeded" || reason === "root budget deadline exceeded";
115
- }
116
- const TEARDOWN_ACKNOWLEDGEMENT_MS = 250;
117
- /** Arm a finite wall-clock deadline in safe chunks. Resource deadlines unref by default;
118
- * a standalone wait opts into keeping the process alive until it settles or is cancelled. */
119
- function armDeadlineTimer(delayMs, onDeadline, keepAlive = false) {
120
- const deadlineAtMs = Date.now() + Math.max(0, delayMs);
121
- if (!Number.isFinite(delayMs) || !Number.isSafeInteger(Math.ceil(deadlineAtMs))) throw new ValidationError$1("timer delay must produce a finite safe deadline");
122
- let cleared = false;
123
- let timer;
124
- const arm = () => {
125
- if (cleared) return;
126
- const remainingMs = Math.max(0, deadlineAtMs - Date.now());
127
- timer = setTimeout(() => {
128
- if (cleared) return;
129
- if (Date.now() >= deadlineAtMs) onDeadline();
130
- else arm();
131
- }, Math.min(remainingMs, MAX_TIMER_DELAY_MS));
132
- if (!keepAlive && typeof timer.unref === "function") timer.unref();
133
- };
134
- arm();
135
- return () => {
136
- cleared = true;
137
- if (timer !== void 0) clearTimeout(timer);
138
- };
139
- }
140
- /**
141
- * Resolve a spawned child's duration into one absolute cutoff. An omitted child deadline inherits
142
- * the parent cutoff; an explicit child duration may shorten, but never extend, that cutoff.
143
- */
144
- function boundedChildDeadlineAt(parentDeadlineAtMs, childDeadlineMs, nowMs) {
145
- const parent = parentDeadlineAtMs > 0 ? parentDeadlineAtMs : void 0;
146
- const child = childDeadlineMs === void 0 ? void 0 : nowMs + childDeadlineMs;
147
- if (parent === void 0) return child;
148
- if (child === void 0) return parent;
149
- return Math.min(parent, child);
150
- }
151
- /** Invoke teardown once and bound how long the runtime waits for its acknowledgement. A hard
152
- * execution deadline always wins; without one, numeric grace gets a short acknowledgement
153
- * allowance and a brutal kill gets only that allowance. Explicit `infinity` remains unbounded
154
- * only when no execution deadline exists. The losing promise stays observed. `ask` issues the
155
- * request; a scope passes its per-child single-flight asker (see `singleFlightTeardown`). */
156
- async function teardownExecutor(executor, grace, deadlineAtMs, now, ask = (requested) => Promise.resolve(executor.teardown(requested))) {
157
- const work = Promise.resolve(ask(grace));
158
- const requestedWaitMs = grace === "infinity" ? void 0 : grace === "brutalKill" ? executor.teardownTimeoutMs ?? TEARDOWN_ACKNOWLEDGEMENT_MS : grace + TEARDOWN_ACKNOWLEDGEMENT_MS;
159
- const deadlineWaitMs = deadlineAtMs === void 0 ? void 0 : Math.max(0, deadlineAtMs - now()) + TEARDOWN_ACKNOWLEDGEMENT_MS;
160
- const waitMs = requestedWaitMs === void 0 ? deadlineWaitMs : deadlineWaitMs === void 0 ? requestedWaitMs : Math.min(requestedWaitMs, deadlineWaitMs);
161
- let receipt;
162
- if (waitMs === void 0) receipt = await work;
163
- else if (waitMs <= 0) {
164
- work.catch(() => void 0);
165
- throw new ValidationError$1("executor teardown did not acknowledge before its deadline");
166
- } else {
167
- let clearTimer;
168
- const timedOut = new Promise((_resolve, reject) => {
169
- clearTimer = armDeadlineTimer(waitMs, () => reject(new ValidationError$1(`executor teardown did not acknowledge within ${waitMs}ms`)), true);
170
- });
171
- try {
172
- receipt = await Promise.race([work, timedOut]);
173
- } finally {
174
- clearTimer?.();
175
- }
176
- }
177
- if (!receipt.destroyed) throw new ValidationError$1(`executor teardown reported destroyed=false${receipt.detail ? `: ${receipt.detail}` : ""}`);
178
- }
179
- /**
180
- * The optional teardown surfaces a wrapping executor forwards, so wrapping never changes how a
181
- * child is released: the acknowledgement window a remote teardown needs, the release of a
182
- * retained execution at root settlement, and the environments an unconfirmed teardown names for
183
- * a sweeper. A wrapper that dropped `releaseRetained` left every retained child it wrapped
184
- * running after settlement. Each surface is present only when the inner executor implements it.
185
- */
186
- function teardownSurfaces(inner) {
187
- return {
188
- ...inner.teardownTimeoutMs === void 0 ? {} : { teardownTimeoutMs: inner.teardownTimeoutMs },
189
- ...inner.releaseRetained === void 0 ? {} : { releaseRetained: (signal) => inner.releaseRetained(signal) },
190
- ...inner.heldEnvironments === void 0 ? {} : { heldEnvironments: () => inner.heldEnvironments() }
191
- };
192
- }
193
- /**
194
- * An asker that sends an executor at most one teardown at a time. While a request is still
195
- * running, every later ask returns that same request instead of sending another beside it.
196
- *
197
- * A settlement's own teardown has a short acknowledgement window, and a request that misses it
198
- * keeps running. Without this, the first settlement retry sent a second teardown next to the
199
- * first. An executor that does not deduplicate internally, such as one that re-issues its
200
- * cancels, then ran two teardowns at once. `onRequest` runs once for each request actually sent.
201
- */
202
- function singleFlightTeardown(executor, onRequest) {
203
- let inFlight;
204
- return (grace) => {
205
- if (inFlight !== void 0) return inFlight;
206
- onRequest();
207
- let request;
208
- try {
209
- request = Promise.resolve(executor.teardown(grace));
210
- } catch (error) {
211
- request = Promise.reject(error);
212
- }
213
- inFlight = request;
214
- const settle = () => {
215
- if (inFlight === request) inFlight = void 0;
216
- };
217
- request.then(settle, settle);
218
- return request;
219
- };
220
- }
221
- //#endregion
222
105
  //#region src/runtime/retained-run-binding.ts
223
106
  function exactSession(environment, controlRef) {
224
107
  if (environment.id !== controlRef.environmentId || environment.provider !== controlRef.provider) throw new Error("provider reconstructed a different retained environment");
@@ -315,7 +198,7 @@ async function awaitAbortable$1(work, signal) {
315
198
  if (signal === void 0) return await work;
316
199
  if (signal.aborted) {
317
200
  Promise.resolve(work).catch(() => void 0);
318
- throw abortError$2(signal.reason);
201
+ throw abortError$1(signal.reason);
319
202
  }
320
203
  return await new Promise((resolve, reject) => {
321
204
  let settled = false;
@@ -325,7 +208,7 @@ async function awaitAbortable$1(work, signal) {
325
208
  if (settled) return;
326
209
  settled = true;
327
210
  cleanup();
328
- reject(abortError$2(signal.reason));
211
+ reject(abortError$1(signal.reason));
329
212
  });
330
213
  };
331
214
  signal.addEventListener("abort", onAbort, { once: true });
@@ -382,7 +265,7 @@ function isRecord$3(value) {
382
265
  function assertStableText(value, label) {
383
266
  if (value.length === 0 || value.trim() !== value) throw new Error(`${label} must be non-empty and have no outer whitespace`);
384
267
  }
385
- function abortError$2(reason) {
268
+ function abortError$1(reason) {
386
269
  const error = new Error(reason instanceof Error ? reason.message : reason === void 0 ? "aborted" : String(reason));
387
270
  error.name = "AbortError";
388
271
  return error;
@@ -419,7 +302,7 @@ function isTerminalSessionStatus(status) {
419
302
  return status !== null && sessionStatusIsTerminal[status];
420
303
  }
421
304
  function delay(ms, signal) {
422
- if (signal?.aborted) return Promise.reject(abortError$2(signal.reason));
305
+ if (signal?.aborted) return Promise.reject(abortError$1(signal.reason));
423
306
  return new Promise((resolveDelay, rejectDelay) => {
424
307
  const clearTimer = armDeadlineTimer(ms, finish, true);
425
308
  function finish() {
@@ -429,7 +312,7 @@ function delay(ms, signal) {
429
312
  function onAbort() {
430
313
  clearTimer();
431
314
  signal?.removeEventListener("abort", onAbort);
432
- rejectDelay(abortError$2(signal?.reason));
315
+ rejectDelay(abortError$1(signal?.reason));
433
316
  }
434
317
  signal?.addEventListener("abort", onAbort, { once: true });
435
318
  });
@@ -654,477 +537,6 @@ function isRecord$2(value) {
654
537
  return typeof value === "object" && value !== null && !Array.isArray(value);
655
538
  }
656
539
  //#endregion
657
- //#region src/runtime/supervise/resources.ts
658
- /** Validate caller-owned names and units without assigning domain meaning to them. */
659
- function assertResources(resources, kind, label) {
660
- if (resources === void 0) return;
661
- if (resources === null || typeof resources !== "object" || Array.isArray(resources)) throw new Error(`${label} must be a resource map`);
662
- for (const [name, resource] of Object.entries(resources)) {
663
- if (!name.trim() || !resource || typeof resource !== "object" || typeof resource.unit !== "string" || !resource.unit.trim()) throw new Error(`${label}: resource names and units must be non-empty strings`);
664
- const value = kind === "limit" ? "limit" in resource ? resource.limit : void 0 : "amount" in resource ? resource.amount : void 0;
665
- if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw new Error(`${label}.${name}.${kind} must be a non-negative safe integer`);
666
- if (kind === "amount" && (!("known" in resource) || typeof resource.known !== "boolean")) throw new Error(`${label}.${name}.known must be a boolean`);
667
- }
668
- }
669
- /** Missing contributors are not usage claims; enforced omissions are marked before aggregation.
670
- * Overflow retains a safe lower bound and marks it unknown, preserving readable component receipts. */
671
- function addResourceSpend(...maps) {
672
- const totals = /* @__PURE__ */ new Map();
673
- for (const resources of maps) {
674
- assertResources(resources, "amount", "resource spend");
675
- for (const [name, resource] of Object.entries(resources ?? {})) {
676
- const prior = totals.get(name);
677
- if (prior && prior.unit !== resource.unit) throw new Error(`resource ${name}: unit mismatch`);
678
- const amount = (prior?.amount ?? 0) + resource.amount;
679
- totals.set(name, {
680
- unit: resource.unit,
681
- amount: Math.min(amount, Number.MAX_SAFE_INTEGER),
682
- known: (prior?.known ?? true) && resource.known && Number.isSafeInteger(amount)
683
- });
684
- }
685
- }
686
- return totals.size ? { resources: Object.fromEntries(totals) } : {};
687
- }
688
- /** A terminal omission under an enforced ceiling is unknown, never measured zero. */
689
- function withBudgetResources(spend, budget, notStarted = false) {
690
- const resources = new Map(Object.entries(addResourceSpend(spend.resources).resources ?? {}));
691
- for (const [name, limit] of Object.entries(budget.resources ?? {})) {
692
- const observed = resources.get(name);
693
- if (observed && observed.unit !== limit.unit) throw new Error(`resource ${name}: unit mismatch`);
694
- if (!observed) resources.set(name, {
695
- unit: limit.unit,
696
- amount: 0,
697
- known: notStarted
698
- });
699
- }
700
- return resources.size ? {
701
- ...spend,
702
- resources: Object.fromEntries(resources)
703
- } : spend;
704
- }
705
- /** Stream increments and a terminal total describe the same work; never sum them twice. */
706
- function resourceTelemetry(streamed, terminal) {
707
- const resources = new Map(Object.entries(addResourceSpend(terminal.resources).resources ?? {}));
708
- for (const [name, value] of Object.entries(streamed.resources ?? {})) {
709
- const other = resources.get(name);
710
- if (other && other.unit !== value.unit) throw new Error(`resource ${name}: unit mismatch`);
711
- resources.set(name, {
712
- ...value,
713
- amount: Math.max(value.amount, other?.amount ?? 0),
714
- known: value.known && (other?.known ?? true) && (other === void 0 || other.amount === value.amount)
715
- });
716
- }
717
- return addResourceSpend(Object.fromEntries(resources));
718
- }
719
- //#endregion
720
- //#region src/runtime/util.ts
721
- /**
722
- * Best-effort sandbox delete. Skips instances without a `delete` (test fakes);
723
- * swallows errors (the platform reaps on expiry). Returns `false` when delete
724
- * threw, `true` otherwise, so callers can surface a leak if they choose.
725
- */
726
- async function deleteBoxSafe(box) {
727
- if (!box || typeof box.delete !== "function") return true;
728
- try {
729
- await box.delete();
730
- return true;
731
- } catch {
732
- return false;
733
- }
734
- }
735
- /** Short base36 id for trace correlation. Not cryptographic, not collision-free. */
736
- function randomSuffix(len = 8) {
737
- return Math.random().toString(36).slice(2, 2 + len);
738
- }
739
- /** Collision-resistant id for sandbox naming (find-by-name recovery must be unique). */
740
- function randomUuid() {
741
- return crypto.randomUUID();
742
- }
743
- /** Construct an AbortError. Downstream code pattern-matches on `err.name`. */
744
- function abortError$1() {
745
- const err = /* @__PURE__ */ new Error("aborted");
746
- err.name = "AbortError";
747
- return err;
748
- }
749
- /** Throw an AbortError. */
750
- function throwAbort() {
751
- throw abortError$1();
752
- }
753
- /** Throw if the signal is already aborted; otherwise no-op. */
754
- function throwIfAborted(signal) {
755
- if (signal?.aborted) throw abortError$1();
756
- }
757
- /** True for any error whose `name` is `AbortError` (the cross-kernel abort contract). */
758
- function isAbortError$2(err) {
759
- return err instanceof Error && err.name === "AbortError";
760
- }
761
- /**
762
- * Sleep that resolves early on abort and always clears its timer so it never
763
- * keeps the event loop alive. Resolves (does not reject) on abort — callers
764
- * re-check the signal explicitly after the sleep.
765
- */
766
- function sleep(ms, signal, keepAlive = true) {
767
- if (signal?.aborted) return Promise.resolve();
768
- return new Promise((resolve) => {
769
- const done = () => {
770
- clearTimer();
771
- signal?.removeEventListener("abort", done);
772
- resolve();
773
- };
774
- const clearTimer = armDeadlineTimer(ms, done, keepAlive);
775
- signal?.addEventListener("abort", done, { once: true });
776
- });
777
- }
778
- /**
779
- * Race a promise against a timeout. Resolves with the value if it settles in
780
- * time, otherwise resolves with `undefined`. Always clears the timer.
781
- */
782
- function withTimeout(promise, ms) {
783
- return new Promise((resolve) => {
784
- const clearTimer = armDeadlineTimer(ms, () => resolve(void 0), true);
785
- promise.then((value) => {
786
- clearTimer();
787
- resolve(value);
788
- }, () => {
789
- clearTimer();
790
- resolve(void 0);
791
- });
792
- });
793
- }
794
- /**
795
- * `JSON.stringify` with a `String()` fallback on throw (cyclic / non-JSON).
796
- * Strings pass through unstringified so a preview of a string output is the
797
- * string itself, not a quoted re-encoding.
798
- */
799
- function stringifySafe(value, opts = {}) {
800
- let s;
801
- try {
802
- if (typeof value === "string") s = value;
803
- else s = (opts.pretty ? JSON.stringify(value, null, 2) : JSON.stringify(value)) ?? String(value);
804
- } catch {
805
- s = String(value);
806
- }
807
- if (opts.max !== void 0 && s.length > opts.max) return `${s.slice(0, opts.max)}…`;
808
- return s;
809
- }
810
- /** A fresh zero token-usage accumulator. */
811
- function zeroTokenUsage() {
812
- return {
813
- input: 0,
814
- output: 0
815
- };
816
- }
817
- /**
818
- * Sum the catalog-priced part of a dollar total across spends, as a field to spread.
819
- *
820
- * Returns nothing when no input carried one. A fold of pure provider receipts must not gain a
821
- * `usdEstimated: 0`, which would read as "this runtime checked and priced none" on a path that
822
- * never prices at all.
823
- */
824
- function usdEstimatedOf(...spends) {
825
- let total = 0;
826
- let priced = false;
827
- for (const spend of spends) {
828
- if (spend.usdEstimated === void 0) continue;
829
- priced = true;
830
- total += spend.usdEstimated;
831
- }
832
- return priced ? { usdEstimated: total } : {};
833
- }
834
- /** A conserved spend with every channel at zero and no completeness claim on it. */
835
- function zeroSpend() {
836
- return {
837
- iterations: 0,
838
- tokens: zeroTokenUsage(),
839
- usd: 0,
840
- ms: 0
841
- };
842
- }
843
- /**
844
- * The spend of work that HAPPENED and reported no usage receipt.
845
- *
846
- * Not the same value as {@link zeroSpend} even though both carry `{0,0}` tokens and `$0`. A bare
847
- * zero asserts a MEASUREMENT — "this ran and cost nothing" — and every consumer downstream reads it
848
- * that way: the pool keeps reporting `readout().tokensKnown === true`, the journal totals stay
849
- * clean, the OTEL span records a priced zero, and a caller's token-denominated ceiling can never
850
- * fire no matter how much the work really burned. A ceiling that cannot fire is worse than no
851
- * ceiling, because it reads as protection.
852
- *
853
- * `tokensKnown` is the marker the substrate already threads end to end for exactly this case
854
- * (`budget.ts`, `otel-spans.ts`, `spawn-journal.ts`, `supervisor.ts`): the work is recorded, the
855
- * zero is labelled a floor rather than a total, and every rollup that touches it reports its
856
- * balance as a ceiling rather than a measurement. Use this — never a bare zero — whenever a runtime
857
- * cannot see what its worker spent.
858
- *
859
- * The same rule applies to dollars. A dollar-capped run must refuse an executor whose billed spend
860
- * is unknowable; `budgetExempt` does not authorize Runtime to relabel unknown spend as a measured
861
- * zero. Callers that require dollar accounting must use a backend with a trusted billing receipt.
862
- */
863
- function unmeteredSpend(ms) {
864
- return {
865
- iterations: 0,
866
- tokens: zeroTokenUsage(),
867
- tokensKnown: false,
868
- usd: 0,
869
- usdKnown: false,
870
- ms
871
- };
872
- }
873
- /** Copy a conserved spend without dropping a completeness marker or the catalog-priced part. */
874
- function cloneSpend(spend) {
875
- return {
876
- ...addResourceSpend(spend.resources),
877
- iterations: spend.iterations,
878
- tokens: cloneTokenUsage(spend.tokens),
879
- ...spend.tokensKnown === false ? { tokensKnown: false } : {},
880
- usd: spend.usd,
881
- ...spend.usdKnown === false ? { usdKnown: false } : {},
882
- ...spend.usdEstimated !== void 0 ? { usdEstimated: spend.usdEstimated } : {},
883
- ms: spend.ms,
884
- ...boxMinutesOf(spend),
885
- ...spend.tokensProvenance === void 0 ? {} : { tokensProvenance: spend.tokensProvenance }
886
- };
887
- }
888
- /**
889
- * Sum two conserved spends per channel. Tokens and dollars never fold into each other, an
890
- * incomplete input keeps the sum incomplete on that channel, and the catalog-priced part of the
891
- * dollar total is summed separately so `usd - usdEstimated` still names what a provider billed.
892
- */
893
- function addSpend(a, b) {
894
- const tokens = cloneTokenUsage(a.tokens);
895
- addTokenUsage(tokens, b.tokens);
896
- return {
897
- ...addResourceSpend(a.resources, b.resources),
898
- iterations: a.iterations + b.iterations,
899
- tokens,
900
- ...a.tokensKnown === false || b.tokensKnown === false ? { tokensKnown: false } : {},
901
- usd: a.usd + b.usd,
902
- ...a.usdKnown === false || b.usdKnown === false ? { usdKnown: false } : {},
903
- ...usdEstimatedOf(a, b),
904
- ms: a.ms + b.ms,
905
- ...boxMinutesOf(a, b),
906
- ...tokensProvenanceOf(a, b)
907
- };
908
- }
909
- /**
910
- * Fold the token-provenance channel across spends, as a field to spread.
911
- *
912
- * Returns nothing when no contributor stated one, because ABSENT already means "the executor's own
913
- * live stream", which is what every path reported before a harness store was readable. A
914
- * contributor that stated one and a contributor that did not therefore disagree, and the sum is
915
- * `'mixed'` — the honest answer for a tree whose spend came from two kinds of receipt.
916
- */
917
- function tokensProvenanceOf(...spends) {
918
- let folded;
919
- let sawStated = false;
920
- for (const spend of spends) {
921
- const stated = spend.tokensProvenance ?? "stream-receipt";
922
- if (spend.tokensProvenance !== void 0) sawStated = true;
923
- folded = folded === void 0 || folded === stated ? stated : "mixed";
924
- }
925
- return !sawStated || folded === void 0 || folded === "stream-receipt" ? {} : { tokensProvenance: folded };
926
- }
927
- /**
928
- * Fold the platform box-time channel across spends, as a field to spread.
929
- *
930
- * Returns nothing when no input carried the channel, so a fold over router or cli-bridge work —
931
- * which runs no box at all — never gains a `boxMinutesProvenance: 'uncaptured'` that would claim
932
- * a box ran and went unmetered.
933
- *
934
- * Three rules, one per field:
935
- * - `boxMinutes` sums the numbers that are present, and stays ABSENT when none is. A missing
936
- * measurement never enters the sum as a zero.
937
- * - `boxMinutesKnown` is sticky-false, like `tokensKnown`: one contributor that could not state
938
- * its box time makes the whole sum a floor.
939
- * - `boxMinutesProvenance` degrades. `'observed'` survives only when every contributor that
940
- * carried a number was observed; one derived number makes the sum `'estimated'`; no number at
941
- * all is `'uncaptured'`.
942
- */
943
- function boxMinutesOf(...spends) {
944
- const present = spends.filter((spend) => spend.boxMinutesProvenance !== void 0);
945
- if (present.length === 0) return {};
946
- let minutes = 0;
947
- let sawNumber = false;
948
- let known = true;
949
- let observedOnly = true;
950
- for (const spend of present) {
951
- if (typeof spend.boxMinutes === "number" && Number.isFinite(spend.boxMinutes)) {
952
- minutes += spend.boxMinutes;
953
- sawNumber = true;
954
- if (spend.boxMinutesProvenance !== "observed") observedOnly = false;
955
- }
956
- if (spend.boxMinutesKnown !== true) known = false;
957
- }
958
- return {
959
- ...sawNumber ? { boxMinutes: roundBoxMinutes(minutes) } : {},
960
- boxMinutesKnown: known,
961
- boxMinutesProvenance: sawNumber ? observedOnly ? "observed" : "estimated" : "uncaptured"
962
- };
963
- }
964
- /**
965
- * Box minutes at four decimals — a tenth of a second.
966
- *
967
- * Fine enough that a box alive for two seconds reports `0.0333` instead of a zero that would read
968
- * as a measured free box, and coarse enough that summing floats does not print
969
- * `1.5000000000000002`.
970
- */
971
- function roundBoxMinutes(minutes) {
972
- return Number(minutes.toFixed(4));
973
- }
974
- /** Copy a token subtotal without dropping optional provider cache telemetry. */
975
- function cloneTokenUsage(usage) {
976
- const cacheBreakdownUnknown = usage.cacheBreakdownKnown === false || usage.input > 0 && !hasClassifiedCacheBreakdown(usage);
977
- return {
978
- input: usage.input,
979
- output: usage.output,
980
- ...usage.tokensKnown === false ? { tokensKnown: false } : {},
981
- ...usage.freshInput !== void 0 ? { freshInput: usage.freshInput } : {},
982
- ...usage.cacheRead !== void 0 ? { cacheRead: usage.cacheRead } : {},
983
- ...usage.cacheWrite !== void 0 ? { cacheWrite: usage.cacheWrite } : {},
984
- ...cacheBreakdownUnknown ? { cacheBreakdownKnown: false } : {}
985
- };
986
- }
987
- /** True only when every positive prompt token has a consistent cache classification. */
988
- function hasCompleteCacheBreakdown(usage) {
989
- if (usage.cacheBreakdownKnown === false) return false;
990
- return hasClassifiedCacheBreakdown(usage);
991
- }
992
- function hasClassifiedCacheBreakdown(usage) {
993
- if (usage.input === 0) return true;
994
- if (usage.freshInput === void 0 || usage.cacheRead === void 0 || usage.cacheWrite === void 0) return false;
995
- return usage.freshInput + usage.cacheRead + usage.cacheWrite === usage.input;
996
- }
997
- /**
998
- * The token charge for one observation: every token counted ONCE, at the moment it first enters
999
- * the context — `input − cacheRead + output`.
1000
- *
1001
- * `input` is a rolled-up prompt total that re-counts a cached prefix on every turn that reads it,
1002
- * so charging `input` makes a 100K prefix read 40 times cost 4.1M for content authored once. A
1003
- * cache read is content that was already charged when it was written, so it is the one class the
1004
- * charge subtracts. Under a complete split the result is exactly `freshInput + cacheWrite`. No
1005
- * price weight is involved: this counts work, and money is a separate channel.
1006
- *
1007
- * The subtraction form is what makes the charge ADDITIVE. `input` and `cacheRead` both accumulate
1008
- * through `addTokenUsage`, so the charge on an aggregate equals the sum of the charges on the
1009
- * records that built it — including an aggregate that mixes classified and unclassified turns,
1010
- * where the unclassified remainder is charged in full and only the reported cache reads are
1011
- * credited. A form that read `freshInput + cacheWrite` directly loses that: one unclassified turn
1012
- * would drop the whole aggregate to `input + output` and over-charge every classified turn with it.
1013
- *
1014
- * The one arithmetic guarantee: a set of classes that does not FIT inside the prompt total it
1015
- * partitions credits nothing, so the charge is never below `output` and a class that overflows its
1016
- * own total buys no tokens. It is not a guarantee against a provider that reports a cache read it
1017
- * never served — that provider can under-report `input` just as easily, and the token channel is an
1018
- * accounting unit, not a trust boundary. Prompt tokens the provider left unclassified are charged
1019
- * in full, so a spend with no readable split charges an upper bound on newly-presented work rather
1020
- * than a measurement, and every caller that enforces a ceiling must report the difference
1021
- * (`BudgetPool` does it through `readout().cacheBreakdownKnown`).
1022
- */
1023
- function chargedTokens(usage) {
1024
- return usage.input - creditedCacheRead(usage) + usage.output;
1025
- }
1026
- /** `cacheRead` if the reported classes fit inside `input`, else nothing. */
1027
- function creditedCacheRead(usage) {
1028
- const { cacheRead } = usage;
1029
- if (cacheRead === void 0) return 0;
1030
- return classifiedTotal(usage, cacheRead) > usage.input ? 0 : cacheRead;
1031
- }
1032
- function classifiedTotal(usage, cacheRead) {
1033
- return (usage.freshInput ?? 0) + cacheRead + (usage.cacheWrite ?? 0);
1034
- }
1035
- /**
1036
- * Translate one provider prompt-cache report into the prompt token classes `addTokenUsage` folds
1037
- * and `chargedTokens` credits.
1038
- *
1039
- * The input is the open `promptCache` record an `llm_call` carries, keyed by the `PromptCacheUsage`
1040
- * vocabulary (`readTokens`, `writeTokens`). Providers report that vocabulary unevenly, and the
1041
- * three outcomes are different facts that must not collapse into one another:
1042
- *
1043
- * - **Nothing reported** — no classes and no marker. The caller's own unknown handling decides,
1044
- * because a provider that says nothing about caching has not said the split is unknowable.
1045
- * - **Read and write both reported, and fitting inside `input`** — a complete partition, so
1046
- * `freshInput` is the remainder and the split is known.
1047
- * - **One counter reported, or classes that overflow `input`** — the counters that ARE measured
1048
- * pass through and `cacheBreakdownKnown` is false. A read with no write counter (OpenAI reports
1049
- * no write) still credits the read it measured, while declaring the rest unclassified so the
1050
- * charge stays a declared upper bound. An overflowing claim buys nothing: it cannot be a
1051
- * partition of a total it exceeds.
1052
- *
1053
- * A counter the provider did not report stays absent. A zero would claim the provider measured no
1054
- * cache, which is a different fact from a provider that did not report.
1055
- */
1056
- function promptCacheTokenClasses(input, promptCache) {
1057
- if (promptCache === void 0) return {};
1058
- const read = tokenCount(promptCache.readTokens);
1059
- const write = tokenCount(promptCache.writeTokens);
1060
- if (read === void 0 && write === void 0) return {};
1061
- if (input === void 0 || (read ?? 0) + (write ?? 0) > input) return { cacheBreakdownKnown: false };
1062
- if (read !== void 0 && write !== void 0) return {
1063
- freshInput: input - read - write,
1064
- cacheRead: read,
1065
- cacheWrite: write
1066
- };
1067
- return {
1068
- ...read !== void 0 ? { cacheRead: read } : {},
1069
- ...write !== void 0 ? { cacheWrite: write } : {},
1070
- cacheBreakdownKnown: false
1071
- };
1072
- }
1073
- function tokenCount(value) {
1074
- return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
1075
- }
1076
- /**
1077
- * Add the observed subtotal into `acc`; token and cache incompleteness are sticky.
1078
- *
1079
- * A delta whose classes do not FIT inside its own `input` contributes its prompt total and NO
1080
- * classes. Folding them in would hide the overflow: the accumulator's larger `input` can absorb a
1081
- * class total that overflowed the one delta that reported it, and `chargedTokens` would then credit
1082
- * at the aggregate a cache read it refuses at the record. That is the one way the charge could come
1083
- * out below the sum of the charges on the records that built it.
1084
- */
1085
- function addTokenUsage(acc, delta) {
1086
- acc.input += delta.input ?? 0;
1087
- acc.output += delta.output ?? 0;
1088
- if (delta.tokensKnown === false) acc.tokensKnown = false;
1089
- const input = delta.input ?? 0;
1090
- const fits = classifiedTotal(delta, delta.cacheRead ?? 0) <= input;
1091
- if (fits) {
1092
- if (delta.freshInput !== void 0) acc.freshInput = (acc.freshInput ?? 0) + delta.freshInput;
1093
- if (delta.cacheRead !== void 0) acc.cacheRead = (acc.cacheRead ?? 0) + delta.cacheRead;
1094
- if (delta.cacheWrite !== void 0) acc.cacheWrite = (acc.cacheWrite ?? 0) + delta.cacheWrite;
1095
- }
1096
- const classified = fits && delta.freshInput !== void 0 && delta.cacheRead !== void 0 && delta.cacheWrite !== void 0 && delta.freshInput + delta.cacheRead + delta.cacheWrite === input;
1097
- if (delta.cacheBreakdownKnown === false || input > 0 && !classified) acc.cacheBreakdownKnown = false;
1098
- }
1099
- /**
1100
- * Map `items` through `fn` with at most `limit` calls in flight at once,
1101
- * preserving input order in the result. On the first `fn` rejection no NEW
1102
- * items are picked up; already-in-flight calls are awaited, then the first
1103
- * error is rethrown. `limit` is clamped to ≥ 1.
1104
- *
1105
- * Used where a burst of provisioning (e.g. forking N child boxes) must respect
1106
- * the loop's concurrency bound instead of firing all N at once.
1107
- */
1108
- async function mapWithConcurrency(items, limit, fn) {
1109
- const results = new Array(items.length);
1110
- let next = 0;
1111
- for await (const settled of runTaskQueue({
1112
- concurrency: Math.max(1, Math.min(Math.floor(limit), items.length)),
1113
- take: () => {
1114
- const index = next++;
1115
- return index < items.length ? {
1116
- id: String(index),
1117
- value: index
1118
- } : void 0;
1119
- },
1120
- execute: ({ value: index }) => fn(items[index], index)
1121
- })) {
1122
- if (settled.status === "rejected") throw settled.reason;
1123
- results[settled.task.value] = settled.value;
1124
- }
1125
- return results;
1126
- }
1127
- //#endregion
1128
540
  //#region src/runtime/sandbox-events.ts
1129
541
  const CANONICAL_STREAM_EVENT_TYPES = /* @__PURE__ */ new Set([
1130
542
  "child-task",
@@ -1809,6 +1221,7 @@ function mapSandboxToolEvent(event, state) {
1809
1221
  if (String(part.type ?? "") !== "tool") return [];
1810
1222
  return projectToolPart(part, state, typeof event.id === "string" ? event.id : void 0);
1811
1223
  }
1224
+ if (CANONICAL_STREAM_EVENT_TYPES.has(type)) return [];
1812
1225
  if (type.includes("tool")) {
1813
1226
  const callId = pickString(data, [
1814
1227
  "toolCallId",
@@ -2494,140 +1907,6 @@ function providerAttemptEvidence(model) {
2494
1907
  });
2495
1908
  }
2496
1909
  //#endregion
2497
- //#region src/durable/jsonl-file.ts
2498
- /** Read a fixed file prefix one record at a time, never allocating the whole journal as a string.
2499
- * A reader cannot chase concurrent appends forever. Missing files are empty only when requested;
2500
- * corruption, short reads, and other I/O errors remain failures. Closing the iterator closes the fd. */
2501
- async function* readCommittedJsonLines(path, options = {}) {
2502
- const fs = await import("node:fs/promises");
2503
- let handle;
2504
- try {
2505
- handle = await fs.open(path, "r");
2506
- } catch (error) {
2507
- if (options.allowMissing && isNoEntError(error)) return;
2508
- throw error;
2509
- }
2510
- try {
2511
- const { size } = await handle.stat();
2512
- if (size === 0) return;
2513
- const { StringDecoder } = await import("node:string_decoder");
2514
- const decoder = new StringDecoder("utf8");
2515
- const stream = handle.createReadStream({
2516
- autoClose: false,
2517
- end: size - 1
2518
- });
2519
- const fragments = [];
2520
- let lineNumber = 1;
2521
- try {
2522
- for await (const chunk of stream) {
2523
- options.onBytes?.(chunk);
2524
- const text = decoder.write(chunk);
2525
- let start = 0;
2526
- let end = text.indexOf("\n", start);
2527
- while (end !== -1) {
2528
- fragments.push(text.slice(start, end));
2529
- const record = parseRecord(fragments.join(""), path, lineNumber++, true);
2530
- fragments.length = 0;
2531
- if (record !== void 0) yield record.value;
2532
- start = end + 1;
2533
- end = text.indexOf("\n", start);
2534
- }
2535
- if (start < text.length) fragments.push(text.slice(start));
2536
- }
2537
- if (stream.bytesRead !== size) throw new Error(`${path}: journal changed while reading its committed prefix`);
2538
- fragments.push(decoder.end());
2539
- const record = parseRecord(fragments.join(""), path, lineNumber, false);
2540
- if (record !== void 0) yield record.value;
2541
- } finally {
2542
- stream.destroy();
2543
- }
2544
- } finally {
2545
- await handle.close();
2546
- }
2547
- }
2548
- /** An invalid unterminated tail may be a torn write; other parse failures are not evidence of one. */
2549
- function parseRecord(line, source, lineNumber, terminated) {
2550
- if (line.length === 0) return void 0;
2551
- try {
2552
- return { value: JSON.parse(line) };
2553
- } catch (cause) {
2554
- if (!(cause instanceof SyntaxError)) throw cause;
2555
- if (!terminated) return void 0;
2556
- throw new Error(`${source}: malformed JSONL record at line ${lineNumber}`, { cause });
2557
- }
2558
- }
2559
- /** FileHandle.write may legally make a short write. Loop until every byte is appended. */
2560
- async function writeAllBytes(handle, value) {
2561
- const bytes = typeof value === "string" ? Buffer.from(value) : Buffer.from(value);
2562
- let offset = 0;
2563
- while (offset < bytes.byteLength) {
2564
- const { bytesWritten } = await handle.write(bytes, offset, bytes.byteLength - offset, null);
2565
- if (bytesWritten <= 0) throw new Error(`append-only file write made no progress at byte ${offset}`);
2566
- offset += bytesWritten;
2567
- }
2568
- }
2569
- /** Prepare the tail under the journal owner's existing single-writer discipline.
2570
- * Healthy appends read one byte, regardless of history size. Only recovery scans backward,
2571
- * retaining a valid unterminated value or truncating an uncommitted torn tail. */
2572
- async function prepareJsonlAppend(path) {
2573
- const fs = await import("node:fs/promises");
2574
- let handle;
2575
- try {
2576
- handle = await fs.open(path, "r+");
2577
- } catch (error) {
2578
- if (isNoEntError(error)) return false;
2579
- throw error;
2580
- }
2581
- try {
2582
- const size = (await handle.stat()).size;
2583
- if (size === 0) return false;
2584
- const lastByte = Buffer.allocUnsafe(1);
2585
- await readAt(handle, lastByte, size - 1);
2586
- if (lastByte[0] === 10) return false;
2587
- const chunks = [];
2588
- let end = size;
2589
- let tailStart = 0;
2590
- while (end > 0) {
2591
- const start = Math.max(0, end - 65536);
2592
- const chunk = Buffer.allocUnsafe(end - start);
2593
- await readAt(handle, chunk, start);
2594
- const newline = chunk.lastIndexOf(10);
2595
- chunks.push(chunk.subarray(newline + 1));
2596
- if (newline >= 0) {
2597
- tailStart = start + newline + 1;
2598
- break;
2599
- }
2600
- end = start;
2601
- }
2602
- const tail = Buffer.concat(chunks.reverse()).toString("utf8");
2603
- try {
2604
- JSON.parse(tail);
2605
- return true;
2606
- } catch (error) {
2607
- if (!(error instanceof SyntaxError)) throw error;
2608
- await handle.truncate(tailStart);
2609
- await handle.sync();
2610
- return false;
2611
- }
2612
- } finally {
2613
- await handle.close();
2614
- }
2615
- }
2616
- /** A short read is legal; an unexpected EOF means the owner's snapshot changed. */
2617
- async function readAt(handle, buffer, position) {
2618
- let offset = 0;
2619
- while (offset < buffer.length) {
2620
- const { bytesRead } = await handle.read(buffer, offset, buffer.length - offset, position + offset);
2621
- if (bytesRead === 0) throw new Error("journal changed while preparing its append tail");
2622
- offset += bytesRead;
2623
- }
2624
- }
2625
- /** True for a filesystem error meaning "the file is not there yet" — the one condition an
2626
- * append-only reader treats as an empty log rather than a fault. */
2627
- function isNoEntError(error) {
2628
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
2629
- }
2630
- //#endregion
2631
1910
  //#region src/agent/profile-materialization.ts
2632
1911
  const KNOWN_AXIS_SET = new Set(AGENT_PROFILE_MATERIALIZATION_AXES);
2633
1912
  /**
@@ -7313,6 +6592,49 @@ function normalizeWorkerSlotBound(value) {
7313
6592
  if (!Number.isSafeInteger(value)) throw new ValidationError$1(`workerSlots must be a positive safe integer, or 0 or less for no bound, got ${String(value)}`);
7314
6593
  return value;
7315
6594
  }
6595
+ const checkpointSlotKeys = /* @__PURE__ */ new WeakMap();
6596
+ function checkpointSlots(port) {
6597
+ let key = checkpointSlotKeys.get(port);
6598
+ if (key === void 0) {
6599
+ key = Object.freeze({ maxConcurrentCaptures: port.maxConcurrentCaptures });
6600
+ checkpointSlotKeys.set(port, key);
6601
+ }
6602
+ return key;
6603
+ }
6604
+ /**
6605
+ * Capture a checkpoint through the port on its own queue and bound, then verify that the store
6606
+ * holds every file of the returned tree and, when the checkpoint took a marker, that the tree
6607
+ * holds the marker's exact bytes, which proves it read this checkpoint and no other state.
6608
+ */
6609
+ async function captureProviderCheckpointWorkspace(port, context, marker) {
6610
+ assertProviderWorkspaceRetentionPort(port, "provider workspace retention");
6611
+ const capture = port.captureCheckpoint;
6612
+ if (capture === void 0) throw new ValidationError$1("provider workspace retention: the port has no captureCheckpoint");
6613
+ const controller = new AbortController();
6614
+ const clearDeadline = armDeadlineTimer(port.timeoutMs, () => controller.abort(/* @__PURE__ */ new Error(`checkpoint capture timed out after ${port.timeoutMs}ms`)), true);
6615
+ try {
6616
+ return await runAbortable(() => withCaptureSlot(checkpointSlots(port), controller.signal, async () => {
6617
+ const tree = detachedSnapshot(await capture.call(port, {
6618
+ ...context,
6619
+ signal: controller.signal
6620
+ }), "checkpoint capture tree");
6621
+ if (tree?.kind !== "agent-candidate-workspace-tree") throw new Error("checkpoint capture returned no workspace tree");
6622
+ const material = await verifyAgentCandidateWorkspaceTree(tree, port.artifacts, {
6623
+ ...port.limits === void 0 ? {} : { limits: port.limits },
6624
+ signal: controller.signal
6625
+ });
6626
+ if (material.files.length !== tree.files) throw new Error("checkpoint capture tree misstates its file count");
6627
+ if (marker !== void 0) {
6628
+ const bytes = Buffer.from(marker.content, "utf8");
6629
+ const held = material.files.find((file) => file.path === marker.path);
6630
+ if (held === void 0 || held.byteLength !== bytes.byteLength || held.sha256 !== `sha256:${createHash("sha256").update(bytes).digest("hex")}`) throw new Error(`checkpoint capture does not hold the checkpoint's marker ${marker.path}`);
6631
+ }
6632
+ return tree;
6633
+ }), controller.signal, `checkpoint capture timed out after ${port.timeoutMs}ms`);
6634
+ } finally {
6635
+ clearDeadline();
6636
+ }
6637
+ }
7316
6638
  /** Validate the executable retention port at the create boundary. */
7317
6639
  function assertProviderWorkspaceRetentionPort(port, context) {
7318
6640
  if (!Number.isSafeInteger(port.timeoutMs) || port.timeoutMs <= 0) throw new ValidationError$1(`${context}: workspaceRetention.timeoutMs must be a positive safe integer`);
@@ -7320,6 +6642,7 @@ function assertProviderWorkspaceRetentionPort(port, context) {
7320
6642
  if (port.artifacts === null || typeof port.artifacts?.read !== "function") throw new ValidationError$1(`${context}: workspaceRetention.artifacts.read is required`);
7321
6643
  if (typeof port.capture !== "function") throw new ValidationError$1(`${context}: workspaceRetention.capture is required`);
7322
6644
  if (port.captureNative !== void 0 && typeof port.captureNative !== "function") throw new ValidationError$1(`${context}: workspaceRetention.captureNative must be a function`);
6645
+ if (port.captureCheckpoint !== void 0 && typeof port.captureCheckpoint !== "function") throw new ValidationError$1(`${context}: workspaceRetention.captureCheckpoint must be a function`);
7323
6646
  for (const key of ["nativeIntervalMs", "nativeTimeoutMs"]) {
7324
6647
  const value = port[key];
7325
6648
  if (value !== void 0 && (!Number.isSafeInteger(value) || value <= 0)) throw new ValidationError$1(`${context}: workspaceRetention.${key} must be a positive safe integer`);
@@ -7335,6 +6658,7 @@ function nativeSlots(port) {
7335
6658
  }
7336
6659
  return key;
7337
6660
  }
6661
+ const capturesInFlight = /* @__PURE__ */ new WeakMap();
7338
6662
  async function withCaptureSlot(port, signal, capture) {
7339
6663
  if (port.maxConcurrentCaptures === void 0) return capture();
7340
6664
  let group = captureGroups.get(port);
@@ -7351,13 +6675,56 @@ async function withCaptureSlot(port, signal, capture) {
7351
6675
  permit.release();
7352
6676
  }
7353
6677
  }
7354
- /**
7355
- * Capture, require durable refs, and verify every returned manifest/archive byte.
7356
- * `native` calls {@link ProviderWorkspaceRetentionPort.captureNative} under its own queue and
7357
- * bound, and judges coverage by the sessions alone.
7358
- */
7359
- async function captureProviderWorkspaceSnapshot(port, context, scope = "environment") {
7360
- assertProviderWorkspaceRetentionPort(port, "provider workspace retention");
6678
+ /** Count one capture of `port` in flight until `work` settles, and say how many were ahead. */
6679
+ function trackCapture(port, work) {
6680
+ const ahead = capturesInFlight.get(port) ?? 0;
6681
+ capturesInFlight.set(port, ahead + 1);
6682
+ return work(ahead).finally(() => {
6683
+ capturesInFlight.set(port, Math.max(0, (capturesInFlight.get(port) ?? 1) - 1));
6684
+ });
6685
+ }
6686
+ /**
6687
+ * Capture, require durable refs, and verify every returned manifest/archive byte.
6688
+ * `native` calls {@link ProviderWorkspaceRetentionPort.captureNative} under its own queue and
6689
+ * bound, and judges coverage by the sessions alone. `onTiming` receives the queue wait and the
6690
+ * capture time of a workspace capture once it settles, whether it succeeded or failed.
6691
+ */
6692
+ async function captureProviderWorkspaceSnapshot(port, context, scope = "environment", onTiming) {
6693
+ assertProviderWorkspaceRetentionPort(port, "provider workspace retention");
6694
+ if (scope === "native" || onTiming === void 0) return await captureWithinSlot(port, context, scope);
6695
+ return await trackCapture(port, async (ahead) => {
6696
+ const requestedAt = Date.now();
6697
+ let grantedAt;
6698
+ const report = (timing) => {
6699
+ const settledAt = Date.now();
6700
+ try {
6701
+ onTiming({
6702
+ ahead,
6703
+ queuedMs: (grantedAt ?? settledAt) - requestedAt,
6704
+ ...grantedAt === void 0 ? {} : { captureMs: settledAt - grantedAt },
6705
+ ...timing
6706
+ });
6707
+ } catch {}
6708
+ };
6709
+ try {
6710
+ const captured = await captureWithinSlot(port, context, scope, () => {
6711
+ grantedAt = Date.now();
6712
+ });
6713
+ report({
6714
+ outcome: "captured",
6715
+ archiveBytes: captured.snapshot.archive.byteLength
6716
+ });
6717
+ return captured;
6718
+ } catch (error) {
6719
+ report({
6720
+ outcome: "failed",
6721
+ error: (error instanceof Error ? error.message : String(error)).slice(0, 1e3)
6722
+ });
6723
+ throw error;
6724
+ }
6725
+ });
6726
+ }
6727
+ async function captureWithinSlot(port, context, scope, onGranted) {
7361
6728
  const native = scope === "native";
7362
6729
  if (native && port.captureNative === void 0) throw new ValidationError$1("provider workspace retention: the port has no captureNative");
7363
6730
  const timeoutMs = native ? port.nativeTimeoutMs ?? 12e4 : port.timeoutMs;
@@ -7367,6 +6734,7 @@ async function captureProviderWorkspaceSnapshot(port, context, scope = "environm
7367
6734
  const clearDeadline = armDeadlineTimer(timeoutMs, () => controller.abort(/* @__PURE__ */ new Error(`provider workspace retention timed out after ${timeoutMs}ms`)), true);
7368
6735
  try {
7369
6736
  return await runAbortable(() => withCaptureSlot(native ? nativeSlots(port) : port, controller.signal, async () => {
6737
+ onGranted?.();
7370
6738
  const input = {
7371
6739
  ...context,
7372
6740
  ...controlRef === void 0 ? {} : { controlRef: Object.freeze({ ...controlRef }) },
@@ -7539,7 +6907,7 @@ async function environmentGone(provider, environmentId, signal) {
7539
6907
  }
7540
6908
  /** Create one environment while retaining ownership if cancellation wins the race. */
7541
6909
  async function createInteractiveEnvironment(create, signal) {
7542
- if (signal?.aborted) throw abortError$2(signal.reason);
6910
+ if (signal?.aborted) throw abortError$1(signal.reason);
7543
6911
  const creation = Promise.resolve().then(create);
7544
6912
  if (signal === void 0) return creation;
7545
6913
  return new Promise((resolve, reject) => {
@@ -7550,7 +6918,7 @@ async function createInteractiveEnvironment(create, signal) {
7550
6918
  owner = "runtime";
7551
6919
  removeAbortListener();
7552
6920
  disposeInteractiveEnvironment(creation, signal.reason);
7553
- reject(abortError$2(signal.reason));
6921
+ reject(abortError$1(signal.reason));
7554
6922
  };
7555
6923
  signal.addEventListener("abort", onAbort, { once: true });
7556
6924
  creation.then((environment) => {
@@ -7570,7 +6938,7 @@ async function createInteractiveEnvironment(create, signal) {
7570
6938
  async function startInteractiveProcess(environment, start, signal) {
7571
6939
  if (signal?.aborted) {
7572
6940
  disposeInteractiveEnvironment(Promise.resolve(environment), signal.reason);
7573
- throw abortError$2(signal.reason);
6941
+ throw abortError$1(signal.reason);
7574
6942
  }
7575
6943
  const pending = Promise.resolve().then(start);
7576
6944
  if (signal === void 0) return pending;
@@ -7582,7 +6950,7 @@ async function startInteractiveProcess(environment, start, signal) {
7582
6950
  owner = "runtime";
7583
6951
  removeAbortListener();
7584
6952
  disposeInteractiveEnvironment(Promise.resolve(environment), signal.reason);
7585
- reject(abortError$2(signal.reason));
6953
+ reject(abortError$1(signal.reason));
7586
6954
  };
7587
6955
  signal.addEventListener("abort", onAbort, { once: true });
7588
6956
  pending.then((result) => {
@@ -7717,7 +7085,7 @@ async function* retainedRunEvents(session, controlRef, options, now) {
7717
7085
  try {
7718
7086
  Promise.resolve(iterator.return?.()).catch(() => void 0);
7719
7087
  } catch {}
7720
- throw abortError$2(options.signal.reason);
7088
+ throw abortError$1(options.signal.reason);
7721
7089
  }
7722
7090
  if (error instanceof RetainedRunProviderContractError) throw error;
7723
7091
  const fromProvider = error instanceof Error && !runtimeChecks.has(error);
@@ -7768,13 +7136,13 @@ function createRetainedRunHandle(environment, session, initialControlRef, capabi
7768
7136
  }
7769
7137
  };
7770
7138
  const snapshot = async (reason, signal) => {
7771
- if (signal?.aborted) throw abortError$2(signal.reason);
7139
+ if (signal?.aborted) throw abortError$1(signal.reason);
7772
7140
  synchronizeActiveControlRef();
7773
7141
  let status;
7774
7142
  try {
7775
7143
  status = await awaitAbortable$1(Promise.resolve().then(() => session.status({ signal })), signal);
7776
7144
  } catch {
7777
- if (signal?.aborted) throw abortError$2(signal.reason);
7145
+ if (signal?.aborted) throw abortError$1(signal.reason);
7778
7146
  status = "unknown";
7779
7147
  }
7780
7148
  synchronizeActiveControlRef();
@@ -8001,7 +7369,7 @@ function createRetainedRunHandle(environment, session, initialControlRef, capabi
8001
7369
  synchronizeActiveControlRef();
8002
7370
  assertStableText(options.operationId, "retained cancellation operation id");
8003
7371
  if (options.reason !== void 0) assertStableText(options.reason, "retained cancellation reason");
8004
- if (options.signal?.aborted) throw abortError$2(options.signal.reason);
7372
+ if (options.signal?.aborted) throw abortError$1(options.signal.reason);
8005
7373
  if (!hasDurableCancel(session)) throw new Error(`provider "${activeControlRef.provider}" does not expose durable cancellation operations`);
8006
7374
  const request = cancellationRequest(activeControlRef, options.operationId, options.reason);
8007
7375
  let effect = "unknown";
@@ -8366,6 +7734,7 @@ async function recoverRetainedRun(options) {
8366
7734
  if (options.admission.provider !== options.provider.name) throw new Error("retained run intent belongs to another provider");
8367
7735
  return {
8368
7736
  outcome: "recovered",
7737
+ via: "resumed",
8369
7738
  handle: await startRetainedRun({
8370
7739
  provider: options.provider,
8371
7740
  ...options.replay,
@@ -8406,6 +7775,7 @@ async function recoverRetainedRun(options) {
8406
7775
  const exact = exactSession(environment, controlRef);
8407
7776
  return {
8408
7777
  outcome: "recovered",
7778
+ via: "reattached",
8409
7779
  handle: createRetainedRunHandle(environment, exact.session, exact.controlRef, capabilities, options.now)
8410
7780
  };
8411
7781
  }
@@ -8652,6 +8022,119 @@ function describeRetainedNativeStops(stops) {
8652
8022
  }).join("; ");
8653
8023
  }
8654
8024
  //#endregion
8025
+ //#region src/runtime/supervise/executor-seams.ts
8026
+ function assertExactConfigKeys(value, allowed, context) {
8027
+ const unknown = Object.keys(value).filter((key) => !allowed.has(key));
8028
+ if (unknown.length > 0) throw new ValidationError$1(`${context}: unknown fields ${unknown.sort().join(", ")}; execution behavior belongs in AgentProfile`);
8029
+ }
8030
+ /** Narrow a named seam off the `ExecutorContext`, failing loud when absent — no
8031
+ * silent default for a required external-boundary seam. */
8032
+ function readSeam(ctx, key, who) {
8033
+ const seam = ctx.seams[key];
8034
+ if (seam === void 0 || seam === null) throw new ValidationError$1(`${who} executor: missing required seam "${key}" on ExecutorContext`);
8035
+ return seam;
8036
+ }
8037
+ function readOptionalAbortSignal(ctx, key, who) {
8038
+ const value = ctx.seams[key];
8039
+ if (value === void 0) return void 0;
8040
+ if (value === null || typeof value !== "object" || typeof value.aborted !== "boolean" || typeof value.addEventListener !== "function") throw new ValidationError$1(`${who} executor: seam "${key}" must be an AbortSignal`);
8041
+ return value;
8042
+ }
8043
+ /** Narrow the Runtime-owned MCP attachment seam. Absent means the run mounts nothing; a present
8044
+ * value must be a named map of MCP servers, never an empty one that would silently mount nothing. */
8045
+ function readOptionalMcpAttachments(ctx, key, who) {
8046
+ const value = ctx.seams[key];
8047
+ if (value === void 0) return void 0;
8048
+ const entries = value !== null && typeof value === "object" && !Array.isArray(value) ? Object.entries(value) : void 0;
8049
+ if (entries === void 0 || entries.length === 0 || entries.some(([, server]) => server === null || typeof server !== "object")) throw new ValidationError$1(`${who} executor: seam ${JSON.stringify(key)} must be a non-empty map of MCP servers`);
8050
+ return value;
8051
+ }
8052
+ //#endregion
8053
+ //#region src/runtime/supervise/bridge-config.ts
8054
+ const bridgeSeamKey = "bridge";
8055
+ /** Internal control seam used by Runtime-owned external supervisors. A completion request stops
8056
+ * the next bridge turn; it must not abort the paid request that is already streaming. */
8057
+ const bridgeStopSignalKey = "__bridge_stop_signal";
8058
+ /** Internal attachment seam used by Runtime-owned external supervisors. The named MCP servers ride
8059
+ * beside the AgentProfile as `runtime_attachments`, so the bridge mounts them for the run and keeps
8060
+ * them out of its session profile binding. A rebound coordination port therefore cannot move the
8061
+ * authored profile digest that binds a durable session. */
8062
+ const bridgeRuntimeAttachmentsKey = "__bridge_runtime_attachments";
8063
+ const maxBridgeTimeoutMs = 2147483647;
8064
+ function isLoopbackBridgeHost(hostname) {
8065
+ const host = hostname.trim().toLowerCase().replace(/^\[/, "").replace(/\]$/, "");
8066
+ if (host === "localhost" || host === "::1" || host === "0:0:0:0:0:0:0:1") return true;
8067
+ if (host === "::ffff:127.0.0.1") return true;
8068
+ return /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/u.test(host);
8069
+ }
8070
+ function isLoopbackBridgeUrl(value) {
8071
+ try {
8072
+ const target = new URL(value);
8073
+ return (target.protocol === "http:" || target.protocol === "https:") && isLoopbackBridgeHost(target.hostname);
8074
+ } catch {
8075
+ return false;
8076
+ }
8077
+ }
8078
+ /** Validate and capture the non-serialisable credential service without reading its value. */
8079
+ function captureBridgeModelCredential(value, context) {
8080
+ if (value === null || typeof value !== "object") throw new ValidationError$1(`${context}: modelCredential must be an object`);
8081
+ assertExactConfigKeys(value, /* @__PURE__ */ new Set([
8082
+ "baseUrlKey",
8083
+ "key",
8084
+ "provider"
8085
+ ]), `${context} modelCredential`);
8086
+ if (typeof value.key !== "string" || value.key.trim().length === 0) throw new ValidationError$1(`${context}: modelCredential.key must be a non-empty string`);
8087
+ if (typeof value.baseUrlKey !== "string" || value.baseUrlKey.trim().length === 0) throw new ValidationError$1(`${context}: modelCredential.baseUrlKey must be a non-empty string`);
8088
+ if (value.baseUrlKey === value.key) throw new ValidationError$1(`${context}: modelCredential.baseUrlKey must differ from key`);
8089
+ if (!value.provider || typeof value.provider.get !== "function") throw new ValidationError$1(`${context}: modelCredential.provider must implement get(name)`);
8090
+ const captured = {
8091
+ key: value.key,
8092
+ baseUrlKey: value.baseUrlKey
8093
+ };
8094
+ Object.defineProperty(captured, "provider", {
8095
+ configurable: false,
8096
+ enumerable: false,
8097
+ value: value.provider,
8098
+ writable: false
8099
+ });
8100
+ return Object.freeze(captured);
8101
+ }
8102
+ function validateBridgeModelCredential(value, bridgeUrl, context) {
8103
+ if (value === void 0) return void 0;
8104
+ if (!isLoopbackBridgeUrl(bridgeUrl)) throw new ValidationError$1(`${context}: modelCredential is allowed only for a loopback bridge URL`);
8105
+ return captureBridgeModelCredential(value, context);
8106
+ }
8107
+ function resolveProtectedModelBaseUrl(value, context) {
8108
+ let target;
8109
+ try {
8110
+ target = new URL(value);
8111
+ } catch {
8112
+ throw new ValidationError$1(`${context}: modelCredential.baseUrl must be an absolute HTTPS URL`);
8113
+ }
8114
+ if (target.protocol !== "https:" || target.username || target.password || target.search || target.hash) throw new ValidationError$1(`${context}: modelCredential.baseUrl must be an HTTPS URL without credentials, query, or fragment`);
8115
+ return target.toString().replace(/\/$/u, "");
8116
+ }
8117
+ /** Resolve only at the outbound boundary. Provider errors are redacted because they may contain
8118
+ * the protected value; diagnostics identify key names, never values or provider errors. */
8119
+ async function resolveBridgeModelCredential(credential, context) {
8120
+ if (credential === void 0) return void 0;
8121
+ const resolveValue = async (key) => {
8122
+ let value;
8123
+ try {
8124
+ value = await credential.provider.get(key);
8125
+ } catch {
8126
+ throw new ValidationError$1(`${context}: modelCredential provider failed for '${key}'`);
8127
+ }
8128
+ if (typeof value !== "string" || value.length === 0 || /[\r\n\0]/u.test(value)) throw new ValidationError$1(`${context}: modelCredential provider has no usable value for '${key}'`);
8129
+ return value;
8130
+ };
8131
+ const [token, baseUrl] = await Promise.all([resolveValue(credential.key), resolveValue(credential.baseUrlKey)]);
8132
+ return {
8133
+ token,
8134
+ baseUrl: resolveProtectedModelBaseUrl(baseUrl, context)
8135
+ };
8136
+ }
8137
+ //#endregion
8655
8138
  //#region src/runtime/supervise/cost-estimate.ts
8656
8139
  /**
8657
8140
  * Pricing for work that arrived without a provider receipt.
@@ -9405,12 +8888,7 @@ function contentRef$1(prefix, value) {
9405
8888
  } catch {
9406
8889
  str = String(value);
9407
8890
  }
9408
- let h = 2166136261;
9409
- for (let i = 0; i < str.length; i += 1) {
9410
- h ^= str.charCodeAt(i);
9411
- h = Math.imul(h, 16777619);
9412
- }
9413
- return `${prefix}:${(h >>> 0).toString(16).padStart(8, "0")}`;
8891
+ return `${prefix}:${fnv1a32Hex(str)}`;
9414
8892
  }
9415
8893
  //#endregion
9416
8894
  //#region src/runtime/supervise/trace-evidence.ts
@@ -9530,6 +9008,140 @@ function runtimeOwnedNestedDriverTreeRoot(owner, parentTreeRoot, driverNodeId) {
9530
9008
  return nestedDriverTreeOwners.has(owner) ? nestedDriverTreeRoot(parentTreeRoot, driverNodeId) : void 0;
9531
9009
  }
9532
9010
  //#endregion
9011
+ //#region src/durable/jsonl-file.ts
9012
+ /** Read a fixed file prefix one record at a time, never allocating the whole journal as a string.
9013
+ * A reader cannot chase concurrent appends forever. Missing files are empty only when requested;
9014
+ * corruption, short reads, and other I/O errors remain failures. Closing the iterator closes the fd. */
9015
+ async function* readCommittedJsonLines(path, options = {}) {
9016
+ const fs = await import("node:fs/promises");
9017
+ let handle;
9018
+ try {
9019
+ handle = await fs.open(path, "r");
9020
+ } catch (error) {
9021
+ if (options.allowMissing && isNoEntError(error)) return;
9022
+ throw error;
9023
+ }
9024
+ try {
9025
+ const { size } = await handle.stat();
9026
+ if (size === 0) return;
9027
+ const { StringDecoder } = await import("node:string_decoder");
9028
+ const decoder = new StringDecoder("utf8");
9029
+ const stream = handle.createReadStream({
9030
+ autoClose: false,
9031
+ end: size - 1
9032
+ });
9033
+ const fragments = [];
9034
+ let lineNumber = 1;
9035
+ try {
9036
+ for await (const chunk of stream) {
9037
+ options.onBytes?.(chunk);
9038
+ const text = decoder.write(chunk);
9039
+ let start = 0;
9040
+ let end = text.indexOf("\n", start);
9041
+ while (end !== -1) {
9042
+ fragments.push(text.slice(start, end));
9043
+ const record = parseRecord(fragments.join(""), path, lineNumber++, true);
9044
+ fragments.length = 0;
9045
+ if (record !== void 0) yield record.value;
9046
+ start = end + 1;
9047
+ end = text.indexOf("\n", start);
9048
+ }
9049
+ if (start < text.length) fragments.push(text.slice(start));
9050
+ }
9051
+ if (stream.bytesRead !== size) throw new Error(`${path}: journal changed while reading its committed prefix`);
9052
+ fragments.push(decoder.end());
9053
+ const record = parseRecord(fragments.join(""), path, lineNumber, false);
9054
+ if (record !== void 0) yield record.value;
9055
+ } finally {
9056
+ stream.destroy();
9057
+ }
9058
+ } finally {
9059
+ await handle.close();
9060
+ }
9061
+ }
9062
+ /** An invalid unterminated tail may be a torn write; other parse failures are not evidence of one. */
9063
+ function parseRecord(line, source, lineNumber, terminated) {
9064
+ if (line.length === 0) return void 0;
9065
+ try {
9066
+ return { value: JSON.parse(line) };
9067
+ } catch (cause) {
9068
+ if (!(cause instanceof SyntaxError)) throw cause;
9069
+ if (!terminated) return void 0;
9070
+ throw new Error(`${source}: malformed JSONL record at line ${lineNumber}`, { cause });
9071
+ }
9072
+ }
9073
+ /** FileHandle.write may legally make a short write. Loop until every byte is appended. */
9074
+ async function writeAllBytes(handle, value) {
9075
+ const bytes = typeof value === "string" ? Buffer.from(value) : Buffer.from(value);
9076
+ let offset = 0;
9077
+ while (offset < bytes.byteLength) {
9078
+ const { bytesWritten } = await handle.write(bytes, offset, bytes.byteLength - offset, null);
9079
+ if (bytesWritten <= 0) throw new Error(`append-only file write made no progress at byte ${offset}`);
9080
+ offset += bytesWritten;
9081
+ }
9082
+ }
9083
+ /** Prepare the tail under the journal owner's existing single-writer discipline.
9084
+ * Healthy appends read one byte, regardless of history size. Only recovery scans backward,
9085
+ * retaining a valid unterminated value or truncating an uncommitted torn tail. */
9086
+ async function prepareJsonlAppend(path) {
9087
+ const fs = await import("node:fs/promises");
9088
+ let handle;
9089
+ try {
9090
+ handle = await fs.open(path, "r+");
9091
+ } catch (error) {
9092
+ if (isNoEntError(error)) return false;
9093
+ throw error;
9094
+ }
9095
+ try {
9096
+ const size = (await handle.stat()).size;
9097
+ if (size === 0) return false;
9098
+ const lastByte = Buffer.allocUnsafe(1);
9099
+ await readAt(handle, lastByte, size - 1);
9100
+ if (lastByte[0] === 10) return false;
9101
+ const chunks = [];
9102
+ let end = size;
9103
+ let tailStart = 0;
9104
+ while (end > 0) {
9105
+ const start = Math.max(0, end - 65536);
9106
+ const chunk = Buffer.allocUnsafe(end - start);
9107
+ await readAt(handle, chunk, start);
9108
+ const newline = chunk.lastIndexOf(10);
9109
+ chunks.push(chunk.subarray(newline + 1));
9110
+ if (newline >= 0) {
9111
+ tailStart = start + newline + 1;
9112
+ break;
9113
+ }
9114
+ end = start;
9115
+ }
9116
+ const tail = Buffer.concat(chunks.reverse()).toString("utf8");
9117
+ try {
9118
+ JSON.parse(tail);
9119
+ return true;
9120
+ } catch (error) {
9121
+ if (!(error instanceof SyntaxError)) throw error;
9122
+ await handle.truncate(tailStart);
9123
+ await handle.sync();
9124
+ return false;
9125
+ }
9126
+ } finally {
9127
+ await handle.close();
9128
+ }
9129
+ }
9130
+ /** A short read is legal; an unexpected EOF means the owner's snapshot changed. */
9131
+ async function readAt(handle, buffer, position) {
9132
+ let offset = 0;
9133
+ while (offset < buffer.length) {
9134
+ const { bytesRead } = await handle.read(buffer, offset, buffer.length - offset, position + offset);
9135
+ if (bytesRead === 0) throw new Error("journal changed while preparing its append tail");
9136
+ offset += bytesRead;
9137
+ }
9138
+ }
9139
+ /** True for a filesystem error meaning "the file is not there yet" — the one condition an
9140
+ * append-only reader treats as an empty log rather than a fault. */
9141
+ function isNoEntError(error) {
9142
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
9143
+ }
9144
+ //#endregion
9533
9145
  //#region src/durable/spawn-journal.ts
9534
9146
  /**
9535
9147
  * Mint the content-addressed `outRef` for a result artifact: `sha256:<hex>` over a
@@ -10175,17 +9787,15 @@ var SpawnEventIndex = class {
10175
9787
  }
10176
9788
  };
10177
9789
  /**
10178
- * The records that CLOSE a node's cursor slot: a settlement, a cancellation, or a wait being
10179
- * woken. The complement question to {@link outsideCursorNamespace}, and the one a resume needs —
9790
+ * The records that CLOSE a node's cursor slot: a settlement or a cancellation. The complement question to {@link outsideCursorNamespace}, and the one a resume needs —
10180
9791
  * a kind missing here leaves a finished node looking live, so its budget is never reclaimed and
10181
9792
  * its reservation is replayed as still in doubt.
10182
9793
  */
10183
9794
  function closesCursorSlot(ev) {
10184
- return ev.kind === "settled" || ev.kind === "cancelled" || ev.kind === "woken";
9795
+ return ev.kind === "settled" || ev.kind === "cancelled";
10185
9796
  }
10186
9797
  const outsideKinds = /* @__PURE__ */ new Set([
10187
9798
  "spawned",
10188
- "waiting",
10189
9799
  "metered",
10190
9800
  "materialized",
10191
9801
  "execution-bound",
@@ -10202,8 +9812,12 @@ const outsideKinds = /* @__PURE__ */ new Set([
10202
9812
  "environment-teardown",
10203
9813
  "workspace-checkpoint-requested",
10204
9814
  "workspace-checkpoint",
9815
+ "workspace-checkpoint-fork-requested",
9816
+ "workspace-checkpoint-fork-teardown",
9817
+ "workspace-checkpoint-capture",
10205
9818
  "workspace-checkpoint-cleanup",
10206
9819
  "workspace-restored",
9820
+ "workspace-capture",
10207
9821
  "trace-unpropagated",
10208
9822
  "paused",
10209
9823
  "driver-attempt",
@@ -10242,7 +9856,7 @@ async function replaySpawnTree(journal, blobs, root) {
10242
9856
  const materializations = /* @__PURE__ */ new Map();
10243
9857
  const executionBindings = /* @__PURE__ */ new Map();
10244
9858
  for (const ev of ordered) {
10245
- if (ev.kind === "spawned" || ev.kind === "waiting") labels.set(ev.id, ev.label);
9859
+ if (ev.kind === "spawned") labels.set(ev.id, ev.label);
10246
9860
  if (ev.kind === "spawned" && ev.assignmentId !== void 0) assignmentIds.set(ev.id, ev.assignmentId);
10247
9861
  if (ev.kind === "spawned" && ev.identity !== void 0) identities.set(ev.id, copyFrozenIdentity(ev.identity));
10248
9862
  if (ev.kind === "materialized") materializations.set(ev.id, ev.receipt);
@@ -10265,7 +9879,6 @@ async function replaySpawnTree(journal, blobs, root) {
10265
9879
  const settled = [];
10266
9880
  for (const ev of ordered) {
10267
9881
  if (ev.kind === "spawned") continue;
10268
- if (ev.kind === "waiting") continue;
10269
9882
  if (ev.kind === "metered") continue;
10270
9883
  if (ev.kind === "progress") continue;
10271
9884
  if (ev.kind === "reconciled") continue;
@@ -10278,47 +9891,18 @@ async function replaySpawnTree(journal, blobs, root) {
10278
9891
  if (ev.kind === "environment-teardown") continue;
10279
9892
  if (ev.kind === "workspace-checkpoint-requested") continue;
10280
9893
  if (ev.kind === "workspace-checkpoint") continue;
9894
+ if (ev.kind === "workspace-checkpoint-fork-requested") continue;
9895
+ if (ev.kind === "workspace-checkpoint-fork-teardown") continue;
9896
+ if (ev.kind === "workspace-checkpoint-capture") continue;
10281
9897
  if (ev.kind === "workspace-checkpoint-cleanup") continue;
10282
9898
  if (ev.kind === "workspace-restored") continue;
9899
+ if (ev.kind === "workspace-capture") continue;
10283
9900
  if (ev.kind === "trace-unpropagated") continue;
10284
9901
  if (ev.kind === "paused") continue;
10285
9902
  if (ev.kind === "driver-attempt") continue;
10286
9903
  if (ev.kind === "node-inputs-resolved") continue;
10287
9904
  if (ev.kind === "edge-verdict") continue;
10288
9905
  if (ev.kind === "join-state") continue;
10289
- if (ev.kind === "woken") {
10290
- if (ev.by === "cancelled" || ev.outRef === void 0) {
10291
- settled.push({
10292
- kind: "down",
10293
- handle: handleFor(ev.id, "cancelled"),
10294
- reason: "wait cancelled",
10295
- infra: false,
10296
- trace: {
10297
- status: "unavailable",
10298
- reason: "not-an-executor"
10299
- },
10300
- ...settlementTime(ev.at),
10301
- seq: ev.seq
10302
- });
10303
- continue;
10304
- }
10305
- const outcome = await blobs.get(ev.outRef);
10306
- if (outcome === void 0) throw new Error(`replaySpawnTree: blob store has no wait outcome for outRef '${ev.outRef}' (node '${ev.id}', seq ${ev.seq})`);
10307
- settled.push({
10308
- kind: "done",
10309
- handle: handleFor(ev.id, "done"),
10310
- out: outcome,
10311
- outRef: ev.outRef,
10312
- spent: zeroSpend(),
10313
- trace: {
10314
- status: "unavailable",
10315
- reason: "not-an-executor"
10316
- },
10317
- ...settlementTime(ev.at),
10318
- seq: ev.seq
10319
- });
10320
- continue;
10321
- }
10322
9906
  if (ev.kind === "cancelled") {
10323
9907
  settled.push({
10324
9908
  kind: "down",
@@ -10418,24 +10002,9 @@ function copyFrozenIdentity(identity) {
10418
10002
  function materializeTreeView(events) {
10419
10003
  const nodes = /* @__PURE__ */ new Map();
10420
10004
  let root;
10421
- const spawns = events.filter((ev) => ev.kind === "spawned" || ev.kind === "waiting").sort((a, b) => a.seq - b.seq);
10005
+ const spawns = events.filter((ev) => ev.kind === "spawned").sort((a, b) => a.seq - b.seq);
10422
10006
  const settlements = events.filter((ev) => insideCursorNamespace(ev)).sort((a, b) => a.seq - b.seq);
10423
10007
  for (const ev of spawns) {
10424
- if (ev.kind === "waiting") {
10425
- nodes.set(ev.id, {
10426
- id: ev.id,
10427
- parent: ev.parent,
10428
- label: ev.label,
10429
- status: "waiting",
10430
- runtime: "wait",
10431
- budget: {
10432
- maxIterations: 0,
10433
- maxTokens: 0
10434
- },
10435
- spent: zeroSpend()
10436
- });
10437
- continue;
10438
- }
10439
10008
  if (ev.parent === void 0 && root === void 0) root = ev.id;
10440
10009
  nodes.set(ev.id, {
10441
10010
  id: ev.id,
@@ -10463,16 +10032,6 @@ function materializeTreeView(events) {
10463
10032
  if (ev.retainedPendingCause !== void 0) node.retainedPendingCause = ev.retainedPendingCause;
10464
10033
  const settledAt = Date.parse(ev.at);
10465
10034
  if (Number.isFinite(settledAt)) node.settledAt = settledAt;
10466
- } else if (ev.kind === "woken") {
10467
- const node = requireNode(nodes, ev.id);
10468
- node.status = ev.by === "cancelled" ? "cancelled" : "done";
10469
- node.outRef = ev.outRef;
10470
- node.trace = {
10471
- status: "unavailable",
10472
- reason: "not-an-executor"
10473
- };
10474
- const settledAt = Date.parse(ev.at);
10475
- if (Number.isFinite(settledAt)) node.settledAt = settledAt;
10476
10035
  } else {
10477
10036
  const node = requireNode(nodes, ev.id);
10478
10037
  node.status = "cancelled";
@@ -10514,31 +10073,9 @@ function materializeTreeView(events) {
10514
10073
  return {
10515
10074
  root: root ?? snapshots[0]?.id ?? "",
10516
10075
  nodes: snapshots,
10517
- inFlight: snapshots.filter((n) => n.status === "running" || n.status === "acquiring").length,
10518
- waiting: snapshots.filter((n) => n.status === "waiting").length
10076
+ inFlight: snapshots.filter((n) => n.status === "running" || n.status === "acquiring").length
10519
10077
  };
10520
10078
  }
10521
- /**
10522
- * The waits a journaled tree shows as ARMED but never woken — what a resumed run re-arms with the
10523
- * ORIGINAL absolute deadline. Reading it from the journal (rather than from any live state) is
10524
- * what makes "SIGKILL a waiting tree, a new process keeps waiting to the same instant" true.
10525
- */
10526
- function pendingWaits(events) {
10527
- const woken = /* @__PURE__ */ new Set();
10528
- for (const ev of events) if (ev.kind === "woken") woken.add(ev.id);
10529
- const pending = [];
10530
- for (const ev of events) {
10531
- if (ev.kind !== "waiting" || woken.has(ev.id)) continue;
10532
- pending.push({
10533
- id: ev.id,
10534
- label: ev.label,
10535
- spec: ev.spec,
10536
- armedAt: ev.armedAt,
10537
- ordinal: ev.seq
10538
- });
10539
- }
10540
- return pending.sort((a, b) => a.ordinal - b.ordinal);
10541
- }
10542
10079
  /** Copy a terminal record's overspend at the journal boundary; absent stays absent. */
10543
10080
  function budgetViolationOf(event) {
10544
10081
  if (event.budgetViolation === void 0) return {};
@@ -10622,6 +10159,18 @@ function executorEvidenceWriter(args) {
10622
10159
  });
10623
10160
  };
10624
10161
  }
10162
+ /** @internal The journal writer for `onWorkspaceCapture`; `nextSequence` is the node's own. */
10163
+ function workspaceCaptureWriter(args) {
10164
+ return async (capture) => {
10165
+ await args.journal.appendEvent(args.rootId, {
10166
+ kind: "workspace-capture",
10167
+ id: args.nodeId,
10168
+ ...detachedSnapshot(capture, "workspace capture timing"),
10169
+ seq: args.nextSequence(),
10170
+ at: new Date(args.now()).toISOString()
10171
+ });
10172
+ };
10173
+ }
10625
10174
  function retainedExecutorContext(ctx) {
10626
10175
  return ctx.seams[retainedExecutorSeamKey];
10627
10176
  }
@@ -11054,6 +10603,9 @@ function jitteredMs(ms, random) {
11054
10603
  const WORKSPACE_CHECKPOINT_MARKER_PATH = ".agent-runtime-checkpoint";
11055
10604
  /** Bound on one checkpoint: environment lookup, marker write, and the provider operation. */
11056
10605
  const WORKSPACE_CHECKPOINT_TIMEOUT_MS = 12e4;
10606
+ /** Bound on creating and reconstructing the fork a checkpoint's capture reads: a Sandbox box
10607
+ * created from a snapshot (measured 2026-09-24: 19 s). The capture itself is bounded by its port. */
10608
+ const WORKSPACE_CHECKPOINT_FORK_TIMEOUT_MS = 10 * 6e4;
11057
10609
  /** Write the marker. False when the environment cannot take it, so no restore can be verified. */
11058
10610
  async function writeWorkspaceMarker(environment, marker, signal) {
11059
10611
  if (typeof environment.write !== "function") return false;
@@ -11286,6 +10838,18 @@ function createProviderExecutor(provider, profile, ctx, options, placement) {
11286
10838
  let pending = false;
11287
10839
  let harnessTranscript = harnessTranscriptUnavailable("execution-never-started");
11288
10840
  const retention = retainedExecutorContext(ctx);
10841
+ const managerStop = readOptionalAbortSignal(ctx, bridgeStopSignalKey, "provider");
10842
+ const cancelRetainedOnManagerStop = (handle) => {
10843
+ if (managerStop === void 0) return;
10844
+ const cancel = () => {
10845
+ handle.cancel({
10846
+ operationId: `manager-stop:${randomUUID()}`,
10847
+ reason: String(managerStop.reason ?? "the manager stopped")
10848
+ }).catch(() => void 0);
10849
+ };
10850
+ if (managerStop.aborted) cancel();
10851
+ else managerStop.addEventListener("abort", cancel, { once: true });
10852
+ };
11289
10853
  let destroyed = false;
11290
10854
  let workspaceEnvironmentId;
11291
10855
  let workspaceSnapshot;
@@ -11378,7 +10942,19 @@ function createProviderExecutor(provider, profile, ctx, options, placement) {
11378
10942
  profile: createProfile,
11379
10943
  ...outcome === void 0 ? {} : { outcome }
11380
10944
  };
11381
- workspaceCapturePromise = (nativeInFlight ?? Promise.resolve()).then(() => captureProviderWorkspaceSnapshot(workspaceRetention, captureContext)).then(({ snapshot, provenance, coverageComplete, incompleteReason }) => {
10945
+ const reportTiming = retention?.onWorkspaceCapture;
10946
+ let timing;
10947
+ const capturedExecutionId = workspaceExecutionId;
10948
+ workspaceCapturePromise = (nativeInFlight ?? Promise.resolve()).then(() => captureProviderWorkspaceSnapshot(workspaceRetention, captureContext, "environment", reportTiming === void 0 ? void 0 : (measured) => {
10949
+ timing = measured;
10950
+ })).finally(async () => {
10951
+ if (timing === void 0 || reportTiming === void 0) return;
10952
+ await reportTiming({
10953
+ executionId: capturedExecutionId,
10954
+ environmentId: next.id,
10955
+ ...timing
10956
+ }).catch(() => void 0);
10957
+ }).then(({ snapshot, provenance, coverageComplete, incompleteReason }) => {
11382
10958
  workspaceSnapshot = snapshot;
11383
10959
  workspaceProvenance = provenance;
11384
10960
  workspaceCoverageComplete = coverageComplete ?? false;
@@ -11695,10 +11271,12 @@ function createProviderExecutor(provider, profile, ctx, options, placement) {
11695
11271
  ...carried === void 0 ? {} : { carried },
11696
11272
  executionStartedAt,
11697
11273
  mayContinue: options.unavailablePause !== false && invocation.retention?.continueInvocation !== void 0,
11274
+ managerStopped: () => managerStop?.aborted === true,
11698
11275
  onRetained: (handle) => {
11699
11276
  retained = handle;
11700
11277
  workspaceControlRef = freezeControlRef(handle.controlRef);
11701
11278
  providerSessionId = workspaceControlRef.sessionId;
11279
+ cancelRetainedOnManagerStop(handle);
11702
11280
  },
11703
11281
  onPending: (value) => {
11704
11282
  pending = value;
@@ -11978,6 +11556,19 @@ async function* streamProviderExecutor(args) {
11978
11556
  let failure;
11979
11557
  let failed = false;
11980
11558
  let unavailable;
11559
+ let finalCopyTaken = false;
11560
+ const ownerTakesCapture = () => args.options.workspaceRetention?.captureNative !== void 0 && args.createProfile.harness !== void 0 && source.retained && args.retention?.preserveEnvironment === true && args.retention.onEndOfTurnWork !== void 0;
11561
+ const handCaptureToOwner = (reported, captureOutcome, publish) => {
11562
+ args.retention?.onEndOfTurnWork?.(args.captureWorkspace(environment, captureOutcome).then(async (snapshot) => {
11563
+ if (publish) args.onPublishedSnapshot(snapshot);
11564
+ if (snapshot === void 0) return;
11565
+ await args.retention?.onEvidence?.({
11566
+ ...reported,
11567
+ workspaceSnapshot: snapshot,
11568
+ workspaceCapture: providerWorkspaceCaptureReceipt(args, environment, snapshot, turn.sessionId ?? null)
11569
+ });
11570
+ }, () => void 0));
11571
+ };
11981
11572
  let harnessStop;
11982
11573
  const stopEndedHarness = () => {
11983
11574
  if (settled !== void 0 || !linked.aborted) return Promise.resolve();
@@ -12058,14 +11649,17 @@ async function* streamProviderExecutor(args) {
12058
11649
  box: environmentAsSandboxInstance(environment, { requireTerminalEvent: args.options.requireTerminalEvent ?? true }),
12059
11650
  signal: linked
12060
11651
  });
11652
+ const deferCapture = ownerTakesCapture() && args.managerStopped();
12061
11653
  let retainedWorkspace;
12062
11654
  let workspaceCaptureFailure;
12063
- try {
12064
- retainedWorkspace = await args.captureWorkspace(environment, outcome);
12065
- } catch (error) {
12066
- workspaceCaptureFailure = `${errorText(error instanceof Error ? error.message : error)}; source environment preserved`;
11655
+ if (!deferCapture) {
11656
+ try {
11657
+ retainedWorkspace = await args.captureWorkspace(environment, outcome);
11658
+ } catch (error) {
11659
+ workspaceCaptureFailure = `${errorText(error instanceof Error ? error.message : error)}; source environment preserved`;
11660
+ }
11661
+ args.onPublishedSnapshot(retainedWorkspace);
12067
11662
  }
12068
- args.onPublishedSnapshot(retainedWorkspace);
12069
11663
  const settledResult = {
12070
11664
  ...result,
12071
11665
  ...workspaceCaptureFailure === void 0 ? {} : { workspaceCaptureFailure },
@@ -12099,6 +11693,11 @@ async function* streamProviderExecutor(args) {
12099
11693
  else if (retainedWorkspace !== void 0) await args.retention?.onEvidence?.(settledResult);
12100
11694
  args.onPending(false);
12101
11695
  args.onArtifact(settled);
11696
+ if (deferCapture) {
11697
+ await args.finishNativeMirror(environment, "settled");
11698
+ finalCopyTaken = true;
11699
+ handCaptureToOwner(settledResult, outcome, true);
11700
+ }
12102
11701
  } catch (error) {
12103
11702
  failure = source.retained ? new RetainedExecutionPendingError(error) : error;
12104
11703
  failed = true;
@@ -12112,7 +11711,14 @@ async function* streamProviderExecutor(args) {
12112
11711
  await stopEndedHarness();
12113
11712
  if (linked.aborted) await args.finishNativeMirror(environment, "failed");
12114
11713
  args.onTranscriptSettled();
12115
- try {
11714
+ if (ownerTakesCapture()) {
11715
+ if (!linked.aborted) await args.finishNativeMirror(environment, "failed");
11716
+ finalCopyTaken = true;
11717
+ handCaptureToOwner({
11718
+ ...resultFromEvents(archive.events(), text),
11719
+ outcome: failureOutcome
11720
+ }, failureOutcome, false);
11721
+ } else try {
12116
11722
  const retainedWorkspace = await args.captureWorkspace(environment, failureOutcome);
12117
11723
  if (retainedWorkspace !== void 0 && args.retention?.onEvidence !== void 0) await args.retention.onEvidence({
12118
11724
  ...resultFromEvents(archive.events(), text),
@@ -12127,7 +11733,7 @@ async function* streamProviderExecutor(args) {
12127
11733
  if (args.options.workspaceRetention === void 0) args.onHarnessTranscript(await captureHarnessTranscript(environment, args.profile.harness, linked));
12128
11734
  } finally {
12129
11735
  await stopEndedHarness();
12130
- await args.finishNativeMirror(environment, failed ? "failed" : settled !== void 0 ? "settled" : "interrupted");
11736
+ if (!finalCopyTaken) await args.finishNativeMirror(environment, failed ? "failed" : settled !== void 0 ? "settled" : "interrupted");
12131
11737
  if ((!source.retained || settled !== void 0 && !failed) && !(source.retained && args.retention?.preserveEnvironment) && !(unavailable !== void 0 && !failed) && (args.options.destroyOnSettle ?? true)) {
12132
11738
  const cleanup = await args.destroyEnvironment();
12133
11739
  if (!cleanup.destroyed) {
@@ -13277,6 +12883,14 @@ async function runBrainLoop(opts) {
13277
12883
  role: "assistant",
13278
12884
  content: r.content
13279
12885
  });
12886
+ const next = maxTurns === 0 || turn < maxTurns ? await opts.hooks?.afterFinal?.(turn) : void 0;
12887
+ if (next !== void 0) {
12888
+ messages.push({
12889
+ role: "user",
12890
+ content: next
12891
+ });
12892
+ continue;
12893
+ }
13280
12894
  return {
13281
12895
  final: lastText,
13282
12896
  turns: turn,
@@ -14364,34 +13978,6 @@ function buildBackendOptions(profile, overrides) {
14364
13978
  };
14365
13979
  }
14366
13980
  //#endregion
14367
- //#region src/runtime/sandbox-capabilities.ts
14368
- const probeCache = /* @__PURE__ */ new WeakMap();
14369
- /**
14370
- * Probe (and memoize per client) what the loop may rely on. A client without a
14371
- * `criuStatus` method, or whose probe rejects, yields `canFork = false` — a
14372
- * failed probe must never claim a capability the platform may not have. The
14373
- * promise is cached so concurrent fanout branches share one round-trip.
14374
- *
14375
- * @experimental
14376
- */
14377
- function probeSandboxCapabilities(client) {
14378
- const key = client;
14379
- const cached = probeCache.get(key);
14380
- if (cached) return cached;
14381
- const probe = resolveCapabilities(client);
14382
- probeCache.set(key, probe);
14383
- return probe;
14384
- }
14385
- async function resolveCapabilities(client) {
14386
- const criuStatus = client.criuStatus;
14387
- if (typeof criuStatus !== "function") return { canFork: false };
14388
- try {
14389
- return { canFork: (await criuStatus.call(client))?.available === true };
14390
- } catch {
14391
- return { canFork: false };
14392
- }
14393
- }
14394
- //#endregion
14395
13981
  //#region src/runtime/sandbox-lineage.ts
14396
13982
  const TEARDOWN_TIMEOUT_MS$1 = 15e3;
14397
13983
  const DEFAULT_FORK_CONCURRENCY = 4;
@@ -14457,13 +14043,11 @@ function promptEvents(streaming, box, prompt, sessionId, signal, promptOptions)
14457
14043
  });
14458
14044
  }
14459
14045
  /**
14460
- * Build a lineage bound to one client + its probed capabilities. The
14461
- * capabilities are passed in (not re-probed) so the kernel probes once per run
14462
- * and the lineage stays a pure function of "what this platform can do".
14046
+ * Build a lineage bound to one client. Branching is read from each box.
14463
14047
  *
14464
14048
  * @experimental
14465
14049
  */
14466
- function createSandboxLineage(client, capabilities, options = {}) {
14050
+ function createSandboxLineage(client, options = {}) {
14467
14051
  if (!client || typeof client.create !== "function") throw new ValidationError$1("createSandboxLineage: client.create is required");
14468
14052
  const streaming = options.streaming ?? "sse";
14469
14053
  const recordMount = options.recordMount ?? (() => {});
@@ -14553,30 +14137,10 @@ function createSandboxLineage(client, capabilities, options = {}) {
14553
14137
  };
14554
14138
  });
14555
14139
  }
14556
- const checkpointId = capabilities.canFork ? await checkpointForFork(parent.box, signal) : void 0;
14557
14140
  return mapWithConcurrency(prompts, forkConcurrency, async (prompt, i) => {
14558
14141
  throwIfAborted(signal);
14559
14142
  const spec = specs[i % specs.length];
14560
14143
  if (!spec) throw new ValidationError$1("SandboxLineage.fork: no AgentRunSpec for branch");
14561
- if (checkpointId !== void 0) {
14562
- const box = await forkFromCheckpoint(parent.box, checkpointId, signal);
14563
- owned.push(box);
14564
- const inheritedProfile = profiles.get(parent.box) ?? spec.profile;
14565
- profiles.set(box, inheritedProfile);
14566
- options.onAcquire?.(box, inheritedProfile);
14567
- await spec.prepareBox?.(box, {
14568
- signal,
14569
- recordMount
14570
- });
14571
- const sessionId = mintSessionId();
14572
- return {
14573
- handle: {
14574
- box,
14575
- sessionId
14576
- },
14577
- events: promptEvents(streaming, box, prompt, sessionId, signal, optionsFor(i))
14578
- };
14579
- }
14580
14144
  const box = await acquireFresh(spec, signal);
14581
14145
  const sessionId = mintSessionId();
14582
14146
  return {
@@ -14616,8 +14180,8 @@ function mintSessionId() {
14616
14180
  }
14617
14181
  /**
14618
14182
  * Branch a running parent through the current Sandbox SDK, in bounded waves.
14619
- * `undefined` means the box exposes only the legacy checkpoint API (or no
14620
- * branching API), so the caller may try the legacy capability-gated path.
14183
+ * `undefined` means the box exposes no branching API, so the caller starts
14184
+ * fresh boxes.
14621
14185
  */
14622
14186
  async function branchParent(box, count, concurrency, signal) {
14623
14187
  const branch = box.branch;
@@ -14638,34 +14202,6 @@ async function branchParent(box, count, concurrency, signal) {
14638
14202
  }
14639
14203
  }
14640
14204
  /**
14641
- * Checkpoint the parent leaving it running, returning the checkpoint id to fork
14642
- * from, or `undefined` when the box exposes no legacy `checkpoint` method or
14643
- * the call produced no id. `undefined` makes the caller use fresh boxes — a
14644
- * fork that cannot preserve context must not pretend to share it.
14645
- */
14646
- async function checkpointForFork(box, signal) {
14647
- const checkpoint = box.checkpoint;
14648
- if (typeof checkpoint !== "function") return void 0;
14649
- if (signal.aborted) throwAbort();
14650
- const id = (await checkpoint.call(box, { leaveRunning: true }))?.checkpointId;
14651
- return typeof id === "string" && id.length > 0 ? id : void 0;
14652
- }
14653
- /**
14654
- * Fork a child box from `checkpointId`. The box exposes `fork` whenever the
14655
- * platform advertised `canFork`; a missing `fork` here is a contract violation
14656
- * (probe said yes, box says no) and fails loud rather than silently degrading.
14657
- *
14658
- * `signal` gates entry only: the legacy SDK's `fork(checkpointId, options)`
14659
- * takes no abort signal, so an in-flight fork cannot be interrupted. The
14660
- * caller checks abort per branch, so cancellation is responsive at boundaries.
14661
- */
14662
- async function forkFromCheckpoint(box, checkpointId, signal) {
14663
- const fork = box.fork;
14664
- if (typeof fork !== "function") throw new ValidationError$1("SandboxLineage.fork: capabilities report canFork but the box has no fork() method");
14665
- if (signal.aborted) throwAbort();
14666
- return fork.call(box, checkpointId);
14667
- }
14668
- /**
14669
14205
  * Fail loud when a handle's session is no longer known to the sandbox. The real
14670
14206
  * SDK box exposes `session(id).status()` which resolves `null` for an unknown /
14671
14207
  * reaped id; a `null` here means a `continue` would run WITHOUT the prior
@@ -14909,9 +14445,8 @@ async function setUpLineage(options, maxConcurrency, recordMount, promptOptions,
14909
14445
  const lineageOpts = options.lineage;
14910
14446
  if (!lineageOpts || !lineageOpts.sessionContinuity && !lineageOpts.forkFanout) return void 0;
14911
14447
  if (options.onWorkerBox) throw new ValidationError$1("runAgentRounds: `lineage` and `onWorkerBox` both own worker boxes — pass only one");
14912
- const capabilities = await probeSandboxCapabilities(options.ctx.sandboxClient);
14913
14448
  return {
14914
- lineage: createSandboxLineage(options.ctx.sandboxClient, capabilities, {
14449
+ lineage: createSandboxLineage(options.ctx.sandboxClient, {
14915
14450
  maxConcurrency,
14916
14451
  streaming: lineageOpts.streaming,
14917
14452
  recordMount,
@@ -15526,209 +15061,91 @@ const TERMINAL_DECISIONS = [
15526
15061
  ];
15527
15062
  /** True when the kernel stops the loop for this decision value. @stable */
15528
15063
  function isTerminalDecision(decision) {
15529
- return TERMINAL_DECISIONS.includes(decision);
15530
- }
15531
- function emitRunLoopHook(options, event) {
15532
- notifyRuntimeHookEvent(options.ctx.hooks, {
15533
- id: `${event.runId}:${event.target}:${event.phase}${event.stepIndex === void 0 ? "" : `:${event.stepIndex}`}`,
15534
- runId: event.runId,
15535
- target: event.target,
15536
- phase: event.phase,
15537
- timestamp: event.timestamp,
15538
- stepIndex: event.stepIndex,
15539
- payload: event.payload,
15540
- metadata: { producer: "run-loop" }
15541
- }, { signal: options.ctx.signal });
15542
- }
15543
- async function emitTrace(emitter, event) {
15544
- if (!emitter) return;
15545
- await emitter.emit(event);
15546
- }
15547
- /**
15548
- * Stable hash for the trace payload. Not cryptographic — only used so
15549
- * downstream eval pipelines can group iterations whose task / output is the
15550
- * same. Bare structural hash; non-JSON values stringify via their `toString`.
15551
- */
15552
- function hashJson(value) {
15553
- let str;
15554
- try {
15555
- str = JSON.stringify(value) ?? String(value);
15556
- } catch {
15557
- str = String(value);
15558
- }
15559
- let h = 2166136261;
15560
- for (let i = 0; i < str.length; i += 1) {
15561
- h ^= str.charCodeAt(i);
15562
- h = Math.imul(h, 16777619);
15563
- }
15564
- return (h >>> 0).toString(16).padStart(8, "0");
15565
- }
15566
- //#endregion
15567
- //#region src/runtime/sandbox-executor-output.ts
15568
- /** Project the complete Sandbox event stream into the standard executor result shape. */
15569
- function sandboxLeafOutputFromEvents(events) {
15570
- const content = collectAgentFinalMessageText(events) ?? collectAgentResponseText(events);
15571
- const toolCalls = sandboxToolCalls(events);
15572
- const servedBackend = lastServedBackend(events);
15573
- return {
15574
- events,
15575
- content,
15576
- output: sandboxOutputMarker(content, events.some(carriesText)),
15577
- ...servedBackend === void 0 ? {} : { servedBackend },
15578
- ...toolCalls.length === 0 ? {} : { toolCalls }
15579
- };
15580
- }
15581
- /**
15582
- * Classify observed text into the explicit output marker. `sawTextEvent` says whether the stream
15583
- * carried a text-bearing event at all, which is what separates a box that answered nothing from a
15584
- * box whose answer was never observed.
15585
- */
15586
- function sandboxOutputMarker(content, sawTextEvent = content !== void 0) {
15587
- if (content !== void 0 && content.length > 0) return {
15588
- kind: "text",
15589
- bytes: Buffer.byteLength(content, "utf8")
15590
- };
15591
- return sawTextEvent ? { kind: "empty" } : { kind: "absent" };
15592
- }
15593
- /** True when the event carries a text field a turn's answer could come from, empty or not. */
15594
- function carriesText(event) {
15595
- if (!event || typeof event !== "object") return false;
15596
- const data = event.data && typeof event.data === "object" ? event.data : {};
15597
- if (typeof data.finalText === "string" || typeof data.text === "string") return true;
15598
- if (typeof data.delta === "string") return true;
15599
- const part = data.part && typeof data.part === "object" ? data.part : void 0;
15600
- return part !== void 0 && part.type === "text" && typeof part.text === "string";
15601
- }
15602
- /** The last served identity the platform reported across a turn's events, or `undefined`. */
15603
- function lastServedBackend(events) {
15604
- let served;
15605
- for (const event of events) {
15606
- const next = sandboxEventServedBackend(event);
15607
- if (next !== void 0) served = next;
15608
- }
15609
- return served;
15610
- }
15611
- function sandboxToolCalls(events) {
15612
- const state = createSandboxToolPartState();
15613
- return events.flatMap((event) => mapSandboxToolEvent(event, state).flatMap((projected) => projected.type === "tool_call" ? [{
15614
- ...projected.toolCallId === void 0 ? {} : { id: projected.toolCallId },
15615
- name: projected.toolName,
15616
- arguments: projected.args ?? {}
15617
- }] : []));
15618
- }
15619
- //#endregion
15620
- //#region src/runtime/supervise/executor-seams.ts
15621
- function assertExactConfigKeys(value, allowed, context) {
15622
- const unknown = Object.keys(value).filter((key) => !allowed.has(key));
15623
- if (unknown.length > 0) throw new ValidationError$1(`${context}: unknown fields ${unknown.sort().join(", ")}; execution behavior belongs in AgentProfile`);
15624
- }
15625
- /** Narrow a named seam off the `ExecutorContext`, failing loud when absent — no
15626
- * silent default for a required external-boundary seam. */
15627
- function readSeam(ctx, key, who) {
15628
- const seam = ctx.seams[key];
15629
- if (seam === void 0 || seam === null) throw new ValidationError$1(`${who} executor: missing required seam "${key}" on ExecutorContext`);
15630
- return seam;
15631
- }
15632
- function readOptionalAbortSignal(ctx, key, who) {
15633
- const value = ctx.seams[key];
15634
- if (value === void 0) return void 0;
15635
- if (value === null || typeof value !== "object" || typeof value.aborted !== "boolean" || typeof value.addEventListener !== "function") throw new ValidationError$1(`${who} executor: seam "${key}" must be an AbortSignal`);
15636
- return value;
15637
- }
15638
- /** Narrow the Runtime-owned MCP attachment seam. Absent means the run mounts nothing; a present
15639
- * value must be a named map of MCP servers, never an empty one that would silently mount nothing. */
15640
- function readOptionalMcpAttachments(ctx, key, who) {
15641
- const value = ctx.seams[key];
15642
- if (value === void 0) return void 0;
15643
- const entries = value !== null && typeof value === "object" && !Array.isArray(value) ? Object.entries(value) : void 0;
15644
- if (entries === void 0 || entries.length === 0 || entries.some(([, server]) => server === null || typeof server !== "object")) throw new ValidationError$1(`${who} executor: seam ${JSON.stringify(key)} must be a non-empty map of MCP servers`);
15645
- return value;
15646
- }
15647
- //#endregion
15648
- //#region src/runtime/supervise/bridge-config.ts
15649
- const bridgeSeamKey = "bridge";
15650
- /** Internal control seam used by Runtime-owned external supervisors. A completion request stops
15651
- * the next bridge turn; it must not abort the paid request that is already streaming. */
15652
- const bridgeStopSignalKey = "__bridge_stop_signal";
15653
- /** Internal attachment seam used by Runtime-owned external supervisors. The named MCP servers ride
15654
- * beside the AgentProfile as `runtime_attachments`, so the bridge mounts them for the run and keeps
15655
- * them out of its session profile binding. A rebound coordination port therefore cannot move the
15656
- * authored profile digest that binds a durable session. */
15657
- const bridgeRuntimeAttachmentsKey = "__bridge_runtime_attachments";
15658
- const maxBridgeTimeoutMs = 2147483647;
15659
- function isLoopbackBridgeHost(hostname) {
15660
- const host = hostname.trim().toLowerCase().replace(/^\[/, "").replace(/\]$/, "");
15661
- if (host === "localhost" || host === "::1" || host === "0:0:0:0:0:0:0:1") return true;
15662
- if (host === "::ffff:127.0.0.1") return true;
15663
- return /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/u.test(host);
15664
- }
15665
- function isLoopbackBridgeUrl(value) {
15666
- try {
15667
- const target = new URL(value);
15668
- return (target.protocol === "http:" || target.protocol === "https:") && isLoopbackBridgeHost(target.hostname);
15669
- } catch {
15670
- return false;
15671
- }
15672
- }
15673
- /** Validate and capture the non-serialisable credential service without reading its value. */
15674
- function captureBridgeModelCredential(value, context) {
15675
- if (value === null || typeof value !== "object") throw new ValidationError$1(`${context}: modelCredential must be an object`);
15676
- assertExactConfigKeys(value, /* @__PURE__ */ new Set([
15677
- "baseUrlKey",
15678
- "key",
15679
- "provider"
15680
- ]), `${context} modelCredential`);
15681
- if (typeof value.key !== "string" || value.key.trim().length === 0) throw new ValidationError$1(`${context}: modelCredential.key must be a non-empty string`);
15682
- if (typeof value.baseUrlKey !== "string" || value.baseUrlKey.trim().length === 0) throw new ValidationError$1(`${context}: modelCredential.baseUrlKey must be a non-empty string`);
15683
- if (value.baseUrlKey === value.key) throw new ValidationError$1(`${context}: modelCredential.baseUrlKey must differ from key`);
15684
- if (!value.provider || typeof value.provider.get !== "function") throw new ValidationError$1(`${context}: modelCredential.provider must implement get(name)`);
15685
- const captured = {
15686
- key: value.key,
15687
- baseUrlKey: value.baseUrlKey
15688
- };
15689
- Object.defineProperty(captured, "provider", {
15690
- configurable: false,
15691
- enumerable: false,
15692
- value: value.provider,
15693
- writable: false
15694
- });
15695
- return Object.freeze(captured);
15064
+ return TERMINAL_DECISIONS.includes(decision);
15696
15065
  }
15697
- function validateBridgeModelCredential(value, bridgeUrl, context) {
15698
- if (value === void 0) return void 0;
15699
- if (!isLoopbackBridgeUrl(bridgeUrl)) throw new ValidationError$1(`${context}: modelCredential is allowed only for a loopback bridge URL`);
15700
- return captureBridgeModelCredential(value, context);
15066
+ function emitRunLoopHook(options, event) {
15067
+ notifyRuntimeHookEvent(options.ctx.hooks, {
15068
+ id: `${event.runId}:${event.target}:${event.phase}${event.stepIndex === void 0 ? "" : `:${event.stepIndex}`}`,
15069
+ runId: event.runId,
15070
+ target: event.target,
15071
+ phase: event.phase,
15072
+ timestamp: event.timestamp,
15073
+ stepIndex: event.stepIndex,
15074
+ payload: event.payload,
15075
+ metadata: { producer: "run-loop" }
15076
+ }, { signal: options.ctx.signal });
15701
15077
  }
15702
- function resolveProtectedModelBaseUrl(value, context) {
15703
- let target;
15078
+ async function emitTrace(emitter, event) {
15079
+ if (!emitter) return;
15080
+ await emitter.emit(event);
15081
+ }
15082
+ /**
15083
+ * Stable hash for the trace payload. Not cryptographic — only used so
15084
+ * downstream eval pipelines can group iterations whose task / output is the
15085
+ * same. Bare structural hash; non-JSON values stringify via their `toString`.
15086
+ */
15087
+ function hashJson(value) {
15088
+ let str;
15704
15089
  try {
15705
- target = new URL(value);
15090
+ str = JSON.stringify(value) ?? String(value);
15706
15091
  } catch {
15707
- throw new ValidationError$1(`${context}: modelCredential.baseUrl must be an absolute HTTPS URL`);
15092
+ str = String(value);
15708
15093
  }
15709
- if (target.protocol !== "https:" || target.username || target.password || target.search || target.hash) throw new ValidationError$1(`${context}: modelCredential.baseUrl must be an HTTPS URL without credentials, query, or fragment`);
15710
- return target.toString().replace(/\/$/u, "");
15094
+ return fnv1a32Hex(str);
15711
15095
  }
15712
- /** Resolve only at the outbound boundary. Provider errors are redacted because they may contain
15713
- * the protected value; diagnostics identify key names, never values or provider errors. */
15714
- async function resolveBridgeModelCredential(credential, context) {
15715
- if (credential === void 0) return void 0;
15716
- const resolveValue = async (key) => {
15717
- let value;
15718
- try {
15719
- value = await credential.provider.get(key);
15720
- } catch {
15721
- throw new ValidationError$1(`${context}: modelCredential provider failed for '${key}'`);
15722
- }
15723
- if (typeof value !== "string" || value.length === 0 || /[\r\n\0]/u.test(value)) throw new ValidationError$1(`${context}: modelCredential provider has no usable value for '${key}'`);
15724
- return value;
15725
- };
15726
- const [token, baseUrl] = await Promise.all([resolveValue(credential.key), resolveValue(credential.baseUrlKey)]);
15096
+ //#endregion
15097
+ //#region src/runtime/sandbox-executor-output.ts
15098
+ /** Project the complete Sandbox event stream into the standard executor result shape. */
15099
+ function sandboxLeafOutputFromEvents(events) {
15100
+ const content = collectAgentFinalMessageText(events) ?? collectAgentResponseText(events);
15101
+ const toolCalls = sandboxToolCalls(events);
15102
+ const servedBackend = lastServedBackend(events);
15727
15103
  return {
15728
- token,
15729
- baseUrl: resolveProtectedModelBaseUrl(baseUrl, context)
15104
+ events,
15105
+ content,
15106
+ output: sandboxOutputMarker(content, events.some(carriesText)),
15107
+ ...servedBackend === void 0 ? {} : { servedBackend },
15108
+ ...toolCalls.length === 0 ? {} : { toolCalls }
15730
15109
  };
15731
15110
  }
15111
+ /**
15112
+ * Classify observed text into the explicit output marker. `sawTextEvent` says whether the stream
15113
+ * carried a text-bearing event at all, which is what separates a box that answered nothing from a
15114
+ * box whose answer was never observed.
15115
+ */
15116
+ function sandboxOutputMarker(content, sawTextEvent = content !== void 0) {
15117
+ if (content !== void 0 && content.length > 0) return {
15118
+ kind: "text",
15119
+ bytes: Buffer.byteLength(content, "utf8")
15120
+ };
15121
+ return sawTextEvent ? { kind: "empty" } : { kind: "absent" };
15122
+ }
15123
+ /** True when the event carries a text field a turn's answer could come from, empty or not. */
15124
+ function carriesText(event) {
15125
+ if (!event || typeof event !== "object") return false;
15126
+ const data = event.data && typeof event.data === "object" ? event.data : {};
15127
+ if (typeof data.finalText === "string" || typeof data.text === "string") return true;
15128
+ if (typeof data.delta === "string") return true;
15129
+ const part = data.part && typeof data.part === "object" ? data.part : void 0;
15130
+ return part !== void 0 && part.type === "text" && typeof part.text === "string";
15131
+ }
15132
+ /** The last served identity the platform reported across a turn's events, or `undefined`. */
15133
+ function lastServedBackend(events) {
15134
+ let served;
15135
+ for (const event of events) {
15136
+ const next = sandboxEventServedBackend(event);
15137
+ if (next !== void 0) served = next;
15138
+ }
15139
+ return served;
15140
+ }
15141
+ function sandboxToolCalls(events) {
15142
+ const state = createSandboxToolPartState();
15143
+ return events.flatMap((event) => mapSandboxToolEvent(event, state).flatMap((projected) => projected.type === "tool_call" ? [{
15144
+ ...projected.toolCallId === void 0 ? {} : { id: projected.toolCallId },
15145
+ name: projected.toolName,
15146
+ arguments: projected.args ?? {}
15147
+ }] : []));
15148
+ }
15732
15149
  //#endregion
15733
15150
  //#region src/runtime/codex-rollout-store.ts
15734
15151
  const zeroCounters = {
@@ -17179,9 +16596,6 @@ async function cancelBridgeRunToTerminal(seam, run, grace, stopSignal) {
17179
16596
  await new Promise((resolve) => setTimeout(resolve, 10));
17180
16597
  }
17181
16598
  }
17182
- function errorMessage(error) {
17183
- return error instanceof Error ? error.message : String(error);
17184
- }
17185
16599
  /** Read only the Router-owned one-sided field from an error body. */
17186
16600
  function providerDispatchFromErrorBody(body) {
17187
16601
  let parsed;
@@ -17197,13 +16611,7 @@ function providerDispatchFromErrorBody(body) {
17197
16611
  }
17198
16612
  //#endregion
17199
16613
  //#region src/runtime/supervise/node-status.ts
17200
- /**
17201
- * Which {@link NodeStatus} values mean the node is finished.
17202
- *
17203
- * `'waiting'` is deliberately NOT terminal: a wait-state node holds no executor, no box and no
17204
- * conserved budget, so it is neither in flight nor settled. Callers that must also exclude it say
17205
- * so at their own site, because "finished" and "not a live worker" are different questions.
17206
- */
16614
+ /** Which {@link NodeStatus} values mean the node is finished. */
17207
16615
  const terminalNodeStatuses = /* @__PURE__ */ new Set([
17208
16616
  "done",
17209
16617
  "failed",
@@ -17613,11 +17021,20 @@ function renderPeerMail(message, nonce) {
17613
17021
  function createInbox() {
17614
17022
  const pending = [];
17615
17023
  let live = null;
17024
+ let waiters = [];
17616
17025
  return {
17026
+ nextDelivery() {
17027
+ return new Promise((resolve) => {
17028
+ waiters.push(resolve);
17029
+ });
17030
+ },
17617
17031
  deliver(msg) {
17618
17032
  const m = parseDown(msg);
17619
17033
  if (!m) return false;
17620
17034
  pending.push(m);
17035
+ const woken = waiters;
17036
+ waiters = [];
17037
+ for (const wake of woken) wake();
17621
17038
  if (m.interrupt && live && !live.signal.aborted) live.abort();
17622
17039
  return true;
17623
17040
  },
@@ -19171,8 +18588,7 @@ function createSteerableSandboxSession(args) {
19171
18588
  let preservationFailure;
19172
18589
  let preservationError;
19173
18590
  let executionFailure;
19174
- const capabilities = await probeSandboxCapabilities(args.sandboxClient);
19175
- const lineage = createSandboxLineage(args.sandboxClient, capabilities, {
18591
+ const lineage = createSandboxLineage(args.sandboxClient, {
19176
18592
  maxConcurrency: 1,
19177
18593
  failOnDestroyError: args.failOnDestroyError
19178
18594
  });
@@ -20923,9 +20339,6 @@ function bridgeOutputText(out) {
20923
20339
  return String(out);
20924
20340
  }
20925
20341
  }
20926
- function isAsyncIterable$1(value) {
20927
- return value !== null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function";
20928
- }
20929
20342
  /**
20930
20343
  * The leaf `createWorktreeCliExecutor` as a backend-as-data factory: a supervisor-authored
20931
20344
  * `AgentProfile` driving claude / codex / opencode on its own worktree. `budgetExempt` like
@@ -21737,7 +21150,13 @@ async function startRetainedInteractiveRun(options) {
21737
21150
  });
21738
21151
  return createRetainedInteractiveRunHandle(environment, ref, capabilities, request);
21739
21152
  }
21740
- /** Retry one exact start after its provider response may have been lost. @stable */
21153
+ /**
21154
+ * Retry one exact start after its provider response may have been lost.
21155
+ *
21156
+ * Resolves to the handle of the admitted process (resumed through the exact,
21157
+ * idempotent start request), or `null` when the provider no longer holds the
21158
+ * environment (not found; nothing remains to stop). @stable
21159
+ */
21741
21160
  async function recoverRetainedInteractiveRun(options) {
21742
21161
  options.signal?.throwIfAborted();
21743
21162
  if (typeof options.onAdmission !== "function") throw new Error("recoverRetainedInteractiveRun requires an awaited onAdmission durability hook");
@@ -22169,27 +21588,6 @@ function workerInteractiveAdmissionFile(eventDir, workerId, phase) {
22169
21588
  assertNoSymlinkDescendant(eventDir, dir, "interactive admission");
22170
21589
  return join(dir, `${canonicalCandidateDigest({ workerId: id }).slice(7).slice(0, 32)}.${phase}.admission.json`);
22171
21590
  }
22172
- /** Read all durable admissions for one worker, oldest phase first. */
22173
- function readWorkerInteractiveAdmissions(eventDir, workerId) {
22174
- const phases = [
22175
- "interactive_intent",
22176
- "interactive_environment",
22177
- "interactive_started"
22178
- ];
22179
- const admissions = [];
22180
- let missingPhase = false;
22181
- for (const phase of phases) {
22182
- const file = workerInteractiveAdmissionFile(eventDir, workerId, phase);
22183
- if (!existsSync(file)) {
22184
- missingPhase = true;
22185
- continue;
22186
- }
22187
- if (missingPhase) throw new Error(`interactive admission phase '${phase}' exists after a missing earlier phase`);
22188
- const parsed = JSON.parse(readFileSync(file, "utf8"));
22189
- admissions.push(parseAdmission(parsed, workerId, phase));
22190
- }
22191
- return admissions;
22192
- }
22193
21591
  /**
22194
21592
  * Persist one retained-interactive admission without retaining sensitive start material.
22195
21593
  *
@@ -22848,8 +22246,6 @@ async function prepareScopeResume(opts, events, signal, now, parentId = opts.run
22848
22246
  view: materializeTreeView(prior),
22849
22247
  maxSpawnOrdinal: maxSeqOf(prior, (event) => event.kind === "spawned"),
22850
22248
  maxCursorSeq: reservedCursorFloor(prior),
22851
- maxWaitOrdinal: maxSeqOf(prior, (event) => event.kind === "waiting"),
22852
- waits: pendingWaits(prior),
22853
22249
  keys: keyedAssignments(prior, settled),
22854
22250
  priorSpend: sumMeasuredSpendFromEvents(prior)
22855
22251
  }
@@ -23245,6 +22641,18 @@ function registerScopeRetainedOwner(scope, args) {
23245
22641
  nextSequence: () => state.nextSequence(),
23246
22642
  now: args.now
23247
22643
  }),
22644
+ onWorkspaceCapture: workspaceCaptureWriter({
22645
+ journal: args.journal,
22646
+ rootId: args.rootId,
22647
+ nodeId: args.nodeId,
22648
+ nextSequence: () => state.nextSequence(),
22649
+ now: args.now
22650
+ }),
22651
+ onEndOfTurnWork: (work) => {
22652
+ const prior = state.turnEnd;
22653
+ const settled = work.catch(() => void 0);
22654
+ state.turnEnd = prior === void 0 ? settled : Promise.all([prior, settled]).then(() => {});
22655
+ },
23248
22656
  onResult: async (result) => {
23249
22657
  scope.signal.throwIfAborted();
23250
22658
  assertValidSpend(result.spent, "retained owner result");
@@ -23274,10 +22682,16 @@ function registerScopeRetainedOwner(scope, args) {
23274
22682
  function scopeRetainedOwnerContext(scope) {
23275
22683
  return owners.get(scope)?.context;
23276
22684
  }
23277
- /** Bind cleanup before replay can return an already accepted owner result. */
23278
- function bindScopeRetainedOwnerProvider(scope, provider) {
22685
+ /**
22686
+ * Bind cleanup before replay can return an already accepted owner result. `checkpointCapture` is
22687
+ * where each checkpoint's files are stored before the checkpoint is deleted; without it, no
22688
+ * checkpoint of this owner is deleted.
22689
+ */
22690
+ function bindScopeRetainedOwnerProvider(scope, provider, checkpointCapture) {
23279
22691
  const state = owners.get(scope);
23280
- if (state) state.provider = provider;
22692
+ if (state === void 0) return;
22693
+ state.provider = provider;
22694
+ if (checkpointCapture !== void 0) state.checkpointCapture = checkpointCapture;
23281
22695
  }
23282
22696
  /** Bind the owner cleanup policy selected by its provider executor. */
23283
22697
  function bindScopeRetainedOwnerWorkspaceRetention(scope, enabled) {
@@ -23452,7 +22866,8 @@ async function checkpointOwnerWorkspace(scope, state) {
23452
22866
  seq: state.nextSequence(),
23453
22867
  at
23454
22868
  });
23455
- await deleteCheckpoints(state, branching, pendingCheckpoints(await args.journal.loadTree(args.rootId) ?? [], state).filter((event) => event.environmentId === environment.id).slice(0, -2), signal);
22869
+ const events = await args.journal.loadTree(args.rootId) ?? [];
22870
+ await cleanCheckpoints(state, branching, pendingCheckpoints(events, state).filter((event) => event.environmentId === environment.id && state.captureRefused?.has(event.checkpoint.checkpointId) !== true).slice(0, -2), events, scope.signal);
23456
22871
  }
23457
22872
  /** Reconstruct authority for this source only; a replacement cannot own its snapshots. */
23458
22873
  async function checkpointHandle(state, sourceEnvironmentId, signal) {
@@ -23475,7 +22890,14 @@ async function checkpointHandle(state, sourceEnvironmentId, signal) {
23475
22890
  return;
23476
22891
  }
23477
22892
  }
23478
- /** An aborted observation cannot prove that the provider never created a snapshot. */
22893
+ /**
22894
+ * An aborted observation cannot prove that the provider never created a snapshot, so a request
22895
+ * whose lookup does not find it keeps its source alive for a later lookup, with one exception: a
22896
+ * provider that answers `not_found` for a request older than {@link WORKSPACE_CHECKPOINT_ABSENT_AFTER_MS}
22897
+ * never created it. No operation that request started can still be in flight, and keeping the
22898
+ * source then holds a sandbox for nothing: on Discovery Lab runs terraform-economics-20261005e and
22899
+ * f, each root was kept after its run settled over requests made hours earlier.
22900
+ */
23479
22901
  async function reconcileCheckpointRequests(state, events) {
23480
22902
  const operationKey = (operation) => JSON.stringify([operation.idempotencyKey, operation.requestDigest]);
23481
22903
  const resolved = new Set(events.flatMap((event) => event.kind === "workspace-checkpoint" && event.id === state.args.nodeId && event.provider === state.provider?.name ? [operationKey(event.checkpoint)] : []));
@@ -23490,7 +22912,29 @@ async function reconcileCheckpointRequests(state, events) {
23490
22912
  idempotencyKey: event.request.idempotencyKey,
23491
22913
  requestDigest: event.request.requestDigest
23492
22914
  }, { signal }), signal, "retained owner checkpoint lookup timed out");
23493
- if (result.status !== "found" || !workspaceCheckpointResultMatchesRequest(event.request, result)) throw new Error("checkpoint operation outcome is unresolved");
22915
+ if (result.status === "not_found") {
22916
+ const requestedAt = Date.parse(event.at);
22917
+ if (Number.isFinite(requestedAt) && state.args.now() - requestedAt >= 12e5) continue;
22918
+ unconfirmed.push({
22919
+ event,
22920
+ reason: "lookup not_found while the request may be in flight"
22921
+ });
22922
+ continue;
22923
+ }
22924
+ if (result.status !== "found") {
22925
+ unconfirmed.push({
22926
+ event,
22927
+ reason: `lookup ${result.status}${"message" in result && result.message ? `: ${result.message}` : ""}`
22928
+ });
22929
+ continue;
22930
+ }
22931
+ if (!workspaceCheckpointResultMatchesRequest(event.request, result)) {
22932
+ unconfirmed.push({
22933
+ event,
22934
+ reason: "lookup found a checkpoint for another request"
22935
+ });
22936
+ continue;
22937
+ }
23494
22938
  const recovered = {
23495
22939
  kind: "workspace-checkpoint",
23496
22940
  id: event.id,
@@ -23503,8 +22947,11 @@ async function reconcileCheckpointRequests(state, events) {
23503
22947
  };
23504
22948
  await state.args.journal.appendEvent(state.args.rootId, recovered);
23505
22949
  events.push(recovered);
23506
- } catch {
23507
- unconfirmed.push(event);
22950
+ } catch (error) {
22951
+ unconfirmed.push({
22952
+ event,
22953
+ reason: `lookup failed: ${errorText(error instanceof Error ? error.message : error)}`
22954
+ });
23508
22955
  }
23509
22956
  }
23510
22957
  return unconfirmed;
@@ -23513,10 +22960,35 @@ function pendingCheckpoints(events, state) {
23513
22960
  const confirmed = new Set(events.flatMap((event) => event.kind === "workspace-checkpoint-cleanup" && event.id === state.args.nodeId && event.provider === state.provider?.name && event.confirmed ? [JSON.stringify([event.environmentId, event.checkpointId])] : []));
23514
22961
  return events.filter((event) => event.kind === "workspace-checkpoint" && event.id === state.args.nodeId && event.provider === state.provider?.name && !confirmed.has(JSON.stringify([event.environmentId, event.checkpoint.checkpointId])));
23515
22962
  }
23516
- /** Only the source-scoped handle can attest deletion, including after its source is lost. */
23517
- async function deleteCheckpoints(state, branching, checkpoints, signal) {
22963
+ /**
22964
+ * Delete checkpoints, each only after its files are captured into the run's content-addressed
22965
+ * store; a checkpoint no capture holds is kept, and the cleanup record says why. Only the
22966
+ * source-scoped handle can fork a checkpoint and attest its deletion, including after its source
22967
+ * is lost. `parent` cancels the captures (the owner's scope during rotation); each provider
22968
+ * operation also has its own bound.
22969
+ */
22970
+ async function cleanCheckpoints(state, branching, checkpoints, events, parent) {
23518
22971
  const unconfirmed = [];
22972
+ const refused = [];
23519
22973
  for (const event of checkpoints) {
22974
+ const captured = await captureBeforeCleanup(state, branching, event, events, parent);
22975
+ if ("reason" in captured) {
22976
+ (state.captureRefused ??= /* @__PURE__ */ new Set()).add(event.checkpoint.checkpointId);
22977
+ refused.push(captured);
22978
+ await state.args.journal.appendEvent(state.args.rootId, {
22979
+ kind: "workspace-checkpoint-cleanup",
22980
+ id: state.args.nodeId,
22981
+ provider: event.provider,
22982
+ environmentId: event.environmentId,
22983
+ checkpointId: event.checkpoint.checkpointId,
22984
+ confirmed: false,
22985
+ refused: captured.reason.slice(0, 1e3),
22986
+ seq: state.nextSequence(),
22987
+ at: new Date(state.args.now()).toISOString()
22988
+ });
22989
+ continue;
22990
+ }
22991
+ state.captureRefused?.delete(event.checkpoint.checkpointId);
23520
22992
  const material = {
23521
22993
  kind: "checkpoint",
23522
22994
  targetId: event.checkpoint.checkpointId,
@@ -23530,6 +23002,7 @@ async function deleteCheckpoints(state, branching, checkpoints, signal) {
23530
23002
  let confirmed = false;
23531
23003
  try {
23532
23004
  if (branching === void 0) throw new Error("source-scoped checkpoint handle unavailable");
23005
+ const signal = AbortSignal.timeout(3e4);
23533
23006
  const acknowledgement = await runAbortable(() => branching.deleteCheckpoint(request, { signal }), signal, "retained owner checkpoint cleanup timed out");
23534
23007
  confirmed = workspaceCleanupAcknowledgementMatches(request, acknowledgement) && (acknowledgement.status === "deleted" || acknowledgement.status === "already_absent");
23535
23008
  } catch {}
@@ -23541,11 +23014,178 @@ async function deleteCheckpoints(state, branching, checkpoints, signal) {
23541
23014
  environmentId: event.environmentId,
23542
23015
  checkpointId: event.checkpoint.checkpointId,
23543
23016
  confirmed,
23017
+ capturedDigest: captured.digest,
23544
23018
  seq: state.nextSequence(),
23545
23019
  at: new Date(state.args.now()).toISOString()
23546
23020
  });
23547
23021
  }
23548
- return unconfirmed;
23022
+ return {
23023
+ unconfirmed,
23024
+ refused
23025
+ };
23026
+ }
23027
+ /**
23028
+ * The digest of the tree that holds a checkpoint's files, capturing it first when no record says
23029
+ * one exists, or why it cannot be had. The files are read from a fork of the checkpoint: a box
23030
+ * created from the snapshot itself, so the capture is the checkpoint's state and not the live
23031
+ * workspace's, which has moved on. The fork request is journaled before it is made and the fork
23032
+ * destroyed once the capture is journaled, so neither a failure nor a crash leaves it running
23033
+ * unrecorded.
23034
+ */
23035
+ async function captureBeforeCleanup(state, branching, event, events, parent) {
23036
+ const { args } = state;
23037
+ const checkpointId = event.checkpoint.checkpointId;
23038
+ const recorded = events.find((prior) => prior.kind === "workspace-checkpoint-capture" && prior.id === args.nodeId && prior.provider === event.provider && prior.environmentId === event.environmentId && prior.checkpointId === checkpointId);
23039
+ if (recorded !== void 0) return { digest: recorded.tree.digest };
23040
+ const refuse = (reason, needsSource) => ({
23041
+ event,
23042
+ reason,
23043
+ needsSource
23044
+ });
23045
+ const capture = state.checkpointCapture;
23046
+ if (capture?.port.captureCheckpoint === void 0) return refuse("no checkpoint capture: the owner backend has no captureCheckpoint", false);
23047
+ const provider = state.provider;
23048
+ if (provider?.get === void 0) return refuse("the provider cannot reconstruct a fork of the checkpoint", false);
23049
+ if (branching === void 0) return refuse("source-scoped checkpoint handle unavailable", true);
23050
+ const material = {
23051
+ checkpoint: event.checkpoint,
23052
+ placement: { kind: "sandbox" }
23053
+ };
23054
+ const request = {
23055
+ ...material,
23056
+ idempotencyKey: `${event.checkpoint.idempotencyKey}:capture:${state.nextSequence()}`,
23057
+ requestDigest: workspaceForkRequestDigest(material)
23058
+ };
23059
+ const forkSignal = AbortSignal.any([...parent === void 0 ? [] : [parent], AbortSignal.timeout(WORKSPACE_CHECKPOINT_FORK_TIMEOUT_MS)]);
23060
+ let forkEnvironmentId;
23061
+ try {
23062
+ await args.journal.appendEvent(args.rootId, {
23063
+ kind: "workspace-checkpoint-fork-requested",
23064
+ id: args.nodeId,
23065
+ provider: event.provider,
23066
+ environmentId: event.environmentId,
23067
+ checkpointId,
23068
+ idempotencyKey: request.idempotencyKey,
23069
+ requestDigest: request.requestDigest,
23070
+ seq: state.nextSequence(),
23071
+ at: new Date(args.now()).toISOString()
23072
+ });
23073
+ const result = await runAbortable(() => branching.fork(request, { signal: forkSignal }), forkSignal, "checkpoint fork timed out");
23074
+ if (result.status === "created" || result.status === "replayed") forkEnvironmentId = result.environment.environmentId;
23075
+ if (result.status !== "created" && result.status !== "replayed" || !workspaceForkResultMatchesRequest(request, result)) return refuse(`fork ${result.status}${"message" in result ? `: ${result.message}` : ""}`, true);
23076
+ const forkId = result.environment.environmentId;
23077
+ const get = provider.get.bind(provider);
23078
+ const environment = await runAbortable(() => get(forkId), forkSignal, "checkpoint fork lookup timed out");
23079
+ if (environment === null || environment.id !== forkId || environment.provider !== provider.name) return refuse(`fork ${forkId} could not be reconstructed`, true);
23080
+ parent?.throwIfAborted();
23081
+ const tree = await captureProviderCheckpointWorkspace(capture.port, {
23082
+ environment,
23083
+ checkpoint: event.checkpoint,
23084
+ executionId: `${args.nodeId}:checkpoint:${checkpointId}`,
23085
+ profile: capture.profile
23086
+ }, event.marker);
23087
+ await args.journal.appendEvent(args.rootId, {
23088
+ kind: "workspace-checkpoint-capture",
23089
+ id: args.nodeId,
23090
+ provider: event.provider,
23091
+ environmentId: event.environmentId,
23092
+ checkpointId,
23093
+ fork: {
23094
+ idempotencyKey: request.idempotencyKey,
23095
+ environmentId: forkId
23096
+ },
23097
+ tree: {
23098
+ digest: tree.digest,
23099
+ manifest: tree.manifest,
23100
+ files: tree.files,
23101
+ bytes: tree.bytes,
23102
+ storedBytes: tree.storedBytes
23103
+ },
23104
+ seq: state.nextSequence(),
23105
+ at: new Date(args.now()).toISOString()
23106
+ });
23107
+ return { digest: tree.digest };
23108
+ } catch (error) {
23109
+ return refuse(`capture failed: ${errorText(error instanceof Error ? error.message : error)}`, true);
23110
+ } finally {
23111
+ if (forkEnvironmentId !== void 0) await destroyCaptureFork(state, branching, {
23112
+ provider: event.provider,
23113
+ environmentId: event.environmentId,
23114
+ checkpointId,
23115
+ fork: {
23116
+ idempotencyKey: request.idempotencyKey,
23117
+ environmentId: forkEnvironmentId
23118
+ }
23119
+ });
23120
+ }
23121
+ }
23122
+ /** Destroy a capture's fork and journal whether the provider confirmed it. */
23123
+ async function destroyCaptureFork(state, branching, target) {
23124
+ const material = {
23125
+ kind: "fork",
23126
+ targetId: target.fork.environmentId,
23127
+ provider: target.provider
23128
+ };
23129
+ const request = {
23130
+ ...material,
23131
+ operationId: `${target.fork.idempotencyKey}:destroy`,
23132
+ requestDigest: workspaceCleanupRequestDigest(material)
23133
+ };
23134
+ let destroyed = false;
23135
+ try {
23136
+ const signal = AbortSignal.timeout(3e4);
23137
+ const acknowledgement = await runAbortable(() => branching.destroyFork(request, { signal }), signal, "checkpoint capture fork cleanup timed out");
23138
+ destroyed = workspaceCleanupAcknowledgementMatches(request, acknowledgement) && (acknowledgement.status === "deleted" || acknowledgement.status === "already_absent");
23139
+ } catch {}
23140
+ await state.args.journal.appendEvent(state.args.rootId, {
23141
+ kind: "workspace-checkpoint-fork-teardown",
23142
+ id: state.args.nodeId,
23143
+ ...target,
23144
+ destroyed,
23145
+ seq: state.nextSequence(),
23146
+ at: new Date(state.args.now()).toISOString()
23147
+ });
23148
+ return destroyed;
23149
+ }
23150
+ /**
23151
+ * Destroy every capture fork the journal does not show destroyed: one a crash left between its
23152
+ * request and its teardown, or whose teardown the provider did not confirm. Returns the forks
23153
+ * still not confirmed destroyed, by environment or, when none was ever named, by request key.
23154
+ */
23155
+ async function settleCaptureForks(state) {
23156
+ const { args } = state;
23157
+ const providerName = state.provider?.name;
23158
+ const events = (await args.journal.loadTree(args.rootId) ?? []).filter((event) => event.id === args.nodeId);
23159
+ const named = (key) => {
23160
+ for (const event of events) if ((event.kind === "workspace-checkpoint-capture" || event.kind === "workspace-checkpoint-fork-teardown") && event.fork.idempotencyKey === key) return event.fork.environmentId;
23161
+ };
23162
+ const destroyed = new Set(events.flatMap((event) => event.kind === "workspace-checkpoint-fork-teardown" && event.destroyed ? [event.fork.idempotencyKey] : []));
23163
+ const unresolved = [];
23164
+ for (const request of events) {
23165
+ if (request.kind !== "workspace-checkpoint-fork-requested" || request.provider !== providerName) continue;
23166
+ if (destroyed.has(request.idempotencyKey)) continue;
23167
+ const signal = AbortSignal.timeout(3e4);
23168
+ const branching = await checkpointHandle(state, request.environmentId, signal);
23169
+ let forkEnvironmentId = named(request.idempotencyKey);
23170
+ if (forkEnvironmentId === void 0 && branching !== void 0) try {
23171
+ const found = await runAbortable(() => branching.lookupFork({
23172
+ idempotencyKey: request.idempotencyKey,
23173
+ requestDigest: request.requestDigest
23174
+ }, { signal }), signal, "checkpoint capture fork lookup timed out");
23175
+ if (found.status === "not_found") continue;
23176
+ if (found.status === "found") forkEnvironmentId = found.environment.environmentId;
23177
+ } catch {}
23178
+ if (forkEnvironmentId === void 0 || branching === void 0 || !await destroyCaptureFork(state, branching, {
23179
+ provider: request.provider,
23180
+ environmentId: request.environmentId,
23181
+ checkpointId: request.checkpointId,
23182
+ fork: {
23183
+ idempotencyKey: request.idempotencyKey,
23184
+ environmentId: forkEnvironmentId
23185
+ }
23186
+ })) unresolved.push(forkEnvironmentId ?? request.idempotencyKey);
23187
+ }
23188
+ return unresolved;
23549
23189
  }
23550
23190
  /**
23551
23191
  * The checkpoint a new environment of this owner starts from: the latest one journaled before
@@ -23565,33 +23205,111 @@ async function restoreCapable(provider) {
23565
23205
  }
23566
23206
  }
23567
23207
  /**
23568
- * What the owner's next new environment will hold of the lost one, read before the drive so the
23569
- * re-entered director is told: the checkpoint's time, or undefined when there is nothing to
23570
- * restore.
23208
+ * What the owner's next new environment will hold of the lost one, read before the drive so the
23209
+ * re-entered director is told: the checkpoint's time, or undefined when there is nothing to
23210
+ * restore.
23211
+ */
23212
+ async function scopeRetainedOwnerRestorePoint(scope) {
23213
+ const state = owners.get(scope);
23214
+ if (state === void 0 || !await restoreCapable(state.provider)) return void 0;
23215
+ const latest = restoreBefore((await state.args.journal.loadTree(state.args.rootId) ?? []).filter((event) => event.id === state.args.nodeId), -1);
23216
+ return latest === void 0 ? void 0 : {
23217
+ checkpointId: latest.checkpoint.checkpointId,
23218
+ takenAt: latest.at
23219
+ };
23220
+ }
23221
+ /** @internal Whether another owner release could still destroy what the last one left. */
23222
+ function retainedOwnerReleaseRetriable(scope) {
23223
+ return owners.get(scope)?.releaseRetriable ?? false;
23224
+ }
23225
+ /**
23226
+ * Mark one drive of the owner in progress until the returned function is called. An abort settles
23227
+ * the node while the drive is still ending its turn: stopping the harness, copying its session and
23228
+ * handing its workspace capture over. A release that ran then would find no receipt for the turn
23229
+ * and keep the source alive, as on terraform-economics-20261005f, where the root's last attempt was
23230
+ * recorded two minutes after its environment's release.
23231
+ */
23232
+ function beginScopeRetainedOwnerDrive(scope) {
23233
+ const state = owners.get(scope);
23234
+ if (state === void 0) return () => {};
23235
+ let end;
23236
+ const drive = new Promise((resolve) => {
23237
+ end = resolve;
23238
+ });
23239
+ state.drive = drive;
23240
+ return () => {
23241
+ end();
23242
+ if (state.drive === drive) delete state.drive;
23243
+ };
23244
+ }
23245
+ /** Wait, bounded like a turn's own ending, for the owner's drive in progress to end. */
23246
+ async function ownerDriveEnded(state) {
23247
+ const drive = state.drive;
23248
+ if (drive === void 0) return;
23249
+ let timer;
23250
+ try {
23251
+ await Promise.race([drive, new Promise((resolve) => {
23252
+ timer = setTimeout(resolve, HARNESS_TRANSCRIPT_SETTLE_TIMEOUT_MS);
23253
+ })]);
23254
+ } finally {
23255
+ if (timer !== void 0) clearTimeout(timer);
23256
+ }
23257
+ }
23258
+ /**
23259
+ * Wait for the end-of-turn work the owner's last turn handed over: its workspace capture and the
23260
+ * evidence record of its receipt. A turn hands it over so that its node settles without it; the
23261
+ * owner's next turn and its environment's release wait for it here.
23262
+ */
23263
+ async function scopeRetainedOwnerTurnEnded(scope) {
23264
+ const state = owners.get(scope);
23265
+ if (state === void 0) return;
23266
+ for (;;) {
23267
+ const pending = state.turnEnd;
23268
+ if (pending === void 0) return;
23269
+ await pending;
23270
+ if (state.turnEnd === pending) {
23271
+ delete state.turnEnd;
23272
+ return;
23273
+ }
23274
+ }
23275
+ }
23276
+ /** @internal Wait for everything this owner still has in flight: the drive ending its turn, the
23277
+ * work that turn handed over, and a release. */
23278
+ async function scopeRetainedOwnerSettled(scope) {
23279
+ const state = owners.get(scope);
23280
+ if (state === void 0) return;
23281
+ await ownerDriveEnded(state);
23282
+ await scopeRetainedOwnerTurnEnded(scope);
23283
+ await state.releasing?.catch(() => void 0);
23284
+ }
23285
+ /**
23286
+ * Release the owner's environment once no turn of it will run again: at the run's final
23287
+ * settlement for the root, and when a nested manager's own scope has finished. A second call while
23288
+ * one is in flight joins it. The release first waits for the end-of-turn capture of the owner's
23289
+ * last turn, so the capture always precedes the destroy.
23571
23290
  */
23572
- async function scopeRetainedOwnerRestorePoint(scope) {
23291
+ function releaseScopeRetainedOwnerEnvironment(scope) {
23573
23292
  const state = owners.get(scope);
23574
- if (state === void 0 || !await restoreCapable(state.provider)) return void 0;
23575
- const latest = restoreBefore((await state.args.journal.loadTree(state.args.rootId) ?? []).filter((event) => event.id === state.args.nodeId), -1);
23576
- return latest === void 0 ? void 0 : {
23577
- checkpointId: latest.checkpoint.checkpointId,
23578
- takenAt: latest.at
23579
- };
23580
- }
23581
- /** @internal Whether another owner release could still destroy what the last one left. */
23582
- function retainedOwnerReleaseRetriable(scope) {
23583
- return owners.get(scope)?.releaseRetriable ?? false;
23293
+ const provider = state?.provider;
23294
+ if (state === void 0 || provider === void 0) return Promise.resolve([]);
23295
+ if (state.releasing !== void 0) return state.releasing;
23296
+ const tracked = (async () => {
23297
+ await ownerDriveEnded(state);
23298
+ await scopeRetainedOwnerTurnEnded(scope);
23299
+ return await releaseOwnerEnvironment(state, provider);
23300
+ })().finally(() => {
23301
+ if (state.releasing === tracked) delete state.releasing;
23302
+ });
23303
+ state.releasing = tracked;
23304
+ return tracked;
23584
23305
  }
23585
- /** The existing scope settlement barrier releases the owner's environment after all its turns. */
23586
- async function releaseScopeRetainedOwnerEnvironment(scope) {
23587
- const state = owners.get(scope);
23588
- if (!state?.provider) return [];
23589
- const { provider, args } = state;
23306
+ async function releaseOwnerEnvironment(state, provider) {
23307
+ const { args } = state;
23590
23308
  state.checkpointsUnavailable ??= "released";
23591
23309
  await state.checkpointing?.catch(() => void 0);
23592
23310
  const events = [...await args.journal.loadTree(args.rootId) ?? []];
23593
23311
  const requestFailures = await reconcileCheckpointRequests(state, events);
23594
- const pendingSources = new Set(requestFailures.map((event) => event.environmentId));
23312
+ const pendingSources = new Set(requestFailures.map(({ event }) => event.environmentId));
23595
23313
  const released = new Set(events.flatMap((event) => event.kind === "environment-teardown" && event.id === args.nodeId && event.provider === provider.name && event.destroyed ? [event.environmentId] : []));
23596
23314
  const environments = new Set(events.flatMap((event) => event.id === args.nodeId && event.kind === "execution-admitted" && event.admission.phase === "environment" ? [event.admission.environmentId] : []));
23597
23315
  const retentionFailures = state.workspaceRetention || events.some((event) => event.kind === "execution-input" && event.id === args.nodeId && event.workspaceRetention === true) ? await ownerWorkspaceRetentionFailures(events, args.nodeId, args.blobs) : /* @__PURE__ */ new Set();
@@ -23600,19 +23318,23 @@ async function releaseScopeRetainedOwnerEnvironment(scope) {
23600
23318
  let lastDetail;
23601
23319
  let retriable = false;
23602
23320
  const checkpointFailures = [];
23321
+ const checkpointsKept = [];
23322
+ const uncapturedSources = /* @__PURE__ */ new Set();
23603
23323
  const pending = pendingCheckpoints(events, state).filter((event) => !retentionFailures.has(event.environmentId));
23604
23324
  for (const sourceEnvironmentId of new Set(pending.map((event) => event.environmentId))) {
23605
- const signal = AbortSignal.timeout(3e4);
23606
- const branching = await checkpointHandle(state, sourceEnvironmentId, signal);
23607
- checkpointFailures.push(...await deleteCheckpoints(state, branching, pending.filter((event) => event.environmentId === sourceEnvironmentId), signal));
23325
+ const cleaned = await cleanCheckpoints(state, await checkpointHandle(state, sourceEnvironmentId, AbortSignal.timeout(3e4)), pending.filter((event) => event.environmentId === sourceEnvironmentId), events);
23326
+ checkpointFailures.push(...cleaned.unconfirmed);
23327
+ checkpointsKept.push(...cleaned.refused);
23328
+ for (const refusal of cleaned.refused) if (refusal.needsSource) uncapturedSources.add(sourceEnvironmentId);
23608
23329
  }
23330
+ const forksUnresolved = await settleCaptureForks(state);
23609
23331
  for (const event of checkpointFailures) pendingSources.add(event.environmentId);
23610
23332
  for (const environmentId of environments) {
23611
23333
  if (released.has(environmentId)) continue;
23612
23334
  let destroyed = false;
23613
23335
  let detail;
23614
- if (retentionFailures.has(environmentId) || pendingSources.has(environmentId)) {
23615
- detail = pendingSources.has(environmentId) ? "checkpoint cleanup unresolved: source preserved for exact lookup and cleanup" : "provider workspace retention: source preserved because the owner execution has no verified workspace receipt";
23336
+ if (retentionFailures.has(environmentId) || pendingSources.has(environmentId) || uncapturedSources.has(environmentId)) {
23337
+ detail = pendingSources.has(environmentId) ? "checkpoint cleanup unresolved: source preserved for exact lookup and cleanup" : uncapturedSources.has(environmentId) ? "checkpoint kept uncaptured: source preserved so its checkpoint can still be forked and captured" : "provider workspace retention: source preserved because the owner execution has no verified workspace receipt";
23616
23338
  preserved.push(environmentId);
23617
23339
  lastDetail = detail;
23618
23340
  } else {
@@ -23668,19 +23390,36 @@ async function releaseScopeRetainedOwnerEnvironment(scope) {
23668
23390
  });
23669
23391
  }
23670
23392
  state.releaseRetriable = retriable;
23671
- const checkpointTeardowns = [...checkpointFailures.map((event) => ({
23672
- id: args.nodeId,
23673
- label: "scope owner workspace checkpoint",
23674
- runtime: provider.name,
23675
- status: "done",
23676
- detail: `checkpoint cleanup unconfirmed: ${event.checkpoint.checkpointId} from ${event.environmentId}`
23677
- })), ...requestFailures.map((event) => ({
23678
- id: args.nodeId,
23679
- label: "scope owner checkpoint request",
23680
- runtime: provider.name,
23681
- status: "done",
23682
- detail: `checkpoint request unresolved: ${event.request.idempotencyKey} from ${event.environmentId}`
23683
- }))];
23393
+ const checkpointTeardowns = [
23394
+ ...checkpointFailures.map((event) => ({
23395
+ id: args.nodeId,
23396
+ label: "scope owner workspace checkpoint",
23397
+ runtime: provider.name,
23398
+ status: "done",
23399
+ detail: `checkpoint cleanup unconfirmed: ${event.checkpoint.checkpointId} from ${event.environmentId}`
23400
+ })),
23401
+ ...requestFailures.map(({ event, reason }) => ({
23402
+ id: args.nodeId,
23403
+ label: "scope owner checkpoint request",
23404
+ runtime: provider.name,
23405
+ status: "done",
23406
+ detail: `checkpoint request unresolved: ${event.request.idempotencyKey} from ${event.environmentId} (${reason})`
23407
+ })),
23408
+ ...checkpointsKept.map(({ event, reason }) => ({
23409
+ id: args.nodeId,
23410
+ label: "scope owner workspace checkpoint",
23411
+ runtime: provider.name,
23412
+ status: "done",
23413
+ detail: `checkpoint kept uncaptured: ${event.checkpoint.checkpointId} from ${event.environmentId} (${reason})`
23414
+ })),
23415
+ ...forksUnresolved.length === 0 ? [] : [{
23416
+ id: args.nodeId,
23417
+ label: "scope owner checkpoint capture fork",
23418
+ runtime: provider.name,
23419
+ status: "done",
23420
+ detail: `checkpoint capture fork destruction unconfirmed: ${forksUnresolved.join(", ")}`
23421
+ }]
23422
+ ];
23684
23423
  return unconfirmed.length > 0 || preserved.length > 0 ? [{
23685
23424
  id: args.nodeId,
23686
23425
  label: "scope owner",
@@ -23718,7 +23457,15 @@ function unsettledOwnerRuns(events, nodeId, environmentId) {
23718
23457
  close();
23719
23458
  return [...runs.values()];
23720
23459
  }
23721
- /** Group owner admissions by input and require a verified workspace receipt before deletion. */
23460
+ /**
23461
+ * Group owner admissions by input and require a verified workspace receipt before deletion.
23462
+ *
23463
+ * The receipt is the attempt's committed result, or an evidence record of the same attempt: a
23464
+ * turn its manager stopped commits its result first and journals its capture as evidence after
23465
+ * it, and a turn that failed journals the capture it took of the stopped session. This runs only
23466
+ * at a release no process will resume, so a complete, verified capture of the exact execution is
23467
+ * the whole of what keeping the source would preserve.
23468
+ */
23722
23469
  async function ownerWorkspaceRetentionFailures(events, nodeId, blobs) {
23723
23470
  const attempts = [];
23724
23471
  let current;
@@ -23726,30 +23473,26 @@ async function ownerWorkspaceRetentionFailures(events, nodeId, blobs) {
23726
23473
  if (current !== void 0) attempts.push(current);
23727
23474
  current = void 0;
23728
23475
  };
23476
+ const fresh = (executionId) => ({
23477
+ ...executionId === void 0 ? {} : { executionId },
23478
+ environmentIds: /* @__PURE__ */ new Set(),
23479
+ controlByEnvironment: /* @__PURE__ */ new Map(),
23480
+ evidence: []
23481
+ });
23729
23482
  for (const event of events) {
23730
23483
  if (!("id" in event) || event.id !== nodeId) continue;
23731
23484
  if (event.kind === "execution-input") {
23732
23485
  flush();
23733
- current = {
23734
- executionId: `${nodeId}:input:${event.seq}`,
23735
- environmentIds: /* @__PURE__ */ new Set(),
23736
- controlByEnvironment: /* @__PURE__ */ new Map()
23737
- };
23486
+ current = fresh(`${nodeId}:input:${event.seq}`);
23738
23487
  } else if (event.kind === "execution-admitted" && event.admission.phase === "environment") {
23739
23488
  if (current?.result !== void 0) flush();
23740
- current ??= {
23741
- environmentIds: /* @__PURE__ */ new Set(),
23742
- controlByEnvironment: /* @__PURE__ */ new Map()
23743
- };
23489
+ current ??= fresh();
23744
23490
  current.environmentIds.add(event.admission.environmentId);
23745
23491
  } else if (event.kind === "execution-admitted" && event.admission.phase === "dispatched") current?.controlByEnvironment.set(event.admission.controlRef.environmentId, event.admission.controlRef);
23746
23492
  else if (event.kind === "execution-result") {
23747
- current ??= {
23748
- environmentIds: /* @__PURE__ */ new Set(),
23749
- controlByEnvironment: /* @__PURE__ */ new Map()
23750
- };
23493
+ current ??= fresh();
23751
23494
  current.result = event;
23752
- }
23495
+ } else if (event.kind === "execution-evidence") current?.evidence.push(event);
23753
23496
  }
23754
23497
  flush();
23755
23498
  const failures = /* @__PURE__ */ new Set();
@@ -23759,25 +23502,30 @@ async function ownerWorkspaceRetentionFailures(events, nodeId, blobs) {
23759
23502
  for (const environmentId of attempt.environmentIds) failures.add(environmentId);
23760
23503
  continue;
23761
23504
  }
23762
- const result = attempt.result;
23763
- if (result === void 0) {
23764
- for (const environmentId of attempt.environmentIds) failures.add(environmentId);
23765
- continue;
23766
- }
23767
- let output;
23768
- try {
23769
- output = await blobs.get(result.outRef);
23770
- if (output === void 0 || contentAddress(output) !== result.outRef) throw new Error();
23771
- } catch {
23772
- output = void 0;
23773
- }
23774
- const snapshot = output !== null && typeof output === "object" ? output.workspaceSnapshot : void 0;
23775
23505
  const environmentId = [...attempt.environmentIds][0];
23776
23506
  const controlRef = attempt.controlByEnvironment.get(environmentId);
23777
- if (!hasDurableWorkspaceCapture(output, snapshot, environmentId, attempt.executionId, controlRef)) failures.add(environmentId);
23507
+ const receipts = [...attempt.result === void 0 ? [] : [attempt.result.outRef], ...attempt.evidence.map((event) => event.outRef)];
23508
+ let verified = false;
23509
+ for (const outRef of receipts) {
23510
+ const output = await storedOutput(blobs, outRef);
23511
+ if (hasDurableWorkspaceCapture(output, output !== null && typeof output === "object" ? output.workspaceSnapshot : void 0, environmentId, attempt.executionId, controlRef)) {
23512
+ verified = true;
23513
+ break;
23514
+ }
23515
+ }
23516
+ if (!verified) failures.add(environmentId);
23778
23517
  }
23779
23518
  return failures;
23780
23519
  }
23520
+ /** A stored output whose bytes match its content reference, or undefined. */
23521
+ async function storedOutput(blobs, outRef) {
23522
+ try {
23523
+ const output = await blobs.get(outRef);
23524
+ return output === void 0 || contentAddress(output) !== outRef ? void 0 : output;
23525
+ } catch {
23526
+ return;
23527
+ }
23528
+ }
23781
23529
  /** A stored result authorizes cleanup only for the exact source and complete capture. */
23782
23530
  function hasDurableWorkspaceCapture(output, snapshot, environmentId, executionId, controlRef) {
23783
23531
  const parsed = agentCandidateWorkspaceSnapshotEvidenceSchema.safeParse(snapshot);
@@ -23976,180 +23724,6 @@ function consumeScopeRetainedOwnerResult(scope) {
23976
23724
  state.acceptedConsumed = true;
23977
23725
  }
23978
23726
  //#endregion
23979
- //#region src/runtime/supervise/wait.ts
23980
- /**
23981
- *
23982
- * WAIT-STATES — a supervision-tree node that waits on wall-clock time or an external condition
23983
- * without holding a worker, an executor, a sandbox, or a single LLM turn.
23984
- *
23985
- * A long-horizon run spends most of its wall-clock NOT computing: waiting for CI to finish,
23986
- * for a nightly job to land, for a human to reply, for a rate-limit window to reopen. Before
23987
- * this, the only way to express that was to keep something alive and re-ask — which spends
23988
- * driver tokens per re-ask and pins a process to the wait.
23989
- *
23990
- * Two node kinds, both first-class:
23991
- * - `timer` — wake at an ABSOLUTE wall-clock instant (`untilMs`).
23992
- * - `poll` — re-run a named predicate every `intervalMs` until it returns true, or until an
23993
- * absolute `timeoutAtMs` passes (CI status, file existence, an HTTP probe, an
23994
- * inbox message).
23995
- *
23996
- * ── How this differs from `await_event`'s 45s poll fence (`DEFAULT_AWAIT_EVENT_TIMEOUT_MS`) ──
23997
- *
23998
- * They look similar and are not the same mechanism. `await_event` is an IN-RUN RENDEZVOUS: the
23999
- * driver blocks on the coordination bus for the next event from a live worker, and the 45s fence
24000
- * exists only so a remote MCP request does not exceed the client's timeout — the caller re-polls.
24001
- * Every re-poll is another driver inference turn (real tokens) against a process that must stay
24002
- * up, and nothing about that wait is recorded: kill the process and the wait is simply gone.
24003
- *
24004
- * A wait-state is a NODE, not a call. It has a node id in the tree, a journal record carrying its
24005
- * ABSOLUTE deadline, and it settles through the same `Scope.next()` cursor as any worker. Nobody
24006
- * is blocked on it — the driver can stop reasoning entirely, and the process can die. Cost while
24007
- * waiting: zero LLM calls, zero executor, zero sandbox, zero conserved budget (a wait reserves
24008
- * nothing from the pool). The only in-process residue is one timer entry.
24009
- *
24010
- * ── Why probes are NAMED, not passed as closures ────────────────────────────────────────────
24011
- *
24012
- * A wait must survive a process restart with its original deadline intact, and a closure cannot
24013
- * be journaled. So a `poll` names its predicate (`probe: 'ci-green'`) and the run resolves it
24014
- * through a `WaitProbeRegistry`. A brand-new process re-resolves the SAME name against its own
24015
- * registry and re-arms the wait — which is what makes "kill the box, the wait keeps waiting"
24016
- * true rather than aspirational.
24017
- *
24018
- * Absolute instants for the same reason: `untilMs` / `timeoutAtMs` are epoch ms, not durations,
24019
- * so a resumed wait counts down from the original arm, not from the restart. `timerAt`/`pollFor`
24020
- * build them from a duration when that is what the caller has.
24021
- *
24022
- * @experimental
24023
- */
24024
- /** Build a `timer` spec from a DURATION. The instant is resolved once, at arm time — a resumed
24025
- * wait re-uses the journaled instant, never a fresh `now + ms`. */
24026
- function timerAt(ms, now) {
24027
- return {
24028
- kind: "timer",
24029
- untilMs: now + ms
24030
- };
24031
- }
24032
- /** Build a bounded `poll` spec from a duration. */
24033
- function pollFor(probe, opts, now) {
24034
- return {
24035
- kind: "poll",
24036
- probe,
24037
- intervalMs: opts.intervalMs,
24038
- ...opts.timeoutMs !== void 0 ? { timeoutAtMs: now + opts.timeoutMs } : {},
24039
- ...opts.args ? { args: opts.args } : {}
24040
- };
24041
- }
24042
- /** Registry over a plain name→predicate record. */
24043
- function createWaitProbes(entries) {
24044
- const map = new Map(Object.entries(entries));
24045
- return { resolve: (name) => map.get(name) };
24046
- }
24047
- /** Narrow a settlement's `out` to a wait outcome — a wait settles on the SAME cursor as workers,
24048
- * so a driver that mixes them tags them apart with this. */
24049
- function isWaitOutcome(value) {
24050
- return typeof value === "object" && value !== null && value.waitOutcome === true;
24051
- }
24052
- /** The absolute instant a spec is bounded by, or `undefined` for an unbounded wait. */
24053
- function waitUntil(spec) {
24054
- if (spec.kind === "timer") return spec.untilMs;
24055
- if (spec.kind === "token") return spec.expiresAtMs;
24056
- return spec.timeoutAtMs;
24057
- }
24058
- /** Structural validation, independent of the run. Returns null when the spec is usable. */
24059
- function validateWaitSpec(spec) {
24060
- if (spec.kind === "timer") return Number.isFinite(spec.untilMs) ? null : "timer.untilMs must be a finite epoch-ms instant";
24061
- if (spec.kind === "token") return "token waits are graph-engine-owned; deliver them through engine resume/expire";
24062
- if (typeof spec.probe !== "string" || spec.probe.length === 0) return "poll.probe must be a non-empty probe name";
24063
- if (!Number.isFinite(spec.intervalMs) || spec.intervalMs <= 0) return "poll.intervalMs must be > 0";
24064
- if (spec.timeoutAtMs !== void 0 && !Number.isFinite(spec.timeoutAtMs)) return "poll.timeoutAtMs must be a finite epoch-ms instant";
24065
- return null;
24066
- }
24067
- /**
24068
- * A wait must not silently outlive the run's HARD wall-clock ceiling. When the conserved pool
24069
- * carries an absolute `deadlineMs`, a wait bounded past it — or an unbounded poll — is REFUSED at
24070
- * arm time (`deadline-exceeded`) rather than sleeping through a ceiling the caller already set.
24071
- * The alternative (extending the pool's deadline to cover the wait) would let a wait override a
24072
- * hard budget guard, which is exactly what mechanic D forbids; a run that intends week-long waits
24073
- * either sets a deadline that covers them or sets none.
24074
- */
24075
- function assertWaitWithinDeadline(spec, deadlineMs) {
24076
- if (deadlineMs <= 0) return true;
24077
- const until = waitUntil(spec);
24078
- if (until === void 0) return false;
24079
- return until <= deadlineMs;
24080
- }
24081
- /**
24082
- * Drive one wait to its resolution. Spends nothing: a `timer` is one sleep, a `poll` is a sleep
24083
- * between predicate checks. No LLM call, no executor, no box, no budget reservation.
24084
- */
24085
- async function runWait(args) {
24086
- const { spec, label, armedAt, resumed, signal, now } = args;
24087
- const sleep = args.sleep ?? defaultSleep$1;
24088
- if (signal.aborted) return {
24089
- kind: "cancelled",
24090
- reason: "aborted before arming"
24091
- };
24092
- if (spec.kind === "timer") {
24093
- const remaining = spec.untilMs - now();
24094
- if (remaining > 0) await sleep(remaining, signal);
24095
- if (signal.aborted) return {
24096
- kind: "cancelled",
24097
- reason: "wait aborted"
24098
- };
24099
- return {
24100
- kind: "woke",
24101
- outcome: outcome("timer", "fired", label, spec.untilMs, armedAt, now(), 0, 0, resumed)
24102
- };
24103
- }
24104
- if (spec.kind === "token") throw new ValidationError$1(`wait '${label}': token waits are graph-engine-owned; deliver them through engine resume/expire`);
24105
- const probe = args.probes?.resolve(spec.probe);
24106
- if (!probe) throw new ValidationError$1(`wait '${label}': poll probe '${spec.probe}' is not registered in this run's WaitProbeRegistry`);
24107
- let polls = 0;
24108
- let probeErrors = 0;
24109
- for (;;) {
24110
- if (signal.aborted) return {
24111
- kind: "cancelled",
24112
- reason: "wait aborted"
24113
- };
24114
- polls += 1;
24115
- let fired = false;
24116
- try {
24117
- fired = await probe(spec.args, signal);
24118
- } catch {
24119
- probeErrors += 1;
24120
- }
24121
- if (fired) return {
24122
- kind: "woke",
24123
- outcome: outcome("poll", "fired", label, spec.timeoutAtMs, armedAt, now(), polls, probeErrors, resumed)
24124
- };
24125
- if (spec.timeoutAtMs !== void 0 && now() >= spec.timeoutAtMs) return {
24126
- kind: "woke",
24127
- outcome: outcome("poll", "timeout", label, spec.timeoutAtMs, armedAt, now(), polls, probeErrors, resumed)
24128
- };
24129
- await sleep(spec.timeoutAtMs === void 0 ? spec.intervalMs : Math.min(spec.intervalMs, Math.max(0, spec.timeoutAtMs - now())), signal);
24130
- }
24131
- }
24132
- function outcome(kind, settled, label, untilMs, armedAt, wokenAt, polls, probeErrors, resumed) {
24133
- return {
24134
- waitOutcome: true,
24135
- kind,
24136
- settled,
24137
- label,
24138
- ...untilMs !== void 0 ? { untilMs } : {},
24139
- armedAt,
24140
- wokenAt,
24141
- polls,
24142
- probeErrors,
24143
- resumed
24144
- };
24145
- }
24146
- /** `setTimeout` that resolves early (and clears) when the scope aborts, so a cancelled wait
24147
- * releases the event loop immediately instead of holding the process to its deadline. */
24148
- function defaultSleep$1(ms, signal) {
24149
- if (ms <= 0 || signal?.aborted) return Promise.resolve();
24150
- return sleep(ms, signal);
24151
- }
24152
- //#endregion
24153
23727
  //#region src/runtime/supervise/scope.ts
24154
23728
  /**
24155
23729
  *
@@ -24191,6 +23765,10 @@ const teardownRetriable = /* @__PURE__ */ new WeakMap();
24191
23765
  const ownerUnconfirmedByScope = /* @__PURE__ */ new WeakMap();
24192
23766
  /** The scope a recursive executor owns, so the settlement retry reaches its descendants. */
24193
23767
  const nestedTeardownScopes = /* @__PURE__ */ new WeakMap();
23768
+ /** Each scope's reader of the manager scopes its children own, read live. */
23769
+ const nestedManagerScopeReaders = /* @__PURE__ */ new WeakMap();
23770
+ /** A manager scope's release of its own environment, started once and joined by later callers. */
23771
+ const managerEnvironmentReleases = /* @__PURE__ */ new WeakMap();
24194
23772
  /** Scopes whose settlement released retained environments: none of their retained children is
24195
23773
  * kept for a resume any longer. */
24196
23774
  const releasingScopes = /* @__PURE__ */ new WeakSet();
@@ -24268,9 +23846,47 @@ async function releaseRetainedEnvironments(scope) {
24268
23846
  releasingScopes.add(scope);
24269
23847
  const release = retainedReleasers.get(scope);
24270
23848
  if (release) await release();
23849
+ await releaseNestedManagerEnvironments(scope);
24271
23850
  ownerUnconfirmedByScope.set(scope, await releaseScopeRetainedOwnerEnvironment(scope));
24272
23851
  return unconfirmedTeardowns(scope);
24273
23852
  }
23853
+ /** The manager scopes this scope's children own, read live. */
23854
+ function nestedManagerScopes(scope) {
23855
+ return nestedManagerScopeReaders.get(scope)?.() ?? [];
23856
+ }
23857
+ async function releaseNestedManagerEnvironments(scope) {
23858
+ await Promise.all(nestedManagerScopes(scope).map(async (nested) => {
23859
+ await releaseNestedManagerEnvironments(nested);
23860
+ if (!ownerUnconfirmedByScope.has(nested)) await releaseManagerEnvironment(nested);
23861
+ }));
23862
+ }
23863
+ /**
23864
+ * @internal Release the environment a manager kept between its turns, once its own scope has
23865
+ * finished and no turn of it will run again. The release first waits for the manager's last
23866
+ * end-of-turn capture, so it runs in the background of the manager's settlement; a later call,
23867
+ * including the run's settlement sweep, joins it. Its receipt is journaled in the manager's own
23868
+ * tree. It is the manager's own resource, not one of its descendants, so it never changes the
23869
+ * teardown answer its executor gives the parent.
23870
+ */
23871
+ function releaseManagerEnvironment(scope) {
23872
+ let release = managerEnvironmentReleases.get(scope);
23873
+ if (release === void 0) {
23874
+ release = releaseScopeRetainedOwnerEnvironment(scope).then(() => void 0);
23875
+ managerEnvironmentReleases.set(scope, release);
23876
+ }
23877
+ return release;
23878
+ }
23879
+ /**
23880
+ * @internal Wait for the work every manager in this scope's tree still has in flight after its
23881
+ * node settled: the end-of-turn capture its last turn handed over, and the release of its
23882
+ * environment. The run's settlement awaits it under either retention policy, so nothing writes to
23883
+ * the run's journal after the run settles and no capture is cut short by the process exiting.
23884
+ */
23885
+ async function settleManagerWork(scope) {
23886
+ await Promise.all(nestedManagerScopes(scope).map((nested) => settleManagerWork(nested)));
23887
+ await scopeRetainedOwnerSettled(scope);
23888
+ await managerEnvironmentReleases.get(scope)?.catch(() => void 0);
23889
+ }
24274
23890
  /**
24275
23891
  * @internal Close the cursor slot of every retained child this scope and its nested scopes still
24276
23892
  * hold open, once the settlement is final and the release and its retries are done.
@@ -24441,13 +24057,11 @@ function createScope(args) {
24441
24057
  } : void 0;
24442
24058
  let spawnOrdinal = args.resumeFrom ? args.resumeFrom.maxSpawnOrdinal + 1 : 0;
24443
24059
  let cursorSeq = args.resumeFrom ? args.resumeFrom.maxCursorSeq + 1 : 0;
24444
- let waitOrdinal = args.resumeFrom ? args.resumeFrom.maxWaitOrdinal + 1 : 0;
24445
24060
  let meterSeq = 0;
24446
24061
  let ownerTurns = 0;
24447
24062
  let ownerLastTurnAt = 0;
24448
24063
  let progressSeq = 0;
24449
24064
  const now = args.now ?? Date.now;
24450
- const unclaimedWaits = new Map((args.resumeFrom?.waits ?? []).map((w) => [w.label, w]));
24451
24065
  const keyed = /* @__PURE__ */ new Map();
24452
24066
  for (const [key, prior] of args.resumeFrom?.keys ?? []) if (prior.state === "completed" && prior.settled?.kind === "done") {
24453
24067
  if (prior.identity === void 0) continue;
@@ -24694,6 +24308,14 @@ function createScope(args) {
24694
24308
  }, "accepted retained child result");
24695
24309
  live.recoveryPending = false;
24696
24310
  });
24311
+ let captureSeq = 0;
24312
+ const onWorkspaceCapture = workspaceCaptureWriter({
24313
+ journal: args.journal,
24314
+ rootId: args.root,
24315
+ nodeId: id,
24316
+ nextSequence: () => captureSeq++,
24317
+ now
24318
+ });
24697
24319
  const onPause = (pause) => retainedWrite(async () => {
24698
24320
  await args.journal.appendEvent(args.root, {
24699
24321
  kind: "paused",
@@ -24722,6 +24344,7 @@ function createScope(args) {
24722
24344
  now
24723
24345
  }),
24724
24346
  onPause,
24347
+ onWorkspaceCapture,
24725
24348
  continueInvocation: async (nextTask) => {
24726
24349
  controller.signal.throwIfAborted();
24727
24350
  if (live.acceptedResult === void 0) throw new ValidationError$1("scope: a retained child continues only after its invocation committed a result");
@@ -24838,7 +24461,7 @@ function createScope(args) {
24838
24461
  abortChild: (reason) => controller.abort(reason)
24839
24462
  };
24840
24463
  const recordCancellation = () => {
24841
- if (!live.executorDone && live.acceptedResult === void 0 && controller.signal.reason instanceof RunCancellationReason) live.cancellationReason = controller.signal.reason;
24464
+ if (!live.executorDone && live.acceptedResult === void 0 && executor.resultAccepted?.() !== true && controller.signal.reason instanceof RunCancellationReason) live.cancellationReason = controller.signal.reason;
24842
24465
  };
24843
24466
  if (controller.signal.aborted) recordCancellation();
24844
24467
  else controller.signal.addEventListener("abort", recordCancellation, { once: true });
@@ -25109,165 +24732,6 @@ function createScope(args) {
25109
24732
  child.lastActivityAt = now();
25110
24733
  return true;
25111
24734
  }
25112
- /**
25113
- * Arm a wait-state node. Deliberately NOT a `spawn` with a sleeping executor: it resolves no
25114
- * `AgentSpec`, constructs no `Executor`, and — the point of the whole mechanic — reserves NOTHING
25115
- * from the conserved pool, so a week-long wait costs zero tokens and zero dollars and cannot
25116
- * starve a worker of budget.
25117
- *
25118
- * Fail-closed admission, mirroring `spawn`'s typed outcome. The deadline check is the one that
25119
- * matters: a wait may not silently sleep past the pool's hard wall-clock ceiling, and it may not
25120
- * extend that ceiling either (that would make a wait override a budget guard).
25121
- */
25122
- function wait(spec, opts) {
25123
- if (args.signal.aborted) return {
25124
- ok: false,
25125
- reason: "deadline-exceeded"
25126
- };
25127
- if (validateWaitSpec(spec) !== null) return {
25128
- ok: false,
25129
- reason: "invalid-spec"
25130
- };
25131
- if (spec.kind === "poll" && args.probes?.resolve(spec.probe) === void 0) return {
25132
- ok: false,
25133
- reason: "unknown-probe"
25134
- };
25135
- const adopted = unclaimedWaits.get(opts.label);
25136
- if (adopted) unclaimedWaits.delete(opts.label);
25137
- const effectiveSpec = adopted?.spec ?? spec;
25138
- const armedAt = adopted?.armedAt ?? now();
25139
- if (!assertWaitWithinDeadline(effectiveSpec, args.pool.readout().deadlineMs)) return {
25140
- ok: false,
25141
- reason: "deadline-exceeded"
25142
- };
25143
- const id = adopted ? adopted.id : `${args.parentId}:w${waitOrdinal}`;
25144
- const ordinal = adopted ? adopted.ordinal : waitOrdinal;
25145
- if (!adopted) waitOrdinal += 1;
25146
- const waitAbort = new AbortController();
25147
- const cascadeAbort = () => waitAbort.abort();
25148
- if (args.signal.aborted) waitAbort.abort();
25149
- else args.signal.addEventListener("abort", cascadeAbort, { once: true });
25150
- const handle = {
25151
- id,
25152
- label: opts.label,
25153
- get status() {
25154
- return children.get(id)?.status ?? "cancelled";
25155
- },
25156
- abort(reason) {
25157
- waitAbort.abort(reason);
25158
- }
25159
- };
25160
- const live = {
25161
- id,
25162
- status: "waiting",
25163
- runtime: "wait",
25164
- abortChild: (reason) => waitAbort.abort(reason),
25165
- budget: {
25166
- maxIterations: 0,
25167
- maxTokens: 0
25168
- },
25169
- label: opts.label,
25170
- spent: zeroSpend(),
25171
- settled: void 0,
25172
- delivered: false,
25173
- executorDone: false,
25174
- cleanupConfirmed: true,
25175
- teardownAttempts: 0,
25176
- executionBindings: [],
25177
- startedAt: armedAt,
25178
- lastActivityAt: now(),
25179
- wait: {
25180
- spec: effectiveSpec,
25181
- armedAt,
25182
- label: opts.label,
25183
- armCommitted: adopted !== void 0
25184
- }
25185
- };
25186
- children.set(id, live);
25187
- live.settled = (adopted ? Promise.resolve() : args.journal.appendEvent(args.root, {
25188
- kind: "waiting",
25189
- id,
25190
- parent: args.parentId,
25191
- label: opts.label,
25192
- spec: effectiveSpec,
25193
- armedAt,
25194
- seq: ordinal,
25195
- at: new Date(now()).toISOString()
25196
- })).then(() => {
25197
- if (live.wait) live.wait.armCommitted = true;
25198
- notifyRuntimeHookEvent(args.hooks, {
25199
- id: `${id}:waiting`,
25200
- runId: args.root,
25201
- target: "agent.spawn",
25202
- phase: "after",
25203
- timestamp: now(),
25204
- stepIndex: ordinal,
25205
- parentId: args.parentId,
25206
- payload: {
25207
- childId: id,
25208
- label: opts.label,
25209
- runtime: "wait",
25210
- wait: effectiveSpec,
25211
- armedAt,
25212
- resumed: adopted !== void 0
25213
- }
25214
- }, { signal: args.signal });
25215
- return runWait({
25216
- spec: effectiveSpec,
25217
- label: opts.label,
25218
- armedAt,
25219
- resumed: adopted !== void 0,
25220
- signal: waitAbort.signal,
25221
- ...args.probes ? { probes: args.probes } : {},
25222
- now,
25223
- ...args.waitSleep ? { sleep: args.waitSleep } : {}
25224
- });
25225
- }).then(async (resolution) => {
25226
- live.executorDone = true;
25227
- live.lastActivityAt = now();
25228
- if (resolution.kind === "cancelled") return {
25229
- kind: "down",
25230
- reason: resolution.reason,
25231
- infra: false,
25232
- trace: {
25233
- status: "unavailable",
25234
- reason: "not-an-executor"
25235
- }
25236
- };
25237
- const outRef = contentAddress(resolution.outcome);
25238
- await args.blobs.put(outRef, resolution.outcome);
25239
- return {
25240
- kind: "done",
25241
- out: resolution.outcome,
25242
- outRef,
25243
- spent: zeroSpend(),
25244
- trace: {
25245
- status: "unavailable",
25246
- reason: "not-an-executor"
25247
- }
25248
- };
25249
- }).catch((err) => {
25250
- live.executorDone = true;
25251
- return {
25252
- kind: "down",
25253
- reason: errMessage(err),
25254
- infra: true,
25255
- trace: {
25256
- status: "unavailable",
25257
- reason: "not-an-executor"
25258
- }
25259
- };
25260
- }).then((s) => {
25261
- live.resolved = s;
25262
- return s;
25263
- }).finally(() => {
25264
- args.signal.removeEventListener("abort", cascadeAbort);
25265
- });
25266
- return {
25267
- ok: true,
25268
- handle
25269
- };
25270
- }
25271
24735
  function progress(nodeId, opts = {}) {
25272
24736
  const child = children.get(nodeId);
25273
24737
  if (!child) return void 0;
@@ -25317,7 +24781,7 @@ function createScope(args) {
25317
24781
  function interactive(nodeId) {
25318
24782
  const child = children.get(nodeId);
25319
24783
  if (!child) return noInteractiveSession("unknown-node");
25320
- if (child.wait || child.executorDone || isTerminalNodeStatus(child.status)) return noInteractiveSession("not-live");
24784
+ if (child.executorDone || isTerminalNodeStatus(child.status)) return noInteractiveSession("not-live");
25321
24785
  const session = readInteractiveSession(child);
25322
24786
  if (args.interactiveBindingDir !== void 0 && session.status === "available") writeWorkerInteractiveBinding(args.interactiveBindingDir, child.id, child.label, args.root, session, now);
25323
24787
  return session;
@@ -25361,7 +24825,6 @@ function createScope(args) {
25361
24825
  const resume = args.resumeFrom ? {
25362
24826
  settled: args.resumeFrom.settled,
25363
24827
  view: args.resumeFrom.view,
25364
- waits: args.resumeFrom.waits,
25365
24828
  keys: args.resumeFrom.keys,
25366
24829
  priorSpend: args.resumeFrom.priorSpend
25367
24830
  } : void 0;
@@ -25370,7 +24833,6 @@ function createScope(args) {
25370
24833
  next,
25371
24834
  nextResolved,
25372
24835
  send,
25373
- wait,
25374
24836
  progress,
25375
24837
  traceSource,
25376
24838
  interactive,
@@ -25498,6 +24960,10 @@ function createScope(args) {
25498
24960
  return child.ownedTreeRoot === void 0 || nested === void 0 || hasRetriableTeardowns(nested, true);
25499
24961
  });
25500
24962
  teardownRetriable.set(scope, (release) => retriableTeardowns().length > 0 || release && (releasable().length > 0 || retainedOwnerReleaseRetriable(scope)));
24963
+ nestedManagerScopeReaders.set(scope, () => [...children.values()].flatMap((child) => {
24964
+ const nested = child.readNestedScope?.();
24965
+ return nested === void 0 ? [] : [nested];
24966
+ }));
25501
24967
  teardownRetriers.set(scope, async () => {
25502
24968
  await Promise.all(retriableTeardowns().map((child) => {
25503
24969
  child.teardownRetry ??= (async () => {
@@ -25684,6 +25150,15 @@ async function publishOwnerMaterialization(state, runtime, declaration, bindingI
25684
25150
  state.publishedThisProcess = true;
25685
25151
  return;
25686
25152
  }
25153
+ if (state.receipt !== void 0 && state.receipt.status !== "known") {
25154
+ if (!state.bindingPublished) {
25155
+ const boundToCommitted = knownExecutionBindingReceipt(state.receipt, bindingInput);
25156
+ await appendOwnerBinding(state, boundToCommitted);
25157
+ state.onReceipt?.(state.receipt, boundToCommitted);
25158
+ }
25159
+ state.publishedThisProcess = true;
25160
+ return;
25161
+ }
25687
25162
  if (state.receipt !== void 0) {
25688
25163
  if (canonicalCandidateDigest(state.receipt) !== canonicalCandidateDigest(receipt)) {
25689
25164
  const changed = changedRunIdentityFields(state.receipt, receipt);
@@ -25951,7 +25426,6 @@ async function appendAcknowledged(journal, root, event) {
25951
25426
  * `PreSeqSettled` into the frozen `Settled` the driver branches on. */
25952
25427
  async function finalizeSettlement(child, settlement, seq, args, now) {
25953
25428
  const handle = frozenHandle(child);
25954
- if (child.wait) return finalizeWait(child, settlement, seq, args, now, handle);
25955
25429
  const nestedScope = child.readNestedScope?.();
25956
25430
  const subtree = nestedScope === void 0 ? void 0 : subtreeSummaryOf(nestedScope);
25957
25431
  if (subtree !== void 0) child.subtree = subtree;
@@ -26072,68 +25546,6 @@ async function finalizeSettlement(child, settlement, seq, args, now) {
26072
25546
  seq
26073
25547
  };
26074
25548
  }
26075
- /** Journal a wait-state's settlement as a `woken` event and project it onto the same `Settled`
26076
- * the driver branches on. `by` names WHY it woke — `fired` / `timeout` / `cancelled` — which is
26077
- * the fact a resumed reader needs and cannot recover from a payload it may never fetch. */
26078
- async function finalizeWait(child, settlement, seq, args, now, handle) {
26079
- const settledAt = now();
26080
- child.settledAt = settledAt;
26081
- const at = new Date(settledAt).toISOString();
26082
- if (settlement.kind === "down") {
26083
- child.status = "cancelled";
26084
- if (child.wait?.armCommitted) await args.journal.appendEvent(args.root, {
26085
- kind: "woken",
26086
- id: child.id,
26087
- by: "cancelled",
26088
- seq,
26089
- at
26090
- });
26091
- return {
26092
- kind: "down",
26093
- handle,
26094
- reason: settlement.reason,
26095
- ...settlement.infra === void 0 ? {} : { infra: settlement.infra },
26096
- trace: settlement.trace,
26097
- settledAt,
26098
- seq
26099
- };
26100
- }
26101
- child.status = "done";
26102
- child.outRef = settlement.outRef;
26103
- const out = settlement.out;
26104
- await args.journal.appendEvent(args.root, {
26105
- kind: "woken",
26106
- id: child.id,
26107
- by: out.settled,
26108
- outRef: settlement.outRef,
26109
- seq,
26110
- at
26111
- });
26112
- notifyRuntimeHookEvent(args.hooks, {
26113
- id: `${child.id}:woken`,
26114
- runId: args.root,
26115
- target: "agent.child",
26116
- phase: "after",
26117
- timestamp: settledAt,
26118
- stepIndex: seq,
26119
- parentId: args.parentId,
26120
- payload: {
26121
- childId: child.id,
26122
- status: "done",
26123
- wait: out
26124
- }
26125
- }, { signal: args.signal });
26126
- return {
26127
- kind: "done",
26128
- handle,
26129
- out: settlement.out,
26130
- outRef: settlement.outRef,
26131
- spent: settlement.spent,
26132
- trace: settlement.trace,
26133
- settledAt,
26134
- seq
26135
- };
26136
- }
26137
25549
  /**
26138
25550
  * Drive one child's `Executor` to a terminal `PreSeqSettled`, folding usage into the
26139
25551
  * conserved `Spend`, reconciling the reservation, and persisting the result blob. Both
@@ -26261,7 +25673,7 @@ async function runChild(live, executor, childAbort, task, opts, pool, ticket, bl
26261
25673
  const reconcileError = reconcileOnce(accounting?.reservation ?? terminalSpend);
26262
25674
  if (reconcileError !== void 0) throw reconcileError;
26263
25675
  } else {
26264
- const terminal = await retainOutput(await awaitAbortable(Promise.resolve(ran), childAbort.signal));
25676
+ const terminal = await retainOutput(await awaitUnlessAccepted(Promise.resolve(ran), childAbort.signal, executor));
26265
25677
  await executionEvidence.complete();
26266
25678
  const accounting = executor.accounting?.();
26267
25679
  live.spent = accounting?.reported ?? terminal.spent;
@@ -26275,7 +25687,7 @@ async function runChild(live, executor, childAbort, task, opts, pool, ticket, bl
26275
25687
  const ownMetered = executor.metered?.();
26276
25688
  const trace = await captureTraceOnce();
26277
25689
  const childHarnessTranscript = await persistTranscriptOnce();
26278
- if (childAbort.signal.aborted && live.acceptedResult === void 0) {
25690
+ if (childAbort.signal.aborted && live.acceptedResult === void 0 && executor.resultAccepted?.() !== true) {
26279
25691
  await teardownOnce(opts.shutdown ?? "brutalKill");
26280
25692
  return downRecord("aborted before settle", true, trace, ownMetered, runtimeOwnedExecutorProviderEvidence(executor), retainedOutputRef, childHarnessTranscript);
26281
25693
  }
@@ -26410,8 +25822,6 @@ function settledToIteration(settled) {
26410
25822
  tokenUsage: cloneTokenUsage(settled.spent.tokens)
26411
25823
  };
26412
25824
  }
26413
- /** Summarize one scope's children and everything below them, listing the best direct children
26414
- * and counting the rest. Wait-states are not agents and are left out. */
26415
25825
  /** The live team a child manager leads, read through the nested scope it owns. */
26416
25826
  function liveTeamOf(child) {
26417
25827
  let nested;
@@ -26446,7 +25856,6 @@ function readLiveTeam(children, ownerTurns, ownerLastTurnAt) {
26446
25856
  let down = 0;
26447
25857
  let lastActivityAt = ownerLastTurnAt;
26448
25858
  for (const child of children) {
26449
- if (child.wait) continue;
26450
25859
  agents += 1;
26451
25860
  lastActivityAt = Math.max(lastActivityAt, child.lastActivityAt, child.settledAt ?? 0, executorActivityAt(child));
26452
25861
  if (child.status === "done") done += 1;
@@ -26484,7 +25893,6 @@ function summarizeTeam(children) {
26484
25893
  let members = 0;
26485
25894
  const results = [];
26486
25895
  for (const child of children) {
26487
- if (child.wait) continue;
26488
25896
  members += 1;
26489
25897
  const below = child.subtree;
26490
25898
  agents += 1 + (below?.agents ?? 0);
@@ -26544,8 +25952,7 @@ function makeTreeView(root, children) {
26544
25952
  return {
26545
25953
  root,
26546
25954
  nodes,
26547
- inFlight: nodes.filter((n) => n.status === "running" || n.status === "acquiring" || n.status === "queued").length,
26548
- waiting: nodes.filter((n) => n.status === "waiting").length
25955
+ inFlight: nodes.filter((n) => n.status === "running" || n.status === "acquiring" || n.status === "queued").length
26549
25956
  };
26550
25957
  }
26551
25958
  function frozenHandle(child) {
@@ -26667,6 +26074,19 @@ function preserveUnknownTelemetry(streamed, terminal) {
26667
26074
  ...(streamed.tokensProvenance ?? terminal.tokensProvenance) === void 0 ? {} : { tokensProvenance: streamed.tokensProvenance ?? terminal.tokensProvenance }
26668
26075
  };
26669
26076
  }
26077
+ /**
26078
+ * Await a one-shot executor's terminal result unless an abort wins first, except for an execution
26079
+ * whose result was accepted before the abort arrived: it is ending the turn that submitted that
26080
+ * result, so it is awaited rather than discarded, and the executor bounds that wait itself.
26081
+ */
26082
+ async function awaitUnlessAccepted(work, signal, executor) {
26083
+ try {
26084
+ return await awaitAbortable(work, signal);
26085
+ } catch (error) {
26086
+ if (signal.aborted && executor.resultAccepted?.() === true) return await work;
26087
+ throw error;
26088
+ }
26089
+ }
26670
26090
  async function awaitAbortable(work, signal) {
26671
26091
  if (signal.aborted) {
26672
26092
  work.catch(() => void 0);
@@ -26879,6 +26299,7 @@ const driverExecutorFactory = (rawSpec, ctx) => {
26879
26299
  ...spec.progress ? { progress: spec.progress } : {},
26880
26300
  ...spec.harnessTranscript ? { harnessTranscript: spec.harnessTranscript } : {},
26881
26301
  ...spec.harnessTranscriptSettled ? { harnessTranscriptSettled: spec.harnessTranscriptSettled } : {},
26302
+ resultAccepted: () => driver.resultAccepted?.() === true,
26882
26303
  ...deliver ? { deliver(message) {
26883
26304
  return deliver(message) !== false;
26884
26305
  } } : {},
@@ -26901,8 +26322,15 @@ const driverExecutorFactory = (rawSpec, ctx) => {
26901
26322
  if (recovering && (!spec.recoverExecutor || !seam.restore)) throw new RetainedExecutionPendingError(new ValidationError$1("driverExecutor: nested recovery has no original executor reconstruction"), "nested-recovery");
26902
26323
  signal.throwIfAborted();
26903
26324
  const controller = new AbortController();
26904
- const onParentAbort = () => controller.abort(signal.reason);
26905
- if (signal.aborted) controller.abort(signal.reason);
26325
+ let clearAcceptedGrace;
26326
+ const onParentAbort = () => {
26327
+ if (driver.resultAccepted?.() === true) {
26328
+ clearAcceptedGrace ??= armDeadlineTimer(ACCEPTED_RESULT_GRACE_MS, () => controller.abort(signal.reason));
26329
+ return;
26330
+ }
26331
+ controller.abort(signal.reason);
26332
+ };
26333
+ if (signal.aborted) onParentAbort();
26906
26334
  else signal.addEventListener("abort", onParentAbort, { once: true });
26907
26335
  let nestedScope;
26908
26336
  try {
@@ -26925,6 +26353,7 @@ const driverExecutorFactory = (rawSpec, ctx) => {
26925
26353
  const out = await runAbortable(() => driver.act(task, nestedScope), controller.signal, "driver aborted");
26926
26354
  await finalizeScopeOwnerMaterialization(nestedScope);
26927
26355
  await closeActive("driver completed");
26356
+ releaseManagerEnvironment(nestedScope).catch(() => void 0);
26928
26357
  const events = await loadTreeEvents(journal, nestedRoot);
26929
26358
  const childWork = sumSpend(events.filter(isSettled));
26930
26359
  const totalMetered = sumMetered(events);
@@ -26955,6 +26384,7 @@ const driverExecutorFactory = (rawSpec, ctx) => {
26955
26384
  throw err;
26956
26385
  } finally {
26957
26386
  signal.removeEventListener("abort", onParentAbort);
26387
+ clearAcceptedGrace?.();
26958
26388
  active = void 0;
26959
26389
  }
26960
26390
  },
@@ -27020,7 +26450,7 @@ async function closeNestedScope(scope, controller, reason) {
27020
26450
  if (!controller.signal.aborted) controller.abort(reason);
27021
26451
  for (;;) if (await scope.next() === null) break;
27022
26452
  const view = scope.view;
27023
- if (view.inFlight > 0 || view.waiting > 0) throw new ValidationError$1(`driverExecutor: nested cleanup left ${view.inFlight} running and ${view.waiting} waiting nodes`);
26453
+ if (view.inFlight > 0) throw new ValidationError$1(`driverExecutor: nested cleanup left ${view.inFlight} running nodes`);
27024
26454
  }
27025
26455
  /** The nested tree's full event list — the one evidence the spend, verdict, AND driver-inference
27026
26456
  * roll-ups read off the same journal the supervisor sums. */
@@ -27953,7 +27383,7 @@ var DriverAttemptsExhaustedError = class extends RuntimeRunStateError {
27953
27383
  function summarizeDriverAttempts(records) {
27954
27384
  let barren = 0;
27955
27385
  for (const record of records) if (record.madeProgress) barren = 0;
27956
- else if (record.error === void 0 && record.reentry !== void 0 && record.contract === "unmet") barren += 1;
27386
+ else if (record.error === void 0 && record.reentry !== void 0 && record.reentry !== "wake" && record.contract === "unmet") barren += 1;
27957
27387
  const last = records.at(-1);
27958
27388
  const refused = records.filter((record) => record.classification === "unavailable");
27959
27389
  return {
@@ -27963,6 +27393,8 @@ function summarizeDriverAttempts(records) {
27963
27393
  unavailablePauses: refused.filter((record) => record.retryInMs !== void 0).length,
27964
27394
  unavailableMs: refused.reduce((sum, record) => sum + (record.madeProgress ? 0 : record.durationMs) + (record.retryInMs ?? 0), 0),
27965
27395
  barrenReentries: barren,
27396
+ wakes: records.filter((record) => record.reentry === "wake").length,
27397
+ waitedMs: records.reduce((sum, record) => sum + (record.waitedMs ?? 0), 0),
27966
27398
  ended: last?.stop ?? "unrecorded",
27967
27399
  ...last?.repromptRefusedBy === void 0 ? {} : { repromptRefusedBy: last.repromptRefusedBy }
27968
27400
  };
@@ -28005,6 +27437,7 @@ async function runDriverWithRetry(run) {
28005
27437
  let consecutivePauses = 0;
28006
27438
  let pauses = 0;
28007
27439
  let continuations = 0;
27440
+ let wakes = 0;
28008
27441
  let reentry;
28009
27442
  const emit = async (record) => {
28010
27443
  const entered = reentry === void 0 ? {} : { reentry: reentry.reason };
@@ -28164,7 +27597,28 @@ async function runDriverWithRetry(run) {
28164
27597
  const contract = contractOf(after);
28165
27598
  const contractField = contract === "none" ? {} : { contract };
28166
27599
  if (progressed) barrenReentries = 0;
28167
- else if (reentry !== void 0 && contract === "unmet") barrenReentries += 1;
27600
+ else if (reentry !== void 0 && reentry.reason !== "wake" && contract === "unmet") barrenReentries += 1;
27601
+ const wait = run.wait;
27602
+ if (wait !== void 0 && contract !== "met" && !(continuation?.closed() ?? false) && !run.signal.aborted && budgetStop(run.budget(), now()) === void 0 && wait.open()) {
27603
+ const woken = await wait.wake(attempt + 1);
27604
+ if (woken !== void 0 && !run.signal.aborted) {
27605
+ wakes += 1;
27606
+ await emit({
27607
+ attempt,
27608
+ durationMs,
27609
+ madeProgress: progressed,
27610
+ ...contractField,
27611
+ waitedMs: woken.idleMs,
27612
+ retryInMs: 0
27613
+ });
27614
+ reentry = {
27615
+ reason: "wake",
27616
+ input: woken.input,
27617
+ wake: wakes
27618
+ };
27619
+ continue;
27620
+ }
27621
+ }
28168
27622
  if (contract === "unmet" && continuation !== void 0) {
28169
27623
  const decision = await decideContinuation(continuation, attempt, after);
28170
27624
  if ("steer" in decision) {
@@ -28544,7 +27998,7 @@ function describeRejection(error) {
28544
27998
  function createSupervisor() {
28545
27999
  let attached;
28546
28000
  async function run(root, task, opts) {
28547
- const { budget, rootIdentity, rootMaterialization, runId, journal: journalStore, blobs: blobStore, executors: executorRegistry, recoverExecutor, probes, maxDepth, workerSlots, reservationPolicy, maxRestarts, withinMs, childSettleGraceMs, teardownConfirmMs, resume, retainedAtSettlement: requestedRetainedAtSettlement, ownerWorkspaceRetention, now: suppliedNow, signal, hooks, workerTrace, workerTraceUnpropagated, interactiveBindingDir } = opts;
28001
+ const { budget, rootIdentity, rootMaterialization, runId, journal: journalStore, blobs: blobStore, executors: executorRegistry, recoverExecutor, maxDepth, workerSlots, reservationPolicy, maxRestarts, withinMs, childSettleGraceMs, teardownConfirmMs, resume, retainedAtSettlement: requestedRetainedAtSettlement, ownerWorkspaceRetention, now: suppliedNow, signal, hooks, workerTrace, workerTraceUnpropagated, interactiveBindingDir } = opts;
28548
28002
  const input = detachedSnapshot({
28549
28003
  task,
28550
28004
  options: {
@@ -28579,7 +28033,6 @@ function createSupervisor() {
28579
28033
  blobs: persistence.blobs,
28580
28034
  executors: executorRegistry,
28581
28035
  ...recoverExecutor ? { recoverExecutor } : {},
28582
- ...probes === void 0 ? {} : { probes },
28583
28036
  ...suppliedNow === void 0 ? {} : { now: suppliedNow },
28584
28037
  ...signal === void 0 ? {} : { signal },
28585
28038
  ...hooks === void 0 ? {} : { hooks },
@@ -28590,6 +28043,7 @@ function createSupervisor() {
28590
28043
  task = input.task;
28591
28044
  const rootAct = root.act.bind(root);
28592
28045
  const rootDeliver = root.deliver?.bind(root);
28046
+ const rootResultAccepted = root.resultAccepted?.bind(root);
28593
28047
  const now = opts.now ?? Date.now;
28594
28048
  assertRootIdentity(opts);
28595
28049
  const rootLease = attached?.acquire();
@@ -28696,7 +28150,6 @@ function createSupervisor() {
28696
28150
  requiredKnown: true,
28697
28151
  ...priorRootMaterialization === void 0 ? {} : { prior: priorRootMaterialization }
28698
28152
  } } : {},
28699
- ...opts.probes ? { probes: opts.probes } : {},
28700
28153
  ...opts.workerTrace ? { workerTrace: opts.workerTrace } : {},
28701
28154
  ...opts.workerTraceUnpropagated ? { workerTraceUnpropagated: opts.workerTraceUnpropagated } : {},
28702
28155
  ...opts.interactiveBindingDir ? { interactiveBindingDir: opts.interactiveBindingDir } : {},
@@ -28711,10 +28164,19 @@ function createSupervisor() {
28711
28164
  });
28712
28165
  let deadlineExceeded = false;
28713
28166
  const rootDeadlineAtMs = pool.readout().deadlineMs;
28714
- if (rootDeadlineAtMs > 0 && now() >= rootDeadlineAtMs) deadlineExceeded = cascadeAbort(ROOT_DEADLINE_REASON);
28715
- const clearRootDeadline = opts.budget.deadlineMs === void 0 ? void 0 : armDeadlineTimer(Math.max(0, rootDeadlineAtMs - now()), () => {
28167
+ let clearAcceptedGrace;
28168
+ const reachRootDeadline = () => {
28169
+ if (clearAcceptedGrace !== void 0) return;
28170
+ if (rootResultAccepted?.() === true) {
28171
+ clearAcceptedGrace = armDeadlineTimer(ACCEPTED_RESULT_GRACE_MS, () => {
28172
+ deadlineExceeded = cascadeAbort(ROOT_DEADLINE_REASON);
28173
+ });
28174
+ return;
28175
+ }
28716
28176
  deadlineExceeded = cascadeAbort(ROOT_DEADLINE_REASON);
28717
- });
28177
+ };
28178
+ if (rootDeadlineAtMs > 0 && now() >= rootDeadlineAtMs) reachRootDeadline();
28179
+ const clearRootDeadline = opts.budget.deadlineMs === void 0 ? void 0 : armDeadlineTimer(Math.max(0, rootDeadlineAtMs - now()), reachRootDeadline);
28718
28180
  let actOutcome = {
28719
28181
  ok: false,
28720
28182
  error: new RuntimeRunStateError("supervisor: root execution did not start")
@@ -28741,9 +28203,11 @@ function createSupervisor() {
28741
28203
  allChildrenDownAtSettle = allSpawnedChildrenDown(runTree(openScope));
28742
28204
  if (!controller.signal.aborted && rootDeadlineAtMs > 0 && now() >= rootDeadlineAtMs) deadlineExceeded = true;
28743
28205
  clearRootDeadline?.();
28206
+ clearAcceptedGrace?.();
28744
28207
  const settleGraceMs = !controller.signal.aborted ? boundedSettleGrace(opts.childSettleGraceMs, rootDeadlineAtMs, now) : 0;
28745
28208
  try {
28746
28209
  teardownUnconfirmed = await drainLiveChildren(openScope, controller, settleGraceMs);
28210
+ await settleManagerWork(openScope);
28747
28211
  if (!persistence.failed && retainedAtSettlement === "release") teardownUnconfirmed = await releaseRetainedEnvironments(openScope);
28748
28212
  const confirmWindowMs = opts.teardownConfirmMs ?? DEFAULT_TEARDOWN_CONFIRM_MS;
28749
28213
  const releasing = !persistence.failed && retainedAtSettlement === "release";
@@ -29036,8 +28500,7 @@ function wrapJournalForBreaker(journal, breaker) {
29036
28500
  * `allSettled`'d — a stray throw here is NOT the primary error (firstError precedence).
29037
28501
  */
29038
28502
  async function drainLiveChildren(scope, controller, settleGraceMs = 0) {
29039
- const view = scope.view;
29040
- if (!(view.inFlight > 0 || view.waiting > 0)) {
28503
+ if (scope.view.inFlight === 0) {
29041
28504
  await drainCursor(scope);
29042
28505
  return unconfirmedTeardowns(scope);
29043
28506
  }
@@ -29050,7 +28513,7 @@ async function drainLiveChildren(scope, controller, settleGraceMs = 0) {
29050
28513
  clearGraceTimer?.();
29051
28514
  }
29052
28515
  const after = scope.view;
29053
- if (after.inFlight > 0 || after.waiting > 0) throw new RuntimeRunStateError(`supervisor: cleanup ended with ${after.inFlight} running, ${after.waiting} waiting, and ` + describeUnconfirmed(scope));
28516
+ if (after.inFlight > 0) throw new RuntimeRunStateError(`supervisor: cleanup ended with ${after.inFlight} running and ` + describeUnconfirmed(scope));
29054
28517
  return unconfirmedTeardowns(scope);
29055
28518
  }
29056
28519
  /** Five minutes: long enough to outlast a provider's transient delete failures and a slow
@@ -29315,6 +28778,6 @@ function isNonEmptySpend(s) {
29315
28778
  return s.iterations > 0 || s.tokens.input > 0 || s.tokens.output > 0 || s.usd > 0 || s.ms > 0 || s.tokensKnown === false || s.usdKnown === false || Object.values(s.resources ?? {}).some((resource) => resource.amount > 0 || !resource.known);
29316
28779
  }
29317
28780
  //#endregion
29318
- export { bindScopeRetainedOwnerProvider as $, detachedFrozen as $i, parseWorkerToolTraceArtifact as $n, sanitizeRuntimeStreamEvent as $r, isPeerMailEnvelope as $t, driverExecutorFactory as A, addResourceSpend as Aa, prepareJsonlAppend as Ai, resolveAgentEnvironmentProvider as An, contentAddress as Ar, createExecutor as At, recordScopeOwnerDriverAttempt as B, promptFromAgentTurnInput as Ba, newExecutionAttemptId as Bi, InMemoryResultBlobStore as Bn, buildRuntimeEventOtelSpans as Br, workerTraceEnv as Bt, createContinuationKeeper as C, sleep as Ca, renderProfileMaterializationIssues as Ci, readPromptOptions as Cn, runAbortable as Cr, freeSlots as Ct, passedItems as D, unmeteredSpend as Da, validateProfileMaterialization as Di, createAgentEnvironmentProviderRegistry as Dn, readHarnessTranscript as Dr, captureReusableExecutorConfig as Dt, failedItems as E, throwIfAborted as Ea, unsupportedProfileDimensions as Ei, LEAF_CONTINUATION_TASK as En, persistHarnessTranscript as Er, bindReusableExecutorExecutionId as Et, beginScopeOwnerAttempt as F, awaitAbortable$1 as Fa, authoredProfileDigest as Fi, sandboxSessionTraceSource as Fn, defaultRedactor as Fr, createSteerableSandboxSession as Ft, settledToIteration as G, runtimeOwnedExecutorMaterialization as Gi, insideCursorNamespace as Gn, loopEventToOtelSpan as Gr, createActivityLog as Gt, recordScopeOwnerPause as H, providerMessageText as Ha, recordRuntimeOwnedDriveHarnessProviderEvidence as Hi, SpawnEventIndex as Hn, createOtelExporter as Hr, workerTraceSeamKey as Ht, createScope as I, DEFAULT_SUCCESSFUL_SHUTDOWN_MS as Ia, finalizeRuntimeOwnedPendingExecutor as Ii, registerRetainedExecutorPreparation as In, defaultRedactorIdentityMaterial as Ir, createRouterTranscript as It, pollFor as J, runtimeOwnedScopeOwnerRuntime as Ji, pendingWaits as Jn, toOtelAttributes as Jr, AUTHORITY_MARKERS as Jt, createWaitProbes as K, runtimeOwnedExecutorProviderEvidence as Ki, loadSpawnForest as Kn, padSpanId as Kr, readWorkerProgress as Kt, deriveNodeExecutionIdentity as L, armDeadlineTimer as La, inheritRuntimeOwnedExecutorAttestation as Li, retainedExecutorSeamKey as Ln, resolveRedactor as Lr, createInPlaceCliExecutor as Lt, withDriverExecutor as M, withBudgetResources as Ma, writeAllBytes as Mi, unavailableSignalOfFailure as Mn, mergeTraceEnv as Mr, snapshotExecutorConfig as Mt, SUBTREE_RESULT_LIMIT as N, decodeHarnessUsage as Na, attestRuntimeOwnedPendingExecutor as Ni, createPushTraceSource as Nn, readTraceContextFromEnv as Nr, createWorktreeCliExecutor as Nt, verdictFromJudgeScore as O, withTimeout as Oa, worktreeCliProfileMaterialization as Oi, providerAsExecutor as On, resolveHarnessTranscriptCapture as Or, cliInPlaceExecutor as Ot, assertRecursiveReservationPolicy as P, abortError$2 as Pa, attestRuntimeOwnedScopeOwner as Pi, decodeToolPart as Pn, traceContextToEnv as Pr, DEFAULT_SANDBOX_STEERING_MAX_TURNS as Pt, bindScopeRetainedOwnerEnvironmentId as Q, executableAgentSpecSnapshot as Qi, isTraceAnalysisStore as Qn, sanitizeKnowledgeReadinessReport as Qr, createPeerMailbox as Qt, meterRuntimeOwnedAccounting as R, teardownExecutor as Ra, knownExecutionBindingReceipt as Ri, FileResultBlobStore as Rn, buildLoopOtelSpans as Rr, WORKER_TRACE_PROPAGATION as Rt, composeContinuationNote as S, randomSuffix as Sa, promptResourceProfileMaterialization as Si, assertBoxlessPromptOptions as Sn, linkAbort as Sr, startRetainedInteractiveRun as St, expandQuestions as T, throwAbort as Ta, sandboxActProfileMaterialization as Ti, runBrainLoop as Tn, harnessTranscriptArtifact as Tr, rollingDispatch as Tt, restoreScopeOwnerAcceptedExecution as U, runtimeOwnedDriveHarnessProviderEvidence as Ui, assertContentAddress as Un, flatOtelSpan as Ur, taskToPrompt as Ut, recordScopeOwnerMaterialization as V, promptOptionsFromAgentTurnInput as Va, providerAttemptEvidence as Vi, InMemorySpawnJournal as Vn, createOpenInferenceFileExporter as Vr, workerTraceHeaders as Vt, scopeOwnerExecutorNodeContext as W, runtimeOwnedExecutorExecutionBinding as Wi, encodeResultBlob as Wn, generateSpanId as Wr, DEFAULT_STALL_AFTER_MS as Wt, validateWaitSpec as X, unknownMaterializationReceipt as Xi, WORKER_TOOL_TRACE_SCHEMA_VERSION as Xn, createRuntimeStreamEventCollector as Xr, PEER_MAIL_WIRE_KEY as Xt, timerAt as Y, unknownExecutionBindingReceipt as Yi, replaySpawnTree as Yn, createRuntimeEventCollector as Yr, DEFAULT_PEER_MAIL_LIMITS as Yt, waitUntil as Z, executableAgentProfileSnapshot as Zi, captureWorkerTraceEvidence as Zn, sanitizeAgentRuntimeEvent as Zr, claimsAuthority as Zt, CheckUnavailableError as _, cloneSpend as _a, fullProfileMaterialization as _i, createSandboxLineage as _n, environmentGone as _r, readWorkerInteractiveBinding as _t, collectDelivered as a, createSandboxToolPartState as aa, DEFAULT_LOCAL_HARNESS as ai, bridgeModelRouteRefusal as an, createBudgetPool as ar, scopeRetainedOwnerPriorSpend as at, bestComposite as b, isAbortError$2 as ba, promptModelProfileMaterialization as bi, SandboxEvidenceRetentionError as bn, RunCancellationReason as br, reconnectRetainedInteractiveRun as bt, runTree as c, isSandboxTerminalEvent as ca, harnessSupportsReasoningEffort as ci, harnessUsageIsEmpty as cn, spendFromUsageEvents as cr, scopeRetainedOwnerResult as ct, classifyDriverFailure as d, notifySandboxEventObserver as da, CodexExecutionDiagnosticError as di, bridgeStopSignalKey as dn, reconnectRetainedRun as dr, hostDirectoryReader as dt, detachedSnapshot as ea, runSettledCommand as ei, peerMailTools as en, workerTraceAnalysisStore as er, consumeScopeRetainedOwnerResult as et, runDriverWithRetry as f, sandboxEventServedBackend as fa, terminateProcessTreeAndConfirm as fi, TERMINAL_DECISIONS as fn, recoverRetainedRun as fr, resolveSpawnResourcePaths as ft, CONTINUATION_FACTS as g, chargedTokens as ga, defineProfileMaterializationContract as gi, runAgentRounds as gn, destroyInteractiveEnvironment as gr, attachWorker as gt, CONTINUATIONS_DIR as h, addSpend as ha, controlProfileMaterialization as hi, isTerminalDecision as hn, retainedCreateMaterial as hr, workerInteractiveAdmissionFile as ht, bestDelivered as i, canonicalStreamEventFromSandboxEvent as ia, removeWorktree as ii, bridgeAdmissionRefusal as in, assertValidBudget as ir, scopeRetainedOwnerContext as it, isDriverSpec as j, resourceTelemetry as ja, readCommittedJsonLines as ji, unavailablePauseMs as jn, createPropagatingTraceEmitter as jr, createExecutorRegistry as jt, driverChild as k, zeroSpend as ka, isNoEntError as ki, providerAsSandboxClient as kn, retainHarnessTranscript as kr, cliWorktreeExecutor as kt, DriverAttemptsExhaustedError as l, mapSandboxEvent as la, localHarnessExecutable as li, readCodexRolloutSession as ln, spendFromUsageTotals as lr, SPAWN_RESOURCE_PATH_MAX_BYTES as lt, upstreamUnavailableSignal as m, sumSandboxUsage as ma, assertProfileMaterialization as mi, defaultSelectWinner as mn, startRetainedRunInEnvironment as mr, readWorkerInteractiveAdmissions as mt, createRootHandle as n, readSandboxOutcome as na, captureWorktreeDiff as ni, isLiveNodeStatus as nn, BudgetReconcileFault as nr, prepareScopeRetainedOwnerTask as nt, pickBestDelivered as o, createSandboxUsageLedger as oa, LOCAL_HARNESSES as oi, addHarnessUsage as on, meterUsageEvent as or, scopeRetainedOwnerResourceReader as ot, summarizeDriverAttempts as p, sandboxProgressEvents as pa, AGENT_PROFILE_MATERIALIZATION_AXES as pi, createSandboxForSpec as pn, startRetainedRun as pr, interactiveAdmissionSeamKey as pt, isWaitOutcome as q, runtimeOwnedPendingExecutorMaterialization as qi, materializeTreeView as qn, padTraceId as qr, createInbox as qt, createSupervisor as r, assertSandboxServedModel as ra, createWorktree as ri, isTerminalNodeStatus as rn, ReservationWaitRefused as rr, reconcileScopeRetainedOwnerEnvironment as rt, runFinalizer as s, extractLlmCallEvent as sa, harnessInvocation as si, createCodexRolloutStoreReader as sn, newUsageTotals as sr, scopeRetainedOwnerRestorePoint as st, DEFAULT_MAX_DEPTH as t, projectSandboxOutcome as ta, runWorktreeHarness as ti, peerMailVerbNames as tn, executorFailure as tr, noteScopeRetainedOwnerCoordination as tt, HarnessTurnFailedError as u, mapSandboxToolEvent as ua, parseCodexTokenUsage as ui, bridgeRuntimeAttachmentsKey as un, errMessage as ur, environmentReader as ut, admitContinuationPolicy as v, deleteBoxSafe as va, profileMaterializationAxes$1 as vi, probeSandboxCapabilities as vn, createWorkerSlots as vr, workerInteractiveBindingFile as vt, distillFindings as w, stringifySafe as wa, renderUnsupported as wi, routerBrain as wn, captureHarnessTranscript as wr, queueOf as wt, checkVerdictOf as x, promptCacheTokenClasses as xa, promptOnlyProfileMaterialization as xi, captureBeforeDestroy as xn, abortError as xr, recoverRetainedInteractiveRun as xt, admitFinding as y, hasCompleteCacheBreakdown as ya, promptControlProfileMaterialization as yi, acquireSandbox as yn, openSlotGroup as yr, workerInteractiveBindingsDir as yt, meterRuntimeOwnedProviderAttempt as z, teardownSurfaces as za, knownMaterializationReceipt as zi, FileSpawnJournal as zn, buildLoopSpanNodes as zr, readWorkerTraceContext as zt };
28781
+ export { scopeRetainedOwnerPriorSpend as $, sandboxProgressEvents as $i, bridgeStopSignalKey as $n, localHarnessExecutable as $r, harnessUsageIsEmpty as $t, isDriverSpec as A, runtimeOwnedExecutorExecutionBinding as Ai, insideCursorNamespace as An, buildRuntimeEventOtelSpans as Ar, readWorkerTraceContext as At, recordScopeOwnerMaterialization as B, detachedSnapshot as Bi, isTraceAnalysisStore as Bn, createRuntimeStreamEventCollector as Br, DEFAULT_PEER_MAIL_LIMITS as Bt, distillFindings as C, inheritRuntimeOwnedExecutorAttestation as Ci, sandboxSessionTraceSource as Cn, readTraceContextFromEnv as Cr, snapshotExecutorConfig as Ct, verdictFromJudgeScore as D, providerAttemptEvidence as Di, FileSpawnJournal as Dn, resolveRedactor as Dr, createRouterTranscript as Dt, passedItems as E, newExecutionAttemptId as Ei, FileResultBlobStore as En, defaultRedactorIdentityMaterial as Er, createSteerableSandboxSession as Et, createScope as F, unknownExecutionBindingReceipt as Fi, prepareJsonlAppend as Fn, loopEventToOtelSpan as Fr, DEFAULT_STALL_AFTER_MS as Ft, beginScopeRetainedOwnerDrive as G, createSandboxToolPartState as Gi, ReservationWaitRefused as Gn, runWorktreeHarness as Gr, peerMailTools as Gt, restoreScopeOwnerAcceptedExecution as H, readSandboxOutcome as Hi, workerTraceAnalysisStore as Hn, sanitizeKnowledgeReadinessReport as Hr, claimsAuthority as Ht, deriveNodeExecutionIdentity as I, unknownMaterializationReceipt as Ii, readCommittedJsonLines as In, padSpanId as Ir, createActivityLog as It, consumeScopeRetainedOwnerResult as J, isSandboxTerminalEvent as Ji, meterUsageEvent as Jn, removeWorktree as Jr, isTerminalNodeStatus as Jt, bindScopeRetainedOwnerEnvironmentId as K, createSandboxUsageLedger as Ki, assertValidBudget as Kn, captureWorktreeDiff as Kr, peerMailVerbNames as Kt, meterRuntimeOwnedAccounting as L, executableAgentProfileSnapshot as Li, writeAllBytes as Ln, padTraceId as Lr, readWorkerProgress as Lt, SUBTREE_RESULT_LIMIT as M, runtimeOwnedExecutorProviderEvidence as Mi, materializeTreeView as Mn, createOtelExporter as Mr, workerTraceHeaders as Mt, assertRecursiveReservationPolicy as N, runtimeOwnedPendingExecutorMaterialization as Ni, replaySpawnTree as Nn, flatOtelSpan as Nr, workerTraceSeamKey as Nt, driverChild as O, recordRuntimeOwnedDriveHarnessProviderEvidence as Oi, InMemoryResultBlobStore as On, buildLoopOtelSpans as Or, createInPlaceCliExecutor as Ot, beginScopeOwnerAttempt as P, runtimeOwnedScopeOwnerRuntime as Pi, isNoEntError as Pn, generateSpanId as Pr, taskToPrompt as Pt, scopeRetainedOwnerContext as Q, sandboxEventServedBackend as Qi, bridgeRuntimeAttachmentsKey as Qn, harnessSupportsReasoningEffort as Qr, createCodexRolloutStoreReader as Qt, meterRuntimeOwnedProviderAttempt as R, executableAgentSpecSnapshot as Ri, WORKER_TOOL_TRACE_SCHEMA_VERSION as Rn, toOtelAttributes as Rr, createInbox as Rt, createContinuationKeeper as S, finalizeRuntimeOwnedPendingExecutor as Si, decodeToolPart as Sn, mergeTraceEnv as Sr, createExecutorRegistry as St, failedItems as T, knownMaterializationReceipt as Ti, retainedExecutorSeamKey as Tn, defaultRedactor as Tr, DEFAULT_SANDBOX_STEERING_MAX_TURNS as Tt, scopeOwnerExecutorNodeContext as U, assertSandboxServedModel as Ui, executorFailure as Un, sanitizeRuntimeStreamEvent as Ur, createPeerMailbox as Ut, recordScopeOwnerPause as V, projectSandboxOutcome as Vi, parseWorkerToolTraceArtifact as Vn, sanitizeAgentRuntimeEvent as Vr, PEER_MAIL_WIRE_KEY as Vt, settledToIteration as W, canonicalStreamEventFromSandboxEvent as Wi, BudgetReconcileFault as Wn, runSettledCommand as Wr, isPeerMailEnvelope as Wt, prepareScopeRetainedOwnerTask as X, mapSandboxToolEvent as Xi, spendFromUsageEvents as Xn, LOCAL_HARNESSES as Xr, bridgeModelRouteRefusal as Xt, noteScopeRetainedOwnerCoordination as Y, mapSandboxEvent as Yi, newUsageTotals as Yn, DEFAULT_LOCAL_HARNESS as Yr, bridgeAdmissionRefusal as Yt, reconcileScopeRetainedOwnerEnvironment as Z, notifySandboxEventObserver as Zi, spendFromUsageTotals as Zn, harnessInvocation as Zr, addHarnessUsage as Zt, CheckUnavailableError as _, validateProfileMaterialization as _i, providerAsSandboxClient as _n, readHarnessTranscript as _r, bindReusableExecutorExecutionId as _t, collectDelivered as a, promptOptionsFromAgentTurnInput as aa, controlProfileMaterialization as ai, runAgentRounds as an, retainedCreateMaterial as ar, environmentReader as at, bestComposite as b, attestRuntimeOwnedScopeOwner as bi, unavailableSignalOfFailure as bn, contentAddress as br, cliWorktreeExecutor as bt, runTree as c, profileMaterializationAxes$1 as ci, SandboxEvidenceRetentionError as cn, createWorkerSlots as cr, interactiveAdmissionSeamKey as ct, classifyDriverFailure as d, promptOnlyProfileMaterialization as di, readPromptOptions as dn, abortError as dr, reconnectRetainedInteractiveRun as dt, sumSandboxUsage as ea, parseCodexTokenUsage as ei, readCodexRolloutSession as en, errMessage as er, scopeRetainedOwnerResourceReader as et, runDriverWithRetry as f, promptResourceProfileMaterialization as fi, routerBrain as fn, linkAbort as fr, recoverRetainedInteractiveRun as ft, CONTINUATION_FACTS as g, unsupportedProfileDimensions as gi, providerAsExecutor as gn, persistHarnessTranscript as gr, rollingDispatch as gt, CONTINUATIONS_DIR as h, sandboxActProfileMaterialization as hi, createAgentEnvironmentProviderRegistry as hn, harnessTranscriptArtifact as hr, queueOf as ht, bestDelivered as i, promptFromAgentTurnInput as ia, assertProfileMaterialization as ii, isTerminalDecision as in, startRetainedRunInEnvironment as ir, SPAWN_RESOURCE_PATH_MAX_BYTES as it, withDriverExecutor as j, runtimeOwnedExecutorMaterialization as ji, loadSpawnForest as jn, createOpenInferenceFileExporter as jr, workerTraceEnv as jt, driverExecutorFactory as k, runtimeOwnedDriveHarnessProviderEvidence as ki, InMemorySpawnJournal as kn, buildLoopSpanNodes as kr, WORKER_TRACE_PROPAGATION as kt, DriverAttemptsExhaustedError as l, promptControlProfileMaterialization as li, captureBeforeDestroy as ln, openSlotGroup as lr, attachWorker as lt, upstreamUnavailableSignal as m, renderUnsupported as mi, LEAF_CONTINUATION_TASK as mn, captureHarnessTranscript as mr, freeSlots as mt, createRootHandle as n, abortError$1 as na, terminateProcessTreeAndConfirm as ni, createSandboxForSpec as nn, recoverRetainedRun as nr, scopeRetainedOwnerResult as nt, pickBestDelivered as o, providerMessageText as oa, defineProfileMaterializationContract as oi, createSandboxLineage as on, destroyInteractiveEnvironment as or, hostDirectoryReader as ot, summarizeDriverAttempts as p, renderProfileMaterializationIssues as pi, runBrainLoop as pn, runAbortable as pr, startRetainedInteractiveRun as pt, bindScopeRetainedOwnerProvider as q, extractLlmCallEvent as qi, createBudgetPool as qn, createWorktree as qr, isLiveNodeStatus as qt, createSupervisor as r, awaitAbortable$1 as ra, AGENT_PROFILE_MATERIALIZATION_AXES as ri, defaultSelectWinner as rn, startRetainedRun as rr, scopeRetainedOwnerTurnEnded as rt, runFinalizer as s, fullProfileMaterialization as si, acquireSandbox as sn, environmentGone as sr, resolveSpawnResourcePaths as st, DEFAULT_MAX_DEPTH as t, decodeHarnessUsage as ta, CodexExecutionDiagnosticError as ti, TERMINAL_DECISIONS as tn, reconnectRetainedRun as tr, scopeRetainedOwnerRestorePoint as tt, HarnessTurnFailedError as u, promptModelProfileMaterialization as ui, assertBoxlessPromptOptions as un, RunCancellationReason as ur, readWorkerInteractiveBinding as ut, admitContinuationPolicy as v, worktreeCliProfileMaterialization as vi, resolveAgentEnvironmentProvider as vn, resolveHarnessTranscriptCapture as vr, captureReusableExecutorConfig as vt, expandQuestions as w, knownExecutionBindingReceipt as wi, registerRetainedExecutorPreparation as wn, traceContextToEnv as wr, createWorktreeCliExecutor as wt, checkVerdictOf as x, authoredProfileDigest as xi, createPushTraceSource as xn, createPropagatingTraceEmitter as xr, createExecutor as xt, admitFinding as y, attestRuntimeOwnedPendingExecutor as yi, unavailablePauseMs as yn, retainHarnessTranscript as yr, cliInPlaceExecutor as yt, recordScopeOwnerDriverAttempt as z, detachedFrozen as zi, captureWorkerTraceEvidence as zn, createRuntimeEventCollector as zr, AUTHORITY_MARKERS as zt };
29319
28782
 
29320
- //# sourceMappingURL=supervisor-CQSu5XGl.js.map
28783
+ //# sourceMappingURL=supervisor-gCfG6K1-.js.map