@tangle-network/agent-runtime 0.142.3 → 0.153.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/README.md +32 -0
  2. package/dist/{activation-o7JKmtxi.js → activation-DKxQsHiO.js} +3 -3
  3. package/dist/{activation-o7JKmtxi.js.map → activation-DKxQsHiO.js.map} +1 -1
  4. package/dist/agent.d.ts +2 -2
  5. package/dist/agent.js +3 -3
  6. package/dist/{analyst-loop-GcX0BY75.js → analyst-loop-B2kTHKNh.js} +2 -2
  7. package/dist/{analyst-loop-GcX0BY75.js.map → analyst-loop-B2kTHKNh.js.map} +1 -1
  8. package/dist/analyst-loop.d.ts +1 -1
  9. package/dist/analyst-loop.js +1 -1
  10. package/dist/{authoring-Bm1WlGPv.js → authoring-Tk2xFys0.js} +2 -2
  11. package/dist/{authoring-Bm1WlGPv.js.map → authoring-Tk2xFys0.js.map} +1 -1
  12. package/dist/candidate-execution/index.js +4 -4
  13. package/dist/{candidate-execution-CD5PoNmC.js → candidate-execution-CB9RJbbJ.js} +4 -4
  14. package/dist/{candidate-execution-CD5PoNmC.js.map → candidate-execution-CB9RJbbJ.js.map} +1 -1
  15. package/dist/{conversation-DXKJHyqB.js → conversation-D64WyWrK.js} +4 -4
  16. package/dist/{conversation-DXKJHyqB.js.map → conversation-D64WyWrK.js.map} +1 -1
  17. package/dist/conversation.d.ts +1 -1
  18. package/dist/conversation.js +1 -1
  19. package/dist/durable.d.ts +102 -4
  20. package/dist/durable.js +259 -10
  21. package/dist/durable.js.map +1 -1
  22. package/dist/{environment-provider-BicwCDK5.d.ts → environment-provider-DJG0yIYl.d.ts} +3 -3
  23. package/dist/{environment-provider-DCEACNt9.js → environment-provider-D_MXw3jK.js} +88 -9
  24. package/dist/environment-provider-D_MXw3jK.js.map +1 -0
  25. package/dist/environment-provider.d.ts +1 -1
  26. package/dist/environment-provider.js +1 -1
  27. package/dist/executable-spec-BUcUcEPk.js +73 -0
  28. package/dist/executable-spec-BUcUcEPk.js.map +1 -0
  29. package/dist/{graph-DhrLuLOS.js → graph-M0Qr4863.js} +4 -4
  30. package/dist/{graph-DhrLuLOS.js.map → graph-M0Qr4863.js.map} +1 -1
  31. package/dist/{improvement-cycle-lcwlR6E2.js → improvement-cycle-CDxlGQGE.js} +7 -7
  32. package/dist/{improvement-cycle-lcwlR6E2.js.map → improvement-cycle-CDxlGQGE.js.map} +1 -1
  33. package/dist/{index-Bx3-tqG-.d.ts → index-BihHgUAI.d.ts} +4 -4
  34. package/dist/{index-D_aH0F4C.d.ts → index-Dlz7ejRx.d.ts} +342 -521
  35. package/dist/{index-CV1xRWy2.d.ts → index-LQfgFJoX.d.ts} +3 -3
  36. package/dist/index.d.ts +9 -9
  37. package/dist/index.js +13 -13
  38. package/dist/intelligence.d.ts +5 -5
  39. package/dist/intelligence.js +6 -6
  40. package/dist/kernel.d.ts +7 -7
  41. package/dist/kernel.js +13 -13
  42. package/dist/{knowledge-C9LlSJAR.js → knowledge-DM-i40b9.js} +10 -7
  43. package/dist/{knowledge-C9LlSJAR.js.map → knowledge-DM-i40b9.js.map} +1 -1
  44. package/dist/knowledge.d.ts +1 -1
  45. package/dist/knowledge.js +1 -1
  46. package/dist/{loop-runner-bin-CctBy5-X.d.ts → loop-runner-bin-D-BW51yr.d.ts} +3 -3
  47. package/dist/{loop-runner-bin-DFo6Ss-1.js → loop-runner-bin-pD5WJuqJ.js} +4 -4
  48. package/dist/{loop-runner-bin-DFo6Ss-1.js.map → loop-runner-bin-pD5WJuqJ.js.map} +1 -1
  49. package/dist/loop-runner-bin.d.ts +1 -1
  50. package/dist/loop-runner-bin.js +1 -1
  51. package/dist/{materialization-CrdcfWXp.js → materialization-Bo6j3Hg9.js} +261 -24
  52. package/dist/materialization-Bo6j3Hg9.js.map +1 -0
  53. package/dist/mcp/bin.js +3 -3
  54. package/dist/mcp/index.d.ts +5 -5
  55. package/dist/mcp/index.js +6 -6
  56. package/dist/{model-policy-DgRJIJse.js → model-policy-Sw4ywhtL.js} +68 -6
  57. package/dist/model-policy-Sw4ywhtL.js.map +1 -0
  58. package/dist/{openai-tools-CSm460sC.js → openai-tools-CWBywy-e.js} +2 -2
  59. package/dist/{openai-tools-CSm460sC.js.map → openai-tools-CWBywy-e.js.map} +1 -1
  60. package/dist/{openai-tools-t5-6h5bj.d.ts → openai-tools-z-whdYNC.d.ts} +2 -2
  61. package/dist/{prepare-D3n7cA39.js → prepare-C3eFd3UA.js} +2 -2
  62. package/dist/{prepare-D3n7cA39.js.map → prepare-C3eFd3UA.js.map} +1 -1
  63. package/dist/primeintellect/index.d.ts +1 -1
  64. package/dist/profiles.d.ts +1 -1
  65. package/dist/profiles.js +1 -1
  66. package/dist/{protected-model-port-bq6bD9YX.js → protected-model-port-Dn2b6peS.js} +2 -2
  67. package/dist/{protected-model-port-bq6bD9YX.js.map → protected-model-port-Dn2b6peS.js.map} +1 -1
  68. package/dist/{redact-B0gDSTZO.d.ts → redact-NAptmqKw.d.ts} +3 -3
  69. package/dist/{researcher-CiSY6Wzb.js → researcher-BMFFPwKb.js} +2 -2
  70. package/dist/{researcher-CiSY6Wzb.js.map → researcher-BMFFPwKb.js.map} +1 -1
  71. package/dist/{run-layout-Be_Z0dF8.js → run-layout-C2jgwsCq.js} +111 -6
  72. package/dist/run-layout-C2jgwsCq.js.map +1 -0
  73. package/dist/{runtime-htqI3fKL.d.ts → runtime-B-5dp5Iz.d.ts} +223 -11
  74. package/dist/{runtime-DQs5xHdt.js → runtime-RY_rvv7t.js} +93 -84
  75. package/dist/runtime-RY_rvv7t.js.map +1 -0
  76. package/dist/{sandbox-events-BK-g19wx.js → sandbox-events-DMijDq2p.js} +53 -49
  77. package/dist/sandbox-events-DMijDq2p.js.map +1 -0
  78. package/dist/{spawn-journal-D2HKUImC.js → spawn-journal-CLguaA2A.js} +8 -43
  79. package/dist/spawn-journal-CLguaA2A.js.map +1 -0
  80. package/dist/{stream-agent-turn-Dfy12OjG.d.ts → stream-agent-turn-BGyszuPH.d.ts} +6 -3
  81. package/dist/{stream-agent-turn-BMHUIuQS.js → stream-agent-turn-D6HoaRPV.js} +140 -23
  82. package/dist/stream-agent-turn-D6HoaRPV.js.map +1 -0
  83. package/dist/{structural-rollout-CzZKDkmA.js → structural-rollout-P1YxFRfl.js} +11 -8
  84. package/dist/structural-rollout-P1YxFRfl.js.map +1 -0
  85. package/dist/{supervise-BEs5MB91.js → supervise-BezbzKiJ.js} +1550 -1186
  86. package/dist/supervise-BezbzKiJ.js.map +1 -0
  87. package/dist/{supervisor-B_0ISTFG.js → supervisor-DBVlPONC.js} +697 -230
  88. package/dist/supervisor-DBVlPONC.js.map +1 -0
  89. package/dist/testing.d.ts +2 -2
  90. package/dist/testing.js +12 -12
  91. package/dist/{top-app-BMOSKK06.js → top-app-tKo9OrON.js} +189 -86
  92. package/dist/top-app-tKo9OrON.js.map +1 -0
  93. package/dist/tui/bin.js +1 -1
  94. package/dist/tui/index.d.ts +32 -4
  95. package/dist/tui/index.js +1 -1
  96. package/dist/{types-_7w24mMg.d.ts → types-BPQhQRrC.d.ts} +508 -11
  97. package/dist/{types-DZrBoBpN.d.ts → types-DeX8ibLc.d.ts} +4 -1
  98. package/dist/{util-C1bv6yog.js → util-Bncw0o_F.js} +41 -2
  99. package/dist/util-Bncw0o_F.js.map +1 -0
  100. package/dist/{workspace-archive-C52LjkeN.js → workspace-archive-Dm73lTfB.js} +2 -2
  101. package/dist/{workspace-archive-C52LjkeN.js.map → workspace-archive-Dm73lTfB.js.map} +1 -1
  102. package/package.json +6 -6
  103. package/dist/environment-provider-DCEACNt9.js.map +0 -1
  104. package/dist/materialization-CrdcfWXp.js.map +0 -1
  105. package/dist/model-policy-DgRJIJse.js.map +0 -1
  106. package/dist/retained-run-binding-Dp2e8xne.js +0 -268
  107. package/dist/retained-run-binding-Dp2e8xne.js.map +0 -1
  108. package/dist/run-layout-Be_Z0dF8.js.map +0 -1
  109. package/dist/runtime-DQs5xHdt.js.map +0 -1
  110. package/dist/sandbox-events-BK-g19wx.js.map +0 -1
  111. package/dist/spawn-journal-D2HKUImC.js.map +0 -1
  112. package/dist/stream-agent-turn-BMHUIuQS.js.map +0 -1
  113. package/dist/structural-rollout-CzZKDkmA.js.map +0 -1
  114. package/dist/supervise-BEs5MB91.js.map +0 -1
  115. package/dist/supervisor-B_0ISTFG.js.map +0 -1
  116. package/dist/top-app-BMOSKK06.js.map +0 -1
  117. 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-Bo6j3Hg9.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 { a as extractLlmCallEvent, c as notifySandboxEventObserver, n as assertSandboxServedModel, t as assertSandboxEventSucceeded } from "./sandbox-events-BK-g19wx.js";
