@tangle-network/agent-runtime 0.143.0 → 0.153.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/README.md +32 -0
  2. package/dist/{activation-mi8TgSLM.js → activation-Bbic0THc.js} +3 -3
  3. package/dist/{activation-mi8TgSLM.js.map → activation-Bbic0THc.js.map} +1 -1
  4. package/dist/agent.d.ts +1 -1
  5. package/dist/agent.js +3 -3
  6. package/dist/{analyst-loop-CvkmfhUB.js → analyst-loop-Bouu53-l.js} +2 -2
  7. package/dist/{analyst-loop-CvkmfhUB.js.map → analyst-loop-Bouu53-l.js.map} +1 -1
  8. package/dist/analyst-loop.js +1 -1
  9. package/dist/{authoring-DuyShLdw.js → authoring-CcVhJ1lP.js} +2 -2
  10. package/dist/{authoring-DuyShLdw.js.map → authoring-CcVhJ1lP.js.map} +1 -1
  11. package/dist/candidate-execution/index.js +4 -4
  12. package/dist/{candidate-execution-CD5PoNmC.js → candidate-execution-DYOB1juU.js} +4 -4
  13. package/dist/{candidate-execution-CD5PoNmC.js.map → candidate-execution-DYOB1juU.js.map} +1 -1
  14. package/dist/{conversation-1hNtDeMM.js → conversation-BHMwAiMo.js} +28 -13
  15. package/dist/{conversation-1hNtDeMM.js.map → conversation-BHMwAiMo.js.map} +1 -1
  16. package/dist/conversation.d.ts +1 -1
  17. package/dist/conversation.js +1 -1
  18. package/dist/durable.d.ts +102 -4
  19. package/dist/durable.js +259 -13
  20. package/dist/durable.js.map +1 -1
  21. package/dist/{environment-provider-DCBJ13VP.js → environment-provider-3eCszBEm.js} +218 -34
  22. package/dist/environment-provider-3eCszBEm.js.map +1 -0
  23. package/dist/{environment-provider-B8eZ85Ga.d.ts → environment-provider-DJG0yIYl.d.ts} +2 -2
  24. package/dist/environment-provider.d.ts +1 -1
  25. package/dist/environment-provider.js +1 -1
  26. package/dist/executable-spec-BUcUcEPk.js +73 -0
  27. package/dist/executable-spec-BUcUcEPk.js.map +1 -0
  28. package/dist/{graph-De_XEsfH.js → graph-CIh2HDmH.js} +4 -4
  29. package/dist/{graph-De_XEsfH.js.map → graph-CIh2HDmH.js.map} +1 -1
  30. package/dist/{improvement-cycle-Bi-Tf4QF.js → improvement-cycle-GCDSsTN6.js} +7 -7
  31. package/dist/{improvement-cycle-Bi-Tf4QF.js.map → improvement-cycle-GCDSsTN6.js.map} +1 -1
  32. package/dist/{index-C2caGomG.d.ts → index-DLn9WI-f.d.ts} +342 -505
  33. package/dist/{index-B8rKtH3U.d.ts → index-lMADJLfq.d.ts} +4 -4
  34. package/dist/{index-D4sLkOPY.d.ts → index-rxVSm9-z.d.ts} +6 -4
  35. package/dist/index.d.ts +7 -7
  36. package/dist/index.js +13 -13
  37. package/dist/intelligence.d.ts +4 -4
  38. package/dist/intelligence.js +6 -6
  39. package/dist/jsonl-file-CDfsCI5s.js +59 -0
  40. package/dist/jsonl-file-CDfsCI5s.js.map +1 -0
  41. package/dist/kernel.d.ts +6 -6
  42. package/dist/kernel.js +13 -13
  43. package/dist/{knowledge-CVE6Wk1i.js → knowledge-CaY53BW2.js} +10 -7
  44. package/dist/{knowledge-CVE6Wk1i.js.map → knowledge-CaY53BW2.js.map} +1 -1
  45. package/dist/knowledge.d.ts +1 -1
  46. package/dist/knowledge.js +1 -1
  47. package/dist/{loop-runner-bin-BoHdQqLm.d.ts → loop-runner-bin-BwPqxKhR.d.ts} +3 -3
  48. package/dist/{loop-runner-bin-DdaI1nLL.js → loop-runner-bin-Dw43kB_-.js} +4 -4
  49. package/dist/{loop-runner-bin-DdaI1nLL.js.map → loop-runner-bin-Dw43kB_-.js.map} +1 -1
  50. package/dist/loop-runner-bin.d.ts +1 -1
  51. package/dist/loop-runner-bin.js +1 -1
  52. package/dist/{materialization-P86EciBw.js → materialization-Dl9J8ek4.js} +279 -58
  53. package/dist/materialization-Dl9J8ek4.js.map +1 -0
  54. package/dist/mcp/bin.js +3 -3
  55. package/dist/mcp/index.d.ts +3 -3
  56. package/dist/mcp/index.js +6 -6
  57. package/dist/{model-policy-DgRJIJse.js → model-policy-Sw4ywhtL.js} +68 -6
  58. package/dist/model-policy-Sw4ywhtL.js.map +1 -0
  59. package/dist/{openai-tools-BiAWKjh6.js → openai-tools-C4XKuK4t.js} +2 -2
  60. package/dist/{openai-tools-BiAWKjh6.js.map → openai-tools-C4XKuK4t.js.map} +1 -1
  61. package/dist/{prepare-D3n7cA39.js → prepare-C5tI-H4o.js} +2 -2
  62. package/dist/{prepare-D3n7cA39.js.map → prepare-C5tI-H4o.js.map} +1 -1
  63. package/dist/primeintellect/index.d.ts +1 -1
  64. package/dist/profiles.js +1 -1
  65. package/dist/{protected-model-port-bq6bD9YX.js → protected-model-port-DHDKNeY7.js} +2 -2
  66. package/dist/{protected-model-port-bq6bD9YX.js.map → protected-model-port-DHDKNeY7.js.map} +1 -1
  67. package/dist/{redact-DexTuAiX.d.ts → redact-NAptmqKw.d.ts} +3 -3
  68. package/dist/{researcher-CiSY6Wzb.js → researcher-BMFFPwKb.js} +2 -2
  69. package/dist/{researcher-CiSY6Wzb.js.map → researcher-BMFFPwKb.js.map} +1 -1
  70. package/dist/{run-layout-Be_Z0dF8.js → run-layout-C2jgwsCq.js} +111 -6
  71. package/dist/run-layout-C2jgwsCq.js.map +1 -0
  72. package/dist/{runtime-BnqjbOGX.js → runtime--Jsq8JCC.js} +118 -97
  73. package/dist/runtime--Jsq8JCC.js.map +1 -0
  74. package/dist/{runtime-J6Toky8K.d.ts → runtime-B-5dp5Iz.d.ts} +214 -14
  75. package/dist/{sandbox-events-COwCWUVB.js → sandbox-events-BVjstFgb.js} +70 -3
  76. package/dist/sandbox-events-BVjstFgb.js.map +1 -0
  77. package/dist/{spawn-journal-D2HKUImC.js → spawn-journal-BLnveCRS.js} +34 -104
  78. package/dist/spawn-journal-BLnveCRS.js.map +1 -0
  79. package/dist/{stream-agent-turn-C1Vs_3B9.d.ts → stream-agent-turn-BGyszuPH.d.ts} +2 -2
  80. package/dist/{stream-agent-turn-CXRugSGO.js → stream-agent-turn-DYi8ymsU.js} +91 -16
  81. package/dist/stream-agent-turn-DYi8ymsU.js.map +1 -0
  82. package/dist/{structural-rollout-CJgj9YXH.js → structural-rollout-D7V-HgXJ.js} +30 -13
  83. package/dist/structural-rollout-D7V-HgXJ.js.map +1 -0
  84. package/dist/{supervise-hCgG6ROJ.js → supervise-k_8VOASb.js} +2499 -2171
  85. package/dist/supervise-k_8VOASb.js.map +1 -0
  86. package/dist/{supervisor-s8SfZYbW.js → supervisor-CMZsJ7Wn.js} +673 -446
  87. package/dist/supervisor-CMZsJ7Wn.js.map +1 -0
  88. package/dist/testing.d.ts +2 -2
  89. package/dist/testing.js +12 -12
  90. package/dist/{top-app-BMOSKK06.js → top-app-3rYfFPTW.js} +192 -147
  91. package/dist/top-app-3rYfFPTW.js.map +1 -0
  92. package/dist/tui/bin.js +1 -1
  93. package/dist/tui/index.d.ts +32 -5
  94. package/dist/tui/index.js +1 -1
  95. package/dist/{types-Df9vulGc.d.ts → types-BPQhQRrC.d.ts} +507 -10
  96. package/dist/{util-C1bv6yog.js → util-D6ZEuBMi.js} +71 -2
  97. package/dist/util-D6ZEuBMi.js.map +1 -0
  98. package/dist/{workspace-archive-C52LjkeN.js → workspace-archive-B9ui4rrR.js} +2 -2
  99. package/dist/{workspace-archive-C52LjkeN.js.map → workspace-archive-B9ui4rrR.js.map} +1 -1
  100. package/package.json +7 -7
  101. package/dist/environment-provider-DCBJ13VP.js.map +0 -1
  102. package/dist/materialization-P86EciBw.js.map +0 -1
  103. package/dist/model-policy-DgRJIJse.js.map +0 -1
  104. package/dist/retained-run-binding-Dp2e8xne.js +0 -268
  105. package/dist/retained-run-binding-Dp2e8xne.js.map +0 -1
  106. package/dist/run-layout-Be_Z0dF8.js.map +0 -1
  107. package/dist/runtime-BnqjbOGX.js.map +0 -1
  108. package/dist/sandbox-events-COwCWUVB.js.map +0 -1
  109. package/dist/spawn-journal-D2HKUImC.js.map +0 -1
  110. package/dist/stream-agent-turn-CXRugSGO.js.map +0 -1
  111. package/dist/structural-rollout-CJgj9YXH.js.map +0 -1
  112. package/dist/supervise-hCgG6ROJ.js.map +0 -1
  113. package/dist/supervisor-s8SfZYbW.js.map +0 -1
  114. package/dist/top-app-BMOSKK06.js.map +0 -1
  115. package/dist/util-C1bv6yog.js.map +0 -1
@@ -1,11 +1,12 @@
1
+ import { C as unknownExecutionBindingReceipt, S as runtimeOwnedScopeOwnerRuntime, a as authoredProfileDigest, b as runtimeOwnedExecutorProviderEvidence, c as knownExecutionBindingReceipt, f as recordRuntimeOwnedProviderAttemptStart, g as runtimeOwnedDeferredExecutorRuntime, h as recordRuntimeOwnedProviderModel, l as knownMaterializationReceipt, m as recordRuntimeOwnedProviderIdentityConflict, n as attestRuntimeOwnedExecutor, o as finalizeRuntimeOwnedPendingExecutor, p as recordRuntimeOwnedProviderDispatchNotStarted, r as attestRuntimeOwnedPendingExecutor, s as inheritRuntimeOwnedExecutorAttestation, t as attestRuntimeOwnedDeferredExecutor, u as newExecutionAttemptId, v as runtimeOwnedExecutorExecutionBinding, w as unknownMaterializationReceipt, x as runtimeOwnedPendingExecutorMaterialization, y as runtimeOwnedExecutorMaterialization } from "./materialization-Dl9J8ek4.js";
1
2
  import { f as RuntimeRunStateError, m as ValidationError, r as BackendTransportError } from "./errors-CDZ8XsVj.js";
2
3
  import { t as detachedSnapshot } from "./snapshot-cK9K420n.js";
3
- import { S as contentAddress, a as aggregateProviderModelEvidence, c as pendingWaits, g as runtimeOwnedNestedDriverTreeRoot, h as nestedDriverTreeRoot, l as replaySpawnTree, m as driverRuntime, o as loadSpawnForest, p as attestNestedDriverTreeOwner, s as materializeTreeView, v as captureWorkerTraceEvidence } from "./spawn-journal-D2HKUImC.js";
4
- import { _ as zeroTokenUsage, a as hasCompleteCacheBreakdown, c as promptCacheTokenClasses, d as sleep, f as stringifySafe, g as withTimeout, h as usdEstimatedOf, i as deleteBoxSafe, l as randomSuffix, m as throwIfAborted, n as chargedTokens, p as throwAbort, r as cloneTokenUsage, s as mapWithConcurrency, t as addTokenUsage, u as randomUuid } from "./util-C1bv6yog.js";
5
- import { i as extractLlmCallEvent, o as mapSandboxToolEvent, r as createSandboxToolPartState, s as notifySandboxEventObserver, t as assertSandboxServedModel } from "./sandbox-events-COwCWUVB.js";
6
- import { C as unknownExecutionBindingReceipt, D as projectSandboxOutcome, E as executableAgentSpecSnapshot, S as runtimeOwnedScopeOwnerRuntime, T as executableAgentProfileSnapshot, a as authoredProfileDigest, b as runtimeOwnedExecutorProviderEvidence, c as knownExecutionBindingReceipt, f as recordRuntimeOwnedProviderAttemptStart, g as runtimeOwnedDeferredExecutorRuntime, h as recordRuntimeOwnedProviderModel, l as knownMaterializationReceipt, m as recordRuntimeOwnedProviderIdentityConflict, n as attestRuntimeOwnedExecutor, o as finalizeRuntimeOwnedPendingExecutor, p as recordRuntimeOwnedProviderDispatchNotStarted, r as attestRuntimeOwnedPendingExecutor, t as attestRuntimeOwnedDeferredExecutor, u as newExecutionAttemptId, v as runtimeOwnedExecutorExecutionBinding, w as unknownMaterializationReceipt, x as runtimeOwnedPendingExecutorMaterialization, y as runtimeOwnedExecutorMaterialization } from "./materialization-P86EciBw.js";
7
- import { a as concreteProfileModel, l as resolveRouterRetryPolicy, o as profileBridgeWireModel, s as profileModelExecutionSettings, t as assertExecutableAgentProfile, u as agentHarness } from "./model-policy-DgRJIJse.js";
8
- import { i as resolveAgentEnvironmentProvider, n as providerAsExecutor, r as providerAsSandboxClient } from "./environment-provider-DCBJ13VP.js";
4
+ import { _ as captureWorkerTraceEvidence, a as aggregateProviderModelEvidence, c as loadSpawnForest, d as replaySpawnTree, f as attestNestedDriverTreeOwner, h as runtimeOwnedNestedDriverTreeRoot, l as materializeTreeView, m as nestedDriverTreeRoot, o as closesCursorSlot, p as driverRuntime, u as pendingWaits, x as contentAddress } from "./spawn-journal-BLnveCRS.js";
5
+ import { _ as unmeteredSpend, a as cloneTokenUsage, b as zeroTokenUsage, d as randomSuffix, f as randomUuid, g as throwIfAborted, h as throwAbort, l as mapWithConcurrency, m as stringifySafe, n as addTokenUsage, o as deleteBoxSafe, p as sleep, r as chargedTokens, s as hasCompleteCacheBreakdown, t as addSpend, u as promptCacheTokenClasses, v as withTimeout, y as zeroSpend } from "./util-D6ZEuBMi.js";
6
+ import { c as notifySandboxEventObserver, i as extractLlmCallEvent, l as sandboxEventServedBackend, r as createSandboxToolPartState, s as mapSandboxToolEvent, t as assertSandboxServedModel, u as sandboxProgressEvents } from "./sandbox-events-BVjstFgb.js";
7
+ import { n as executableAgentSpecSnapshot, r as projectSandboxOutcome, t as executableAgentProfileSnapshot } from "./executable-spec-BUcUcEPk.js";
8
+ import { a as concreteProfileModel, c as profileModelExecutionSettings, d as agentHarness, o as enforceTokenLimits, s as profileBridgeWireModel, t as assertExecutableAgentProfile, u as resolveRouterRetryPolicy } from "./model-policy-Sw4ywhtL.js";
9
+ import { c as linkAbort, i as resolveAgentEnvironmentProvider, l as runAbortable, n as providerAsExecutor, r as providerAsSandboxClient, s as abortError } from "./environment-provider-3eCszBEm.js";
9
10
  import { i as notifyRuntimeHookEvent } from "./runtime-hooks-tXpAarhW.js";
10
11
  import { AGENT_PROFILE_MATERIALIZATION_AXES, AgentTurnInputSchema, REASONING_EFFORTS, agentProfileSchema, canonicalAgentProfileDigest, canonicalCandidateDigest, profileMaterializationAxes, profileMaterializationAxes as profileMaterializationAxes$1, renderInputPartsAsText, sha256DigestSchema } from "@tangle-network/agent-interface";
11
12
  import { estimateCost, isModelPriced } from "@tangle-network/agent-eval";
@@ -218,6 +219,43 @@ function assertProfileMaterialization(options) {
218
219
  if (issues.length === 0) return;
219
220
  throw new ValidationError(renderProfileMaterializationIssues(issues, options.context));
220
221
  }
222
+ /**
223
+ * Throw when the CHOSEN HARNESS has no control for a dimension the profile asks for.
224
+ *
225
+ * The contract above answers which axes a run path carries; this answers whether the harness can
226
+ * execute them. `materializeProfile` is pure, so the verdict costs no process and no IO.
227
+ *
228
+ * `skip` must mirror what the EXECUTING caller skips, or this refuses a profile that would have
229
+ * run: a dimension handled by the executor's own native control is not unsupported, it is simply
230
+ * not the plan's to lower.
231
+ */
232
+ function assertProfileMaterializes(profile, harness, context, skip) {
233
+ const plan = materializeProfile(profile, harness, skip ? { skip: [...skip] } : void 0);
234
+ if (plan.unsupported.length > 0) throw new ValidationError(`${context}: ${harness} cannot materialize the profile: ${renderUnsupported(plan.unsupported)}`);
235
+ return plan;
236
+ }
237
+ /**
238
+ * Ask the materializer which of `dimensions` this harness has no control for, without executing
239
+ * the profile's own `resources.failOnError` policy.
240
+ *
241
+ * A caller that gates only SOME dimensions needs the verdict as data, not as a throw: the
242
+ * materializer throws while planning when `failOnError` is set (its strict default), which hides
243
+ * the dimension list and would conflate a gated dimension with an ungated one. The query copy sets
244
+ * `failOnError: false` so every dimension comes back on `plan.unsupported` and the caller decides.
245
+ */
246
+ function unsupportedProfileDimensions(profile, harness, dimensions, skip) {
247
+ return materializeProfile({
248
+ ...profile,
249
+ resources: {
250
+ ...profile.resources,
251
+ failOnError: false
252
+ }
253
+ }, harness, skip ? { skip: [...skip] } : void 0).unsupported.filter((entry) => dimensions.includes(entry.dimension));
254
+ }
255
+ /** One clause per dimension the harness cannot execute, carrying the materializer's own reason. */
256
+ function renderUnsupported(unsupported) {
257
+ return unsupported.map(({ dimension, reason }) => `${dimension}: ${reason}`).join("; ");
258
+ }
221
259
  /** Format profile-axis drop issues into a concise operator-facing error. */