6
- import { a as concreteProfileModel, l as resolveRouterRetryPolicy, o as profileBridgeWireModel, s as profileModelExecutionSettings, t as assertExecutableAgentProfile, u as agentHarness } from "./model-policy-DgRJIJse.js";
7
- import { C as unknownExecutionBindingReceipt, 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-CrdcfWXp.js";
8
- import { i as resolveAgentEnvironmentProvider, n as providerAsExecutor, r as providerAsSandboxClient } from "./environment-provider-DCEACNt9.js";
4
+ 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-CLguaA2A.js";
5
+ import { _ as withTimeout, a as cloneTokenUsage, 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 zeroSpend, y as zeroTokenUsage } from "./util-Bncw0o_F.js";
6
+ import { c as sandboxEventServedBackend, i as extractLlmCallEvent, l as sandboxProgressEvents, o as mapSandboxToolEvent, r as createSandboxToolPartState, s as notifySandboxEventObserver, t as assertSandboxServedModel } from "./sandbox-events-DMijDq2p.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 { i as resolveAgentEnvironmentProvider, n as providerAsExecutor, r as providerAsSandboxClient } from "./environment-provider-D_MXw3jK.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";
@@ -17,11 +18,13 @@ import { appendFileSync, constants, createReadStream } from "node:fs";
17
18
  import { spawn } from "node:child_process";
18
19
  import { homedir, tmpdir } from "node:os";
19
20
  import { stripVTControlCharacters } from "node:util";
21
+ import { createAgentRunOutcomeTracker } from "@tangle-network/sandbox/runtime";
20
22
  import { request } from "node:http";
21
23
  import { request as request$1 } from "node:https";
22
24
  import { Readable } from "node:stream";
23
25
  import { deriveHexId, isW3CSpanId, isW3CTraceId } from "@tangle-network/agent-trace-contract";
24
26
  import { SDKError, generateIdempotencyKey, withRetry } from "@tangle-network/agent-core";
27
+ import { collectAgentFinalMessageText, collectAgentResponseText } from "@tangle-network/sandbox";
25
28
  //#region src/agent/profile-materialization.ts
26
29
  const KNOWN_AXIS_SET = new Set(AGENT_PROFILE_MATERIALIZATION_AXES);
27
30
  /**
@@ -216,6 +219,43 @@ function assertProfileMaterialization(options) {
216
219
  if (issues.length === 0) return;
217
220
  throw new ValidationError(renderProfileMaterializationIssues(issues, options.context));
218
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
+ }
219
259
  /** Format profile-axis drop issues into a concise operator-facing error. */
220
260
  function renderProfileMaterializationIssues(issues, context) {
221
261
  if (issues.length === 0) return "";
@@ -1801,8 +1841,7 @@ function prepareWorktreeProfile(profile, harness) {
1801
1841
  const workspaceProfile = materializationOnlyProfile(profile);
1802
1842
  assertSupportedWorktreeProfile(profile, harness);
1803
1843
  assertSafeProfileResourcePaths(profile);
1804
- const plan = materializeProfile(workspaceProfile, harness);
1805
- 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");
1806
1845
  assertSafeMaterializedPaths(plan);
1807
1846
  return {
1808
1847
  plan,
@@ -3326,12 +3365,14 @@ async function routerChatWithUsage(cfg, messages, opts) {
3326
3365
  const headers = routerRequestHeaders(cfg, opts);
3327
3366
  const temperature = opts?.temperature;
3328
3367
  const maxTokens = opts?.maxTokens ?? cfg.maxTokens;
3368
+ const maxCompletionTokens = opts?.maxCompletionTokens ?? cfg.maxCompletionTokens;
3329
3369
  const body = () => ({
3330
3370
  ...providerRequestExtras(opts?.extraBody, [
3331
3371
  "model",
3332
3372
  "messages",
3333
3373
  "temperature",
3334
3374
  "max_tokens",
3375
+ "max_completion_tokens",
3335
3376
  "seed",
3336
3377
  "reasoning_effort",
3337
3378
  "stream",
@@ -3341,6 +3382,7 @@ async function routerChatWithUsage(cfg, messages, opts) {
3341
3382
  messages,
3342
3383
  ...temperature !== void 0 ? { temperature } : {},
3343
3384
  ...maxTokens !== void 0 ? { max_tokens: maxTokens } : {},
3385
+ ...maxCompletionTokens !== void 0 ? { max_completion_tokens: maxCompletionTokens } : {},
3344
3386
  ...opts?.seed !== void 0 ? { seed: opts.seed } : {},
3345
3387
  ...opts?.reasoningEffort ? { reasoning_effort: opts.reasoningEffort } : {}
3346
3388
  });
@@ -3455,6 +3497,7 @@ async function routerChatWithTools(cfg, messages, tools, opts) {
3455
3497
  /** The OpenAI-shape request body both tool-calling transports send. One builder so the streamed
3456
3498
  * turn cannot drift from the buffered one on model, temperature, tool_choice, or the ceiling. */
3457
3499
  function toolCompletionBody(cfg, messages, tools, opts) {
3500
+ const maxCompletionTokens = opts?.maxCompletionTokens ?? cfg.maxCompletionTokens;
3458
3501
  return {
3459
3502
  ...providerRequestExtras(opts?.extraBody, [
3460
3503
  "model",
@@ -3463,6 +3506,7 @@ function toolCompletionBody(cfg, messages, tools, opts) {
3463
3506
  "tool_choice",
3464
3507
  "temperature",
3465
3508
  "max_tokens",
3509
+ "max_completion_tokens",
3466
3510
  "seed",
3467
3511
  "reasoning_effort",
3468
3512
  "stream",
@@ -3476,6 +3520,7 @@ function toolCompletionBody(cfg, messages, tools, opts) {
3476
3520
  } : {},
3477
3521
  ...opts?.temperature !== void 0 ? { temperature: opts.temperature } : {},
3478
3522
  ...opts?.maxTokens ? { max_tokens: opts.maxTokens } : {},
3523
+ ...maxCompletionTokens !== void 0 ? { max_completion_tokens: maxCompletionTokens } : {},
3479
3524
  ...opts?.seed !== void 0 ? { seed: opts.seed } : {},
3480
3525
  ...opts?.reasoningEffort ? { reasoning_effort: opts.reasoningEffort } : {}
3481
3526
  };
@@ -3936,7 +3981,7 @@ async function acquireSandbox(client, options, acquire = {}) {
3936
3981
  while (now() < deadline) {
3937
3982
  throwIfAborted(acquire.signal);
3938
3983
  try {
3939
- return await waitReadyOrDestroy(await client.create(createOpts), deadline, pollMs, acquire.signal, now, sleep$1);
3984
+ return await waitReadyOrDestroy(await client.create(createOpts, acquire.signal === void 0 ? void 0 : { signal: acquire.signal }), deadline, pollMs, acquire.signal, now, sleep$1);
3940
3985
  } catch (err) {
3941
3986
  throwIfAborted(acquire.signal);
3942
3987
  if (!isRetryable(err)) throw err;
@@ -4117,14 +4162,34 @@ async function* pollPromptEvents(box, prompt, sessionId, signal, promptOptions)
4117
4162
  })).sessionId;
4118
4163
  const result = await box.session(activeSessionId).result();
4119
4164
  if (signal.aborted) throwAbort();
4165
+ const resultData = {
4166
+ finalText: result.response ?? "",
4167
+ success: result.success,
4168
+ ...result.status ? { status: result.status } : {},
4169
+ ...result.error ? { error: result.error } : {},
4170
+ ...result.errorCode ? { errorCode: result.errorCode } : {},
4171
+ ...result.toolInvocations ? { toolInvocations: result.toolInvocations } : {},
4172
+ ...result.approval ? { approval: result.approval } : {},
4173
+ ...result.question ? { question: result.question } : {},
4174
+ ...result.interaction ? { interaction: result.interaction } : {},
4175
+ ...result.plan ? { plan: result.plan } : {},
4176
+ ...result.usage ? { usage: result.usage } : {},
4177
+ ...result.costUsd !== void 0 ? { costUsd: result.costUsd } : {}
4178
+ };
4120
4179
  yield {
4121
4180
  type: "result",
4122
4181
  id: activeSessionId,
4182
+ data: resultData
4183
+ };
4184
+ yield {
4185
+ type: "done",
4186
+ id: activeSessionId,
4123
4187
  data: {
4124
- finalText: result.response ?? "",
4125
- success: result.success,
4126
- ...result.error ? { error: result.error } : {},
4127
- ...result.usage ? { usage: result.usage } : {}
4188
+ ...resultData,
4189
+ outcome: result.status === "awaiting_plan_decision" && result.plan ? {
4190
+ type: "awaiting_plan_decision",
4191
+ plan: result.plan
4192
+ } : { type: "completed" }
4128
4193
  }
4129
4194
  };
4130
4195
  }
@@ -4702,14 +4767,14 @@ async function executeIteration(args) {
4702
4767
  ...requestedModel !== void 0 ? { model: requestedModel } : {}
4703
4768
  };
4704
4769
  let sawLlmCall = false;
4770
+ const outcomeTracker = createAgentRunOutcomeTracker();
4705
4771
  for await (const event of stream) {
4706
4772
  events.push(event);
4773
+ outcomeTracker.observe(event);
4707
4774
  notifySandboxEventObserver(event, args.ctx.onSandboxEvent, {
4708
4775
  iterationIndex: args.item.index,
4709
4776
  agentRunName: slot.agentRunName
4710
4777
  });
4711
- assertSandboxEventSucceeded(event);
4712
- assertSandboxServedModel(event, requested);
4713
4778
  const llmCall = extractLlmCallEvent(event, slot.agentRunName);
4714
4779
  if (llmCall) {
4715
4780
  sawLlmCall = true;
@@ -4728,18 +4793,24 @@ async function executeIteration(args) {
4728
4793
  });
4729
4794
  args.ctx.runHandle?.observe(llmCall);
4730
4795
  }
4796
+ assertSandboxServedModel(event, requested);
4731
4797
  }
4798
+ const outcome = outcomeTracker.finish();
4799
+ slot.sandboxOutcome = outcome;
4732
4800
  if (!sawLlmCall) {
4733
4801
  slot.tokenUsage.tokensKnown = false;
4734
4802
  slot.costUsdKnown = false;
4735
4803
  }
4736
4804
  slot.output = args.output.parse(events);
4737
- if (args.validator) slot.verdict = await args.validator.validate(slot.output, {
4805
+ const projection = projectSandboxOutcome(outcome);
4806
+ if (projection.status === "failed") throw new Error(projection.reason);
4807
+ if (projection.status === "completed" && args.validator) slot.verdict = await args.validator.validate(slot.output, {
4738
4808
  iteration: args.item.index,
4739
4809
  ...box ? { box } : {},
4740
4810
  signal: args.signal,
4741
4811
  traceEmitter: args.ctx.traceEmitter
4742
4812
  });
4813
+ else if (projection.status !== "completed") slot.verdict = projection.verdict;
4743
4814
  } catch (err) {
4744
4815
  slot.error = err instanceof Error ? err : new Error(String(err));
4745
4816
  } finally {
@@ -5110,6 +5181,59 @@ function hashJson(value) {
5110
5181
  return (h >>> 0).toString(16).padStart(8, "0");
5111
5182
  }
5112
5183
  //#endregion
5184
+ //#region src/runtime/sandbox-executor-output.ts
5185
+ /** Project the complete Sandbox event stream into the standard executor result shape. */
5186
+ function sandboxLeafOutputFromEvents(events) {
5187
+ const content = collectAgentFinalMessageText(events) ?? collectAgentResponseText(events);
5188
+ const toolCalls = sandboxToolCalls(events);
5189
+ const servedBackend = lastServedBackend(events);
5190
+ return {
5191
+ events,
5192
+ content,
5193
+ output: sandboxOutputMarker(content, events.some(carriesText)),
5194
+ ...servedBackend === void 0 ? {} : { servedBackend },
5195
+ ...toolCalls.length === 0 ? {} : { toolCalls }
5196
+ };
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
+ }
5228
+ function sandboxToolCalls(events) {
5229
+ const state = createSandboxToolPartState();
5230
+ return events.flatMap((event) => mapSandboxToolEvent(event, state).flatMap((projected) => projected.type === "tool_call" ? [{
5231
+ ...projected.toolCallId === void 0 ? {} : { id: projected.toolCallId },
5232
+ name: projected.toolName,
5233
+ arguments: projected.args ?? {}
5234
+ }] : []));
5235
+ }
5236
+ //#endregion
5113
5237
  //#region src/runtime/supervise/cost-estimate.ts
5114
5238
  /**
5115
5239
  * Pricing for work that arrived without a provider receipt.
@@ -5132,7 +5256,8 @@ function priceUnreceiptedWork(work) {
5132
5256
  const unknown = {
5133
5257
  kind: "cost",
5134
5258
  usd: 0,
5135
- usdKnown: false
5259
+ usdKnown: false,
5260
+ provenance: "uncaptured"
5136
5261
  };
5137
5262
  const { inputTokens, outputTokens, model } = work;
5138
5263
  if (model === void 0 || !isModelPriced(model)) return unknown;
@@ -5144,7 +5269,8 @@ function priceUnreceiptedWork(work) {
5144
5269
  kind: "cost",
5145
5270
  usd,
5146
5271
  usdKnown: false,
5147
- usdEstimated: usd
5272
+ usdEstimated: usd,
5273
+ provenance: "catalog-estimate"
5148
5274
  };
5149
5275
  }
5150
5276
  //#endregion
@@ -5867,12 +5993,21 @@ function createSteerableSandboxSession(args) {
5867
5993
  });
5868
5994
  const state = {
5869
5995
  turns: 0,
5870
- lastText: "",
5996
+ /** `undefined` until a text-bearing terminal event is observed; never seeded with `''`. */
5997
+ lastText: void 0,
5998
+ servedBackend: void 0,
5871
5999
  seenToolCalls: /* @__PURE__ */ new Set(),
6000
+ toolCalls: [],
5872
6001
  artifact: void 0,
6002
+ latestOutcome: void 0,
6003
+ /** Reads the live lineage handle once a box and session exist, for exact cancellation. */
6004
+ session: void 0,
5873
6005
  teardown: void 0,
5874
6006
  note: "starting"
5875
6007
  };
6008
+ const toolParts = createSandboxToolPartState();
6009
+ /** Record one box event for the trace and the activity window, and return the live output it
6010
+ * carries so the caller can publish it to the turn stream. */
5876
6011
  const recordEvent = (event) => {
5877
6012
  const at = now();
5878
6013
  const data = event.data;
@@ -5896,7 +6031,19 @@ function createSteerableSandboxSession(args) {
5896
6031
  }
5897
6032
  }
5898
6033
  const text = readFinalText(event);
5899
- if (text) state.lastText = text;
6034
+ if (text !== void 0) state.lastText = text;
6035
+ const served = sandboxEventServedBackend(event);
6036
+ if (served !== void 0) state.servedBackend = served;
6037
+ const progress = sandboxProgressEvents(event, toolParts);
6038
+ for (const item of progress) {
6039
+ if (item.kind !== "tool_call") continue;
6040
+ state.toolCalls.push({
6041
+ ...item.toolCallId === void 0 ? {} : { id: item.toolCallId },
6042
+ name: item.toolName,
6043
+ arguments: item.args ?? {}
6044
+ });
6045
+ }
6046
+ return progress;
5900
6047
  };
5901
6048
  async function* stream(task, signal) {
5902
6049
  const capabilities = await probeSandboxCapabilities(args.sandboxClient);
@@ -5922,6 +6069,7 @@ function createSteerableSandboxSession(args) {
5922
6069
  let tokensKnown = true;
5923
6070
  let usd = 0;
5924
6071
  let handle;
6072
+ state.session = () => handle;
5925
6073
  let nextPrompt = args.taskToPrompt(task);
5926
6074
  try {
5927
6075
  for (let turn = 0; maxTurns === 0 || turn < maxTurns; turn += 1) {
@@ -5958,6 +6106,7 @@ function createSteerableSandboxSession(args) {
5958
6106
  };
5959
6107
  let events;
5960
6108
  let sawLlmCall = false;
6109
+ const outcomeTracker = createAgentRunOutcomeTracker();
5961
6110
  try {
5962
6111
  if (!handle) {
5963
6112
  const opened = await lineage.start(spec, prompt, turnController.signal, promptOptions);
@@ -5965,36 +6114,42 @@ function createSteerableSandboxSession(args) {
5965
6114
  events = opened.events;
5966
6115
  } else events = await lineage.continue(handle, prompt, turnController.signal, promptOptions);
5967
6116
  for await (const event of events) {
5968
- recordEvent(event);
5969
- assertSandboxEventSucceeded(event);
5970
- assertSandboxServedModel(event, requested);
6117
+ outcomeTracker.observe(event);
6118
+ for (const progress of recordEvent(event)) yield {
6119
+ kind: "progress",
6120
+ progress
6121
+ };
5971
6122
  const call = extractLlmCallEvent(event, spec.name ?? String(args.harness));
5972
- if (!call) continue;
5973
- sawLlmCall = true;
5974
- const callTokensKnown = call.tokensKnown !== false && typeof call.tokensIn === "number" && typeof call.tokensOut === "number";
5975
- if (!callTokensKnown) tokensKnown = false;
5976
- const input = call.tokensIn ?? 0;
5977
- const output = call.tokensOut ?? 0;
5978
- if (input || output || !callTokensKnown) {
5979
- const usage = {
5980
- kind: "tokens",
5981
- input,
5982
- output,
5983
- ...callTokensKnown ? {} : { tokensKnown: false },
5984
- ...promptCacheTokenClasses(call.tokensIn, call.promptCache)
5985
- };
5986
- addTokenUsage(tokens, usage);
5987
- yield usage;
5988
- }
5989
- if (typeof call.costUsd === "number" && call.costUsd > 0) {
5990
- usd += call.costUsd;
5991
- yield {
5992
- kind: "cost",
5993
- usd: call.costUsd,
5994
- usdKnown: false
5995
- };
6123
+ if (call) {
6124
+ sawLlmCall = true;
6125
+ const callTokensKnown = call.tokensKnown !== false && typeof call.tokensIn === "number" && typeof call.tokensOut === "number";
6126
+ if (!callTokensKnown) tokensKnown = false;
6127
+ const input = call.tokensIn ?? 0;
6128
+ const output = call.tokensOut ?? 0;
6129
+ if (input || output || !callTokensKnown) {
6130
+ const usage = {
6131
+ kind: "tokens",
6132
+ input,
6133
+ output,
6134
+ ...callTokensKnown ? {} : { tokensKnown: false },
6135
+ ...promptCacheTokenClasses(call.tokensIn, call.promptCache)
6136
+ };
6137
+ addTokenUsage(tokens, usage);
6138
+ yield usage;
6139
+ }
6140
+ if (typeof call.costUsd === "number" && call.costUsd > 0) {
6141
+ usd += call.costUsd;
6142
+ yield {
6143
+ kind: "cost",
6144
+ usd: call.costUsd,
6145
+ usdKnown: false,
6146
+ provenance: "uncaptured"
6147
+ };
6148
+ }
5996
6149
  }
6150
+ assertSandboxServedModel(event, requested);
5997
6151
  }
6152
+ state.latestOutcome = outcomeTracker.finish();
5998
6153
  } catch (e) {
5999
6154
  cleanup();
6000
6155
  if (isInterruptAbort(e, interruptSig, signal, args.controller.signal)) {
@@ -6035,7 +6190,8 @@ function createSteerableSandboxSession(args) {
6035
6190
  if (state.turns > 0) yield {
6036
6191
  kind: "cost",
6037
6192
  usd: 0,
6038
- usdKnown: false
6193
+ usdKnown: false,
6194
+ provenance: "uncaptured"
6039
6195
  };
6040
6196
  const spent = {
6041
6197
  iterations: state.turns,
@@ -6047,20 +6203,79 @@ function createSteerableSandboxSession(args) {
6047
6203
  };
6048
6204
  const out = {
6049
6205
  content: state.lastText,
6206
+ output: sandboxOutputMarker(state.lastText),
6207
+ ...state.servedBackend === void 0 ? {} : { servedBackend: state.servedBackend },
6050
6208
  turns: state.turns,
6051
- toolCalls: activity.read().filter((n) => n.kind === "tool").map((n) => n.label)
6209
+ toolCalls: state.toolCalls,
6210
+ ...state.latestOutcome ? { outcome: state.latestOutcome } : {}
6052
6211
  };
6212
+ const verdict = state.latestOutcome ? projectSandboxOutcome(state.latestOutcome).verdict : void 0;
6053
6213
  state.artifact = {
6054
6214
  outRef: args.contentRef("sandbox-steerable", {
6055
6215
  harness: args.harness,
6056
6216
  out
6057
6217
  }),
6058
6218
  out,
6219
+ ...verdict ? { verdict } : {},
6059
6220
  spent
6060
6221
  };
6061
6222
  }
6062
6223
  return {
6063
6224
  stream,
6225
+ async cancel(request) {
6226
+ const live = state.session?.();
6227
+ const observedAt = () => (/* @__PURE__ */ new Date()).toISOString();
6228
+ if (!live) return {
6229
+ status: "unknown",
6230
+ effect: "cancel_requested",
6231
+ observedAt: observedAt(),
6232
+ detail: "no box session exists yet for this worker; nothing remote could be asked"
6233
+ };
6234
+ const session = live.box.session?.(live.sessionId);
6235
+ if (!session || typeof session.interrupt !== "function") return {
6236
+ status: "unknown",
6237
+ effect: "cancel_requested",
6238
+ observedAt: observedAt(),
6239
+ detail: "the sandbox client exposes no session interrupt operation",
6240
+ evidence: { sessionId: live.sessionId }
6241
+ };
6242
+ try {
6243
+ const result = await session.interrupt();
6244
+ const evidence = {
6245
+ sessionId: live.sessionId,
6246
+ operationId: request.operationId,
6247
+ result
6248
+ };
6249
+ if (result?.cancelled === true) {
6250
+ args.controller.abort("executor cancelled");
6251
+ return {
6252
+ status: "accepted",
6253
+ effect: "cancelled",
6254
+ observedAt: observedAt(),
6255
+ detail: "the box reported the running execution cancelled",
6256
+ evidence
6257
+ };
6258
+ }
6259
+ return {
6260
+ status: "already-terminal",
6261
+ effect: "not_live",
6262
+ observedAt: observedAt(),
6263
+ detail: "the box reported no running execution on this session",
6264
+ evidence
6265
+ };
6266
+ } catch (error) {
6267
+ return {
6268
+ status: "unknown",
6269
+ effect: "cancel_requested",
6270
+ observedAt: observedAt(),
6271
+ detail: `the box interrupt failed: ${error instanceof Error ? error.message : String(error)}`,
6272
+ evidence: {
6273
+ sessionId: live.sessionId,
6274
+ operationId: request.operationId
6275
+ }
6276
+ };
6277
+ }
6278
+ },
6064
6279
  progress: () => ({
6065
6280
  turns: state.turns,
6066
6281
  pendingMessages: args.inbox.pending(),
@@ -6078,14 +6293,16 @@ function createSteerableSandboxSession(args) {
6078
6293
  function isInterruptAbort(err, interrupt, external, owned) {
6079
6294
  return (err instanceof DOMException && err.name === "AbortError" || typeof err === "object" && err !== null && err.name === "AbortError") && interrupt.aborted && !external.aborted && !owned.aborted;
6080
6295
  }
6081
- /** The terminal text a sandbox `result` event carries, when it carries one. */
6296
+ /** The terminal text a sandbox `result` event carries, when it carries one. An observed empty
6297
+ * string is returned as `''`, because "the box answered nothing" is not "the box never
6298
+ * answered". */
6082
6299
  function readFinalText(event) {
6083
6300
  const data = event.data;
6084
6301
  if (!data || typeof data !== "object") return void 0;
6085
6302
  const text = data.finalText;
6086
- if (typeof text === "string" && text.length > 0) return text;
6303
+ if (typeof text === "string") return text;
6087
6304
  const alt = data.text;
6088
- return typeof alt === "string" && alt.length > 0 ? alt : void 0;
6305
+ return typeof alt === "string" ? alt : void 0;
6089
6306
  }
6090
6307
  /** Prompt options the composed loop context already carries (agent profile / cwd), forwarded so
6091
6308
  * a steerable worker runs with the same box configuration as the single-shot path. */
@@ -6493,6 +6710,11 @@ const bridgeSeamKey = "bridge";
6493
6710
  /** Internal control seam used by Runtime-owned external supervisors. A completion request stops
6494
6711
  * the next bridge turn; it must not abort the paid request that is already streaming. */
6495
6712
  const bridgeStopSignalKey = "__bridge_stop_signal";
6713
+ /** Internal attachment seam used by Runtime-owned external supervisors. The named MCP servers ride
6714
+ * beside the AgentProfile as `runtime_attachments`, so the bridge mounts them for the run and keeps
6715
+ * them out of its session profile binding. A rebound coordination port therefore cannot move the
6716
+ * authored profile digest that binds a durable session. */
6717
+ const bridgeRuntimeAttachmentsKey = "__bridge_runtime_attachments";
6496
6718
  const maxBridgeTimeoutMs = 2147483647;
6497
6719
  const bridgeModelCredentialHeader = "x-cli-bridge-model-credential";
6498
6720
  const bridgeModelBaseUrlHeader = "x-cli-bridge-model-base-url";
@@ -6631,6 +6853,19 @@ function unmeteredSpend(ms) {
6631
6853
  * failures (429/5xx/Cloudflare-origin) retry with backoff before the executor
6632
6854
  * fails the task.
6633
6855
  */
6856
+ /**
6857
+ * The honest answer for a backend with no cancel operation: the local request stopped, and
6858
+ * nothing about the remote run is known. Never `accepted` — a client that advertises provider
6859
+ * cancellation from this would claim more than Runtime observed.
6860
+ */
6861
+ function localAbortCancellation(detail) {
6862
+ return {
6863
+ status: "unknown",
6864
+ effect: "cancel_requested",
6865
+ observedAt: (/* @__PURE__ */ new Date()).toISOString(),
6866
+ detail
6867
+ };
6868
+ }
6634
6869
  const routerInlineExecutor = (spec, ctx) => {
6635
6870
  const seam = readSeam(ctx, routerSeamKey, "router/inline");
6636
6871
  const model = exactRouterModel(spec.profile, "routerInlineExecutor");
@@ -6668,7 +6903,7 @@ const routerInlineExecutor = (spec, ctx) => {
6668
6903
  ...profileExecution.temperature !== void 0 ? { temperature: profileExecution.temperature } : {},
6669
6904
  ...linked ? { signal: linked } : {},
6670
6905
  ...profileExecution.toolChoice ? { toolChoice: profileExecution.toolChoice } : {},
6671
- ...profileExecution.maxTokens !== void 0 ? { maxTokens: profileExecution.maxTokens } : {},
6906
+ ...profileExecution.tokenLimits.applied,
6672
6907
  ...profileExecution.seed !== void 0 ? { seed: profileExecution.seed } : {},
6673
6908
  ...Object.keys(extraBody).length > 0 ? { extraBody } : {},
6674
6909
  ...requestIdentity
@@ -6681,7 +6916,7 @@ const routerInlineExecutor = (spec, ctx) => {
6681
6916
  }, messages, {
6682
6917
  ...profileExecution.temperature !== void 0 ? { temperature: profileExecution.temperature } : {},
6683
6918
  ...linked ? { signal: linked } : {},
6684
- ...profileExecution.maxTokens !== void 0 ? { maxTokens: profileExecution.maxTokens } : {},
6919
+ ...profileExecution.tokenLimits.applied,
6685
6920
  ...profileExecution.seed !== void 0 ? { seed: profileExecution.seed } : {},
6686
6921
  ...profileExecution.reasoningEffort ? { reasoningEffort: profileExecution.reasoningEffort } : {},
6687
6922
  ...profileExecution.extraBody ? { extraBody: profileExecution.extraBody } : {},
@@ -6722,6 +6957,10 @@ const routerInlineExecutor = (spec, ctx) => {
6722
6957
  };
6723
6958
  return artifact;
6724
6959
  },
6960
+ cancel(_request) {
6961
+ controller.abort("executor cancelled");
6962
+ 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"));
6963
+ },
6725
6964
  teardown(_grace) {
6726
6965
  controller.abort("executor torn down");
6727
6966
  return Promise.resolve({ destroyed: true });
@@ -6750,7 +6989,7 @@ const routerInlineExecutor = (spec, ctx) => {
6750
6989
  model,
6751
6990
  provider: spec.profile.model?.provider ?? null,
6752
6991
  temperature: profileExecution.temperature ?? null,
6753
- maxTokens: profileExecution.maxTokens ?? null,
6992
+ tokenLimits: profileExecution.tokenLimits,
6754
6993
  retry: profileExecution.retry ?? null,
6755
6994
  seed: profileExecution.seed ?? null,
6756
6995
  reasoningEffort: profileExecution.reasoningEffort ?? null,
@@ -6862,6 +7101,7 @@ const routerToolsInlineExecutor = (spec, ctx) => {
6862
7101
  let reasoningKnown = true;
6863
7102
  const promptCache = {};
6864
7103
  let lastText = "";
7104
+ const executedToolCalls = [];
6865
7105
  const flush = () => {
6866
7106
  const pending = inbox.drain();
6867
7107
  if (pending.length) messages.push({
@@ -6894,7 +7134,7 @@ const routerToolsInlineExecutor = (spec, ctx) => {
6894
7134
  ...profileExecution.temperature !== void 0 ? { temperature: profileExecution.temperature } : {},
6895
7135
  signal: turnController.signal,
6896
7136
  ...profileExecution.toolChoice ? { toolChoice: profileExecution.toolChoice } : {},
6897
- ...profileExecution.maxTokens !== void 0 ? { maxTokens: profileExecution.maxTokens } : {},
7137
+ ...profileExecution.tokenLimits.applied,
6898
7138
  ...profileExecution.seed !== void 0 ? { seed: profileExecution.seed } : {},
6899
7139
  ...profileExecution.reasoningEffort ? { reasoningEffort: profileExecution.reasoningEffort } : {},
6900
7140
  ...profileExecution.extraBody ? { extraBody: profileExecution.extraBody } : {},
@@ -6960,6 +7200,11 @@ const routerToolsInlineExecutor = (spec, ctx) => {
6960
7200
  const tc = toolCalls[i];
6961
7201
  const id = tc?.id ?? `call_${i}`;
6962
7202
  const toolName = tc?.name ?? "";
7203
+ executedToolCalls.push({
7204
+ id,
7205
+ name: toolName,
7206
+ arguments: tc?.arguments ?? ""
7207
+ });
6963
7208
  if (!enabledToolNames.has(toolName)) {
6964
7209
  messages.push({
6965
7210
  role: "tool",
@@ -7030,7 +7275,7 @@ const routerToolsInlineExecutor = (spec, ctx) => {
7030
7275
  ...observedModel !== void 0 ? { model: observedModel } : {},
7031
7276
  messages,
7032
7277
  turns,
7033
- toolCalls: messages.filter((message) => message.role === "tool").length,
7278
+ toolCalls: executedToolCalls,
7034
7279
  transportAttempts,
7035
7280
  ...estimatedUsd !== void 0 ? { estimatedCostUsd: estimatedUsd } : {},
7036
7281
  ...Object.keys(promptCache).length > 0 ? { promptCache } : {},
@@ -7046,6 +7291,10 @@ const routerToolsInlineExecutor = (spec, ctx) => {
7046
7291
  };
7047
7292
  return artifact;
7048
7293
  },
7294
+ cancel(_request) {
7295
+ controller.abort("executor cancelled");
7296
+ 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"));
7297
+ },
7049
7298
  teardown(_grace) {
7050
7299
  controller.abort("executor torn down");
7051
7300
  return Promise.resolve({ destroyed: true });
@@ -7076,7 +7325,7 @@ const routerToolsInlineExecutor = (spec, ctx) => {
7076
7325
  maxTurns,
7077
7326
  tools: seam.tools,
7078
7327
  temperature: profileExecution.temperature ?? null,
7079
- maxTokens: profileExecution.maxTokens ?? null,
7328
+ tokenLimits: profileExecution.tokenLimits,
7080
7329
  retry: profileExecution.retry ?? null,
7081
7330
  toolChoice: profileExecution.toolChoice ?? null,
7082
7331
  extraBody: profileExecution.extraBody ?? null,
@@ -7135,6 +7384,7 @@ const sandboxExecutor = (spec, ctx) => {
7135
7384
  if (!seam.sandboxClient || typeof seam.sandboxClient.create !== "function") throw new ValidationError("sandboxExecutor: SandboxSeam.sandboxClient.create required");
7136
7385
  const maxIterations = seam.maxIterations ?? 1;
7137
7386
  if (!Number.isFinite(maxIterations) || maxIterations <= 0) throw new ValidationError("sandboxExecutor: maxIterations must be > 0");
7387
+ const sandboxTokenLimits = enforceTokenLimits(profileModelExecutionSettings(spec.profile, "sandboxExecutor").tokenLimits, "sandbox", "sandboxExecutor");
7138
7388
  const traceEnv = workerTraceEnv(ctx);
7139
7389
  const controller = new AbortController();
7140
7390
  const abortIfSignalled = () => {
@@ -7165,7 +7415,8 @@ const sandboxExecutor = (spec, ctx) => {
7165
7415
  kind: "sandbox-agent-rounds",
7166
7416
  harness,
7167
7417
  maxIterations,
7168
- steering: seam.steering !== void 0
7418
+ steering: seam.steering !== void 0,
7419
+ tokenLimits: sandboxTokenLimits
7169
7420
  }
7170
7421
  };
7171
7422
  const sandboxBinding = {
@@ -7200,6 +7451,7 @@ const sandboxExecutor = (spec, ctx) => {
7200
7451
  runtime: "sandbox",
7201
7452
  deliver: (m) => inbox.deliver(m),
7202
7453
  progress: () => session.progress(),
7454
+ cancel: (request) => session.cancel(request),
7203
7455
  traceSource: () => session.traceSource(),
7204
7456
  execute(task, signal) {
7205
7457
  return session.stream(task, signal);
@@ -7217,7 +7469,7 @@ const sandboxExecutor = (spec, ctx) => {
7217
7469
  }, sandboxMaterialization, sandboxBinding);
7218
7470
  }
7219
7471
  const output = { parse(events) {
7220
- return { events };
7472
+ return sandboxLeafOutputFromEvents(events);
7221
7473
  } };
7222
7474
  const driver = singleShotDriver(maxIterations);
7223
7475
  return attestRuntimeOwnedExecutor({
@@ -7241,6 +7493,10 @@ const sandboxExecutor = (spec, ctx) => {
7241
7493
  }
7242
7494
  });
7243
7495
  },
7496
+ cancel(_request) {
7497
+ controller.abort("executor cancelled");
7498
+ return Promise.resolve(localAbortCancellation("the composed sandbox run owns its boxes, so this executor retains no exact session control reference to cancel against"));
7499
+ },
7244
7500
  teardown(_grace) {
7245
7501
  controller.abort();
7246
7502
  return Promise.resolve({ destroyed: true });
@@ -7289,12 +7545,21 @@ async function* streamSandboxLeaf(args) {
7289
7545
  const result = await runAgentRounds(loopOptions);
7290
7546
  const failure = failedRound(result);
7291
7547
  if (failure) throw failure;
7292
- const out = result.winner?.output ?? { events: [] };
7293
- const verdict = result.winner?.verdict ?? leafVerdict(result);
7548
+ const winningIteration = result.winner ? result.iterations.find((iteration) => iteration.index === result.winner?.iterationIndex) : result.iterations.at(-1);
7549
+ const out = winningIteration?.output ?? sandboxLeafOutputFromEvents(winningIteration?.events ?? []);
7550
+ const sandboxOutcome = winningIteration?.sandboxOutcome;
7551
+ const outWithOutcome = {
7552
+ ...out,
7553
+ ...sandboxOutcome ? { outcome: sandboxOutcome } : {}
7554
+ };
7555
+ const verdict = sandboxOutcome && !sandboxOutcome.success ? {
7556
+ valid: false,
7557
+ score: 0
7558
+ } : result.winner?.verdict ?? leafVerdict(result);
7294
7559
  const tokensKnown = result.tokenUsage.tokensKnown !== false;
7295
7560
  const usdKnown = result.costUsdKnown !== false;
7296
7561
  const outWithUsage = {
7297
- ...out,
7562
+ ...outWithOutcome,
7298
7563
  ...result.estimatedCostUsd !== void 0 ? { estimatedCostUsd: result.estimatedCostUsd } : {},
7299
7564
  ...result.promptCache ? { promptCache: result.promptCache } : {}
7300
7565
  };
@@ -7326,10 +7591,16 @@ async function* streamSandboxLeaf(args) {
7326
7591
  ...result.tokenUsage.cacheWrite !== void 0 ? { cacheWrite: result.tokenUsage.cacheWrite } : {},
7327
7592
  ...result.tokenUsage.cacheBreakdownKnown === false ? { cacheBreakdownKnown: false } : {}
7328
7593
  };
7329
- if (result.iterations.length > 0 || result.costUsd) yield {
7594
+ if (result.iterations.length > 0 || result.costUsd) yield usdKnown ? {
7595
+ kind: "cost",
7596
+ usdKnown: true,
7597
+ usd: result.costUsd,
7598
+ provenance: "provider-receipt"
7599
+ } : {
7330
7600
  kind: "cost",
7601
+ usdKnown: false,
7331
7602
  usd: result.costUsd,
7332
- ...usdKnown ? {} : { usdKnown: false }
7603
+ provenance: "uncaptured"
7333
7604
  };
7334
7605
  } finally {
7335
7606
  args.signal.removeEventListener("abort", cascadeExternal);
@@ -7528,18 +7799,20 @@ function bridgeProfileModel(profile, context) {
7528
7799
  const bridgeExecutor = (spec, ctx) => {
7529
7800
  const base = readSeam(ctx, bridgeSeamKey, "bridge");
7530
7801
  const stopSignal = readOptionalAbortSignal(ctx, bridgeStopSignalKey, "bridge");
7802
+ const runtimeAttachments = readOptionalMcpAttachments(ctx, bridgeRuntimeAttachmentsKey, "bridge");
7531
7803
  const modelCredential = validateBridgeModelCredential(base.modelCredential, base.bridgeUrl, "bridgeExecutor");
7532
7804
  const effectiveProfile = agentProfileSchema.parse(spec.profile);
7533
7805
  const model = bridgeProfileModel(effectiveProfile, "bridgeExecutor");
7534
7806
  const harness = agentHarness(effectiveProfile.harness);
7535
7807
  const providerModel = harness !== void 0 && model.startsWith(`${harness}/`) ? model.slice(harness.length + 1) : model;
7536
7808
  const profileExecution = profileModelExecutionSettings(effectiveProfile, "bridgeExecutor");
7809
+ const bridgeTokenLimits = enforceTokenLimits(profileExecution.tokenLimits, "bridge", "bridgeExecutor");
7537
7810
  const seam = {
7538
7811
  ...base,
7539
7812
  ...modelCredential === void 0 ? {} : { modelCredential },
7540
7813
  model,
7541
7814
  providerModel,
7542
- ...profileExecution.maxTokens !== void 0 ? { maxTokens: profileExecution.maxTokens } : {}
7815
+ ...bridgeTokenLimits.applied.maxTokens !== void 0 ? { maxTokens: bridgeTokenLimits.applied.maxTokens } : {}
7543
7816
  };
7544
7817
  if (!seam.bridgeUrl || !seam.bridgeBearer) throw new ValidationError("bridgeExecutor: bridgeUrl + bridgeBearer are required");
7545
7818
  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}`);
@@ -7587,7 +7860,7 @@ const bridgeExecutor = (spec, ctx) => {
7587
7860
  maxReconnects,
7588
7861
  timeoutMs: seam.timeoutMs ?? null,
7589
7862
  streaming: true,
7590
- ...seam.maxTokens !== void 0 ? { maxTokens: seam.maxTokens } : {},
7863
+ tokenLimits: bridgeTokenLimits,
7591
7864
  terminalAcknowledgement: null
7592
7865
  }
7593
7866
  };
@@ -7633,11 +7906,16 @@ const bridgeExecutor = (spec, ctx) => {
7633
7906
  }
7634
7907
  },
7635
7908
  traceSource: () => trace.source,
7909
+ interactive: () => Object.freeze({
7910
+ status: "unavailable",
7911
+ reason: "provider-has-no-interactive-contract"
7912
+ }),
7636
7913
  execute(task, signal) {
7637
7914
  return streamBridgeSession({
7638
7915
  task,
7639
7916
  signal,
7640
7917
  ...stopSignal === void 0 ? {} : { stopSignal },
7918
+ ...runtimeAttachments === void 0 ? {} : { runtimeAttachments },
7641
7919
  profile: effectiveProfile,
7642
7920
  seam,
7643
7921
  sessionId,
@@ -7674,6 +7952,41 @@ const bridgeExecutor = (spec, ctx) => {
7674
7952
  }
7675
7953
  });
7676
7954
  },
7955
+ async cancel(request) {
7956
+ const live = [...activeRuns.values()].filter((run) => !run.terminal);
7957
+ const observedAt = () => (/* @__PURE__ */ new Date()).toISOString();
7958
+ if (live.length === 0) return {
7959
+ status: "already-terminal",
7960
+ effect: "not_live",
7961
+ observedAt: observedAt(),
7962
+ detail: "every bridge run for this session was already terminal",
7963
+ evidence: { runs: [...activeRuns.keys()] }
7964
+ };
7965
+ controller.abort("executor cancelled");
7966
+ const grace = request.signal === void 0 ? "infinity" : BRIDGE_CANCEL_LONG_POLL_MS;
7967
+ const terminal = await Promise.all(live.map((run) => cancelBridgeRunToTerminal(seam, run, grace, request.signal)));
7968
+ const evidence = {
7969
+ operationId: request.operationId,
7970
+ runs: live.map((run, index) => ({
7971
+ id: run.id,
7972
+ terminal: terminal[index] === true
7973
+ }))
7974
+ };
7975
+ if (terminal.every(Boolean)) return {
7976
+ status: "accepted",
7977
+ effect: "cancelled",
7978
+ observedAt: observedAt(),
7979
+ detail: "the bridge reported every run terminal after the cancel operation",
7980
+ evidence
7981
+ };
7982
+ return {
7983
+ status: "unknown",
7984
+ effect: "cancel_requested",
7985
+ observedAt: observedAt(),
7986
+ detail: "the bridge accepted the cancel operation but a run had not reached terminal state within the deadline",
7987
+ evidence
7988
+ };
7989
+ },
7677
7990
  async teardown(grace) {
7678
7991
  controller.abort();
7679
7992
  const remaining = [...activeRuns.values()].filter((run) => !run.terminal);
@@ -7739,6 +8052,78 @@ function scheduleBridgeRunStateRefresh(seam, activeRuns, observation) {
7739
8052
  }
7740
8053
  })();
7741
8054
  }
8055
+ /** One bridge GET over the `node:http(s)` core client — the same transport every other bridge
8056
+ * read uses, so a computed provider endpoint never reaches global `fetch`. Resolves the status
8057
+ * and the body text; a transport failure rejects. */
8058
+ function bridgeGet(seam, path, timeoutMs) {
8059
+ const target = new URL(`${seam.bridgeUrl.replace(/\/$/, "")}${path}`);
8060
+ const requestFn = target.protocol === "https:" ? request$1 : request;
8061
+ return new Promise((resolve, reject) => {
8062
+ const req = requestFn(target, {
8063
+ method: "GET",
8064
+ headers: { authorization: `Bearer ${seam.bridgeBearer}` },
8065
+ timeout: timeoutMs
8066
+ }, (res) => {
8067
+ (async () => {
8068
+ const chunks = [];
8069
+ for await (const chunk of res) chunks.push(Buffer.from(chunk));
8070
+ resolve({
8071
+ status: res.statusCode ?? 0,
8072
+ body: Buffer.concat(chunks).toString("utf8")
8073
+ });
8074
+ })().catch(reject);
8075
+ });
8076
+ req.on("timeout", () => req.destroy(/* @__PURE__ */ new Error(`bridge GET ${path} timed out`)));
8077
+ req.on("error", reject);
8078
+ req.end();
8079
+ });
8080
+ }
8081
+ /**
8082
+ * `GET /v1/capabilities?model=<wire id>` — does this bridge route this model AT ALL.
8083
+ *
8084
+ * The bridge answers exactly this question and 404s `no backend matches model "…"`, which is the
8085
+ * error a child would otherwise discover after it was spawned and metered. Returns `undefined`
8086
+ * when the route resolves; otherwise the operator-facing reason it did not. FAIL CLOSED: a
8087
+ * transport error and an unexpected status are both reasons, never a silent pass.
8088
+ */
8089
+ async function bridgeModelRouteRefusal(seam, wireModel) {
8090
+ const base = seam.bridgeUrl.replace(/\/$/, "");
8091
+ let answer;
8092
+ try {
8093
+ answer = await bridgeGet(seam, `/v1/capabilities?model=${encodeURIComponent(wireModel)}`, BRIDGE_RUN_STATE_TIMEOUT_MS);
8094
+ } catch (error) {
8095
+ return `bridge ${base} did not answer for model ${JSON.stringify(wireModel)}: ${error instanceof Error ? error.message : String(error)}`;
8096
+ }
8097
+ if (answer.status === 200) return void 0;
8098
+ return answer.status === 404 ? `bridge ${base} routes no backend for model ${JSON.stringify(wireModel)}` : `bridge ${base} answered ${answer.status} for model ${JSON.stringify(wireModel)}`;
8099
+ }
8100
+ /**
8101
+ * `GET /health` → `admission.{active,maxActive}`, or `undefined` when the bridge does not report
8102
+ * them. ADVISORY by nature — admission fills and drains — so an unanswered or admission-less
8103
+ * `/health` is not evidence about capacity and must not be read as one.
8104
+ */
8105
+ async function bridgeAdmissionRead(seam) {
8106
+ let answer;
8107
+ try {
8108
+ answer = await bridgeGet(seam, "/health", BRIDGE_RUN_STATE_TIMEOUT_MS);
8109
+ } catch {
8110
+ return;
8111
+ }
8112
+ let parsed;
8113
+ try {
8114
+ parsed = JSON.parse(answer.body);
8115
+ } catch {
8116
+ return;
8117
+ }
8118
+ const admission = parsed?.admission;
8119
+ const active = admission?.active;
8120
+ const maxActive = admission?.maxActive;
8121
+ if (typeof active !== "number" || typeof maxActive !== "number" || maxActive <= 0) return;
8122
+ return {
8123
+ active,
8124
+ maxActive
8125
+ };
8126
+ }
7742
8127
  /** `GET /v1/runs/:id` — the bridge's durable-run registry read. Resolves `undefined` for any
7743
8128
  * non-200 or non-conforming body rather than throwing: this is only ever an observability read. */
7744
8129
  function bridgeRunStateGet(seam, runId) {
@@ -7871,6 +8256,7 @@ async function* streamBridgeSession(args) {
7871
8256
  ...seam.timeoutMs !== void 0 ? { timeoutMs: seam.timeoutMs } : {}
7872
8257
  },
7873
8258
  agent_profile: args.profile,
8259
+ ...args.runtimeAttachments === void 0 ? {} : { runtime_attachments: { mcp: args.runtimeAttachments } },
7874
8260
  messages
7875
8261
  };
7876
8262
  let turnText = "";
@@ -7879,6 +8265,7 @@ async function* streamBridgeSession(args) {
7879
8265
  let sawTurnCostStatus = false;
7880
8266
  let turnUsdKnown = true;
7881
8267
  let turnKnownCostSubtotal = 0;
8268
+ let turnCostProvenance;
7882
8269
  let turnEstimatedCostSubtotal = 0;
7883
8270
  let turnInputTokens = 0;
7884
8271
  let turnOutputTokens = 0;
@@ -7901,6 +8288,7 @@ async function* streamBridgeSession(args) {
7901
8288
  profile: args.profile,
7902
8289
  sessionId: args.sessionId,
7903
8290
  body: requestBody,
8291
+ requiresRuntimeAttachments: args.runtimeAttachments !== void 0,
7904
8292
  signal: turnController.signal,
7905
8293
  run: activeRun,
7906
8294
  maxReconnects: args.maxReconnects,
@@ -7925,9 +8313,22 @@ async function* streamBridgeSession(args) {
7925
8313
  }
7926
8314
  observedSystemFingerprint = chunk.systemFingerprint;
7927
8315
  }
7928
- if (chunk.content) turnText += chunk.content;
8316
+ if (chunk.content) {
8317
+ turnText += chunk.content;
8318
+ yield {
8319
+ kind: "progress",
8320
+ progress: {
8321
+ kind: "text_delta",
8322
+ text: chunk.content
8323
+ }
8324
+ };
8325
+ }
7929
8326
  for (const step of chunk.toolCalls ?? []) {
7930
- toolCalls.push(step.toolName);
8327
+ toolCalls.push({
8328
+ ...step.callId === void 0 ? {} : { id: step.callId },
8329
+ name: step.toolName,
8330
+ arguments: step.args
8331
+ });
7931
8332
  observation.activity.push({
7932
8333
  at: Date.now(),
7933
8334
  kind: "tool",
@@ -7935,6 +8336,15 @@ async function* streamBridgeSession(args) {
7935
8336
  ...describeToolArgs(step.args) ? { detail: describeToolArgs(step.args) } : {}
7936
8337
  });
7937
8338
  args.record(step);
8339
+ yield {
8340
+ kind: "progress",
8341
+ progress: {
8342
+ kind: "tool_call",
8343
+ toolName: step.toolName,
8344
+ ...step.callId === void 0 ? {} : { toolCallId: step.callId },
8345
+ args: step.args
8346
+ }
8347
+ };
7938
8348
  }
7939
8349
  if (chunk.usage) {
7940
8350
  sawTurnTokenUsage = true;
@@ -7958,6 +8368,7 @@ async function* streamBridgeSession(args) {
7958
8368
  if (chunk.usage.promptCache.writeInput !== void 0) promptCache.writeTokens = (promptCache.writeTokens ?? 0) + chunk.usage.promptCache.writeInput;
7959
8369
  }
7960
8370
  }
8371
+ if (chunk.costProvenance !== void 0) turnCostProvenance = chunk.costProvenance;
7961
8372
  if (chunk.costKnown !== void 0) {
7962
8373
  sawTurnCostStatus = true;
7963
8374
  if (!chunk.costKnown) turnUsdKnown = false;
@@ -7971,7 +8382,9 @@ async function* streamBridgeSession(args) {
7971
8382
  usd += increment;
7972
8383
  yield {
7973
8384
  kind: "cost",
7974
- usd: increment
8385
+ usdKnown: true,
8386
+ usd: increment,
8387
+ provenance: turnCostProvenance ?? "provider-receipt"
7975
8388
  };
7976
8389
  }
7977
8390
  }
@@ -8016,9 +8429,10 @@ async function* streamBridgeSession(args) {
8016
8429
  }) : {
8017
8430
  kind: "cost",
8018
8431
  usd: 0,
8019
- usdKnown: false
8432
+ usdKnown: false,
8433
+ provenance: "uncaptured"
8020
8434
  };
8021
- if (priced.usdEstimated !== void 0) estimatedUsdCharged += priced.usdEstimated;
8435
+ if (priced.usdKnown === false && priced.usdEstimated !== void 0) estimatedUsdCharged += priced.usdEstimated;
8022
8436
  usd += priced.usd;
8023
8437
  yield priced;
8024
8438
  }
@@ -8072,7 +8486,7 @@ const BRIDGE_BRUTAL_KILL_WAIT_MS = 150;
8072
8486
  * cannot prove continuity fails instead of returning a plausible partial answer.
8073
8487
  */
8074
8488
  async function* streamDurableBridgeRun(args) {
8075
- await assertBridgeExecutionCapabilities(args.seam, args.signal);
8489
+ await assertBridgeExecutionCapabilities(args.seam, args.signal, args.requiresRuntimeAttachments);
8076
8490
  let reconnects = 0;
8077
8491
  let pendingUpstreamError;
8078
8492
  for (;;) {
@@ -8151,7 +8565,7 @@ async function* streamDurableBridgeRun(args) {
8151
8565
  * a process may restart behind the same URL, and a remembered capability from the prior process
8152
8566
  * is not evidence about the process that will receive the next POST. The terminal receipt remains
8153
8567
  * mandatory because the bridge can still restart between this GET and the run request. */
8154
- async function assertBridgeExecutionCapabilities(seam, signal) {
8568
+ async function assertBridgeExecutionCapabilities(seam, signal, requiresRuntimeAttachments) {
8155
8569
  const target = new URL(`${seam.bridgeUrl.replace(/\/$/, "")}/`);
8156
8570
  const requestFn = target.protocol === "https:" ? request$1 : request;
8157
8571
  const response = await new Promise((resolve, reject) => {
@@ -8192,6 +8606,10 @@ async function assertBridgeExecutionCapabilities(seam, signal) {
8192
8606
  }
8193
8607
  if (body.capabilities?.profileMaterialization !== bridgeProfileMaterializationSchema) throw new ValidationError(`bridgeExecutor: bridge does not advertise ${bridgeProfileMaterializationSchema}`);
8194
8608
  if (body.capabilities?.usageCostProvenance !== bridgeUsageCostSchema) throw new ValidationError(`bridgeExecutor: bridge does not advertise ${bridgeUsageCostSchema}`);
8609
+ if (requiresRuntimeAttachments) {
8610
+ const attachments = body.capabilities?.runtimeAttachments;
8611
+ 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`);
8612
+ }
8195
8613
  }
8196
8614
  /**
8197
8615
  * POST one streamed turn to the cli-bridge over the `node:http(s)` core client
@@ -8801,6 +9219,7 @@ function applyBridgeCostReceipt(out, usage) {
8801
9219
  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");
8802
9220
  out.costKnown = true;
8803
9221
  out.cost = cost;
9222
+ out.costProvenance = provenance;
8804
9223
  return;
8805
9224
  }
8806
9225
  if (cost !== void 0) throw new ValidationError("bridgeExecutor: unknown cost cannot carry billed cost");
@@ -9251,13 +9670,14 @@ function createExecutor(config) {
9251
9670
  }
9252
9671
  }
9253
9672
  };
9254
- return {
9255
- ...sandboxExecutor({
9256
- ...spec,
9257
- harness
9258
- }, providerCtx),
9673
+ const executor = sandboxExecutor({
9674
+ ...spec,
9675
+ harness
9676
+ }, providerCtx);
9677
+ return inheritRuntimeOwnedExecutorAttestation(executor, {
9678
+ ...executor,
9259
9679
  runtime: providerSeam.runtime ?? provider.name
9260
- };
9680
+ });
9261
9681
  }
9262
9682
  const profileForCreate = providerSeam.profileForCreate;
9263
9683
  return providerAsExecutor(provider, {
@@ -9359,6 +9779,15 @@ function readOptionalAbortSignal(ctx, key, who) {
9359
9779
  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`);
9360
9780
  return value;
9361
9781
  }
9782
+ /** Narrow the Runtime-owned MCP attachment seam. Absent means the run mounts nothing; a present
9783
+ * value must be a named map of MCP servers, never an empty one that would silently mount nothing. */
9784
+ function readOptionalMcpAttachments(ctx, key, who) {
9785
+ const value = ctx.seams[key];
9786
+ if (value === void 0) return void 0;
9787
+ const entries = value !== null && typeof value === "object" && !Array.isArray(value) ? Object.entries(value) : void 0;
9788
+ 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`);
9789
+ return value;
9790
+ }
9362
9791
  /** A leaf task is opaque (`unknown`). A string is the prompt verbatim; an object
9363
9792
  * with a `prompt`/`content`/`task` string field uses it; otherwise it serializes.
9364
9793
  * Module-exported (not package surface) so sibling leaf executors read a task
@@ -9408,10 +9837,12 @@ function routerProfileExecution(profile, seam, mode) {
9408
9837
  if (enabled && !suppliedNames.has(name)) throw new ValidationError(`routerInlineExecutor: AgentProfile enables tool ${JSON.stringify(name)} but the caller supplied no matching schema`);
9409
9838
  if (!enabled && suppliedNames.has(name)) throw new ValidationError(`routerInlineExecutor: AgentProfile disables tool ${JSON.stringify(name)}`);
9410
9839
  }
9840
+ const { tokenLimits, ...rest } = settings;
9411
9841
  return {
9412
9842
  systemPrompt: renderRouterProfilePrompt(profile),
9413
9843
  ...profileEffort ? { reasoningEffort: profileEffort } : {},
9414
- ...settings
9844
+ ...rest,
9845
+ tokenLimits: enforceTokenLimits(tokenLimits, "router", "routerInlineExecutor")
9415
9846
  };
9416
9847
  }
9417
9848
  /** Resolve the one model id that will cross the Router boundary from the exact profile only. */
@@ -9694,56 +10125,61 @@ function assertValidSpend(spend, label) {
9694
10125
  * channels; iterations come from `'iteration'` events. Pure; `ms` stays zero (the
9695
10126
  * pool does not read wall-clock). */
9696
10127
  function spendFromUsageEvents(events) {
9697
- const tokens = zeroTokenUsage();
9698
- let tokensKnown = true;
9699
- let usd = 0;
9700
- let usdEstimated = 0;
9701
- let usdKnown = true;
9702
- let iterations = 0;
9703
- for (const ev of events) if (ev.kind === "tokens") {
9704
- addTokenUsage(tokens, ev);
9705
- if (ev.tokensKnown === false) tokensKnown = false;
9706
- } else if (ev.kind === "cost") {
9707
- usd += ev.usd;
9708
- usdEstimated += ev.usdEstimated ?? 0;
9709
- if (ev.usdKnown === false) usdKnown = false;
9710
- } else iterations += 1;
10128
+ const totals = newUsageTotals();
10129
+ for (const ev of events) meterUsageEvent(totals, ev);
10130
+ return spendFromUsageTotals(totals);
10131
+ }
10132
+ /** Fresh zeroed {@link UsageTotals}. */
10133
+ function newUsageTotals() {
9711
10134
  return {
9712
- iterations,
9713
- tokens,
9714
- ...tokensKnown ? {} : { tokensKnown: false },
9715
- usd,
9716
- ...usdKnown ? {} : { usdKnown: false },
9717
- ...usdEstimated > 0 ? { usdEstimated } : {},
9718
- ms: 0
10135
+ tokens: zeroTokenUsage(),
10136
+ tokensKnown: true,
10137
+ usd: 0,
10138
+ usdEstimated: 0,
10139
+ usdKnown: true,
10140
+ iterations: 0
9719
10141
  };
9720
10142
  }
9721
- async function foldUsage(events) {
9722
- if (Array.isArray(events)) return spendFromUsageEvents(events);
9723
- const tokens = zeroTokenUsage();
9724
- let tokensKnown = true;
9725
- let usd = 0;
9726
- let usdEstimated = 0;
9727
- let usdKnown = true;
9728
- let iterations = 0;
9729
- for await (const ev of events) if (ev.kind === "tokens") {
9730
- addTokenUsage(tokens, ev);
9731
- if (ev.tokensKnown === false) tokensKnown = false;
9732
- } else if (ev.kind === "cost") {
9733
- usd += ev.usd;
9734
- usdEstimated += ev.usdEstimated ?? 0;
9735
- if (ev.usdKnown === false) usdKnown = false;
9736
- } else iterations += 1;
10143
+ /**
10144
+ * Fold ONE usage event into running totals — the single place that decides which event kinds
10145
+ * meter. `progress` carries observed output rather than accounting, so it meters nothing; only
10146
+ * `iteration` advances the iteration count.
10147
+ */
10148
+ function meterUsageEvent(totals, ev) {
10149
+ if (ev.kind === "tokens") {
10150
+ addTokenUsage(totals.tokens, ev);
10151
+ if (ev.tokensKnown === false) totals.tokensKnown = false;
10152
+ return;
10153
+ }
10154
+ if (ev.kind === "cost") {
10155
+ totals.usd += ev.usd;
10156
+ if (ev.usdKnown === false) {
10157
+ totals.usdEstimated += ev.usdEstimated ?? 0;
10158
+ totals.usdKnown = false;
10159
+ }
10160
+ return;
10161
+ }
10162
+ if (ev.kind === "iteration") totals.iterations += 1;
10163
+ }
10164
+ /** Project folded totals onto the conserved-pool `Spend`. `ms` stays zero — the pool does not
10165
+ * read wall-clock. */
10166
+ function spendFromUsageTotals(totals) {
9737
10167
  return {
9738
- iterations,
9739
- tokens,
9740
- ...tokensKnown ? {} : { tokensKnown: false },
9741
- usd,
9742
- ...usdKnown ? {} : { usdKnown: false },
9743
- ...usdEstimated > 0 ? { usdEstimated } : {},
10168
+ iterations: totals.iterations,
10169
+ tokens: totals.tokens,
10170
+ ...totals.tokensKnown ? {} : { tokensKnown: false },
10171
+ usd: totals.usd,
10172
+ ...totals.usdKnown ? {} : { usdKnown: false },
10173
+ ...totals.usdEstimated > 0 ? { usdEstimated: totals.usdEstimated } : {},
9744
10174
  ms: 0
9745
10175
  };
9746
10176
  }
10177
+ async function foldUsage(events) {
10178
+ if (Array.isArray(events)) return spendFromUsageEvents(events);
10179
+ const totals = newUsageTotals();
10180
+ for await (const ev of events) meterUsageEvent(totals, ev);
10181
+ return spendFromUsageTotals(totals);
10182
+ }
9747
10183
  /**
9748
10184
  * Create a conserved reservation pool from a root `Budget`. `now()` is injected so the
9749
10185
  * deadline readout is deterministic; defaults to `Date.now` for non-test callers. The
@@ -10546,7 +10982,7 @@ function createScope(args) {
10546
10982
  spec = prepared.spec;
10547
10983
  identity = prepared.identity;
10548
10984
  if (opts.key !== void 0 && !isCompleteIdentity(identity)) {
10549
- args.pool.reconcile(reservation.ticket, zeroSpend$1());
10985
+ args.pool.reconcile(reservation.ticket, zeroSpend());
10550
10986
  permit.release();
10551
10987
  return {
10552
10988
  ok: false,
@@ -10557,7 +10993,7 @@ function createScope(args) {
10557
10993
  if (!outcome.succeeded) throw new ValidationError(`scope.spawn: ${outcome.error}`);
10558
10994
  resolved = outcome;
10559
10995
  } catch (error) {
10560
- args.pool.reconcile(reservation.ticket, zeroSpend$1());
10996
+ args.pool.reconcile(reservation.ticket, zeroSpend());
10561
10997
  permit.release();
10562
10998
  throw error;
10563
10999
  }
@@ -10622,7 +11058,7 @@ function createScope(args) {
10622
11058
  label: opts.label,
10623
11059
  ...opts.assignmentId === void 0 ? {} : { assignmentId: opts.assignmentId },
10624
11060
  ...opts.key !== void 0 ? { key: opts.key } : {},
10625
- spent: zeroSpend$1(),
11061
+ spent: zeroSpend(),
10626
11062
  settled: void 0,
10627
11063
  delivered: false,
10628
11064
  executorDone: false,
@@ -10632,7 +11068,10 @@ function createScope(args) {
10632
11068
  lastActivityAt: startedAt,
10633
11069
  ...executor.deliver ? { deliver: (message) => executor.deliver?.(message) !== false } : {},
10634
11070
  ...executor.progress ? { readProgress: executor.progress.bind(executor) } : {},
10635
- ...executor.traceSource ? { readTraceSource: executor.traceSource.bind(executor) } : {}
11071
+ ...executor.traceSource ? { readTraceSource: executor.traceSource.bind(executor) } : {},
11072
+ ...executor.interactive ? { readInteractive: executor.interactive.bind(executor) } : {},
11073
+ ...executor.cancel ? { requestCancel: executor.cancel.bind(executor) } : {},
11074
+ abortChild: (reason) => controller.abort(reason)
10636
11075
  };
10637
11076
  children.set(id, live);
10638
11077
  if (opts.key !== void 0) keyed.set(opts.key, {
@@ -10640,7 +11079,8 @@ function createScope(args) {
10640
11079
  id,
10641
11080
  identity
10642
11081
  });
10643
- const spawnCommitted = args.journal.appendEvent(args.root, {
11082
+ const profileRef = contentAddress(spec.profile);
11083
+ const spawnCommitted = args.blobs.put(profileRef, spec.profile).then(() => args.journal.appendEvent(args.root, {
10644
11084
  kind: "spawned",
10645
11085
  id,
10646
11086
  parent: args.parentId,
@@ -10651,9 +11091,10 @@ function createScope(args) {
10651
11091
  runtime: executor.runtime,
10652
11092
  ...ownedTreeRoot === void 0 ? {} : { ownedTreeRoot },
10653
11093
  ...identity ? { identity } : {},
11094
+ profileRef,
10654
11095
  seq: ordinal,
10655
11096
  at: new Date(now()).toISOString()
10656
- }).then(async () => {
11097
+ })).then(async () => {
10657
11098
  if (args.workerTraceUnpropagated === void 0 || workerTrace === void 0) return;
10658
11099
  await args.journal.appendEvent(args.root, {
10659
11100
  kind: "trace-unpropagated",
@@ -10786,7 +11227,9 @@ function createScope(args) {
10786
11227
  runtime: executor.runtime,
10787
11228
  ...identity ? { identity } : {},
10788
11229
  budget: opts.budget,
10789
- depth: args.depth
11230
+ depth: args.depth,
11231
+ attemptId,
11232
+ startedAt
10790
11233
  }
10791
11234
  }, { signal: args.signal });
10792
11235
  live.settled = runChild(live, executor, controller, task, opts, args.pool, reservation.ticket, args.blobs, now, materializationCommitted, {
@@ -10809,7 +11252,7 @@ function createScope(args) {
10809
11252
  permit.release();
10810
11253
  clearChildDeadline?.();
10811
11254
  if (cascadeAbort) args.signal.removeEventListener("abort", cascadeAbort);
10812
- args.pool.reconcile(reservation.ticket, zeroSpend$1());
11255
+ args.pool.reconcile(reservation.ticket, zeroSpend());
10813
11256
  throw err;
10814
11257
  }
10815
11258
  }
@@ -10903,12 +11346,13 @@ function createScope(args) {
10903
11346
  id,
10904
11347
  status: "waiting",
10905
11348
  runtime: "wait",
11349
+ abortChild: (reason) => waitAbort.abort(reason),
10906
11350
  budget: {
10907
11351
  maxIterations: 0,
10908
11352
  maxTokens: 0
10909
11353
  },
10910
11354
  label: opts.label,
10911
- spent: zeroSpend$1(),
11355
+ spent: zeroSpend(),
10912
11356
  settled: void 0,
10913
11357
  delivered: false,
10914
11358
  executorDone: false,
@@ -10981,7 +11425,7 @@ function createScope(args) {
10981
11425
  kind: "done",
10982
11426
  out: resolution.outcome,
10983
11427
  outRef,
10984
- spent: zeroSpend$1(),
11428
+ spent: zeroSpend(),
10985
11429
  trace: {
10986
11430
  status: "unavailable",
10987
11431
  reason: "not-an-executor"
@@ -11032,6 +11476,18 @@ function createScope(args) {
11032
11476
  ...child.spent.usdKnown === false ? { usdKnown: false } : {}
11033
11477
  }, fromExecutor, opts.now ?? now(), opts.stallAfterMs ?? 18e4);
11034
11478
  }
11479
+ async function cancel(nodeId, request) {
11480
+ const child = children.get(nodeId);
11481
+ if (!child) throw new ValidationError(`scope.cancel: unknown node ${JSON.stringify(nodeId)}`);
11482
+ if (child.requestCancel) return await child.requestCancel(request);
11483
+ child.abortChild("cancelled");
11484
+ return {
11485
+ status: "unknown",
11486
+ effect: "cancel_requested",
11487
+ observedAt: (/* @__PURE__ */ new Date()).toISOString(),
11488
+ detail: `executor runtime ${JSON.stringify(child.runtime ?? "unknown")} exposes no cancellation operation; the child was aborted locally`
11489
+ };
11490
+ }
11035
11491
  function traceSource(nodeId) {
11036
11492
  const child = children.get(nodeId);
11037
11493
  if (!child) return void 0;
@@ -11041,6 +11497,24 @@ function createScope(args) {
11041
11497
  return;
11042
11498
  }
11043
11499
  }
11500
+ function terminalNodeStatus(status) {
11501
+ return status === "done" || status === "failed" || status === "cancelled";
11502
+ }
11503
+ function interactive(nodeId) {
11504
+ const child = children.get(nodeId);
11505
+ if (!child) return noInteractiveSession("unknown-node");
11506
+ if (child.wait || child.executorDone || terminalNodeStatus(child.status)) return noInteractiveSession("not-live");
11507
+ if (!child.readInteractive) return noInteractiveSession("executor-exposes-no-interactive-session");
11508
+ let reported;
11509
+ try {
11510
+ reported = child.readInteractive();
11511
+ } catch {
11512
+ return noInteractiveSession("executor-exposes-no-interactive-session");
11513
+ }
11514
+ if (reported?.status === "unavailable" && reported.reason) return reported;
11515
+ if (reported?.status === "available" && reported.handle) return reported;
11516
+ return noInteractiveSession("executor-exposes-no-interactive-session");
11517
+ }
11044
11518
  async function meterInternal(spend, detail, providerModel, accountingOnly = false) {
11045
11519
  if (args.signal.aborted) throw new ValidationError("scope.meter: cannot record new driver work after scope abort");
11046
11520
  const seq = meterSeq++;
@@ -11088,6 +11562,8 @@ function createScope(args) {
11088
11562
  wait,
11089
11563
  progress,
11090
11564
  traceSource,
11565
+ interactive,
11566
+ cancel,
11091
11567
  signal: args.signal,
11092
11568
  meter: (spend, detail) => meterInternal(spend, detail),
11093
11569
  ...resume ? { resume } : {},
@@ -11100,7 +11576,13 @@ function createScope(args) {
11100
11576
  get workerCapacity() {
11101
11577
  return {
11102
11578
  live: liveWorkerCapacity.live,
11103
- freeSlots: freeSlots(liveWorkerCapacity.live, liveWorkerCapacity.max)
11579
+ freeSlots: freeSlots(liveWorkerCapacity.live, liveWorkerCapacity.max),
11580
+ unconfirmed: Object.freeze([...children.values()].filter((child) => (child.status === "done" || child.status === "failed" || child.status === "cancelled") && !child.cleanupConfirmed).map((child) => Object.freeze({
11581
+ id: child.id,
11582
+ label: child.label,
11583
+ runtime: child.runtime,
11584
+ status: child.status
11585
+ })))
11104
11586
  };
11105
11587
  }
11106
11588
  };
@@ -11340,7 +11822,9 @@ async function finalizeSettlement(child, settlement, seq, args, now) {
11340
11822
  status: "down",
11341
11823
  reason: settlement.reason,
11342
11824
  infra: settlement.infra,
11343
- spent: child.spent
11825
+ spent: child.spent,
11826
+ restartCount: settlement.restartCount,
11827
+ ...settledNodeEvidence(child, settlement, settledAt)
11344
11828
  }
11345
11829
  }, { signal: args.signal });
11346
11830
  return {
@@ -11393,7 +11877,8 @@ async function finalizeSettlement(child, settlement, seq, args, now) {
11393
11877
  outRef: settlement.outRef,
11394
11878
  score: settlement.verdict?.score,
11395
11879
  valid: settlement.verdict?.valid,
11396
- spent: settlement.spent
11880
+ spent: settlement.spent,
11881
+ ...settledNodeEvidence(child, settlement, settledAt)
11397
11882
  }
11398
11883
  }, { signal: args.signal });
11399
11884
  return {
@@ -11409,6 +11894,26 @@ async function finalizeSettlement(child, settlement, seq, args, now) {
11409
11894
  seq
11410
11895
  };
11411
11896
  }
11897
+ /**
11898
+ * The evidence a settled node carries beyond its status: the receipts that name what actually
11899
+ * ran, the own-inference spend the parent tree re-homes as a `metered` event, and the wall-clock
11900
+ * window. One builder feeds BOTH terminal paths, so an observer never sees a `down` node
11901
+ * described in different terms from a `done` one. Every field is omitted when the fact is
11902
+ * absent — an unreported receipt must not read as an empty one. Snapshots are detached because
11903
+ * an observer may serialize them after the live child has moved on.
11904
+ */
11905
+ function settledNodeEvidence(child, settlement, settledAt) {
11906
+ return {
11907
+ runtime: child.runtime,
11908
+ startedAt: child.startedAt,
11909
+ settledAt,
11910
+ ...settlement.metered ? { metered: detachedSnapshot(settlement.metered, "metered") } : {},
11911
+ ...child.providerModel ? { providerModel: detachedSnapshot(child.providerModel, "provider model evidence") } : {},
11912
+ ...child.materialization ? { materialization: detachedSnapshot(child.materialization, "materialization receipt") } : {},
11913
+ ...child.executionBindings.length > 0 ? { executionBindings: detachedSnapshot([...child.executionBindings], "execution binding receipts") } : {},
11914
+ trace: detachedSnapshot(settlement.trace, "worker trace evidence")
11915
+ };
11916
+ }
11412
11917
  /** Journal a wait-state's settlement as a `woken` event and project it onto the same `Settled`
11413
11918
  * the driver branches on. `by` names WHY it woke — `fired` / `timeout` / `cancelled` — which is
11414
11919
  * the fact a resumed reader needs and cannot recover from a payload it may never fetch. */
@@ -11720,30 +12225,20 @@ function freezeCorrelation(value) {
11720
12225
  * now reconciles its real partial spend instead of refunding work the provider already billed.
11721
12226
  */
11722
12227
  async function foldStream(stream, onProgress, signal) {
11723
- const tokens = zeroTokenUsage();
11724
- let tokensKnown = true;
11725
- let usd = 0;
11726
- let usdKnown = true;
11727
- let iterations = 0;
12228
+ const totals = newUsageTotals();
11728
12229
  const iterator = stream[Symbol.asyncIterator]();
11729
12230
  try {
11730
12231
  for (;;) {
11731
12232
  const next = signal ? await awaitAbortable(Promise.resolve(iterator.next()), signal) : await iterator.next();
11732
12233
  if (next.done) break;
11733
12234
  const ev = next.value;
11734
- if (ev.kind === "tokens") {
11735
- addTokenUsage(tokens, ev);
11736
- if (ev.tokensKnown === false) tokensKnown = false;
11737
- } else if (ev.kind === "cost") {
11738
- usd += ev.usd;
11739
- if (ev.usdKnown === false) usdKnown = false;
11740
- } else iterations += 1;
12235
+ meterUsageEvent(totals, ev);
11741
12236
  onProgress?.({
11742
- iterations,
11743
- tokens: cloneTokenUsage(tokens),
11744
- ...tokensKnown ? {} : { tokensKnown: false },
11745
- usd,
11746
- ...usdKnown ? {} : { usdKnown: false },
12237
+ iterations: totals.iterations,
12238
+ tokens: cloneTokenUsage(totals.tokens),
12239
+ ...totals.tokensKnown ? {} : { tokensKnown: false },
12240
+ usd: totals.usd,
12241
+ ...totals.usdKnown ? {} : { usdKnown: false },
11747
12242
  ms: 0
11748
12243
  });
11749
12244
  }
@@ -11751,14 +12246,7 @@ async function foldStream(stream, onProgress, signal) {
11751
12246
  Promise.resolve(iterator.return?.()).catch(() => void 0);
11752
12247
  throw error;
11753
12248
  }
11754
- return {
11755
- iterations,
11756
- tokens,
11757
- ...tokensKnown ? {} : { tokensKnown: false },
11758
- usd,
11759
- ...usdKnown ? {} : { usdKnown: false },
11760
- ms: 0
11761
- };
12249
+ return spendFromUsageTotals(totals);
11762
12250
  }
11763
12251
  /** Usage events carry measured increments; the terminal artifact carries whether a provider omitted
11764
12252
  * a whole accounting channel. Preserve those unknowns on the common streaming path. */
@@ -11819,13 +12307,12 @@ function downRecord(reason, infra, trace, metered, providerModel) {
11819
12307
  ...metered ? { metered } : {}
11820
12308
  };
11821
12309
  }
11822
- function zeroSpend$1() {
11823
- return {
11824
- iterations: 0,
11825
- tokens: zeroTokenUsage(),
11826
- usd: 0,
11827
- ms: 0
11828
- };
12310
+ /** The one place an absent interactive process is spelled, so every refusal reads the same. */
12311
+ function noInteractiveSession(reason) {
12312
+ return Object.freeze({
12313
+ status: "unavailable",
12314
+ reason
12315
+ });
11829
12316
  }
11830
12317
  function isAsyncIterable(value) {
11831
12318
  return typeof value === "object" && value !== null && typeof value[Symbol.asyncIterator] === "function";
@@ -11944,7 +12431,7 @@ const driverExecutorFactory = (rawSpec, ctx) => {
11944
12431
  meteredSpend = nonZeroOrUndef(sumMetered(events));
11945
12432
  accounting = {
11946
12433
  reported: childWork,
11947
- reservation: addSpend$1(childWork, meteredSpend ?? zeroSpend())
12434
+ reservation: addSpend(childWork, meteredSpend ?? zeroSpend())
11948
12435
  };
11949
12436
  const verdict = deriveDeliveryVerdict(settled, out);
11950
12437
  artifact = {
@@ -12028,12 +12515,7 @@ function isSettled(ev) {
12028
12515
  /** Sum the conserved spend over the nested tree's settled events — the honest per-channel
12029
12516
  * roll-up of the whole sub-tree's child WORK. */
12030
12517
  function sumSpend(settled) {
12031
- const total = {
12032
- iterations: 0,
12033
- tokens: zeroTokenUsage(),
12034
- usd: 0,
12035
- ms: 0
12036
- };
12518
+ const total = zeroSpend();
12037
12519
  for (const ev of settled) {
12038
12520
  total.iterations += ev.spent.iterations;
12039
12521
  addTokenUsage(total.tokens, ev.spent.tokens);
@@ -12048,12 +12530,7 @@ function sumSpend(settled) {
12048
12530
  * own turns + any sub-driver inference already re-homed into this tree). Re-homed up to the parent
12049
12531
  * as one `metered` event; never reconciled (already pool-debited live via `observe`). */
12050
12532
  function sumMetered(events) {
12051
- const total = {
12052
- iterations: 0,
12053
- tokens: zeroTokenUsage(),
12054
- usd: 0,
12055
- ms: 0
12056
- };
12533
+ const total = zeroSpend();
12057
12534
  for (const ev of events) {
12058
12535
  if (ev.kind !== "metered") continue;
12059
12536
  total.iterations += ev.spend.iterations;
@@ -12065,28 +12542,6 @@ function sumMetered(events) {
12065
12542
  }
12066
12543
  return total;
12067
12544
  }
12068
- function zeroSpend() {
12069
- return {
12070
- iterations: 0,
12071
- tokens: zeroTokenUsage(),
12072
- usd: 0,
12073
- ms: 0
12074
- };
12075
- }
12076
- function addSpend$1(a, b) {
12077
- return {
12078
- iterations: a.iterations + b.iterations,
12079
- tokens: (() => {
12080
- const tokens = cloneTokenUsage(a.tokens);
12081
- addTokenUsage(tokens, b.tokens);
12082
- return tokens;
12083
- })(),
12084
- ...a.tokensKnown === false || b.tokensKnown === false ? { tokensKnown: false } : {},
12085
- usd: a.usd + b.usd,
12086
- ...a.usdKnown === false || b.usdKnown === false ? { usdKnown: false } : {},
12087
- ms: a.ms + b.ms
12088
- };
12089
- }
12090
12545
  /** An all-zero spend that carries an UNKNOWN marker counts as non-zero: a sub-driver whose turns
12091
12546
  * went unmeasured did real work, and dropping its `metered` event here would re-hide upstream the
12092
12547
  * very turn the driver refused to skip. */
@@ -12109,7 +12564,7 @@ async function safeRollup(journal, nestedRoot) {
12109
12564
  metered,
12110
12565
  accounting: {
12111
12566
  reported: childWork,
12112
- reservation: addSpend$1(childWork, metered ?? zeroSpend())
12567
+ reservation: addSpend(childWork, metered ?? zeroSpend())
12113
12568
  }
12114
12569
  };
12115
12570
  } catch {
@@ -12622,6 +13077,8 @@ function createSupervisor() {
12622
13077
  ok: false,
12623
13078
  error: new RuntimeRunStateError("supervisor: root execution did not start")
12624
13079
  };
13080
+ let teardownUnconfirmed = [];
13081
+ let teardownSeq = 0;
12625
13082
  let executionAborted = controller.signal.aborted;
12626
13083
  let allChildrenDownAtSettle = false;
12627
13084
  let downCountAtSettle = 0;
@@ -12643,7 +13100,16 @@ function createSupervisor() {
12643
13100
  clearRootDeadline?.();
12644
13101
  const settleGraceMs = actOutcome.ok === false && !controller.signal.aborted ? boundedSettleGrace(opts.childSettleGraceMs, rootDeadlineAtMs, now) : 0;
12645
13102
  try {
12646
- await drainLiveChildren(openScope, controller, settleGraceMs);
13103
+ teardownUnconfirmed = await drainLiveChildren(openScope, controller, settleGraceMs);
13104
+ for (const node of teardownUnconfirmed) await opts.journal.appendEvent(opts.runId, {
13105
+ kind: "teardown-unconfirmed",
13106
+ id: node.id,
13107
+ label: node.label,
13108
+ runtime: node.runtime,
13109
+ status: node.status,
13110
+ seq: teardownSeq++,
13111
+ at: new Date(now()).toISOString()
13112
+ });
12647
13113
  } catch (error) {
12648
13114
  if (actOutcome?.ok !== false) actOutcome = {
12649
13115
  ok: false,
@@ -12677,6 +13143,7 @@ function createSupervisor() {
12677
13143
  tree,
12678
13144
  spentTotal,
12679
13145
  providerModel,
13146
+ ...teardownUnconfirmed.length > 0 ? { teardownUnconfirmed } : {},
12680
13147
  ...gaps.length > 0 ? { spendGaps: gaps } : {},
12681
13148
  ...isNonEmptySpend(driverInference) ? { spentBreakdown: {
12682
13149
  driverInference,
@@ -12695,6 +13162,7 @@ function createSupervisor() {
12695
13162
  downCount: breaker.downCount(),
12696
13163
  spentTotal,
12697
13164
  providerModel,
13165
+ ...teardownUnconfirmed.length > 0 ? { teardownUnconfirmed } : {},
12698
13166
  ...gaps.length > 0 ? { spendGaps: gaps } : {}
12699
13167
  };
12700
13168
  const lifecycle = classifyNoWinner(executionAborted, pool, opts, breaker, deadlineExceeded, allChildrenDownAtSettle, downCountAtSettle);
@@ -12839,10 +13307,7 @@ function wrapJournalForBreaker(journal, breaker) {
12839
13307
  */
12840
13308
  async function drainLiveChildren(scope, controller, settleGraceMs = 0) {
12841
13309
  const view = scope.view;
12842
- if (!(view.inFlight > 0 || view.waiting > 0)) {
12843
- if (scope.workerCapacity.live > 0) throw new RuntimeRunStateError(`supervisor: cleanup ended with ${scope.workerCapacity.live} executor resource(s) not confirmed destroyed`);
12844
- return;
12845
- }
13310
+ if (!(view.inFlight > 0 || view.waiting > 0)) return unconfirmedTeardowns(scope);
12846
13311
  let graceTimer;
12847
13312
  if (settleGraceMs > 0 && !controller.signal.aborted) {
12848
13313
  graceTimer = setTimeout(() => controller.abort("root driver failed; child settle grace expired"), settleGraceMs);
@@ -12854,7 +13319,26 @@ async function drainLiveChildren(scope, controller, settleGraceMs = 0) {
12854
13319
  if (graceTimer !== void 0) clearTimeout(graceTimer);
12855
13320
  }
12856
13321
  const after = scope.view;
12857
- 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`);
13322
+ if (after.inFlight > 0 || after.waiting > 0) throw new RuntimeRunStateError(`supervisor: cleanup ended with ${after.inFlight} running, ${after.waiting} waiting, and ` + describeUnconfirmed(scope));
13323
+ return unconfirmedTeardowns(scope);
13324
+ }
13325
+ /**
13326
+ * The settled children whose executor teardown was never acknowledged.
13327
+ *
13328
+ * They still hold their capacity slot — the ledger stays poisoned, so replacement work can never
13329
+ * exceed the physical live count — but every one of them has already reached a terminal state and
13330
+ * journaled its work. That is evidence about an EXECUTOR, not a cause of run failure, so the
13331
+ * barrier NAMES them and lets the run reach its real terminal state. Live work after the drain is
13332
+ * a different fault and still fails loud.
13333
+ */
13334
+ function unconfirmedTeardowns(scope) {
13335
+ return scope.workerCapacity.unconfirmed;
13336
+ }
13337
+ /** The unconfirmed set as one error clause: the count plus the node ids behind it. One integer is
13338
+ * not actionable after a six-hour run. */
13339
+ function describeUnconfirmed(scope) {
13340
+ const named = scope.workerCapacity.unconfirmed.map((node) => `${node.id} (${node.label}, ${node.runtime}, ${node.status})`).join(", ");
13341
+ return `${scope.workerCapacity.live} executor resource(s) not confirmed destroyed${named.length > 0 ? `: ${named}` : ""}`;
12858
13342
  }
12859
13343
  /** The settle window a failed driver's children actually get: the caller's grace, never past the
12860
13344
  * run's own deadline. `0` (the default) keeps the historical immediate cascade. */
@@ -13019,23 +13503,6 @@ function accumulate(a, b) {
13019
13503
  if (b.usdEstimated !== void 0) a.usdEstimated = (a.usdEstimated ?? 0) + b.usdEstimated;
13020
13504
  a.ms += b.ms;
13021
13505
  }
13022
- /** Sum two conserved-spend tallies per channel — the child-work journal sum + the drivers' own
13023
- * metered inference, so `spentTotal` is the true cost of the run. */
13024
- function addSpend(a, b) {
13025
- return {
13026
- iterations: a.iterations + b.iterations,
13027
- tokens: (() => {
13028
- const tokens = cloneTokenUsage(a.tokens);
13029
- addTokenUsage(tokens, b.tokens);
13030
- return tokens;
13031
- })(),
13032
- ...a.tokensKnown === false || b.tokensKnown === false ? { tokensKnown: false } : {},
13033
- usd: a.usd + b.usd,
13034
- ...a.usdKnown === false || b.usdKnown === false ? { usdKnown: false } : {},
13035
- ...usdEstimatedOf(a, b),
13036
- ms: a.ms + b.ms
13037
- };
13038
- }
13039
13506
  /** True when any driver metered inference this run (so the winner carries a `spentBreakdown`).
13040
13507
  * Checks every channel `addSpend` sums — including `ms` — so the gate stays consistent with the
13041
13508
  * total even though the coordination driver currently stamps `ms: 0`. */
@@ -13043,6 +13510,6 @@ function isNonEmptySpend(s) {
13043
13510
  return s.iterations > 0 || s.tokens.input > 0 || s.tokens.output > 0 || s.usd > 0 || s.ms > 0 || s.tokensKnown === false || s.usdKnown === false;
13044
13511
  }
13045
13512
  //#endregion
13046
- 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 };
13513
+ export { DEFAULT_STALL_AFTER_MS as $, localHarnessExecutable as $t, createBudgetPool as A, buildRuntimeEventOtelSpans as At, createExecutorRegistry as B, createRuntimeEventCollector as Bt, effectiveConcurrency as C, createPropagatingTraceEmitter as Ct, DEFAULT_SUCCESSFUL_SHUTDOWN_MS as D, INTELLIGENCE_WIRE_VERSION as Dt, rollingDispatch as E, traceContextToEnv as Et, bridgeRuntimeAttachmentsKey as F, generateSpanId as Ft, workerTraceEnv as G, runSettledCommand as Gt, createWorktreeCliExecutor as H, sanitizeAgentRuntimeEvent as Ht, bridgeStopSignalKey as I, loopEventToOtelSpan as It, DEFAULT_SANDBOX_STEERING_MAX_TURNS as J, createWorktree as Jt, workerTraceHeaders as K, runWorktreeHarness as Kt, captureReusableExecutorConfig as L, padSpanId as Lt, bindReusableExecutorExecutionId as M, createOtelExporter as Mt, bridgeAdmissionRead as N, exportEvalRuns as Nt, teardownExecutor as O, buildLoopOtelSpans as Ot, bridgeModelRouteRefusal as P, flatOtelSpan as Pt, sandboxSessionTraceSource as Q, harnessSupportsReasoningEffort as Qt, cliWorktreeExecutor as R, padTraceId as Rt, waitUntil as S, observedModelMatchesDeclared as St, queueOf as T, readTraceContextFromEnv as Tt, WORKER_TRACE_PROPAGATION as U, sanitizeKnowledgeReadinessReport as Ut, snapshotExecutorConfig as V, createRuntimeStreamEventCollector as Vt, readWorkerTraceContext as W, sanitizeRuntimeStreamEvent as Wt, createPushTraceSource as X, DEFAULT_LOCAL_HARNESS as Xt, createSteerableSandboxSession as Y, removeWorktree as Yt, decodeToolPart as Z, LOCAL_HARNESSES as Zt, createWaitProbes as _, worktreeCliProfileMaterialization as _n, probeSandboxCapabilities as _t, pickBestDelivered as a, defineProfileMaterializationContract as an, PEER_MAIL_WIRE_KEY as at, timerAt as b, runBrainLoop as bt, driverChild as c, promptControlProfileMaterialization as cn, isPeerMailEnvelope as ct, deriveNodeExecutionIdentity as d, promptResourceProfileMaterialization as dn, TERMINAL_DECISIONS as dt, parseCodexTokenUsage as en, createActivityLog as et, meterRuntimeOwnedAccounting as f, renderProfileMaterializationIssues as fn, createSandboxForSpec as ft, settledToIteration as g, validateProfileMaterialization as gn, createSandboxLineage as gt, scopeOwnerExecutorNodeContext as h, unsupportedProfileDimensions as hn, runAgentRounds as ht, collectDelivered as i, controlProfileMaterialization as in, DEFAULT_PEER_MAIL_LIMITS as it, spendFromUsageEvents as j, createOpenInferenceFileExporter as jt, assertValidBudget as k, buildLoopSpanNodes as kt, withDriverExecutor as l, promptModelProfileMaterialization as ln, peerMailTools as lt, recordScopeOwnerMaterialization as m, sandboxActProfileMaterialization as mn, isTerminalDecision as mt, createSupervisor as n, AGENT_PROFILE_MATERIALIZATION_AXES as nn, createInbox as nt, runFinalizer as o, fullProfileMaterialization as on, claimsAuthority as ot, meterRuntimeOwnedProviderAttempt as p, renderUnsupported as pn, defaultSelectWinner as pt, workerTraceSeamKey as q, captureWorktreeDiff as qt, bestDelivered as r, assertProfileMaterialization as rn, AUTHORITY_MARKERS as rt, runTree as s, profileMaterializationAxes$1 as sn, createPeerMailbox as st, createRootHandle as t, CodexExecutionDiagnosticError as tn, readWorkerProgress as tt, createScope as u, promptOnlyProfileMaterialization as un, peerMailVerbNames as ut, isWaitOutcome as v, acquireSandbox as vt, freeSlots as w, mergeTraceEnv as wt, validateWaitSpec as x, canonicalObservedModel as xt, pollFor as y, routerBrain as yt, createExecutor as z, toOtelAttributes as zt };
13047
13514
 
13048
- //# sourceMappingURL=supervisor-B_0ISTFG.js.map
13515
+ //# sourceMappingURL=supervisor-DBVlPONC.js.map