222
260
  function renderProfileMaterializationIssues(issues, context) {
223
261
  if (issues.length === 0) return "";
@@ -1803,8 +1841,7 @@ function prepareWorktreeProfile(profile, harness) {
1803
1841
  const workspaceProfile = materializationOnlyProfile(profile);
1804
1842
  assertSupportedWorktreeProfile(profile, harness);
1805
1843
  assertSafeProfileResourcePaths(profile);
1806
- const plan = materializeProfile(workspaceProfile, harness);
1807
- if (plan.unsupported.length > 0) throw new Error(`runWorktreeHarness: profile cannot be materialized for ${harness}: ${plan.unsupported.map(({ dimension, reason }) => `${dimension}: ${reason}`).join("; ")}`);
1844
+ const plan = assertProfileMaterializes(workspaceProfile, harness, "runWorktreeHarness");
1808
1845
  assertSafeMaterializedPaths(plan);
1809
1846
  return {
1810
1847
  plan,
@@ -3328,12 +3365,14 @@ async function routerChatWithUsage(cfg, messages, opts) {
3328
3365
  const headers = routerRequestHeaders(cfg, opts);
3329
3366
  const temperature = opts?.temperature;
3330
3367
  const maxTokens = opts?.maxTokens ?? cfg.maxTokens;
3368
+ const maxCompletionTokens = opts?.maxCompletionTokens ?? cfg.maxCompletionTokens;
3331
3369
  const body = () => ({
3332
3370
  ...providerRequestExtras(opts?.extraBody, [
3333
3371
  "model",
3334
3372
  "messages",
3335
3373
  "temperature",
3336
3374
  "max_tokens",
3375
+ "max_completion_tokens",
3337
3376
  "seed",
3338
3377
  "reasoning_effort",
3339
3378
  "stream",
@@ -3343,6 +3382,7 @@ async function routerChatWithUsage(cfg, messages, opts) {
3343
3382
  messages,
3344
3383
  ...temperature !== void 0 ? { temperature } : {},
3345
3384
  ...maxTokens !== void 0 ? { max_tokens: maxTokens } : {},
3385
+ ...maxCompletionTokens !== void 0 ? { max_completion_tokens: maxCompletionTokens } : {},
3346
3386
  ...opts?.seed !== void 0 ? { seed: opts.seed } : {},
3347
3387
  ...opts?.reasoningEffort ? { reasoning_effort: opts.reasoningEffort } : {}
3348
3388
  });
@@ -3457,6 +3497,7 @@ async function routerChatWithTools(cfg, messages, tools, opts) {
3457
3497
  /** The OpenAI-shape request body both tool-calling transports send. One builder so the streamed
3458
3498
  * turn cannot drift from the buffered one on model, temperature, tool_choice, or the ceiling. */
3459
3499
  function toolCompletionBody(cfg, messages, tools, opts) {
3500
+ const maxCompletionTokens = opts?.maxCompletionTokens ?? cfg.maxCompletionTokens;
3460
3501
  return {
3461
3502
  ...providerRequestExtras(opts?.extraBody, [
3462
3503
  "model",
@@ -3465,6 +3506,7 @@ function toolCompletionBody(cfg, messages, tools, opts) {
3465
3506
  "tool_choice",
3466
3507
  "temperature",
3467
3508
  "max_tokens",
3509
+ "max_completion_tokens",
3468
3510
  "seed",
3469
3511
  "reasoning_effort",
3470
3512
  "stream",
@@ -3478,6 +3520,7 @@ function toolCompletionBody(cfg, messages, tools, opts) {
3478
3520
  } : {},
3479
3521
  ...opts?.temperature !== void 0 ? { temperature: opts.temperature } : {},
3480
3522
  ...opts?.maxTokens ? { max_tokens: opts.maxTokens } : {},
3523
+ ...maxCompletionTokens !== void 0 ? { max_completion_tokens: maxCompletionTokens } : {},
3481
3524
  ...opts?.seed !== void 0 ? { seed: opts.seed } : {},
3482
3525
  ...opts?.reasoningEffort ? { reasoning_effort: opts.reasoningEffort } : {}
3483
3526
  };
@@ -5141,14 +5184,47 @@ function hashJson(value) {
5141
5184
  //#region src/runtime/sandbox-executor-output.ts
5142
5185
  /** Project the complete Sandbox event stream into the standard executor result shape. */
5143
5186
  function sandboxLeafOutputFromEvents(events) {
5144
- const content = collectAgentFinalMessageText(events) ?? collectAgentResponseText(events) ?? "";
5187
+ const content = collectAgentFinalMessageText(events) ?? collectAgentResponseText(events);
5145
5188
  const toolCalls = sandboxToolCalls(events);
5189
+ const servedBackend = lastServedBackend(events);
5146
5190
  return {
5147
5191
  events,
5148
5192
  content,
5193
+ output: sandboxOutputMarker(content, events.some(carriesText)),
5194
+ ...servedBackend === void 0 ? {} : { servedBackend },
5149
5195
  ...toolCalls.length === 0 ? {} : { toolCalls }
5150
5196
  };
5151
5197
  }
5198
+ /**
5199
+ * Classify observed text into the explicit output marker. `sawTextEvent` says whether the stream
5200
+ * carried a text-bearing event at all, which is what separates a box that answered nothing from a
5201
+ * box whose answer was never observed.
5202
+ */
5203
+ function sandboxOutputMarker(content, sawTextEvent = content !== void 0) {
5204
+ if (content !== void 0 && content.length > 0) return {
5205
+ kind: "text",
5206
+ bytes: Buffer.byteLength(content, "utf8")
5207
+ };
5208
+ return sawTextEvent ? { kind: "empty" } : { kind: "absent" };
5209
+ }
5210
+ /** True when the event carries a text field a turn's answer could come from, empty or not. */
5211
+ function carriesText(event) {
5212
+ if (!event || typeof event !== "object") return false;
5213
+ const data = event.data && typeof event.data === "object" ? event.data : {};
5214
+ if (typeof data.finalText === "string" || typeof data.text === "string") return true;
5215
+ if (typeof data.delta === "string") return true;
5216
+ const part = data.part && typeof data.part === "object" ? data.part : void 0;
5217
+ return part !== void 0 && part.type === "text" && typeof part.text === "string";
5218
+ }
5219
+ /** The last served identity the platform reported across a turn's events, or `undefined`. */
5220
+ function lastServedBackend(events) {
5221
+ let served;
5222
+ for (const event of events) {
5223
+ const next = sandboxEventServedBackend(event);
5224
+ if (next !== void 0) served = next;
5225
+ }
5226
+ return served;
5227
+ }
5152
5228
  function sandboxToolCalls(events) {
5153
5229
  const state = createSandboxToolPartState();
5154
5230
  return events.flatMap((event) => mapSandboxToolEvent(event, state).flatMap((projected) => projected.type === "tool_call" ? [{
@@ -5180,7 +5256,8 @@ function priceUnreceiptedWork(work) {
5180
5256
  const unknown = {
5181
5257
  kind: "cost",
5182
5258
  usd: 0,
5183
- usdKnown: false
5259
+ usdKnown: false,
5260
+ provenance: "uncaptured"
5184
5261
  };
5185
5262
  const { inputTokens, outputTokens, model } = work;
5186
5263
  if (model === void 0 || !isModelPriced(model)) return unknown;
@@ -5192,10 +5269,41 @@ function priceUnreceiptedWork(work) {
5192
5269
  kind: "cost",
5193
5270
  usd,
5194
5271
  usdKnown: false,
5195
- usdEstimated: usd
5272
+ usdEstimated: usd,
5273
+ provenance: "catalog-estimate"
5196
5274
  };
5197
5275
  }
5198
5276
  //#endregion
5277
+ //#region src/runtime/supervise/node-status.ts
5278
+ /**
5279
+ * Which {@link NodeStatus} values mean the node is finished.
5280
+ *
5281
+ * `'waiting'` is deliberately NOT terminal: a wait-state node holds no executor, no box and no
5282
+ * conserved budget, so it is neither in flight nor settled. Callers that must also exclude it say
5283
+ * so at their own site, because "finished" and "not a live worker" are different questions.
5284
+ */
5285
+ const terminalNodeStatuses = /* @__PURE__ */ new Set([
5286
+ "done",
5287
+ "failed",
5288
+ "cancelled"
5289
+ ]);
5290
+ /**
5291
+ * True once a node has reached a terminal status.
5292
+ *
5293
+ * The single owner of this rule. Written per call site it drifts silently: a status added to
5294
+ * `NodeStatus` is classified by whichever sites the author remembered, and the ones they missed
5295
+ * keep a dead node in the live set — a stop rule that never fires, mail delivered to a worker that
5296
+ * cannot read it, or a cancel answered `not_live` for a node that is still running.
5297
+ */
5298
+ function isTerminalNodeStatus(status) {
5299
+ return terminalNodeStatuses.has(status);
5300
+ }
5301
+ /** True while a node has not yet reached a terminal status. The complement of
5302
+ * {@link isTerminalNodeStatus}, so the two can never disagree. */
5303
+ function isLiveNodeStatus(status) {
5304
+ return !terminalNodeStatuses.has(status);
5305
+ }
5306
+ //#endregion
5199
5307
  //#region src/runtime/supervise/peer-mail.ts
5200
5308
  /**
5201
5309
  *
@@ -5281,7 +5389,6 @@ function isPeerMailEnvelope(value) {
5281
5389
  function isPeerMailKind(value) {
5282
5390
  return value === "ask" || value === "tell" || value === "challenge" || value === "answer";
5283
5391
  }
5284
- const isLiveStatus = (status) => status !== "done" && status !== "failed" && status !== "cancelled";
5285
5392
  /** Create the run's post office. One per manager scope; the manager's siblings are its addresses. */
5286
5393
  function createPeerMailbox(opts) {
5287
5394
  const limits = Object.freeze({
@@ -5321,7 +5428,7 @@ function createPeerMailbox(opts) {
5321
5428
  await opts.publish(event);
5322
5429
  return event;
5323
5430
  };
5324
- const liveNodes = () => opts.scope.view.nodes.filter((node) => isLiveStatus(node.status));
5431
+ const liveNodes = () => opts.scope.view.nodes.filter((node) => isLiveNodeStatus(node.status));
5325
5432
  const mailbox = {
5326
5433
  limits,
5327
5434
  setEndpoint(baseUrl) {
@@ -5396,7 +5503,7 @@ function createPeerMailbox(opts) {
5396
5503
  if (opts.scope.signal.aborted) return record(envelope, "scope-stopped");
5397
5504
  const node = opts.scope.view.nodes.find((candidate) => candidate.id === to);
5398
5505
  if (node === void 0) return record(envelope, "unknown-worker");
5399
- if (!isLiveStatus(node.status)) return record(envelope, "already-settled");
5506
+ if (!isLiveNodeStatus(node.status)) return record(envelope, "already-settled");
5400
5507
  let delivered = false;
5401
5508
  try {
5402
5509
  delivered = opts.scope.send(to, { [PEER_MAIL_WIRE_KEY]: envelope });
@@ -5623,6 +5730,29 @@ function createInbox() {
5623
5730
  }
5624
5731
  //#endregion
5625
5732
  //#region src/runtime/supervise/progress.ts
5733
+ /**
5734
+ *
5735
+ * The LIVE read-model of a still-RUNNING worker — what a driver can see BEFORE the worker settles.
5736
+ *
5737
+ * Until this existed, `observe_agent` on a running worker returned `{status:'running', spent:{0,0},
5738
+ * outRef:null, output:null}`: nothing a brain could act on, so a brain that wanted to steer had no
5739
+ * evidence to steer FROM. This is the other half of the steering wire (the first half is
5740
+ * `Executor.deliver`): a supervisor cannot correct a worker it cannot watch.
5741
+ *
5742
+ * Two layers, both pull-based — no timer, no background task, so it is safe to leave on:
5743
+ *
5744
+ * - The SCOPE layer, available for EVERY executor with no executor cooperation at all: usage
5745
+ * events are timestamped as they arrive, so `lastActivityAt` / `idleMs` / `stalled` /
5746
+ * `tokens` / `turns` are derived from the stream the conserved pool already meters.
5747
+ * - The EXECUTOR layer, optional enrichment via `Executor.progress()`: the tool/file activity
5748
+ * the harness exposes, its own turn count, and how many steers are queued but unread.
5749
+ *
5750
+ * `stalled` is a DERIVED read, computed at observation time against `stallAfterMs` — never a
5751
+ * background watchdog. A worker that has produced no metered activity for longer than the
5752
+ * threshold reads `stalled: true`; nothing is killed, nothing is retried. The driver decides.
5753
+ *
5754
+ * @experimental
5755
+ */
5626
5756
  /** How long a worker may produce no metered activity before a `progress()` read calls it stalled.
5627
5757
  * Deliberately generous: a coding harness routinely spends minutes inside one tool call, and a
5628
5758
  * false stall that provokes a steer is worse than a late one. */
@@ -5665,7 +5795,7 @@ function createActivityLog(limit = 12) {
5665
5795
  /** Fold the scope-derived facts and the executor's optional enrichment into one read. Pure: the
5666
5796
  * caller supplies `now`, so a test can observe a stall without waiting for one. */
5667
5797
  function readWorkerProgress(scope, executor, now, stallAfterMs = DEFAULT_STALL_AFTER_MS) {
5668
- const live = scope.status !== "done" && scope.status !== "failed" && scope.status !== "cancelled";
5798
+ const live = isLiveNodeStatus(scope.status);
5669
5799
  const executorActivityAt = executor?.recentActivity?.length ? executor.recentActivity[executor.recentActivity.length - 1].at : 0;
5670
5800
  const lastActivityAt = Math.max(scope.lastActivityAt, executorActivityAt);
5671
5801
  const idleMs = Math.max(0, now - lastActivityAt);
@@ -5915,13 +6045,21 @@ function createSteerableSandboxSession(args) {
5915
6045
  });
5916
6046
  const state = {
5917
6047
  turns: 0,
5918
- lastText: "",
6048
+ /** `undefined` until a text-bearing terminal event is observed; never seeded with `''`. */
6049
+ lastText: void 0,
6050
+ servedBackend: void 0,
5919
6051
  seenToolCalls: /* @__PURE__ */ new Set(),
6052
+ toolCalls: [],
5920
6053
  artifact: void 0,
5921
6054
  latestOutcome: void 0,
6055
+ /** Reads the live lineage handle once a box and session exist, for exact cancellation. */
6056
+ session: void 0,
5922
6057
  teardown: void 0,
5923
6058
  note: "starting"
5924
6059
  };
6060
+ const toolParts = createSandboxToolPartState();
6061
+ /** Record one box event for the trace and the activity window, and return the live output it
6062
+ * carries so the caller can publish it to the turn stream. */
5925
6063
  const recordEvent = (event) => {
5926
6064
  const at = now();
5927
6065
  const data = event.data;
@@ -5945,7 +6083,19 @@ function createSteerableSandboxSession(args) {
5945
6083
  }
5946
6084
  }
5947
6085
  const text = readFinalText(event);
5948
- if (text) state.lastText = text;
6086
+ if (text !== void 0) state.lastText = text;
6087
+ const served = sandboxEventServedBackend(event);
6088
+ if (served !== void 0) state.servedBackend = served;
6089
+ const progress = sandboxProgressEvents(event, toolParts);
6090
+ for (const item of progress) {
6091
+ if (item.kind !== "tool_call") continue;
6092
+ state.toolCalls.push({
6093
+ ...item.toolCallId === void 0 ? {} : { id: item.toolCallId },
6094
+ name: item.toolName,
6095
+ arguments: item.args ?? {}
6096
+ });
6097
+ }
6098
+ return progress;
5949
6099
  };
5950
6100
  async function* stream(task, signal) {
5951
6101
  const capabilities = await probeSandboxCapabilities(args.sandboxClient);
@@ -5971,6 +6121,7 @@ function createSteerableSandboxSession(args) {
5971
6121
  let tokensKnown = true;
5972
6122
  let usd = 0;
5973
6123
  let handle;
6124
+ state.session = () => handle;
5974
6125
  let nextPrompt = args.taskToPrompt(task);
5975
6126
  try {
5976
6127
  for (let turn = 0; maxTurns === 0 || turn < maxTurns; turn += 1) {
@@ -6016,7 +6167,10 @@ function createSteerableSandboxSession(args) {
6016
6167
  } else events = await lineage.continue(handle, prompt, turnController.signal, promptOptions);
6017
6168
  for await (const event of events) {
6018
6169
  outcomeTracker.observe(event);
6019
- recordEvent(event);
6170
+ for (const progress of recordEvent(event)) yield {
6171
+ kind: "progress",
6172
+ progress
6173
+ };
6020
6174
  const call = extractLlmCallEvent(event, spec.name ?? String(args.harness));
6021
6175
  if (call) {
6022
6176
  sawLlmCall = true;
@@ -6040,7 +6194,8 @@ function createSteerableSandboxSession(args) {
6040
6194
  yield {
6041
6195
  kind: "cost",
6042
6196
  usd: call.costUsd,
6043
- usdKnown: false
6197
+ usdKnown: false,
6198
+ provenance: "uncaptured"
6044
6199
  };
6045
6200
  }
6046
6201
  }
@@ -6087,7 +6242,8 @@ function createSteerableSandboxSession(args) {
6087
6242
  if (state.turns > 0) yield {
6088
6243
  kind: "cost",
6089
6244
  usd: 0,
6090
- usdKnown: false
6245
+ usdKnown: false,
6246
+ provenance: "uncaptured"
6091
6247
  };
6092
6248
  const spent = {
6093
6249
  iterations: state.turns,
@@ -6099,8 +6255,10 @@ function createSteerableSandboxSession(args) {
6099
6255
  };
6100
6256
  const out = {
6101
6257
  content: state.lastText,
6258
+ output: sandboxOutputMarker(state.lastText),
6259
+ ...state.servedBackend === void 0 ? {} : { servedBackend: state.servedBackend },
6102
6260
  turns: state.turns,
6103
- toolCalls: activity.read().filter((n) => n.kind === "tool").map((n) => n.label),
6261
+ toolCalls: state.toolCalls,
6104
6262
  ...state.latestOutcome ? { outcome: state.latestOutcome } : {}
6105
6263
  };
6106
6264
  const verdict = state.latestOutcome ? projectSandboxOutcome(state.latestOutcome).verdict : void 0;
@@ -6116,6 +6274,60 @@ function createSteerableSandboxSession(args) {
6116
6274
  }
6117
6275
  return {
6118
6276
  stream,
6277
+ async cancel(request) {
6278
+ const live = state.session?.();
6279
+ const observedAt = () => (/* @__PURE__ */ new Date()).toISOString();
6280
+ if (!live) return {
6281
+ status: "unknown",
6282
+ effect: "cancel_requested",
6283
+ observedAt: observedAt(),
6284
+ detail: "no box session exists yet for this worker; nothing remote could be asked"
6285
+ };
6286
+ const session = live.box.session?.(live.sessionId);
6287
+ if (!session || typeof session.interrupt !== "function") return {
6288
+ status: "unknown",
6289
+ effect: "cancel_requested",
6290
+ observedAt: observedAt(),
6291
+ detail: "the sandbox client exposes no session interrupt operation",
6292
+ evidence: { sessionId: live.sessionId }
6293
+ };
6294
+ try {
6295
+ const result = await session.interrupt();
6296
+ const evidence = {
6297
+ sessionId: live.sessionId,
6298
+ operationId: request.operationId,
6299
+ result
6300
+ };
6301
+ if (result?.cancelled === true) {
6302
+ args.controller.abort("executor cancelled");
6303
+ return {
6304
+ status: "accepted",
6305
+ effect: "cancelled",
6306
+ observedAt: observedAt(),
6307
+ detail: "the box reported the running execution cancelled",
6308
+ evidence
6309
+ };
6310
+ }
6311
+ return {
6312
+ status: "already-terminal",
6313
+ effect: "not_live",
6314
+ observedAt: observedAt(),
6315
+ detail: "the box reported no running execution on this session",
6316
+ evidence
6317
+ };
6318
+ } catch (error) {
6319
+ return {
6320
+ status: "unknown",
6321
+ effect: "cancel_requested",
6322
+ observedAt: observedAt(),
6323
+ detail: `the box interrupt failed: ${error instanceof Error ? error.message : String(error)}`,
6324
+ evidence: {
6325
+ sessionId: live.sessionId,
6326
+ operationId: request.operationId
6327
+ }
6328
+ };
6329
+ }
6330
+ },
6119
6331
  progress: () => ({
6120
6332
  turns: state.turns,
6121
6333
  pendingMessages: args.inbox.pending(),
@@ -6133,14 +6345,16 @@ function createSteerableSandboxSession(args) {
6133
6345
  function isInterruptAbort(err, interrupt, external, owned) {
6134
6346
  return (err instanceof DOMException && err.name === "AbortError" || typeof err === "object" && err !== null && err.name === "AbortError") && interrupt.aborted && !external.aborted && !owned.aborted;
6135
6347
  }
6136
- /** The terminal text a sandbox `result` event carries, when it carries one. */
6348
+ /** The terminal text a sandbox `result` event carries, when it carries one. An observed empty
6349
+ * string is returned as `''`, because "the box answered nothing" is not "the box never
6350
+ * answered". */
6137
6351
  function readFinalText(event) {
6138
6352
  const data = event.data;
6139
6353
  if (!data || typeof data !== "object") return void 0;
6140
6354
  const text = data.finalText;
6141
- if (typeof text === "string" && text.length > 0) return text;
6355
+ if (typeof text === "string") return text;
6142
6356
  const alt = data.text;
6143
- return typeof alt === "string" && alt.length > 0 ? alt : void 0;
6357
+ return typeof alt === "string" ? alt : void 0;
6144
6358
  }
6145
6359
  /** Prompt options the composed loop context already carries (agent profile / cwd), forwarded so
6146
6360
  * a steerable worker runs with the same box configuration as the single-shot path. */
@@ -6341,7 +6555,7 @@ function createWorktreeCliExecutor(options) {
6341
6555
  runtime: "cli",
6342
6556
  budgetExempt,
6343
6557
  async execute(task, signal) {
6344
- const linked = linkSignals$1(signal, controller.signal);
6558
+ const linked = linkSignals(signal, controller.signal);
6345
6559
  const started = Date.now();
6346
6560
  const taskPrompt = executionTaskPrompt(task, options.taskPrompt);
6347
6561
  run = await runWorktreeHarness({
@@ -6468,7 +6682,7 @@ function executionTaskPrompt(task, configuredPrompt) {
6468
6682
  }
6469
6683
  /** Link two abort signals into one that fires when either does. Returns `undefined` when neither
6470
6684
  * is present so the harness runner gets no signal at all. */
6471
- function linkSignals$1(a, b) {
6685
+ function linkSignals(a, b) {
6472
6686
  if (a.aborted || b.aborted) {
6473
6687
  const c = new AbortController();
6474
6688
  c.abort();
@@ -6548,6 +6762,11 @@ const bridgeSeamKey = "bridge";
6548
6762
  /** Internal control seam used by Runtime-owned external supervisors. A completion request stops
6549
6763
  * the next bridge turn; it must not abort the paid request that is already streaming. */
6550
6764
  const bridgeStopSignalKey = "__bridge_stop_signal";
6765
+ /** Internal attachment seam used by Runtime-owned external supervisors. The named MCP servers ride
6766
+ * beside the AgentProfile as `runtime_attachments`, so the bridge mounts them for the run and keeps
6767
+ * them out of its session profile binding. A rebound coordination port therefore cannot move the
6768
+ * authored profile digest that binds a durable session. */
6769
+ const bridgeRuntimeAttachmentsKey = "__bridge_runtime_attachments";
6551
6770
  const maxBridgeTimeoutMs = 2147483647;
6552
6771
  const bridgeModelCredentialHeader = "x-cli-bridge-model-credential";
6553
6772
  const bridgeModelBaseUrlHeader = "x-cli-bridge-model-base-url";
@@ -6646,36 +6865,6 @@ function contentRef(prefix, value) {
6646
6865
  return `${prefix}:${(h >>> 0).toString(16).padStart(8, "0")}`;
6647
6866
  }
6648
6867
  /**
6649
- * The spend of work that HAPPENED and reported no usage receipt.
6650
- *
6651
- * Not the same value as a plain zero even though both carry `{0,0}` tokens and `$0`. A bare zero
6652
- * asserts a MEASUREMENT — "this ran and cost nothing" — and every consumer downstream reads it that
6653
- * way: the pool keeps reporting `readout().tokensKnown === true`, the journal totals stay clean, the
6654
- * OTEL span records a priced zero, and a caller's token-denominated ceiling can never fire no matter
6655
- * how much the work really burned. A ceiling that cannot fire is worse than no ceiling, because it
6656
- * reads as protection.
6657
- *
6658
- * `Spend.tokensKnown` is the marker the substrate already threads end to end for exactly this case
6659
- * (`budget.ts`, `otel-spans.ts`, `spawn-journal.ts`, `supervisor.ts`): the work is recorded, the
6660
- * zero is labelled a floor rather than a total, and every rollup that touches it reports its balance
6661
- * as a ceiling rather than a measurement. Use this — never a bare zero — whenever a runtime cannot
6662
- * see what its worker spent.
6663
- *
6664
- * The same rule applies to dollars. A dollar-capped run must refuse an executor whose billed spend
6665
- * is unknowable; `budgetExempt` does not authorize Runtime to relabel unknown spend as a measured
6666
- * zero. Callers that require dollar accounting must use a backend with a trusted billing receipt.
6667
- */
6668
- function unmeteredSpend(ms) {
6669
- return {
6670
- iterations: 0,
6671
- tokens: zeroTokenUsage(),
6672
- tokensKnown: false,
6673
- usd: 0,
6674
- usdKnown: false,
6675
- ms
6676
- };
6677
- }
6678
- /**
6679
6868
  * A direct OpenAI-compatible Router chat-completion. One-shot: resolves a
6680
6869
  * `ExecutorResult` and reports its terminal usage as `UsageEvent`s through the
6681
6870
  * conserved pool. Reports REAL token usage — when the provider omits `usage`,
@@ -6686,18 +6875,26 @@ function unmeteredSpend(ms) {
6686
6875
  * failures (429/5xx/Cloudflare-origin) retry with backoff before the executor
6687
6876
  * fails the task.
6688
6877
  */
6878
+ /**
6879
+ * The honest answer for a backend with no cancel operation: the local request stopped, and
6880
+ * nothing about the remote run is known. Never `accepted` — a client that advertises provider
6881
+ * cancellation from this would claim more than Runtime observed.
6882
+ */
6883
+ function localAbortCancellation(detail) {
6884
+ return {
6885
+ status: "unknown",
6886
+ effect: "cancel_requested",
6887
+ observedAt: (/* @__PURE__ */ new Date()).toISOString(),
6888
+ detail
6889
+ };
6890
+ }
6689
6891
  const routerInlineExecutor = (spec, ctx) => {
6690
6892
  const seam = readSeam(ctx, routerSeamKey, "router/inline");
6691
6893
  const model = exactRouterModel(spec.profile, "routerInlineExecutor");
6692
6894
  if (!seam.routerBaseUrl || !seam.routerKey) throw new ValidationError("routerInlineExecutor: RouterSeam.routerBaseUrl + routerKey required");
6693
6895
  const profileExecution = routerProfileExecution(spec.profile, seam, { multiTurn: false });
6694
6896
  const requestIdentity = routerRequestIdentity(ctx);
6695
- const controller = new AbortController();
6696
- const abortIfSignalled = () => {
6697
- if (ctx.signal.aborted) controller.abort();
6698
- };
6699
- abortIfSignalled();
6700
- if (!ctx.signal.aborted) ctx.signal.addEventListener("abort", abortIfSignalled, { once: true });
6897
+ const controller = linkAbort(ctx.signal);
6701
6898
  let artifact;
6702
6899
  const executionId = ctx.node?.nodeId ?? `router-request-${randomUUID()}`;
6703
6900
  const attemptId = ctx.node?.attemptId ?? newExecutionAttemptId(executionId);
@@ -6707,7 +6904,7 @@ const routerInlineExecutor = (spec, ctx) => {
6707
6904
  async execute(task, signal) {
6708
6905
  const messages = taskToMessages(task, spec, profileExecution.systemPrompt);
6709
6906
  const started = Date.now();
6710
- const linked = linkSignals(signal, controller.signal);
6907
+ const linked = linkAbort(signal, controller.signal).signal;
6711
6908
  const extraBody = {
6712
6909
  ...profileExecution.extraBody ?? {},
6713
6910
  ...profileExecution.reasoningEffort ? { reasoning_effort: profileExecution.reasoningEffort } : {}
@@ -6723,7 +6920,7 @@ const routerInlineExecutor = (spec, ctx) => {
6723
6920
  ...profileExecution.temperature !== void 0 ? { temperature: profileExecution.temperature } : {},
6724
6921
  ...linked ? { signal: linked } : {},
6725
6922
  ...profileExecution.toolChoice ? { toolChoice: profileExecution.toolChoice } : {},
6726
- ...profileExecution.maxTokens !== void 0 ? { maxTokens: profileExecution.maxTokens } : {},
6923
+ ...profileExecution.tokenLimits.applied,
6727
6924
  ...profileExecution.seed !== void 0 ? { seed: profileExecution.seed } : {},
6728
6925
  ...Object.keys(extraBody).length > 0 ? { extraBody } : {},
6729
6926
  ...requestIdentity
@@ -6736,7 +6933,7 @@ const routerInlineExecutor = (spec, ctx) => {
6736
6933
  }, messages, {
6737
6934
  ...profileExecution.temperature !== void 0 ? { temperature: profileExecution.temperature } : {},
6738
6935
  ...linked ? { signal: linked } : {},
6739
- ...profileExecution.maxTokens !== void 0 ? { maxTokens: profileExecution.maxTokens } : {},
6936
+ ...profileExecution.tokenLimits.applied,
6740
6937
  ...profileExecution.seed !== void 0 ? { seed: profileExecution.seed } : {},
6741
6938
  ...profileExecution.reasoningEffort ? { reasoningEffort: profileExecution.reasoningEffort } : {},
6742
6939
  ...profileExecution.extraBody ? { extraBody: profileExecution.extraBody } : {},
@@ -6748,7 +6945,7 @@ const routerInlineExecutor = (spec, ctx) => {
6748
6945
  tokens: r.usage ? cloneTokenUsage({
6749
6946
  input: r.usage.input,
6750
6947
  output: r.usage.output,
6751
- ...routerPromptCacheUsage(r.usage.input, r.cache)
6948
+ ...promptCacheTokenClasses(r.usage.input, r.cache)
6752
6949
  }) : zeroTokenUsage(),
6753
6950
  usd: r.billedCostUsd ?? 0,
6754
6951
  ...r.usage ? {} : { tokensKnown: false },
@@ -6777,6 +6974,10 @@ const routerInlineExecutor = (spec, ctx) => {
6777
6974
  };
6778
6975
  return artifact;
6779
6976
  },
6977
+ cancel(_request) {
6978
+ controller.abort("executor cancelled");
6979
+ return Promise.resolve(localAbortCancellation("the Router chat-completions API exposes no cancel operation; the local request was aborted and the provider may still bill the completion"));
6980
+ },
6780
6981
  teardown(_grace) {
6781
6982
  controller.abort("executor torn down");
6782
6983
  return Promise.resolve({ destroyed: true });
@@ -6805,7 +7006,7 @@ const routerInlineExecutor = (spec, ctx) => {
6805
7006
  model,
6806
7007
  provider: spec.profile.model?.provider ?? null,
6807
7008
  temperature: profileExecution.temperature ?? null,
6808
- maxTokens: profileExecution.maxTokens ?? null,
7009
+ tokenLimits: profileExecution.tokenLimits,
6809
7010
  retry: profileExecution.retry ?? null,
6810
7011
  seed: profileExecution.seed ?? null,
6811
7012
  reasoningEffort: profileExecution.reasoningEffort ?? null,
@@ -6843,22 +7044,6 @@ function mergePromptCache(target, cache) {
6843
7044
  }
6844
7045
  if (cache.status !== void 0) target.status = cache.status;
6845
7046
  }
6846
- /** Preserve a complete Router cache split; an incomplete provider receipt stays unknown. */
6847
- function routerPromptCacheUsage(input, cache) {
6848
- if (cache === void 0) return {};
6849
- const read = cache.readTokens;
6850
- const write = cache.writeTokens;
6851
- if (read === void 0 && write === void 0) return {};
6852
- if (input === void 0 || !isCacheTokenCount(read) || !isCacheTokenCount(write) || read + write > input) return { cacheBreakdownKnown: false };
6853
- return {
6854
- freshInput: input - read - write,
6855
- cacheRead: read,
6856
- cacheWrite: write
6857
- };
6858
- }
6859
- function isCacheTokenCount(value) {
6860
- return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
6861
- }
6862
7047
  async function runRouterTransport(context, call) {
6863
7048
  try {
6864
7049
  return await call();
@@ -6886,12 +7071,7 @@ const routerToolsInlineExecutor = (spec, ctx) => {
6886
7071
  const enabledToolNames = new Set(seam.tools.map((tool) => tool.function.name));
6887
7072
  const maxTurns = profileExecution.maxTurns ?? 0;
6888
7073
  const requestIdentity = routerRequestIdentity(ctx);
6889
- const controller = new AbortController();
6890
- const abortIfSignalled = () => {
6891
- if (ctx.signal.aborted) controller.abort();
6892
- };
6893
- abortIfSignalled();
6894
- if (!ctx.signal.aborted) ctx.signal.addEventListener("abort", abortIfSignalled, { once: true });
7074
+ const controller = linkAbort(ctx.signal);
6895
7075
  const inbox = createInbox();
6896
7076
  let artifact;
6897
7077
  const executionId = ctx.node?.nodeId ?? `router-tools-run-${randomUUID()}`;
@@ -6917,6 +7097,7 @@ const routerToolsInlineExecutor = (spec, ctx) => {
6917
7097
  let reasoningKnown = true;
6918
7098
  const promptCache = {};
6919
7099
  let lastText = "";
7100
+ const executedToolCalls = [];
6920
7101
  const flush = () => {
6921
7102
  const pending = inbox.drain();
6922
7103
  if (pending.length) messages.push({
@@ -6925,7 +7106,7 @@ const routerToolsInlineExecutor = (spec, ctx) => {
6925
7106
  });
6926
7107
  return pending.length > 0;
6927
7108
  };
6928
- const external = mergeAbortSignals(signal, controller.signal);
7109
+ const external = linkAbort(signal, controller.signal).signal;
6929
7110
  try {
6930
7111
  for (let t = 0; maxTurns === 0 || t < maxTurns; t += 1) {
6931
7112
  flush();
@@ -6949,7 +7130,7 @@ const routerToolsInlineExecutor = (spec, ctx) => {
6949
7130
  ...profileExecution.temperature !== void 0 ? { temperature: profileExecution.temperature } : {},
6950
7131
  signal: turnController.signal,
6951
7132
  ...profileExecution.toolChoice ? { toolChoice: profileExecution.toolChoice } : {},
6952
- ...profileExecution.maxTokens !== void 0 ? { maxTokens: profileExecution.maxTokens } : {},
7133
+ ...profileExecution.tokenLimits.applied,
6953
7134
  ...profileExecution.seed !== void 0 ? { seed: profileExecution.seed } : {},
6954
7135
  ...profileExecution.reasoningEffort ? { reasoningEffort: profileExecution.reasoningEffort } : {},
6955
7136
  ...profileExecution.extraBody ? { extraBody: profileExecution.extraBody } : {},
@@ -6978,12 +7159,12 @@ const routerToolsInlineExecutor = (spec, ctx) => {
6978
7159
  addTokenUsage(tokens, {
6979
7160
  input: res.usage.input,
6980
7161
  output: res.usage.output,
6981
- ...routerPromptCacheUsage(res.usage.input, res.cache)
7162
+ ...promptCacheTokenClasses(res.usage.input, res.cache)
6982
7163
  });
6983
7164
  if (res.usage.reasoning !== void 0) reasoningTokens += res.usage.reasoning;
6984
7165
  else reasoningKnown = false;
6985
7166
  } else {
6986
- addTokenUsage(tokens, routerPromptCacheUsage(void 0, res.cache));
7167
+ addTokenUsage(tokens, promptCacheTokenClasses(void 0, res.cache));
6987
7168
  tokensKnown = false;
6988
7169
  reasoningKnown = false;
6989
7170
  }
@@ -7015,6 +7196,11 @@ const routerToolsInlineExecutor = (spec, ctx) => {
7015
7196
  const tc = toolCalls[i];
7016
7197
  const id = tc?.id ?? `call_${i}`;
7017
7198
  const toolName = tc?.name ?? "";
7199
+ executedToolCalls.push({
7200
+ id,
7201
+ name: toolName,
7202
+ arguments: tc?.arguments ?? ""
7203
+ });
7018
7204
  if (!enabledToolNames.has(toolName)) {
7019
7205
  messages.push({
7020
7206
  role: "tool",
@@ -7085,7 +7271,7 @@ const routerToolsInlineExecutor = (spec, ctx) => {
7085
7271
  ...observedModel !== void 0 ? { model: observedModel } : {},
7086
7272
  messages,
7087
7273
  turns,
7088
- toolCalls: messages.filter((message) => message.role === "tool").length,
7274
+ toolCalls: executedToolCalls,
7089
7275
  transportAttempts,
7090
7276
  ...estimatedUsd !== void 0 ? { estimatedCostUsd: estimatedUsd } : {},
7091
7277
  ...Object.keys(promptCache).length > 0 ? { promptCache } : {},
@@ -7101,6 +7287,10 @@ const routerToolsInlineExecutor = (spec, ctx) => {
7101
7287
  };
7102
7288
  return artifact;
7103
7289
  },
7290
+ cancel(_request) {
7291
+ controller.abort("executor cancelled");
7292
+ return Promise.resolve(localAbortCancellation("the Router chat-completions API exposes no cancel operation; the in-flight turn was aborted and the provider may still bill it"));
7293
+ },
7104
7294
  teardown(_grace) {
7105
7295
  controller.abort("executor torn down");
7106
7296
  return Promise.resolve({ destroyed: true });
@@ -7131,7 +7321,7 @@ const routerToolsInlineExecutor = (spec, ctx) => {
7131
7321
  maxTurns,
7132
7322
  tools: seam.tools,
7133
7323
  temperature: profileExecution.temperature ?? null,
7134
- maxTokens: profileExecution.maxTokens ?? null,
7324
+ tokenLimits: profileExecution.tokenLimits,
7135
7325
  retry: profileExecution.retry ?? null,
7136
7326
  toolChoice: profileExecution.toolChoice ?? null,
7137
7327
  extraBody: profileExecution.extraBody ?? null,
@@ -7190,13 +7380,9 @@ const sandboxExecutor = (spec, ctx) => {
7190
7380
  if (!seam.sandboxClient || typeof seam.sandboxClient.create !== "function") throw new ValidationError("sandboxExecutor: SandboxSeam.sandboxClient.create required");
7191
7381
  const maxIterations = seam.maxIterations ?? 1;
7192
7382
  if (!Number.isFinite(maxIterations) || maxIterations <= 0) throw new ValidationError("sandboxExecutor: maxIterations must be > 0");
7383
+ const sandboxTokenLimits = enforceTokenLimits(profileModelExecutionSettings(spec.profile, "sandboxExecutor").tokenLimits, "sandbox", "sandboxExecutor");
7193
7384
  const traceEnv = workerTraceEnv(ctx);
7194
- const controller = new AbortController();
7195
- const abortIfSignalled = () => {
7196
- if (ctx.signal.aborted) controller.abort();
7197
- };
7198
- abortIfSignalled();
7199
- if (!ctx.signal.aborted) ctx.signal.addEventListener("abort", abortIfSignalled, { once: true });
7385
+ const controller = linkAbort(ctx.signal);
7200
7386
  let artifact;
7201
7387
  const executionId = ctx.node?.nodeId ?? `sandbox-run-${randomUUID()}`;
7202
7388
  const attemptId = ctx.node?.attemptId ?? newExecutionAttemptId(executionId);
@@ -7220,7 +7406,8 @@ const sandboxExecutor = (spec, ctx) => {
7220
7406
  kind: "sandbox-agent-rounds",
7221
7407
  harness,
7222
7408
  maxIterations,
7223
- steering: seam.steering !== void 0
7409
+ steering: seam.steering !== void 0,
7410
+ tokenLimits: sandboxTokenLimits
7224
7411
  }
7225
7412
  };
7226
7413
  const sandboxBinding = {
@@ -7255,6 +7442,7 @@ const sandboxExecutor = (spec, ctx) => {
7255
7442
  runtime: "sandbox",
7256
7443
  deliver: (m) => inbox.deliver(m),
7257
7444
  progress: () => session.progress(),
7445
+ cancel: (request) => session.cancel(request),
7258
7446
  traceSource: () => session.traceSource(),
7259
7447
  execute(task, signal) {
7260
7448
  return session.stream(task, signal);
@@ -7296,6 +7484,10 @@ const sandboxExecutor = (spec, ctx) => {
7296
7484
  }
7297
7485
  });
7298
7486
  },
7487
+ cancel(_request) {
7488
+ controller.abort("executor cancelled");
7489
+ return Promise.resolve(localAbortCancellation("the composed sandbox run owns its boxes, so this executor retains no exact session control reference to cancel against"));
7490
+ },
7299
7491
  teardown(_grace) {
7300
7492
  controller.abort();
7301
7493
  return Promise.resolve({ destroyed: true });
@@ -7307,14 +7499,7 @@ const sandboxExecutor = (spec, ctx) => {
7307
7499
  }, sandboxMaterialization, sandboxBinding);
7308
7500
  };
7309
7501
  async function* streamSandboxLeaf(args) {
7310
- const linked = new AbortController();
7311
- const cascadeExternal = () => linked.abort(abortReasonOf(args.signal));
7312
- const cascadeScope = () => linked.abort(abortReasonOf(args.controller.signal));
7313
- if (args.signal.aborted || args.controller.signal.aborted) linked.abort(abortReasonOf(args.signal.aborted ? args.signal : args.controller.signal));
7314
- else {
7315
- args.signal.addEventListener("abort", cascadeExternal, { once: true });
7316
- args.controller.signal.addEventListener("abort", cascadeScope, { once: true });
7317
- }
7502
+ const linked = linkAbort(args.signal, args.controller.signal);
7318
7503
  const agentRun = {
7319
7504
  profile: args.spec.profile,
7320
7505
  taskToPrompt: (t) => taskToPrompt(t),
@@ -7390,14 +7575,19 @@ async function* streamSandboxLeaf(args) {
7390
7575
  ...result.tokenUsage.cacheWrite !== void 0 ? { cacheWrite: result.tokenUsage.cacheWrite } : {},
7391
7576
  ...result.tokenUsage.cacheBreakdownKnown === false ? { cacheBreakdownKnown: false } : {}
7392
7577
  };
7393
- if (result.iterations.length > 0 || result.costUsd) yield {
7578
+ if (result.iterations.length > 0 || result.costUsd) yield usdKnown ? {
7394
7579
  kind: "cost",
7580
+ usdKnown: true,
7395
7581
  usd: result.costUsd,
7396
- ...usdKnown ? {} : { usdKnown: false }
7582
+ provenance: "provider-receipt"
7583
+ } : {
7584
+ kind: "cost",
7585
+ usdKnown: false,
7586
+ usd: result.costUsd,
7587
+ provenance: "uncaptured"
7397
7588
  };
7398
7589
  } finally {
7399
- args.signal.removeEventListener("abort", cascadeExternal);
7400
- args.controller.signal.removeEventListener("abort", cascadeScope);
7590
+ linked.release();
7401
7591
  }
7402
7592
  }
7403
7593
  /** The loop's own failure, when NO iteration produced an output: the first error it
@@ -7443,12 +7633,7 @@ const cliExecutor = (_spec, ctx) => {
7443
7633
  const seam = readSeam(ctx, cliSeamKey, "cli");
7444
7634
  if (!seam.bin) throw new ValidationError("cliExecutor: CliSeam.bin required");
7445
7635
  const traceEnv = workerTraceEnv(ctx);
7446
- const controller = new AbortController();
7447
- const abortIfSignalled = () => {
7448
- if (ctx.signal.aborted) controller.abort();
7449
- };
7450
- abortIfSignalled();
7451
- if (!ctx.signal.aborted) ctx.signal.addEventListener("abort", abortIfSignalled, { once: true });
7636
+ const controller = linkAbort(ctx.signal);
7452
7637
  let proc;
7453
7638
  let artifact;
7454
7639
  const executionId = ctx.node?.nodeId ?? `cli-process-${randomUUID()}`;
@@ -7592,18 +7777,20 @@ function bridgeProfileModel(profile, context) {
7592
7777
  const bridgeExecutor = (spec, ctx) => {
7593
7778
  const base = readSeam(ctx, bridgeSeamKey, "bridge");
7594
7779
  const stopSignal = readOptionalAbortSignal(ctx, bridgeStopSignalKey, "bridge");
7780
+ const runtimeAttachments = readOptionalMcpAttachments(ctx, bridgeRuntimeAttachmentsKey, "bridge");
7595
7781
  const modelCredential = validateBridgeModelCredential(base.modelCredential, base.bridgeUrl, "bridgeExecutor");
7596
7782
  const effectiveProfile = agentProfileSchema.parse(spec.profile);
7597
7783
  const model = bridgeProfileModel(effectiveProfile, "bridgeExecutor");
7598
7784
  const harness = agentHarness(effectiveProfile.harness);
7599
7785
  const providerModel = harness !== void 0 && model.startsWith(`${harness}/`) ? model.slice(harness.length + 1) : model;
7600
7786
  const profileExecution = profileModelExecutionSettings(effectiveProfile, "bridgeExecutor");
7787
+ const bridgeTokenLimits = enforceTokenLimits(profileExecution.tokenLimits, "bridge", "bridgeExecutor");
7601
7788
  const seam = {
7602
7789
  ...base,
7603
7790
  ...modelCredential === void 0 ? {} : { modelCredential },
7604
7791
  model,
7605
7792
  providerModel,
7606
- ...profileExecution.maxTokens !== void 0 ? { maxTokens: profileExecution.maxTokens } : {}
7793
+ ...bridgeTokenLimits.applied.maxTokens !== void 0 ? { maxTokens: bridgeTokenLimits.applied.maxTokens } : {}
7607
7794
  };
7608
7795
  if (!seam.bridgeUrl || !seam.bridgeBearer) throw new ValidationError("bridgeExecutor: bridgeUrl + bridgeBearer are required");
7609
7796
  if (seam.timeoutMs !== void 0 && (!Number.isSafeInteger(seam.timeoutMs) || seam.timeoutMs < 1 || seam.timeoutMs > maxBridgeTimeoutMs)) throw new ValidationError(`bridgeExecutor: timeoutMs must be an integer from 1 to ${maxBridgeTimeoutMs}`);
@@ -7613,12 +7800,7 @@ const bridgeExecutor = (spec, ctx) => {
7613
7800
  const sessionId = seam.sessionId ?? `bridge-${spec.profile.name ?? "worker"}-${randomUUID()}`;
7614
7801
  const attemptId = ctx.node?.attemptId ?? newExecutionAttemptId(sessionId);
7615
7802
  const traceHeaders = workerTraceHeaders(ctx);
7616
- const controller = new AbortController();
7617
- const abortIfSignalled = () => {
7618
- if (ctx.signal.aborted) controller.abort();
7619
- };
7620
- abortIfSignalled();
7621
- if (!ctx.signal.aborted) ctx.signal.addEventListener("abort", abortIfSignalled, { once: true });
7803
+ const controller = linkAbort(ctx.signal);
7622
7804
  const inbox = createInbox();
7623
7805
  let artifact;
7624
7806
  const activeRuns = /* @__PURE__ */ new Map();
@@ -7651,7 +7833,7 @@ const bridgeExecutor = (spec, ctx) => {
7651
7833
  maxReconnects,
7652
7834
  timeoutMs: seam.timeoutMs ?? null,
7653
7835
  streaming: true,
7654
- ...seam.maxTokens !== void 0 ? { maxTokens: seam.maxTokens } : {},
7836
+ tokenLimits: bridgeTokenLimits,
7655
7837
  terminalAcknowledgement: null
7656
7838
  }
7657
7839
  };
@@ -7697,11 +7879,16 @@ const bridgeExecutor = (spec, ctx) => {
7697
7879
  }
7698
7880
  },
7699
7881
  traceSource: () => trace.source,
7882
+ interactive: () => Object.freeze({
7883
+ status: "unavailable",
7884
+ reason: "provider-has-no-interactive-contract"
7885
+ }),
7700
7886
  execute(task, signal) {
7701
7887
  return streamBridgeSession({
7702
7888
  task,
7703
7889
  signal,
7704
7890
  ...stopSignal === void 0 ? {} : { stopSignal },
7891
+ ...runtimeAttachments === void 0 ? {} : { runtimeAttachments },
7705
7892
  profile: effectiveProfile,
7706
7893
  seam,
7707
7894
  sessionId,
@@ -7738,6 +7925,41 @@ const bridgeExecutor = (spec, ctx) => {
7738
7925
  }
7739
7926
  });
7740
7927
  },
7928
+ async cancel(request) {
7929
+ const live = [...activeRuns.values()].filter((run) => !run.terminal);
7930
+ const observedAt = () => (/* @__PURE__ */ new Date()).toISOString();
7931
+ if (live.length === 0) return {
7932
+ status: "already-terminal",
7933
+ effect: "not_live",
7934
+ observedAt: observedAt(),
7935
+ detail: "every bridge run for this session was already terminal",
7936
+ evidence: { runs: [...activeRuns.keys()] }
7937
+ };
7938
+ controller.abort("executor cancelled");
7939
+ const grace = request.signal === void 0 ? "infinity" : BRIDGE_CANCEL_LONG_POLL_MS;
7940
+ const terminal = await Promise.all(live.map((run) => cancelBridgeRunToTerminal(seam, run, grace, request.signal)));
7941
+ const evidence = {
7942
+ operationId: request.operationId,
7943
+ runs: live.map((run, index) => ({
7944
+ id: run.id,
7945
+ terminal: terminal[index] === true
7946
+ }))
7947
+ };
7948
+ if (terminal.every(Boolean)) return {
7949
+ status: "accepted",
7950
+ effect: "cancelled",
7951
+ observedAt: observedAt(),
7952
+ detail: "the bridge reported every run terminal after the cancel operation",
7953
+ evidence
7954
+ };
7955
+ return {
7956
+ status: "unknown",
7957
+ effect: "cancel_requested",
7958
+ observedAt: observedAt(),
7959
+ detail: "the bridge accepted the cancel operation but a run had not reached terminal state within the deadline",
7960
+ evidence
7961
+ };
7962
+ },
7741
7963
  async teardown(grace) {
7742
7964
  controller.abort();
7743
7965
  const remaining = [...activeRuns.values()].filter((run) => !run.terminal);
@@ -7803,6 +8025,78 @@ function scheduleBridgeRunStateRefresh(seam, activeRuns, observation) {
7803
8025
  }
7804
8026
  })();
7805
8027
  }
8028
+ /** One bridge GET over the `node:http(s)` core client — the same transport every other bridge
8029
+ * read uses, so a computed provider endpoint never reaches global `fetch`. Resolves the status
8030
+ * and the body text; a transport failure rejects. */
8031
+ function bridgeGet(seam, path, timeoutMs) {
8032
+ const target = new URL(`${seam.bridgeUrl.replace(/\/$/, "")}${path}`);
8033
+ const requestFn = target.protocol === "https:" ? request$1 : request;
8034
+ return new Promise((resolve, reject) => {
8035
+ const req = requestFn(target, {
8036
+ method: "GET",
8037
+ headers: { authorization: `Bearer ${seam.bridgeBearer}` },
8038
+ timeout: timeoutMs
8039
+ }, (res) => {
8040
+ (async () => {
8041
+ const chunks = [];
8042
+ for await (const chunk of res) chunks.push(Buffer.from(chunk));
8043
+ resolve({
8044
+ status: res.statusCode ?? 0,
8045
+ body: Buffer.concat(chunks).toString("utf8")
8046
+ });
8047
+ })().catch(reject);
8048
+ });
8049
+ req.on("timeout", () => req.destroy(/* @__PURE__ */ new Error(`bridge GET ${path} timed out`)));
8050
+ req.on("error", reject);
8051
+ req.end();
8052
+ });
8053
+ }
8054
+ /**
8055
+ * `GET /v1/capabilities?model=<wire id>` — does this bridge route this model AT ALL.
8056
+ *
8057
+ * The bridge answers exactly this question and 404s `no backend matches model "…"`, which is the
8058
+ * error a child would otherwise discover after it was spawned and metered. Returns `undefined`
8059
+ * when the route resolves; otherwise the operator-facing reason it did not. FAIL CLOSED: a
8060
+ * transport error and an unexpected status are both reasons, never a silent pass.
8061
+ */
8062
+ async function bridgeModelRouteRefusal(seam, wireModel) {
8063
+ const base = seam.bridgeUrl.replace(/\/$/, "");
8064
+ let answer;
8065
+ try {
8066
+ answer = await bridgeGet(seam, `/v1/capabilities?model=${encodeURIComponent(wireModel)}`, BRIDGE_RUN_STATE_TIMEOUT_MS);
8067
+ } catch (error) {
8068
+ return `bridge ${base} did not answer for model ${JSON.stringify(wireModel)}: ${error instanceof Error ? error.message : String(error)}`;
8069
+ }
8070
+ if (answer.status === 200) return void 0;
8071
+ return answer.status === 404 ? `bridge ${base} routes no backend for model ${JSON.stringify(wireModel)}` : `bridge ${base} answered ${answer.status} for model ${JSON.stringify(wireModel)}`;
8072
+ }
8073
+ /**
8074
+ * `GET /health` → `admission.{active,maxActive}`, or `undefined` when the bridge does not report
8075
+ * them. ADVISORY by nature — admission fills and drains — so an unanswered or admission-less
8076
+ * `/health` is not evidence about capacity and must not be read as one.
8077
+ */
8078
+ async function bridgeAdmissionRead(seam) {
8079
+ let answer;
8080
+ try {
8081
+ answer = await bridgeGet(seam, "/health", BRIDGE_RUN_STATE_TIMEOUT_MS);
8082
+ } catch {
8083
+ return;
8084
+ }
8085
+ let parsed;
8086
+ try {
8087
+ parsed = JSON.parse(answer.body);
8088
+ } catch {
8089
+ return;
8090
+ }
8091
+ const admission = parsed?.admission;
8092
+ const active = admission?.active;
8093
+ const maxActive = admission?.maxActive;
8094
+ if (typeof active !== "number" || typeof maxActive !== "number" || maxActive <= 0) return;
8095
+ return {
8096
+ active,
8097
+ maxActive
8098
+ };
8099
+ }
7806
8100
  /** `GET /v1/runs/:id` — the bridge's durable-run registry read. Resolves `undefined` for any
7807
8101
  * non-200 or non-conforming body rather than throwing: this is only ever an observability read. */
7808
8102
  function bridgeRunStateGet(seam, runId) {
@@ -7861,7 +8155,7 @@ function readBridgeRunState(runId, body) {
7861
8155
  async function* streamBridgeSession(args) {
7862
8156
  const { seam, inbox, observation } = args;
7863
8157
  const started = Date.now();
7864
- const external = mergeAbortSignals(args.signal, args.controller.signal);
8158
+ const external = linkAbort(args.signal, args.controller.signal).signal;
7865
8159
  const tokens = zeroTokenUsage();
7866
8160
  let tokensKnown = true;
7867
8161
  let usd = 0;
@@ -7935,6 +8229,7 @@ async function* streamBridgeSession(args) {
7935
8229
  ...seam.timeoutMs !== void 0 ? { timeoutMs: seam.timeoutMs } : {}
7936
8230
  },
7937
8231
  agent_profile: args.profile,
8232
+ ...args.runtimeAttachments === void 0 ? {} : { runtime_attachments: { mcp: args.runtimeAttachments } },
7938
8233
  messages
7939
8234
  };
7940
8235
  let turnText = "";
@@ -7943,6 +8238,7 @@ async function* streamBridgeSession(args) {
7943
8238
  let sawTurnCostStatus = false;
7944
8239
  let turnUsdKnown = true;
7945
8240
  let turnKnownCostSubtotal = 0;
8241
+ let turnCostProvenance;
7946
8242
  let turnEstimatedCostSubtotal = 0;
7947
8243
  let turnInputTokens = 0;
7948
8244
  let turnOutputTokens = 0;
@@ -7965,6 +8261,7 @@ async function* streamBridgeSession(args) {
7965
8261
  profile: args.profile,
7966
8262
  sessionId: args.sessionId,
7967
8263
  body: requestBody,
8264
+ requiresRuntimeAttachments: args.runtimeAttachments !== void 0,
7968
8265
  signal: turnController.signal,
7969
8266
  run: activeRun,
7970
8267
  maxReconnects: args.maxReconnects,
@@ -7989,9 +8286,22 @@ async function* streamBridgeSession(args) {
7989
8286
  }
7990
8287
  observedSystemFingerprint = chunk.systemFingerprint;
7991
8288
  }
7992
- if (chunk.content) turnText += chunk.content;
8289
+ if (chunk.content) {
8290
+ turnText += chunk.content;
8291
+ yield {
8292
+ kind: "progress",
8293
+ progress: {
8294
+ kind: "text_delta",
8295
+ text: chunk.content
8296
+ }
8297
+ };
8298
+ }
7993
8299
  for (const step of chunk.toolCalls ?? []) {
7994
- toolCalls.push(step.toolName);
8300
+ toolCalls.push({
8301
+ ...step.callId === void 0 ? {} : { id: step.callId },
8302
+ name: step.toolName,
8303
+ arguments: step.args
8304
+ });
7995
8305
  observation.activity.push({
7996
8306
  at: Date.now(),
7997
8307
  kind: "tool",
@@ -7999,6 +8309,15 @@ async function* streamBridgeSession(args) {
7999
8309
  ...describeToolArgs(step.args) ? { detail: describeToolArgs(step.args) } : {}
8000
8310
  });
8001
8311
  args.record(step);
8312
+ yield {
8313
+ kind: "progress",
8314
+ progress: {
8315
+ kind: "tool_call",
8316
+ toolName: step.toolName,
8317
+ ...step.callId === void 0 ? {} : { toolCallId: step.callId },
8318
+ args: step.args
8319
+ }
8320
+ };
8002
8321
  }
8003
8322
  if (chunk.usage) {
8004
8323
  sawTurnTokenUsage = true;
@@ -8022,6 +8341,7 @@ async function* streamBridgeSession(args) {
8022
8341
  if (chunk.usage.promptCache.writeInput !== void 0) promptCache.writeTokens = (promptCache.writeTokens ?? 0) + chunk.usage.promptCache.writeInput;
8023
8342
  }
8024
8343
  }
8344
+ if (chunk.costProvenance !== void 0) turnCostProvenance = chunk.costProvenance;
8025
8345
  if (chunk.costKnown !== void 0) {
8026
8346
  sawTurnCostStatus = true;
8027
8347
  if (!chunk.costKnown) turnUsdKnown = false;
@@ -8035,7 +8355,9 @@ async function* streamBridgeSession(args) {
8035
8355
  usd += increment;
8036
8356
  yield {
8037
8357
  kind: "cost",
8038
- usd: increment
8358
+ usdKnown: true,
8359
+ usd: increment,
8360
+ provenance: turnCostProvenance ?? "provider-receipt"
8039
8361
  };
8040
8362
  }
8041
8363
  }
@@ -8080,9 +8402,10 @@ async function* streamBridgeSession(args) {
8080
8402
  }) : {
8081
8403
  kind: "cost",
8082
8404
  usd: 0,
8083
- usdKnown: false
8405
+ usdKnown: false,
8406
+ provenance: "uncaptured"
8084
8407
  };
8085
- if (priced.usdEstimated !== void 0) estimatedUsdCharged += priced.usdEstimated;
8408
+ if (priced.usdKnown === false && priced.usdEstimated !== void 0) estimatedUsdCharged += priced.usdEstimated;
8086
8409
  usd += priced.usd;
8087
8410
  yield priced;
8088
8411
  }
@@ -8136,7 +8459,7 @@ const BRIDGE_BRUTAL_KILL_WAIT_MS = 150;
8136
8459
  * cannot prove continuity fails instead of returning a plausible partial answer.
8137
8460
  */
8138
8461
  async function* streamDurableBridgeRun(args) {
8139
- await assertBridgeExecutionCapabilities(args.seam, args.signal);
8462
+ await assertBridgeExecutionCapabilities(args.seam, args.signal, args.requiresRuntimeAttachments);
8140
8463
  let reconnects = 0;
8141
8464
  let pendingUpstreamError;
8142
8465
  for (;;) {
@@ -8215,7 +8538,7 @@ async function* streamDurableBridgeRun(args) {
8215
8538
  * a process may restart behind the same URL, and a remembered capability from the prior process
8216
8539
  * is not evidence about the process that will receive the next POST. The terminal receipt remains
8217
8540
  * mandatory because the bridge can still restart between this GET and the run request. */
8218
- async function assertBridgeExecutionCapabilities(seam, signal) {
8541
+ async function assertBridgeExecutionCapabilities(seam, signal, requiresRuntimeAttachments) {
8219
8542
  const target = new URL(`${seam.bridgeUrl.replace(/\/$/, "")}/`);
8220
8543
  const requestFn = target.protocol === "https:" ? request$1 : request;
8221
8544
  const response = await new Promise((resolve, reject) => {
@@ -8256,6 +8579,10 @@ async function assertBridgeExecutionCapabilities(seam, signal) {
8256
8579
  }
8257
8580
  if (body.capabilities?.profileMaterialization !== bridgeProfileMaterializationSchema) throw new ValidationError(`bridgeExecutor: bridge does not advertise ${bridgeProfileMaterializationSchema}`);
8258
8581
  if (body.capabilities?.usageCostProvenance !== bridgeUsageCostSchema) throw new ValidationError(`bridgeExecutor: bridge does not advertise ${bridgeUsageCostSchema}`);
8582
+ if (requiresRuntimeAttachments) {
8583
+ const attachments = body.capabilities?.runtimeAttachments;
8584
+ if (attachments === null || typeof attachments !== "object" || attachments.mcp !== true) throw new ValidationError(`bridgeExecutor: bridge at ${seam.bridgeUrl} does not advertise capabilities.runtimeAttachments.mcp; upgrade cli-bridge to a version that carries Runtime MCP attachments outside the bound AgentProfile`);
8585
+ }
8259
8586
  }
8260
8587
  /**
8261
8588
  * POST one streamed turn to the cli-bridge over the `node:http(s)` core client
@@ -8865,6 +9192,7 @@ function applyBridgeCostReceipt(out, usage) {
8865
9192
  if (cost === void 0 || provenance !== "provider-receipt" && provenance !== "billing-receipt" || estimatedCost !== void 0) throw new ValidationError("bridgeExecutor: known cost requires cost plus provider-receipt or billing-receipt provenance");
8866
9193
  out.costKnown = true;
8867
9194
  out.cost = cost;
9195
+ out.costProvenance = provenance;
8868
9196
  return;
8869
9197
  }
8870
9198
  if (cost !== void 0) throw new ValidationError("bridgeExecutor: unknown cost cannot carry billed cost");
@@ -8955,7 +9283,7 @@ function bridgeWorktreeExecutor(spec, ctx, seam) {
8955
9283
  execute(task, signal) {
8956
9284
  return (async function* bridgeWorktreeStream() {
8957
9285
  const started = Date.now();
8958
- const linked = mergeAbortSignals(signal, controller.signal);
9286
+ const linked = linkAbort(signal, controller.signal).signal;
8959
9287
  let bridgeArtifact;
8960
9288
  try {
8961
9289
  worktree = await createWorktree({
@@ -9315,13 +9643,14 @@ function createExecutor(config) {
9315
9643
  }
9316
9644
  }
9317
9645
  };
9318
- return {
9319
- ...sandboxExecutor({
9320
- ...spec,
9321
- harness
9322
- }, providerCtx),
9646
+ const executor = sandboxExecutor({
9647
+ ...spec,
9648
+ harness
9649
+ }, providerCtx);
9650
+ return inheritRuntimeOwnedExecutorAttestation(executor, {
9651
+ ...executor,
9323
9652
  runtime: providerSeam.runtime ?? provider.name
9324
- };
9653
+ });
9325
9654
  }
9326
9655
  const profileForCreate = providerSeam.profileForCreate;
9327
9656
  return providerAsExecutor(provider, {
@@ -9423,6 +9752,15 @@ function readOptionalAbortSignal(ctx, key, who) {
9423
9752
  if (value === null || typeof value !== "object" || typeof value.aborted !== "boolean" || typeof value.addEventListener !== "function") throw new ValidationError(`${who} executor: seam "${key}" must be an AbortSignal`);
9424
9753
  return value;
9425
9754
  }
9755
+ /** Narrow the Runtime-owned MCP attachment seam. Absent means the run mounts nothing; a present
9756
+ * value must be a named map of MCP servers, never an empty one that would silently mount nothing. */
9757
+ function readOptionalMcpAttachments(ctx, key, who) {
9758
+ const value = ctx.seams[key];
9759
+ if (value === void 0) return void 0;
9760
+ const entries = value !== null && typeof value === "object" && !Array.isArray(value) ? Object.entries(value) : void 0;
9761
+ if (entries === void 0 || entries.length === 0 || entries.some(([, server]) => server === null || typeof server !== "object")) throw new ValidationError(`${who} executor: seam ${JSON.stringify(key)} must be a non-empty map of MCP servers`);
9762
+ return value;
9763
+ }
9426
9764
  /** A leaf task is opaque (`unknown`). A string is the prompt verbatim; an object
9427
9765
  * with a `prompt`/`content`/`task` string field uses it; otherwise it serializes.
9428
9766
  * Module-exported (not package surface) so sibling leaf executors read a task
@@ -9472,10 +9810,12 @@ function routerProfileExecution(profile, seam, mode) {
9472
9810
  if (enabled && !suppliedNames.has(name)) throw new ValidationError(`routerInlineExecutor: AgentProfile enables tool ${JSON.stringify(name)} but the caller supplied no matching schema`);
9473
9811
  if (!enabled && suppliedNames.has(name)) throw new ValidationError(`routerInlineExecutor: AgentProfile disables tool ${JSON.stringify(name)}`);
9474
9812
  }
9813
+ const { tokenLimits, ...rest } = settings;
9475
9814
  return {
9476
9815
  systemPrompt: renderRouterProfilePrompt(profile),
9477
9816
  ...profileEffort ? { reasoningEffort: profileEffort } : {},
9478
- ...settings
9817
+ ...rest,
9818
+ tokenLimits: enforceTokenLimits(tokenLimits, "router", "routerInlineExecutor")
9479
9819
  };
9480
9820
  }
9481
9821
  /** Resolve the one model id that will cross the Router boundary from the exact profile only. */
@@ -9555,113 +9895,6 @@ function singleShotDriver(maxIterations) {
9555
9895
  }
9556
9896
  };
9557
9897
  }
9558
- /** Link two abort signals into one that fires when either does. Returns
9559
- * `undefined` when neither is present so `fetch` gets no signal at all. */
9560
- function linkSignals(a, b) {
9561
- if (a.aborted || b.aborted) {
9562
- const c = new AbortController();
9563
- c.abort(abortReasonOf(a.aborted ? a : b));
9564
- return c.signal;
9565
- }
9566
- const c = new AbortController();
9567
- a.addEventListener("abort", () => c.abort(abortReasonOf(a)), { once: true });
9568
- b.addEventListener("abort", () => c.abort(abortReasonOf(b)), { once: true });
9569
- return c.signal;
9570
- }
9571
- /** The reason a signal carries, or a named fallback. A cascade that drops the upstream reason
9572
- * turns every downstream death into the generic "execution aborted": the worker's `down`
9573
- * record then says nothing about WHY, which is what makes a whole class of child mortality
9574
- * undiagnosable from the journal alone. */
9575
- function abortReasonOf(signal, fallback = "aborted by parent scope") {
9576
- const reason = signal.reason;
9577
- if (typeof reason === "string" && reason.length > 0) return reason;
9578
- if (reason instanceof Error && reason.name !== "AbortError" && reason.message.length > 0) return reason.message;
9579
- return fallback;
9580
- }
9581
- /** Combine N abort signals into one that fires when ANY does. Node-portable (no `AbortSignal.any`,
9582
- * which needs >=20.3 — the package floor is >=20). Module-exported (not package surface) so
9583
- * sibling leaf executors share the one portable implementation. */
9584
- function mergeAbortSignals(...signals) {
9585
- const c = new AbortController();
9586
- const onAbort = () => c.abort();
9587
- for (const s of signals) {
9588
- if (s.aborted) {
9589
- c.abort();
9590
- break;
9591
- }
9592
- s.addEventListener("abort", onAbort, { once: true });
9593
- }
9594
- return c.signal;
9595
- }
9596
- //#endregion
9597
- //#region src/runtime/supervise/abortable.ts
9598
- /**
9599
- * One abort race for the supervision tree.
9600
- *
9601
- * Every layer that can be cancelled needs the same two things: an `AbortError` that
9602
- * carries the signal's own reason, and a settle-once race between the work and the
9603
- * signal. Written per layer, the race drifts — the listener stops being removed on
9604
- * one path, or a late resolution overwrites a cancellation that already won.
9605
- *
9606
- * The fallback message is the only thing a layer supplies, so the error still names
9607
- * which layer cancelled.
9608
- */
9609
- /** An `AbortError` carrying the signal's own string reason, or `fallback` when it states none. */
9610
- function abortError(signal, fallback) {
9611
- const reason = signal.reason;
9612
- const error = new Error(typeof reason === "string" && reason.length > 0 ? reason : fallback);
9613
- error.name = "AbortError";
9614
- return error;
9615
- }
9616
- /**
9617
- * Settle `act()` against `signal`. The first outcome wins and the listener is always
9618
- * removed, so neither a late resolution nor a late abort can settle the promise twice.
9619
- * The losing promise stays observed, so a late rejection cannot surface as an unhandled
9620
- * process error.
9621
- *
9622
- * The abort rejection is deferred one microtask so a result the action had ALREADY
9623
- * produced still wins. It does not hand the race to a listener the action registers
9624
- * from inside `act()`: this function subscribes before it calls `act()`, so its own
9625
- * abort handler runs first and settles the promise. A caller that must let the action
9626
- * observe the abort itself has to hold a live promise and await that instead.
9627
- *
9628
- * A synchronous throw from `act()` propagates as the rejection, not as an abort.
9629
- */
9630
- async function runAbortable(act, signal, fallback) {
9631
- if (signal.aborted) throw abortError(signal, fallback);
9632
- return await new Promise((resolve, reject) => {
9633
- let settled = false;
9634
- const cleanup = () => signal.removeEventListener("abort", onAbort);
9635
- const onAbort = () => {
9636
- queueMicrotask(() => {
9637
- if (settled) return;
9638
- settled = true;
9639
- cleanup();
9640
- reject(abortError(signal, fallback));
9641
- });
9642
- };
9643
- signal.addEventListener("abort", onAbort, { once: true });
9644
- let work;
9645
- try {
9646
- work = Promise.resolve(act());
9647
- } catch (error) {
9648
- cleanup();
9649
- reject(error);
9650
- return;
9651
- }
9652
- work.then((value) => {
9653
- if (settled) return;
9654
- settled = true;
9655
- cleanup();
9656
- resolve(value);
9657
- }, (error) => {
9658
- if (settled) return;
9659
- settled = true;
9660
- cleanup();
9661
- reject(error);
9662
- });
9663
- });
9664
- }
9665
9898
  //#endregion
9666
9899
  //#region src/runtime/supervise/budget.ts
9667
9900
  /**
@@ -9758,56 +9991,61 @@ function assertValidSpend(spend, label) {
9758
9991
  * channels; iterations come from `'iteration'` events. Pure; `ms` stays zero (the
9759
9992
  * pool does not read wall-clock). */
9760
9993
  function spendFromUsageEvents(events) {
9761
- const tokens = zeroTokenUsage();
9762
- let tokensKnown = true;
9763
- let usd = 0;
9764
- let usdEstimated = 0;
9765
- let usdKnown = true;
9766
- let iterations = 0;
9767
- for (const ev of events) if (ev.kind === "tokens") {
9768
- addTokenUsage(tokens, ev);
9769
- if (ev.tokensKnown === false) tokensKnown = false;
9770
- } else if (ev.kind === "cost") {
9771
- usd += ev.usd;
9772
- usdEstimated += ev.usdEstimated ?? 0;
9773
- if (ev.usdKnown === false) usdKnown = false;
9774
- } else iterations += 1;
9994
+ const totals = newUsageTotals();
9995
+ for (const ev of events) meterUsageEvent(totals, ev);
9996
+ return spendFromUsageTotals(totals);
9997
+ }
9998
+ /** Fresh zeroed {@link UsageTotals}. */
9999
+ function newUsageTotals() {
9775
10000
  return {
9776
- iterations,
9777
- tokens,
9778
- ...tokensKnown ? {} : { tokensKnown: false },
9779
- usd,
9780
- ...usdKnown ? {} : { usdKnown: false },
9781
- ...usdEstimated > 0 ? { usdEstimated } : {},
9782
- ms: 0
10001
+ tokens: zeroTokenUsage(),
10002
+ tokensKnown: true,
10003
+ usd: 0,
10004
+ usdEstimated: 0,
10005
+ usdKnown: true,
10006
+ iterations: 0
9783
10007
  };
9784
10008
  }
9785
- async function foldUsage(events) {
9786
- if (Array.isArray(events)) return spendFromUsageEvents(events);
9787
- const tokens = zeroTokenUsage();
9788
- let tokensKnown = true;
9789
- let usd = 0;
9790
- let usdEstimated = 0;
9791
- let usdKnown = true;
9792
- let iterations = 0;
9793
- for await (const ev of events) if (ev.kind === "tokens") {
9794
- addTokenUsage(tokens, ev);
9795
- if (ev.tokensKnown === false) tokensKnown = false;
9796
- } else if (ev.kind === "cost") {
9797
- usd += ev.usd;
9798
- usdEstimated += ev.usdEstimated ?? 0;
9799
- if (ev.usdKnown === false) usdKnown = false;
9800
- } else iterations += 1;
10009
+ /**
10010
+ * Fold ONE usage event into running totals — the single place that decides which event kinds
10011
+ * meter. `progress` carries observed output rather than accounting, so it meters nothing; only
10012
+ * `iteration` advances the iteration count.
10013
+ */
10014
+ function meterUsageEvent(totals, ev) {
10015
+ if (ev.kind === "tokens") {
10016
+ addTokenUsage(totals.tokens, ev);
10017
+ if (ev.tokensKnown === false) totals.tokensKnown = false;
10018
+ return;
10019
+ }
10020
+ if (ev.kind === "cost") {
10021
+ totals.usd += ev.usd;
10022
+ if (ev.usdKnown === false) {
10023
+ totals.usdEstimated += ev.usdEstimated ?? 0;
10024
+ totals.usdKnown = false;
10025
+ }
10026
+ return;
10027
+ }
10028
+ if (ev.kind === "iteration") totals.iterations += 1;
10029
+ }
10030
+ /** Project folded totals onto the conserved-pool `Spend`. `ms` stays zero — the pool does not
10031
+ * read wall-clock. */
10032
+ function spendFromUsageTotals(totals) {
9801
10033
  return {
9802
- iterations,
9803
- tokens,
9804
- ...tokensKnown ? {} : { tokensKnown: false },
9805
- usd,
9806
- ...usdKnown ? {} : { usdKnown: false },
9807
- ...usdEstimated > 0 ? { usdEstimated } : {},
10034
+ iterations: totals.iterations,
10035
+ tokens: totals.tokens,
10036
+ ...totals.tokensKnown ? {} : { tokensKnown: false },
10037
+ usd: totals.usd,
10038
+ ...totals.usdKnown ? {} : { usdKnown: false },
10039
+ ...totals.usdEstimated > 0 ? { usdEstimated: totals.usdEstimated } : {},
9808
10040
  ms: 0
9809
10041
  };
9810
10042
  }
10043
+ async function foldUsage(events) {
10044
+ if (Array.isArray(events)) return spendFromUsageEvents(events);
10045
+ const totals = newUsageTotals();
10046
+ for await (const ev of events) meterUsageEvent(totals, ev);
10047
+ return spendFromUsageTotals(totals);
10048
+ }
9811
10049
  /**
9812
10050
  * Create a conserved reservation pool from a root `Budget`. `now()` is injected so the
9813
10051
  * deadline readout is deterministic; defaults to `Date.now` for non-test callers. The
@@ -10610,7 +10848,7 @@ function createScope(args) {
10610
10848
  spec = prepared.spec;
10611
10849
  identity = prepared.identity;
10612
10850
  if (opts.key !== void 0 && !isCompleteIdentity(identity)) {
10613
- args.pool.reconcile(reservation.ticket, zeroSpend$1());
10851
+ args.pool.reconcile(reservation.ticket, zeroSpend());
10614
10852
  permit.release();
10615
10853
  return {
10616
10854
  ok: false,
@@ -10621,7 +10859,7 @@ function createScope(args) {
10621
10859
  if (!outcome.succeeded) throw new ValidationError(`scope.spawn: ${outcome.error}`);
10622
10860
  resolved = outcome;
10623
10861
  } catch (error) {
10624
- args.pool.reconcile(reservation.ticket, zeroSpend$1());
10862
+ args.pool.reconcile(reservation.ticket, zeroSpend());
10625
10863
  permit.release();
10626
10864
  throw error;
10627
10865
  }
@@ -10686,7 +10924,7 @@ function createScope(args) {
10686
10924
  label: opts.label,
10687
10925
  ...opts.assignmentId === void 0 ? {} : { assignmentId: opts.assignmentId },
10688
10926
  ...opts.key !== void 0 ? { key: opts.key } : {},
10689
- spent: zeroSpend$1(),
10927
+ spent: zeroSpend(),
10690
10928
  settled: void 0,
10691
10929
  delivered: false,
10692
10930
  executorDone: false,
@@ -10696,7 +10934,10 @@ function createScope(args) {
10696
10934
  lastActivityAt: startedAt,
10697
10935
  ...executor.deliver ? { deliver: (message) => executor.deliver?.(message) !== false } : {},
10698
10936
  ...executor.progress ? { readProgress: executor.progress.bind(executor) } : {},
10699
- ...executor.traceSource ? { readTraceSource: executor.traceSource.bind(executor) } : {}
10937
+ ...executor.traceSource ? { readTraceSource: executor.traceSource.bind(executor) } : {},
10938
+ ...executor.interactive ? { readInteractive: executor.interactive.bind(executor) } : {},
10939
+ ...executor.cancel ? { requestCancel: executor.cancel.bind(executor) } : {},
10940
+ abortChild: (reason) => controller.abort(reason)
10700
10941
  };
10701
10942
  children.set(id, live);
10702
10943
  if (opts.key !== void 0) keyed.set(opts.key, {
@@ -10704,7 +10945,8 @@ function createScope(args) {
10704
10945
  id,
10705
10946
  identity
10706
10947
  });
10707
- const spawnCommitted = args.journal.appendEvent(args.root, {
10948
+ const profileRef = contentAddress(spec.profile);
10949
+ const spawnCommitted = args.blobs.put(profileRef, spec.profile).then(() => args.journal.appendEvent(args.root, {
10708
10950
  kind: "spawned",
10709
10951
  id,
10710
10952
  parent: args.parentId,
@@ -10715,9 +10957,10 @@ function createScope(args) {
10715
10957
  runtime: executor.runtime,
10716
10958
  ...ownedTreeRoot === void 0 ? {} : { ownedTreeRoot },
10717
10959
  ...identity ? { identity } : {},
10960
+ profileRef,
10718
10961
  seq: ordinal,
10719
10962
  at: new Date(now()).toISOString()
10720
- }).then(async () => {
10963
+ })).then(async () => {
10721
10964
  if (args.workerTraceUnpropagated === void 0 || workerTrace === void 0) return;
10722
10965
  await args.journal.appendEvent(args.root, {
10723
10966
  kind: "trace-unpropagated",
@@ -10850,7 +11093,9 @@ function createScope(args) {
10850
11093
  runtime: executor.runtime,
10851
11094
  ...identity ? { identity } : {},
10852
11095
  budget: opts.budget,
10853
- depth: args.depth
11096
+ depth: args.depth,
11097
+ attemptId,
11098
+ startedAt
10854
11099
  }
10855
11100
  }, { signal: args.signal });
10856
11101
  live.settled = runChild(live, executor, controller, task, opts, args.pool, reservation.ticket, args.blobs, now, materializationCommitted, {
@@ -10873,7 +11118,7 @@ function createScope(args) {
10873
11118
  permit.release();
10874
11119
  clearChildDeadline?.();
10875
11120
  if (cascadeAbort) args.signal.removeEventListener("abort", cascadeAbort);
10876
- args.pool.reconcile(reservation.ticket, zeroSpend$1());
11121
+ args.pool.reconcile(reservation.ticket, zeroSpend());
10877
11122
  throw err;
10878
11123
  }
10879
11124
  }
@@ -10967,12 +11212,13 @@ function createScope(args) {
10967
11212
  id,
10968
11213
  status: "waiting",
10969
11214
  runtime: "wait",
11215
+ abortChild: (reason) => waitAbort.abort(reason),
10970
11216
  budget: {
10971
11217
  maxIterations: 0,
10972
11218
  maxTokens: 0
10973
11219
  },
10974
11220
  label: opts.label,
10975
- spent: zeroSpend$1(),
11221
+ spent: zeroSpend(),
10976
11222
  settled: void 0,
10977
11223
  delivered: false,
10978
11224
  executorDone: false,
@@ -11045,7 +11291,7 @@ function createScope(args) {
11045
11291
  kind: "done",
11046
11292
  out: resolution.outcome,
11047
11293
  outRef,
11048
- spent: zeroSpend$1(),
11294
+ spent: zeroSpend(),
11049
11295
  trace: {
11050
11296
  status: "unavailable",
11051
11297
  reason: "not-an-executor"
@@ -11096,6 +11342,18 @@ function createScope(args) {
11096
11342
  ...child.spent.usdKnown === false ? { usdKnown: false } : {}
11097
11343
  }, fromExecutor, opts.now ?? now(), opts.stallAfterMs ?? 18e4);
11098
11344
  }
11345
+ async function cancel(nodeId, request) {
11346
+ const child = children.get(nodeId);
11347
+ if (!child) throw new ValidationError(`scope.cancel: unknown node ${JSON.stringify(nodeId)}`);
11348
+ if (child.requestCancel) return await child.requestCancel(request);
11349
+ child.abortChild("cancelled");
11350
+ return {
11351
+ status: "unknown",
11352
+ effect: "cancel_requested",
11353
+ observedAt: (/* @__PURE__ */ new Date()).toISOString(),
11354
+ detail: `executor runtime ${JSON.stringify(child.runtime ?? "unknown")} exposes no cancellation operation; the child was aborted locally`
11355
+ };
11356
+ }
11099
11357
  function traceSource(nodeId) {
11100
11358
  const child = children.get(nodeId);
11101
11359
  if (!child) return void 0;
@@ -11105,6 +11363,21 @@ function createScope(args) {
11105
11363
  return;
11106
11364
  }
11107
11365
  }
11366
+ function interactive(nodeId) {
11367
+ const child = children.get(nodeId);
11368
+ if (!child) return noInteractiveSession("unknown-node");
11369
+ if (child.wait || child.executorDone || isTerminalNodeStatus(child.status)) return noInteractiveSession("not-live");
11370
+ if (!child.readInteractive) return noInteractiveSession("executor-exposes-no-interactive-session");
11371
+ let reported;
11372
+ try {
11373
+ reported = child.readInteractive();
11374
+ } catch {
11375
+ return noInteractiveSession("executor-exposes-no-interactive-session");
11376
+ }
11377
+ if (reported?.status === "unavailable" && reported.reason) return reported;
11378
+ if (reported?.status === "available" && reported.handle) return reported;
11379
+ return noInteractiveSession("executor-exposes-no-interactive-session");
11380
+ }
11108
11381
  async function meterInternal(spend, detail, providerModel, accountingOnly = false) {
11109
11382
  if (args.signal.aborted) throw new ValidationError("scope.meter: cannot record new driver work after scope abort");
11110
11383
  const seq = meterSeq++;
@@ -11152,6 +11425,8 @@ function createScope(args) {
11152
11425
  wait,
11153
11426
  progress,
11154
11427
  traceSource,
11428
+ interactive,
11429
+ cancel,
11155
11430
  signal: args.signal,
11156
11431
  meter: (spend, detail) => meterInternal(spend, detail),
11157
11432
  ...resume ? { resume } : {},
@@ -11164,7 +11439,13 @@ function createScope(args) {
11164
11439
  get workerCapacity() {
11165
11440
  return {
11166
11441
  live: liveWorkerCapacity.live,
11167
- freeSlots: freeSlots(liveWorkerCapacity.live, liveWorkerCapacity.max)
11442
+ freeSlots: freeSlots(liveWorkerCapacity.live, liveWorkerCapacity.max),
11443
+ unconfirmed: Object.freeze([...children.values()].filter((child) => isTerminalNodeStatus(child.status) && !child.cleanupConfirmed).map((child) => Object.freeze({
11444
+ id: child.id,
11445
+ label: child.label,
11446
+ runtime: child.runtime,
11447
+ status: child.status
11448
+ })))
11168
11449
  };
11169
11450
  }
11170
11451
  };
@@ -11404,7 +11685,9 @@ async function finalizeSettlement(child, settlement, seq, args, now) {
11404
11685
  status: "down",
11405
11686
  reason: settlement.reason,
11406
11687
  infra: settlement.infra,
11407
- spent: child.spent
11688
+ spent: child.spent,
11689
+ restartCount: settlement.restartCount,
11690
+ ...settledNodeEvidence(child, settlement, settledAt)
11408
11691
  }
11409
11692
  }, { signal: args.signal });
11410
11693
  return {
@@ -11457,7 +11740,8 @@ async function finalizeSettlement(child, settlement, seq, args, now) {
11457
11740
  outRef: settlement.outRef,
11458
11741
  score: settlement.verdict?.score,
11459
11742
  valid: settlement.verdict?.valid,
11460
- spent: settlement.spent
11743
+ spent: settlement.spent,
11744
+ ...settledNodeEvidence(child, settlement, settledAt)
11461
11745
  }
11462
11746
  }, { signal: args.signal });
11463
11747
  return {
@@ -11473,6 +11757,26 @@ async function finalizeSettlement(child, settlement, seq, args, now) {
11473
11757
  seq
11474
11758
  };
11475
11759
  }
11760
+ /**
11761
+ * The evidence a settled node carries beyond its status: the receipts that name what actually
11762
+ * ran, the own-inference spend the parent tree re-homes as a `metered` event, and the wall-clock
11763
+ * window. One builder feeds BOTH terminal paths, so an observer never sees a `down` node
11764
+ * described in different terms from a `done` one. Every field is omitted when the fact is
11765
+ * absent — an unreported receipt must not read as an empty one. Snapshots are detached because
11766
+ * an observer may serialize them after the live child has moved on.
11767
+ */
11768
+ function settledNodeEvidence(child, settlement, settledAt) {
11769
+ return {
11770
+ runtime: child.runtime,
11771
+ startedAt: child.startedAt,
11772
+ settledAt,
11773
+ ...settlement.metered ? { metered: detachedSnapshot(settlement.metered, "metered") } : {},
11774
+ ...child.providerModel ? { providerModel: detachedSnapshot(child.providerModel, "provider model evidence") } : {},
11775
+ ...child.materialization ? { materialization: detachedSnapshot(child.materialization, "materialization receipt") } : {},
11776
+ ...child.executionBindings.length > 0 ? { executionBindings: detachedSnapshot([...child.executionBindings], "execution binding receipts") } : {},
11777
+ trace: detachedSnapshot(settlement.trace, "worker trace evidence")
11778
+ };
11779
+ }
11476
11780
  /** Journal a wait-state's settlement as a `woken` event and project it onto the same `Settled`
11477
11781
  * the driver branches on. `by` names WHY it woke — `fired` / `timeout` / `cancelled` — which is
11478
11782
  * the fact a resumed reader needs and cannot recover from a payload it may never fetch. */
@@ -11784,30 +12088,20 @@ function freezeCorrelation(value) {
11784
12088
  * now reconciles its real partial spend instead of refunding work the provider already billed.
11785
12089
  */
11786
12090
  async function foldStream(stream, onProgress, signal) {
11787
- const tokens = zeroTokenUsage();
11788
- let tokensKnown = true;
11789
- let usd = 0;
11790
- let usdKnown = true;
11791
- let iterations = 0;
12091
+ const totals = newUsageTotals();
11792
12092
  const iterator = stream[Symbol.asyncIterator]();
11793
12093
  try {
11794
12094
  for (;;) {
11795
12095
  const next = signal ? await awaitAbortable(Promise.resolve(iterator.next()), signal) : await iterator.next();
11796
12096
  if (next.done) break;
11797
12097
  const ev = next.value;
11798
- if (ev.kind === "tokens") {
11799
- addTokenUsage(tokens, ev);
11800
- if (ev.tokensKnown === false) tokensKnown = false;
11801
- } else if (ev.kind === "cost") {
11802
- usd += ev.usd;
11803
- if (ev.usdKnown === false) usdKnown = false;
11804
- } else iterations += 1;
12098
+ meterUsageEvent(totals, ev);
11805
12099
  onProgress?.({
11806
- iterations,
11807
- tokens: cloneTokenUsage(tokens),
11808
- ...tokensKnown ? {} : { tokensKnown: false },
11809
- usd,
11810
- ...usdKnown ? {} : { usdKnown: false },
12100
+ iterations: totals.iterations,
12101
+ tokens: cloneTokenUsage(totals.tokens),
12102
+ ...totals.tokensKnown ? {} : { tokensKnown: false },
12103
+ usd: totals.usd,
12104
+ ...totals.usdKnown ? {} : { usdKnown: false },
11811
12105
  ms: 0
11812
12106
  });
11813
12107
  }
@@ -11815,14 +12109,7 @@ async function foldStream(stream, onProgress, signal) {
11815
12109
  Promise.resolve(iterator.return?.()).catch(() => void 0);
11816
12110
  throw error;
11817
12111
  }
11818
- return {
11819
- iterations,
11820
- tokens,
11821
- ...tokensKnown ? {} : { tokensKnown: false },
11822
- usd,
11823
- ...usdKnown ? {} : { usdKnown: false },
11824
- ms: 0
11825
- };
12112
+ return spendFromUsageTotals(totals);
11826
12113
  }
11827
12114
  /** Usage events carry measured increments; the terminal artifact carries whether a provider omitted
11828
12115
  * a whole accounting channel. Preserve those unknowns on the common streaming path. */
@@ -11883,13 +12170,12 @@ function downRecord(reason, infra, trace, metered, providerModel) {
11883
12170
  ...metered ? { metered } : {}
11884
12171
  };
11885
12172
  }
11886
- function zeroSpend$1() {
11887
- return {
11888
- iterations: 0,
11889
- tokens: zeroTokenUsage(),
11890
- usd: 0,
11891
- ms: 0
11892
- };
12173
+ /** The one place an absent interactive process is spelled, so every refusal reads the same. */
12174
+ function noInteractiveSession(reason) {
12175
+ return Object.freeze({
12176
+ status: "unavailable",
12177
+ reason
12178
+ });
11893
12179
  }
11894
12180
  function isAsyncIterable(value) {
11895
12181
  return typeof value === "object" && value !== null && typeof value[Symbol.asyncIterator] === "function";
@@ -12008,7 +12294,7 @@ const driverExecutorFactory = (rawSpec, ctx) => {
12008
12294
  meteredSpend = nonZeroOrUndef(sumMetered(events));
12009
12295
  accounting = {
12010
12296
  reported: childWork,
12011
- reservation: addSpend$1(childWork, meteredSpend ?? zeroSpend())
12297
+ reservation: addSpend(childWork, meteredSpend ?? zeroSpend())
12012
12298
  };
12013
12299
  const verdict = deriveDeliveryVerdict(settled, out);
12014
12300
  artifact = {
@@ -12092,64 +12378,13 @@ function isSettled(ev) {
12092
12378
  /** Sum the conserved spend over the nested tree's settled events — the honest per-channel
12093
12379
  * roll-up of the whole sub-tree's child WORK. */
12094
12380
  function sumSpend(settled) {
12095
- const total = {
12096
- iterations: 0,
12097
- tokens: zeroTokenUsage(),
12098
- usd: 0,
12099
- ms: 0
12100
- };
12101
- for (const ev of settled) {
12102
- total.iterations += ev.spent.iterations;
12103
- addTokenUsage(total.tokens, ev.spent.tokens);
12104
- if (ev.spent.tokensKnown === false) total.tokensKnown = false;
12105
- total.usd += ev.spent.usd;
12106
- if (ev.spent.usdKnown === false) total.usdKnown = false;
12107
- total.ms += ev.spent.ms;
12108
- }
12109
- return total;
12381
+ return settled.reduce((total, ev) => addSpend(total, ev.spent), zeroSpend());
12110
12382
  }
12111
12383
  /** Sum the nested tree's `metered` events — the sub-tree's whole driver INFERENCE (this driver's
12112
12384
  * own turns + any sub-driver inference already re-homed into this tree). Re-homed up to the parent
12113
12385
  * as one `metered` event; never reconciled (already pool-debited live via `observe`). */
12114
12386
  function sumMetered(events) {
12115
- const total = {
12116
- iterations: 0,
12117
- tokens: zeroTokenUsage(),
12118
- usd: 0,
12119
- ms: 0
12120
- };
12121
- for (const ev of events) {
12122
- if (ev.kind !== "metered") continue;
12123
- total.iterations += ev.spend.iterations;
12124
- addTokenUsage(total.tokens, ev.spend.tokens);
12125
- if (ev.spend.tokensKnown === false) total.tokensKnown = false;
12126
- total.usd += ev.spend.usd;
12127
- if (ev.spend.usdKnown === false) total.usdKnown = false;
12128
- total.ms += ev.spend.ms;
12129
- }
12130
- return total;
12131
- }
12132
- function zeroSpend() {
12133
- return {
12134
- iterations: 0,
12135
- tokens: zeroTokenUsage(),
12136
- usd: 0,
12137
- ms: 0
12138
- };
12139
- }
12140
- function addSpend$1(a, b) {
12141
- return {
12142
- iterations: a.iterations + b.iterations,
12143
- tokens: (() => {
12144
- const tokens = cloneTokenUsage(a.tokens);
12145
- addTokenUsage(tokens, b.tokens);
12146
- return tokens;
12147
- })(),
12148
- ...a.tokensKnown === false || b.tokensKnown === false ? { tokensKnown: false } : {},
12149
- usd: a.usd + b.usd,
12150
- ...a.usdKnown === false || b.usdKnown === false ? { usdKnown: false } : {},
12151
- ms: a.ms + b.ms
12152
- };
12387
+ return events.reduce((total, ev) => ev.kind === "metered" ? addSpend(total, ev.spend) : total, zeroSpend());
12153
12388
  }
12154
12389
  /** An all-zero spend that carries an UNKNOWN marker counts as non-zero: a sub-driver whose turns
12155
12390
  * went unmeasured did real work, and dropping its `metered` event here would re-hide upstream the
@@ -12173,7 +12408,7 @@ async function safeRollup(journal, nestedRoot) {
12173
12408
  metered,
12174
12409
  accounting: {
12175
12410
  reported: childWork,
12176
- reservation: addSpend$1(childWork, metered ?? zeroSpend())
12411
+ reservation: addSpend(childWork, metered ?? zeroSpend())
12177
12412
  }
12178
12413
  };
12179
12414
  } catch {
@@ -12491,7 +12726,7 @@ function rootDeadline(root) {
12491
12726
  }
12492
12727
  /** Child reservations whose spawn was durable but whose terminal record never landed. */
12493
12728
  function uncertainSpawnBudgets(events) {
12494
- const terminal = new Set(events.filter((event) => event.kind === "settled" || event.kind === "cancelled" || event.kind === "woken").map((event) => event.id));
12729
+ const terminal = new Set(events.filter(closesCursorSlot).map((event) => event.id));
12495
12730
  return events.filter((event) => event.kind === "spawned" && event.parent !== void 0 && !terminal.has(event.id)).map((event) => event.budget);
12496
12731
  }
12497
12732
  /** Highest `seq` among events matching `pred`, or `-1` when none match (so a resumed scope's
@@ -12591,7 +12826,7 @@ function createSupervisor() {
12591
12826
  settled,
12592
12827
  view: materializeTreeView(prior),
12593
12828
  maxSpawnOrdinal: maxSeqOf(prior, (ev) => ev.kind === "spawned"),
12594
- maxCursorSeq: maxSeqOf(prior, (ev) => ev.kind === "settled" || ev.kind === "cancelled" || ev.kind === "woken"),
12829
+ maxCursorSeq: maxSeqOf(prior, closesCursorSlot),
12595
12830
  maxWaitOrdinal: maxSeqOf(prior, (ev) => ev.kind === "waiting"),
12596
12831
  waits: pendingWaits(prior),
12597
12832
  keys: keyedAssignments(prior, settled),
@@ -12686,6 +12921,8 @@ function createSupervisor() {
12686
12921
  ok: false,
12687
12922
  error: new RuntimeRunStateError("supervisor: root execution did not start")
12688
12923
  };
12924
+ let teardownUnconfirmed = [];
12925
+ let teardownSeq = 0;
12689
12926
  let executionAborted = controller.signal.aborted;
12690
12927
  let allChildrenDownAtSettle = false;
12691
12928
  let downCountAtSettle = 0;
@@ -12707,7 +12944,16 @@ function createSupervisor() {
12707
12944
  clearRootDeadline?.();
12708
12945
  const settleGraceMs = actOutcome.ok === false && !controller.signal.aborted ? boundedSettleGrace(opts.childSettleGraceMs, rootDeadlineAtMs, now) : 0;
12709
12946
  try {
12710
- await drainLiveChildren(openScope, controller, settleGraceMs);
12947
+ teardownUnconfirmed = await drainLiveChildren(openScope, controller, settleGraceMs);
12948
+ for (const node of teardownUnconfirmed) await opts.journal.appendEvent(opts.runId, {
12949
+ kind: "teardown-unconfirmed",
12950
+ id: node.id,
12951
+ label: node.label,
12952
+ runtime: node.runtime,
12953
+ status: node.status,
12954
+ seq: teardownSeq++,
12955
+ at: new Date(now()).toISOString()
12956
+ });
12711
12957
  } catch (error) {
12712
12958
  if (actOutcome?.ok !== false) actOutcome = {
12713
12959
  ok: false,
@@ -12741,6 +12987,7 @@ function createSupervisor() {
12741
12987
  tree,
12742
12988
  spentTotal,
12743
12989
  providerModel,
12990
+ ...teardownUnconfirmed.length > 0 ? { teardownUnconfirmed } : {},
12744
12991
  ...gaps.length > 0 ? { spendGaps: gaps } : {},
12745
12992
  ...isNonEmptySpend(driverInference) ? { spentBreakdown: {
12746
12993
  driverInference,
@@ -12759,6 +13006,7 @@ function createSupervisor() {
12759
13006
  downCount: breaker.downCount(),
12760
13007
  spentTotal,
12761
13008
  providerModel,
13009
+ ...teardownUnconfirmed.length > 0 ? { teardownUnconfirmed } : {},
12762
13010
  ...gaps.length > 0 ? { spendGaps: gaps } : {}
12763
13011
  };
12764
13012
  const lifecycle = classifyNoWinner(executionAborted, pool, opts, breaker, deadlineExceeded, allChildrenDownAtSettle, downCountAtSettle);
@@ -12903,10 +13151,7 @@ function wrapJournalForBreaker(journal, breaker) {
12903
13151
  */
12904
13152
  async function drainLiveChildren(scope, controller, settleGraceMs = 0) {
12905
13153
  const view = scope.view;
12906
- if (!(view.inFlight > 0 || view.waiting > 0)) {
12907
- if (scope.workerCapacity.live > 0) throw new RuntimeRunStateError(`supervisor: cleanup ended with ${scope.workerCapacity.live} executor resource(s) not confirmed destroyed`);
12908
- return;
12909
- }
13154
+ if (!(view.inFlight > 0 || view.waiting > 0)) return unconfirmedTeardowns(scope);
12910
13155
  let graceTimer;
12911
13156
  if (settleGraceMs > 0 && !controller.signal.aborted) {
12912
13157
  graceTimer = setTimeout(() => controller.abort("root driver failed; child settle grace expired"), settleGraceMs);
@@ -12918,7 +13163,26 @@ async function drainLiveChildren(scope, controller, settleGraceMs = 0) {
12918
13163
  if (graceTimer !== void 0) clearTimeout(graceTimer);
12919
13164
  }
12920
13165
  const after = scope.view;
12921
- if (after.inFlight > 0 || after.waiting > 0 || scope.workerCapacity.live > 0) throw new RuntimeRunStateError(`supervisor: cleanup ended with ${after.inFlight} running, ${after.waiting} waiting, and ${scope.workerCapacity.live} executor resource(s) not confirmed destroyed`);
13166
+ if (after.inFlight > 0 || after.waiting > 0) throw new RuntimeRunStateError(`supervisor: cleanup ended with ${after.inFlight} running, ${after.waiting} waiting, and ` + describeUnconfirmed(scope));
13167
+ return unconfirmedTeardowns(scope);
13168
+ }
13169
+ /**
13170
+ * The settled children whose executor teardown was never acknowledged.
13171
+ *
13172
+ * They still hold their capacity slot — the ledger stays poisoned, so replacement work can never
13173
+ * exceed the physical live count — but every one of them has already reached a terminal state and
13174
+ * journaled its work. That is evidence about an EXECUTOR, not a cause of run failure, so the
13175
+ * barrier NAMES them and lets the run reach its real terminal state. Live work after the drain is
13176
+ * a different fault and still fails loud.
13177
+ */
13178
+ function unconfirmedTeardowns(scope) {
13179
+ return scope.workerCapacity.unconfirmed;
13180
+ }
13181
+ /** The unconfirmed set as one error clause: the count plus the node ids behind it. One integer is
13182
+ * not actionable after a six-hour run. */
13183
+ function describeUnconfirmed(scope) {
13184
+ const named = scope.workerCapacity.unconfirmed.map((node) => `${node.id} (${node.label}, ${node.runtime}, ${node.status})`).join(", ");
13185
+ return `${scope.workerCapacity.live} executor resource(s) not confirmed destroyed${named.length > 0 ? `: ${named}` : ""}`;
12922
13186
  }
12923
13187
  /** The settle window a failed driver's children actually get: the caller's grace, never past the
12924
13188
  * run's own deadline. `0` (the default) keeps the historical immediate cascade. */
@@ -13002,7 +13266,7 @@ function spendGapsFromEvents(events) {
13002
13266
  const labels = /* @__PURE__ */ new Map();
13003
13267
  const terminal = /* @__PURE__ */ new Set();
13004
13268
  for (const ev of events) if (ev.kind === "spawned") labels.set(ev.id, ev.label);
13005
- else if (ev.kind === "settled" || ev.kind === "cancelled" || ev.kind === "woken") terminal.add(ev.id);
13269
+ else if (closesCursorSlot(ev)) terminal.add(ev.id);
13006
13270
  const gaps = /* @__PURE__ */ new Map();
13007
13271
  const record = (id, kind, channels) => {
13008
13272
  if (channels.length === 0) return;
@@ -13054,52 +13318,15 @@ function sumSpendFromEvents(events) {
13054
13318
  return totals;
13055
13319
  }
13056
13320
  function sumMeasuredSpendFromEvents(events) {
13057
- const childWork = {
13058
- iterations: 0,
13059
- tokens: zeroTokenUsage(),
13060
- usd: 0,
13061
- ms: 0
13062
- };
13063
- const driverInference = {
13064
- iterations: 0,
13065
- tokens: zeroTokenUsage(),
13066
- usd: 0,
13067
- ms: 0
13068
- };
13069
- for (const ev of events) if (ev.kind === "settled") accumulate(childWork, ev.spent);
13070
- else if (ev.kind === "metered") accumulate(driverInference, ev.spend);
13321
+ let childWork = zeroSpend();
13322
+ let driverInference = zeroSpend();
13323
+ for (const ev of events) if (ev.kind === "settled") childWork = addSpend(childWork, ev.spent);
13324
+ else if (ev.kind === "metered") driverInference = addSpend(driverInference, ev.spend);
13071
13325
  return {
13072
13326
  childWork,
13073
13327
  driverInference
13074
13328
  };
13075
13329
  }
13076
- /** Add `b` into `a` in place, per channel. */
13077
- function accumulate(a, b) {
13078
- a.iterations += b.iterations;
13079
- addTokenUsage(a.tokens, b.tokens);
13080
- if (b.tokensKnown === false) a.tokensKnown = false;
13081
- a.usd += b.usd;
13082
- if (b.usdKnown === false) a.usdKnown = false;
13083
- if (b.usdEstimated !== void 0) a.usdEstimated = (a.usdEstimated ?? 0) + b.usdEstimated;
13084
- a.ms += b.ms;
13085
- }
13086
- /** Sum two conserved-spend tallies per channel — the child-work journal sum + the drivers' own
13087
- * metered inference, so `spentTotal` is the true cost of the run. */
13088
- function addSpend(a, b) {
13089
- return {
13090
- iterations: a.iterations + b.iterations,
13091
- tokens: (() => {
13092
- const tokens = cloneTokenUsage(a.tokens);
13093
- addTokenUsage(tokens, b.tokens);
13094
- return tokens;
13095
- })(),
13096
- ...a.tokensKnown === false || b.tokensKnown === false ? { tokensKnown: false } : {},
13097
- usd: a.usd + b.usd,
13098
- ...a.usdKnown === false || b.usdKnown === false ? { usdKnown: false } : {},
13099
- ...usdEstimatedOf(a, b),
13100
- ms: a.ms + b.ms
13101
- };
13102
- }
13103
13330
  /** True when any driver metered inference this run (so the winner carries a `spentBreakdown`).
13104
13331
  * Checks every channel `addSpend` sums — including `ms` — so the gate stays consistent with the
13105
13332
  * total even though the coordination driver currently stamps `ms: 0`. */
@@ -13107,6 +13334,6 @@ function isNonEmptySpend(s) {
13107
13334
  return s.iterations > 0 || s.tokens.input > 0 || s.tokens.output > 0 || s.usd > 0 || s.ms > 0 || s.tokensKnown === false || s.usdKnown === false;
13108
13335
  }
13109
13336
  //#endregion
13110
- export { createInbox as $, AGENT_PROFILE_MATERIALIZATION_AXES as $t, createBudgetPool as A, exportEvalRuns as At, WORKER_TRACE_PROPAGATION as B, sanitizeKnowledgeReadinessReport as Bt, effectiveConcurrency as C, traceContextToEnv as Ct, DEFAULT_SUCCESSFUL_SHUTDOWN_MS as D, buildRuntimeEventOtelSpans as Dt, rollingDispatch as E, buildLoopSpanNodes as Et, cliWorktreeExecutor as F, padTraceId as Ft, DEFAULT_SANDBOX_STEERING_MAX_TURNS as G, createWorktree as Gt, workerTraceEnv as H, runSettledCommand as Ht, createExecutor as I, toOtelAttributes as It, decodeToolPart as J, LOCAL_HARNESSES as Jt, createSteerableSandboxSession as K, removeWorktree as Kt, createExecutorRegistry as L, createRuntimeEventCollector as Lt, bindReusableExecutorExecutionId as M, generateSpanId as Mt, bridgeStopSignalKey as N, loopEventToOtelSpan as Nt, teardownExecutor as O, createOpenInferenceFileExporter as Ot, captureReusableExecutorConfig as P, padSpanId as Pt, readWorkerProgress as Q, CodexExecutionDiagnosticError as Qt, snapshotExecutorConfig as R, createRuntimeStreamEventCollector as Rt, waitUntil as S, readTraceContextFromEnv as St, queueOf as T, buildLoopOtelSpans as Tt, workerTraceHeaders as U, runWorktreeHarness as Ut, readWorkerTraceContext as V, sanitizeRuntimeStreamEvent as Vt, workerTraceSeamKey as W, captureWorktreeDiff as Wt, DEFAULT_STALL_AFTER_MS as X, localHarnessExecutable as Xt, sandboxSessionTraceSource as Y, harnessSupportsReasoningEffort as Yt, createActivityLog as Z, parseCodexTokenUsage as Zt, createWaitProbes as _, runBrainLoop as _t, pickBestDelivered as a, promptControlProfileMaterialization as an, isPeerMailEnvelope as at, timerAt as b, createPropagatingTraceEmitter as bt, driverChild as c, promptResourceProfileMaterialization as cn, TERMINAL_DECISIONS as ct, deriveNodeExecutionIdentity as d, validateProfileMaterialization as dn, isTerminalDecision as dt, assertProfileMaterialization as en, AUTHORITY_MARKERS as et, meterRuntimeOwnedAccounting as f, worktreeCliProfileMaterialization as fn, runAgentRounds as ft, settledToIteration as g, routerBrain as gt, scopeOwnerExecutorNodeContext as h, acquireSandbox as ht, collectDelivered as i, profileMaterializationAxes$1 as in, createPeerMailbox as it, spendFromUsageEvents as j, flatOtelSpan as jt, assertValidBudget as k, createOtelExporter as kt, withDriverExecutor as l, renderProfileMaterializationIssues as ln, createSandboxForSpec as lt, recordScopeOwnerMaterialization as m, probeSandboxCapabilities as mt, createSupervisor as n, defineProfileMaterializationContract as nn, PEER_MAIL_WIRE_KEY as nt, runFinalizer as o, promptModelProfileMaterialization as on, peerMailTools as ot, meterRuntimeOwnedProviderAttempt as p, createSandboxLineage as pt, createPushTraceSource as q, DEFAULT_LOCAL_HARNESS as qt, bestDelivered as r, fullProfileMaterialization as rn, claimsAuthority as rt, runTree as s, promptOnlyProfileMaterialization as sn, peerMailVerbNames as st, createRootHandle as t, controlProfileMaterialization as tn, DEFAULT_PEER_MAIL_LIMITS as tt, createScope as u, sandboxActProfileMaterialization as un, defaultSelectWinner as ut, isWaitOutcome as v, canonicalObservedModel as vt, freeSlots as w, INTELLIGENCE_WIRE_VERSION as wt, validateWaitSpec as x, mergeTraceEnv as xt, pollFor as y, observedModelMatchesDeclared as yt, createWorktreeCliExecutor as z, sanitizeAgentRuntimeEvent as zt };
13337
+ export { DEFAULT_STALL_AFTER_MS as $, LOCAL_HARNESSES as $t, createBudgetPool as A, buildLoopOtelSpans as At, createExecutorRegistry as B, padTraceId as Bt, effectiveConcurrency as C, canonicalObservedModel as Ct, DEFAULT_SUCCESSFUL_SHUTDOWN_MS as D, readTraceContextFromEnv as Dt, rollingDispatch as E, mergeTraceEnv as Et, bridgeRuntimeAttachmentsKey as F, exportEvalRuns as Ft, workerTraceEnv as G, sanitizeKnowledgeReadinessReport as Gt, createWorktreeCliExecutor as H, createRuntimeEventCollector as Ht, bridgeStopSignalKey as I, flatOtelSpan as It, DEFAULT_SANDBOX_STEERING_MAX_TURNS as J, runWorktreeHarness as Jt, workerTraceHeaders as K, sanitizeRuntimeStreamEvent as Kt, captureReusableExecutorConfig as L, generateSpanId as Lt, bindReusableExecutorExecutionId as M, buildRuntimeEventOtelSpans as Mt, bridgeAdmissionRead as N, createOpenInferenceFileExporter as Nt, teardownExecutor as O, traceContextToEnv as Ot, bridgeModelRouteRefusal as P, createOtelExporter as Pt, sandboxSessionTraceSource as Q, DEFAULT_LOCAL_HARNESS as Qt, cliWorktreeExecutor as R, loopEventToOtelSpan as Rt, waitUntil as S, runBrainLoop as St, queueOf as T, createPropagatingTraceEmitter as Tt, WORKER_TRACE_PROPAGATION as U, createRuntimeStreamEventCollector as Ut, snapshotExecutorConfig as V, toOtelAttributes as Vt, readWorkerTraceContext as W, sanitizeAgentRuntimeEvent as Wt, createPushTraceSource as X, createWorktree as Xt, createSteerableSandboxSession as Y, captureWorktreeDiff as Yt, decodeToolPart as Z, removeWorktree as Zt, createWaitProbes as _, unsupportedProfileDimensions as _n, runAgentRounds as _t, pickBestDelivered as a, assertProfileMaterialization as an, PEER_MAIL_WIRE_KEY as at, timerAt as b, acquireSandbox as bt, driverChild as c, fullProfileMaterialization as cn, isPeerMailEnvelope as ct, deriveNodeExecutionIdentity as d, promptModelProfileMaterialization as dn, isLiveNodeStatus as dt, harnessSupportsReasoningEffort as en, createActivityLog as et, meterRuntimeOwnedAccounting as f, promptOnlyProfileMaterialization as fn, isTerminalNodeStatus as ft, settledToIteration as g, sandboxActProfileMaterialization as gn, isTerminalDecision as gt, scopeOwnerExecutorNodeContext as h, renderUnsupported as hn, defaultSelectWinner as ht, collectDelivered as i, AGENT_PROFILE_MATERIALIZATION_AXES as in, DEFAULT_PEER_MAIL_LIMITS as it, spendFromUsageEvents as j, buildLoopSpanNodes as jt, assertValidBudget as k, INTELLIGENCE_WIRE_VERSION as kt, withDriverExecutor as l, profileMaterializationAxes$1 as ln, peerMailTools as lt, recordScopeOwnerMaterialization as m, renderProfileMaterializationIssues as mn, createSandboxForSpec as mt, createSupervisor as n, parseCodexTokenUsage as nn, createInbox as nt, runFinalizer as o, controlProfileMaterialization as on, claimsAuthority as ot, meterRuntimeOwnedProviderAttempt as p, promptResourceProfileMaterialization as pn, TERMINAL_DECISIONS as pt, workerTraceSeamKey as q, runSettledCommand as qt, bestDelivered as r, CodexExecutionDiagnosticError as rn, AUTHORITY_MARKERS as rt, runTree as s, defineProfileMaterializationContract as sn, createPeerMailbox as st, createRootHandle as t, localHarnessExecutable as tn, readWorkerProgress as tt, createScope as u, promptControlProfileMaterialization as un, peerMailVerbNames as ut, isWaitOutcome as v, validateProfileMaterialization as vn, createSandboxLineage as vt, freeSlots as w, observedModelMatchesDeclared as wt, validateWaitSpec as x, routerBrain as xt, pollFor as y, worktreeCliProfileMaterialization as yn, probeSandboxCapabilities as yt, createExecutor as z, padSpanId as zt };
13111
13338
 
13112
- //# sourceMappingURL=supervisor-s8SfZYbW.js.map
13339
+ //# sourceMappingURL=supervisor-CMZsJ7Wn.js.map