@tangle-network/agent-runtime 0.115.1 → 0.117.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +7 -1
  2. package/dist/{activation-Bt_XVkjK.js → activation-BZ2FyX0O.js} +3 -3
  3. package/dist/{activation-Bt_XVkjK.js.map → activation-BZ2FyX0O.js.map} +1 -1
  4. package/dist/agent.d.ts +3 -64
  5. package/dist/agent.js +5 -207
  6. package/dist/agent.js.map +1 -1
  7. package/dist/{analyst-loop-BoNIG2hA.js → analyst-loop-DvSciOfB.js} +2 -2
  8. package/dist/{analyst-loop-BoNIG2hA.js.map → analyst-loop-DvSciOfB.js.map} +1 -1
  9. package/dist/analyst-loop.js +1 -1
  10. package/dist/candidate-execution/index.d.ts +3 -3
  11. package/dist/candidate-execution/index.js +5 -5
  12. package/dist/{candidate-execution-CfpJrd3o.js → candidate-execution-PX61zXd2.js} +4 -4
  13. package/dist/{candidate-execution-CfpJrd3o.js.map → candidate-execution-PX61zXd2.js.map} +1 -1
  14. package/dist/{environment-provider-Cygthiy3.d.ts → environment-provider-CTZjdIUg.d.ts} +661 -34
  15. package/dist/{environment-provider-CCaEhA-l.js → environment-provider-CzcEyRL7.js} +140 -31
  16. package/dist/environment-provider-CzcEyRL7.js.map +1 -0
  17. package/dist/environment-provider.d.ts +1 -1
  18. package/dist/environment-provider.js +1 -1
  19. package/dist/{improvement-cycle-tEswzEPr.js → improvement-cycle-Bcqz8rZI.js} +160 -19
  20. package/dist/improvement-cycle-Bcqz8rZI.js.map +1 -0
  21. package/dist/{index-DZukewLl.d.ts → index-BHSYaWrC.d.ts} +3 -3
  22. package/dist/{index-K7nucOmw.d.ts → index-BTUG4Xln.d.ts} +8 -7
  23. package/dist/{index-BUWd8QJq.d.ts → index-DPWJxSRa.d.ts} +884 -497
  24. package/dist/{index-C-FYUuFG.d.ts → index-X2YwyWkc.d.ts} +2 -2
  25. package/dist/index.d.ts +9 -10
  26. package/dist/index.js +12 -13
  27. package/dist/index.js.map +1 -1
  28. package/dist/intelligence.d.ts +10 -9
  29. package/dist/intelligence.js +15 -9
  30. package/dist/intelligence.js.map +1 -1
  31. package/dist/kernel.d.ts +4 -4
  32. package/dist/kernel.js +8 -8
  33. package/dist/{knowledge-CUXQE8Sq.js → knowledge-CDlrayRc.js} +7 -7
  34. package/dist/knowledge-CDlrayRc.js.map +1 -0
  35. package/dist/knowledge.d.ts +1 -1
  36. package/dist/knowledge.js +1 -1
  37. package/dist/{local-harness-BnB1E9nM.d.ts → local-harness-t6cDWDQ2.d.ts} +3 -105
  38. package/dist/{loop-runner-bin-DzJz48Fb.js → loop-runner-bin-BxhhDtmG.js} +4 -4
  39. package/dist/{loop-runner-bin-DzJz48Fb.js.map → loop-runner-bin-BxhhDtmG.js.map} +1 -1
  40. package/dist/{loop-runner-bin-BZl5vp7t.d.ts → loop-runner-bin-oyL7it5O.d.ts} +3 -3
  41. package/dist/loop-runner-bin.d.ts +1 -1
  42. package/dist/loop-runner-bin.js +1 -1
  43. package/dist/mcp/bin.js +43 -10
  44. package/dist/mcp/bin.js.map +1 -1
  45. package/dist/mcp/index.d.ts +4 -43
  46. package/dist/mcp/index.js +5 -205
  47. package/dist/mcp/index.js.map +1 -1
  48. package/dist/{openai-tools-CynwZMZd.js → openai-tools-CO9X36zy.js} +2 -2
  49. package/dist/{openai-tools-CynwZMZd.js.map → openai-tools-CO9X36zy.js.map} +1 -1
  50. package/dist/{prepare-BHQBb02e.js → prepare-BbI6qGOW.js} +5 -2
  51. package/dist/prepare-BbI6qGOW.js.map +1 -0
  52. package/dist/primeintellect/index.d.ts +1 -1
  53. package/dist/{protected-model-port-BP6Z4eau.d.ts → protected-model-port-B0yXMpLL.d.ts} +10 -2
  54. package/dist/{protected-model-port-DqAH1Z2M.js → protected-model-port-COnyZfML.js} +2 -2
  55. package/dist/{protected-model-port-DqAH1Z2M.js.map → protected-model-port-COnyZfML.js.map} +1 -1
  56. package/dist/{redact-BRaHUFMf.d.ts → redact-BEtQtvd6.d.ts} +2 -2
  57. package/dist/{runtime-BatQajPB.js → runtime-Ce39zfqn.js} +145 -53
  58. package/dist/runtime-Ce39zfqn.js.map +1 -0
  59. package/dist/{sandbox-events-DeI5xX8P.js → sandbox-events-Yhd1GYWl.js} +4 -2
  60. package/dist/sandbox-events-Yhd1GYWl.js.map +1 -0
  61. package/dist/spawn-journal-B_mu_oH2.js +857 -0
  62. package/dist/spawn-journal-B_mu_oH2.js.map +1 -0
  63. package/dist/{structural-rollout-DEf37yQy.js → structural-rollout-DLwW69R4.js} +4 -4
  64. package/dist/structural-rollout-DLwW69R4.js.map +1 -0
  65. package/dist/{supervise-B7TIJR3D.js → supervise-U7_K5yuV.js} +2645 -829
  66. package/dist/supervise-U7_K5yuV.js.map +1 -0
  67. package/dist/{supervisor-DzQu5Ydu.js → supervisor-CAXiCKnX.js} +3802 -967
  68. package/dist/supervisor-CAXiCKnX.js.map +1 -0
  69. package/dist/testing.js +98 -76
  70. package/dist/testing.js.map +1 -1
  71. package/dist/{workspace-archive-DXzJq7WP.js → workspace-archive-CqPIijFA.js} +2 -2
  72. package/dist/{workspace-archive-DXzJq7WP.js.map → workspace-archive-CqPIijFA.js.map} +1 -1
  73. package/package.json +1 -1
  74. package/dist/environment-provider-CCaEhA-l.js.map +0 -1
  75. package/dist/improvement-cycle-tEswzEPr.js.map +0 -1
  76. package/dist/knowledge-CUXQE8Sq.js.map +0 -1
  77. package/dist/otel-export-CPZTSADj.js +0 -852
  78. package/dist/otel-export-CPZTSADj.js.map +0 -1
  79. package/dist/prepare-BHQBb02e.js.map +0 -1
  80. package/dist/runtime-BatQajPB.js.map +0 -1
  81. package/dist/sandbox-events-DeI5xX8P.js.map +0 -1
  82. package/dist/spawn-journal-DCPbicXB.js +0 -457
  83. package/dist/spawn-journal-DCPbicXB.js.map +0 -1
  84. package/dist/structural-rollout-DEf37yQy.js.map +0 -1
  85. package/dist/supervise-B7TIJR3D.js.map +0 -1
  86. package/dist/supervisor-DzQu5Ydu.js.map +0 -1
  87. package/dist/trace-propagation-B-pL7xn_.js +0 -57
  88. package/dist/trace-propagation-B-pL7xn_.js.map +0 -1
@@ -1,19 +1,18 @@
1
1
  import { c as RuntimeRunStateError, i as ConfigError, o as NotFoundError, t as AgentEvalError$1, u as ValidationError } from "./errors-DEAvWQPy.js";
2
+ import { S as detachedSnapshot, b as workerTraceAnalysisStore, d as writeAllBytes, i as InMemorySpawnJournal, l as parseCommittedJsonLines, n as FileSpawnJournal, r as InMemoryResultBlobStore, t as FileResultBlobStore, u as prepareJsonlAppend, x as contentAddress } from "./spawn-journal-B_mu_oH2.js";
2
3
  import { a as mapWithConcurrency, c as sleep, d as throwIfAborted, f as withTimeout, l as stringifySafe, n as addTokenUsage, o as randomSuffix, p as zeroTokenUsage, r as deleteBoxSafe, s as randomUuid, t as abortError, u as throwAbort } from "./util-Cc9g9Y-o.js";
3
- import { a as contentAddress, i as InMemorySpawnJournal, n as FileSpawnJournal, r as InMemoryResultBlobStore, t as FileResultBlobStore } from "./spawn-journal-DCPbicXB.js";
4
- import { A as captureWorktreeDiff, C as routerChatWithUsage, E as runBrainLoop, M as removeWorktree, O as runWorktreeChecks, a as runFinalizer, i as pickBestDelivered, j as createWorktree, k as runWorktreeHarness, l as withDriverExecutor, n as bestDelivered, o as runTree, t as createSupervisor, x as routerBrain, y as createActivityLog } from "./supervisor-DzQu5Ydu.js";
4
+ import { C as buildLoopSpanNodes, Ct as controlProfileMaterialization, Dt as promptControlProfileMaterialization, E as createOtelExporter, Et as profileMaterializationAxes, Ot as promptModelProfileMaterialization, Pt as worktreeCliProfileMaterialization, Q as assertValidBudget, St as assertProfileMaterialization, Tt as fullProfileMaterialization, W as createActivityLog, X as DEFAULT_SUCCESSFUL_SHUTDOWN_MS, Z as teardownExecutor, _t as worktreeProfileExecutionPlan, a as pickBestDelivered, at as runtimeOwnedExecutorExecutionBinding, bt as removeWorktree, c as driverChild, ct as routerBrain, d as deriveNodeExecutionIdentity, et as spendFromUsageEvents, f as recordScopeOwnerMaterialization, g as workerTraceEnv, gt as runWorktreeHarness, ht as runWorktreeChecks, it as newExecutionAttemptId, j as toOtelAttributes, k as generateSpanId, l as withDriverExecutor, n as createSupervisor, nt as attestRuntimeOwnedScopeOwner, o as runFinalizer, ot as runtimeOwnedExecutorMaterialization, p as scopeOwnerExecutorNodeContext, pt as runBrainLoop, q as freeSlots, r as bestDelivered, rt as inheritRuntimeOwnedExecutorAttestation, s as runTree, st as runtimeOwnedScopeOwnerRuntime, tt as attestRuntimeOwnedExecutor, ut as routerChatWithUsage, vt as captureWorktreeDiff, wt as defineProfileMaterializationContract, yt as createWorktree } from "./supervisor-CAXiCKnX.js";
5
5
  import { i as notifyRuntimeHookEvent, t as composeRuntimeHooks } from "./runtime-hooks-C7iJOWm3.js";
6
- import { a as notifySandboxEventObserver, n as extractLlmCallEvent } from "./sandbox-events-DeI5xX8P.js";
7
- import { a as createOtelExporter, c as generateSpanId, r as buildLoopSpanNodes, u as toOtelAttributes } from "./otel-export-CPZTSADj.js";
8
- import { i as resolveAgentEnvironmentProvider, n as providerAsExecutor, s as buildBackendOptions } from "./environment-provider-CCaEhA-l.js";
6
+ import { a as notifySandboxEventObserver, n as extractLlmCallEvent } from "./sandbox-events-Yhd1GYWl.js";
7
+ import { i as resolveAgentEnvironmentProvider, n as providerAsExecutor, r as providerAsSandboxClient, s as buildBackendOptions } from "./environment-provider-CzcEyRL7.js";
9
8
  import { t as createStdioToolServer } from "./tool-server-RcWgLIsL.js";
10
9
  import { n as UI_LENSES } from "./substrate-B0TYNrXn.js";
11
10
  import { argHash, computeFindingId, errorStreakDetector, estimateCost, isModelPriced, makeFinding, observeAll, repeatedActionDetector } from "@tangle-network/agent-eval";
12
- import { agentProfileSchema } from "@tangle-network/agent-interface";
11
+ import { agentProfileSchema, canonicalCandidateDigest, mergeAgentProfiles, validateAgentProfileSecurity } from "@tangle-network/agent-interface";
13
12
  import { randomUUID } from "node:crypto";
14
13
  import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
15
14
  import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
16
- import path, { dirname, isAbsolute, join, sep } from "node:path";
15
+ import path, { dirname, isAbsolute, join, resolve, sep } from "node:path";
17
16
  import { spawn } from "node:child_process";
18
17
  import { homedir, tmpdir } from "node:os";
19
18
  import { createServer, request } from "node:http";
@@ -21,6 +20,28 @@ import { request as request$1 } from "node:https";
21
20
  import { Readable, Writable } from "node:stream";
22
21
  //#region src/runtime/supervise/completion-gate.ts
23
22
  /**
23
+ *
24
+ * The completion-oracle: **settled ⟺ DELIVERED.**
25
+ *
26
+ * Foreman's one hard lesson (0/18 self-improvement deliverables) — "done" must mean a check
27
+ * PASSED, not the agent's say-so. `gateOnDeliverable` wraps an `Executor` so its settlement
28
+ * is `valid` ONLY when the deliverable check passes. The child still RUNS and settles (its
29
+ * spend is conserved into the pool either way), but a child that ran WITHOUT delivering
30
+ * settles `valid:false` — so a keep-best driver never counts it as done, and a gate never
31
+ * inflates with self-judged wins.
32
+ *
33
+ * Dual-purpose by construction:
34
+ * - product: the agent fleet only advances on real, checked deliverables.
35
+ * - proof: the gate's `valid` is the honest settle — equal-k comparisons can't be gamed by an
36
+ * arm that "ran" without producing the artifact.
37
+ *
38
+ * The check is a DEPLOYABLE oracle — a test command, a state verifier, the commit0 judge —
39
+ * read off the child's output, never the model judging itself. A throwing check is
40
+ * fail-closed (not delivered), never a crash.
41
+ *
42
+ * @experimental
43
+ */
44
+ /**
24
45
  * Wrap an `Executor` so its settlement `valid` reflects the deliverable check, not the
25
46
  * inner verdict. Handles both `execute` shapes (one-shot `Promise<ExecutorResult>` and
26
47
  * streaming `AsyncIterable<UsageEvent>` + `resultArtifact()`); the check runs once the inner
@@ -40,7 +61,22 @@ function gateOnDeliverable(inner, deliverable) {
40
61
  score: baseScore ?? (delivered ? 1 : 0)
41
62
  };
42
63
  };
43
- return {
64
+ /**
65
+ * Ask the delivery question once, from whatever the inner executor managed to produce.
66
+ *
67
+ * Fail-closed on the artifact being unavailable: an executor that never produced one delivered
68
+ * nothing, and leaving `gated` unset keeps the existing invalid-by-default reading.
69
+ */
70
+ const settleVerdict = async () => {
71
+ let art;
72
+ try {
73
+ art = inner.resultArtifact();
74
+ } catch {
75
+ return;
76
+ }
77
+ gated = await check(art.out, art.verdict?.score);
78
+ };
79
+ return inheritRuntimeOwnedExecutorAttestation(inner, {
44
80
  runtime: inner.runtime,
45
81
  ...inner.budgetExempt !== void 0 ? { budgetExempt: inner.budgetExempt } : {},
46
82
  ...inner.deliver ? { deliver: (m) => inner.deliver?.(m) } : {},
@@ -49,13 +85,21 @@ function gateOnDeliverable(inner, deliverable) {
49
85
  ...inner.metered ? { metered: () => inner.metered?.() } : {},
50
86
  execute(task, signal) {
51
87
  const r = inner.execute(task, signal);
52
- if (isAsyncIterable$1(r)) return (async function* () {
53
- for await (const ev of r) yield ev;
54
- const art = inner.resultArtifact();
55
- gated = await check(art.out, art.verdict?.score);
88
+ if (isAsyncIterable$2(r)) return (async function* () {
89
+ try {
90
+ for await (const ev of r) yield ev;
91
+ } finally {
92
+ await settleVerdict();
93
+ }
56
94
  })();
57
95
  return (async () => {
58
- const res = await r;
96
+ let res;
97
+ try {
98
+ res = await r;
99
+ } catch (error) {
100
+ await settleVerdict();
101
+ throw error;
102
+ }
59
103
  gated = await check(res.out, res.verdict?.score);
60
104
  return {
61
105
  ...res,
@@ -71,19 +115,281 @@ function gateOnDeliverable(inner, deliverable) {
71
115
  verdict: gated ?? art.verdict
72
116
  };
73
117
  }
74
- };
118
+ });
75
119
  }
76
- function isAsyncIterable$1(v) {
120
+ function isAsyncIterable$2(v) {
77
121
  return v != null && typeof v[Symbol.asyncIterator] === "function";
78
122
  }
79
123
  //#endregion
80
- //#region src/runtime/supervise/model-policy.ts
124
+ //#region src/runtime/supervise/authoring.ts
125
+ /**
126
+ *
127
+ * The supervisor's intelligence is AUTHORING the agents it spawns — not pressing buttons.
128
+ *
129
+ * Every agent here is three things: instructions (system prompt), tools, and a model — its
130
+ * `AgentProfile`. The supervisor's job is to WRITE those profiles: read the task, decompose it,
131
+ * and for each sub-task author a tailored worker recipe. `supervisorInstructions` is the how-to the
132
+ * supervisor reads (its system prompt); `authoredWorker` builds a worker AGENT from a profile the
133
+ * supervisor authored — the authored systemPrompt + model shape the worker's call.
134
+ *
135
+ * The skill is the single OPTIMIZABLE surface: edit it → the supervisor designs better agents.
136
+ * That is the self-improvement lever (the prompt/skill lever), not the execution plumbing.
137
+ *
138
+ * @experimental
139
+ */
140
+ /** Narrow an untyped `spawn_agent` profile argument to an `AuthoredProfile`, or null if the
141
+ * supervisor failed to author one (empty/placeholder profile — a skill violation worth catching). */
142
+ function asAuthoredProfile(raw) {
143
+ const parsed = agentProfileSchema.safeParse(raw);
144
+ if (!parsed.success) return null;
145
+ const systemPrompt = parsed.data.prompt?.systemPrompt;
146
+ if (typeof systemPrompt !== "string" || systemPrompt.trim().length === 0) return null;
147
+ return {
148
+ ...parsed.data,
149
+ name: typeof parsed.data.name === "string" && parsed.data.name.length > 0 ? parsed.data.name : "worker",
150
+ prompt: {
151
+ ...parsed.data.prompt,
152
+ systemPrompt
153
+ }
154
+ };
155
+ }
81
156
  /**
82
- * `assertModelAllowed` a fail-loud guard that restricts a run to a chosen subset of
83
- * models. The two front doors (`supervise()` / `improve()`) call it once per configured
84
- * model at resolve time, so a run that names a model outside the allowed set throws before
85
- * any compute is spent never silently swapped or silently allowed.
157
+ * Lift a profile the supervisor AUTHORED into the canonical shape every executor reads.
158
+ *
159
+ * The skill asks for `systemPrompt` and `model` as flat fields the vocabulary a model writes
160
+ * well while `AgentProfile` carries them as `prompt.systemPrompt` and `model.default`. Nothing
161
+ * downstream reads the flat form: the router and cli-bridge leaves read `profile.prompt
162
+ * .systemPrompt`, and the sandbox leaf hands the profile to a strict schema that REJECTS the flat
163
+ * key outright (`Unrecognized key: "systemPrompt"`), which fails the worker's every round. Lift
164
+ * both here, once, so what the supervisor writes is what the worker runs.
165
+ *
166
+ * Purely additive: a profile already canonical is returned untouched, and a flat field is dropped
167
+ * only after its canonical slot is filled. Both spellings of the same standing instruction, set to
168
+ * DIFFERENT text, is a contradiction with no safe reading — it fails loud, matching
169
+ * `resolveSupervisorProfile`'s rule for the supervisor's own profile.
86
170
  */
171
+ function canonicalizeAuthoredProfile(raw) {
172
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return raw ?? {};
173
+ const authored = { ...raw };
174
+ const flatPrompt = authored.systemPrompt;
175
+ if (typeof flatPrompt === "string" && flatPrompt.trim().length > 0) {
176
+ const prompt = authored.prompt && typeof authored.prompt === "object" && !Array.isArray(authored.prompt) ? { ...authored.prompt } : {};
177
+ const canonicalPrompt = prompt.systemPrompt;
178
+ if (typeof canonicalPrompt === "string" && canonicalPrompt !== flatPrompt) throw new ValidationError(`canonicalizeAuthoredProfile: prompt.systemPrompt and systemPrompt are both set and differ — they are the same standing instruction, so author exactly one (prompt.systemPrompt: ${JSON.stringify(canonicalPrompt.slice(0, 80))}; systemPrompt: ${JSON.stringify(flatPrompt.slice(0, 80))})`);
179
+ if (typeof canonicalPrompt !== "string") prompt.systemPrompt = flatPrompt;
180
+ authored.prompt = prompt;
181
+ delete authored.systemPrompt;
182
+ }
183
+ if (typeof authored.model === "string" && authored.model.trim().length > 0) authored.model = { default: authored.model };
184
+ return authored;
185
+ }
186
+ /** The supervisor SKILL — the how-to the supervisor reads (its system prompt). THE optimizable
187
+ * surface: editing this changes how the supervisor designs every agent it spawns. */
188
+ function supervisorInstructions(opts) {
189
+ return [
190
+ "You are a SUPERVISOR. You do NOT do the work yourself — your job is to DESIGN and DRIVE specialist worker agents.",
191
+ "",
192
+ "For the task you are given:",
193
+ "1. DECOMPOSE it into the smallest set of sub-tasks a single focused worker can each deliver.",
194
+ "2. For EACH sub-task, AUTHOR a worker by calling spawn_agent with a COMPLETE `profile`:",
195
+ " • name and description: who this specialist is and why it exists.",
196
+ " • prompt.systemPrompt: rich instructions for THIS sub-task — exact output, process, evidence, and what \"done\" means.",
197
+ " • model.default, model.reasoningEffort, and harness: choose the execution system deliberately when the task benefits from it.",
198
+ " • tools, mcp, resources.skills/files/instructions, hooks, subagents, permissions, and modes: grant or attach every capability the worker needs; omit an axis only when it is intentionally unnecessary.",
199
+ " • metadata.role=\"driver\" when this child should be a sub-supervisor that may author and drive its own children.",
200
+ " NEVER spawn a worker with an empty profile. The quality of the worker IS the quality of the profile you write.",
201
+ "3. await_event (kinds:['settled']) to collect each worker. Its result says valid:true only if the deployable check passed.",
202
+ "4. If a worker did NOT deliver, AUTHOR A NEW profile whose prompt.systemPrompt names the SPECIFIC failure and how to fix it — never just retry the same profile.",
203
+ "5. Stop (reply with no tool call) once the work is delivered. You cannot declare done yourself — only a delivered (valid:true) worker counts.",
204
+ ...opts?.goal ? ["", `The goal: ${opts.goal}`] : []
205
+ ].join("\n");
206
+ }
207
+ /** Build a router-only worker from an authored profile. This helper executes the prompt/model axes;
208
+ * use `workerFromBackend` for full materialization of tools, MCP, resources, hooks, and subagents. */
209
+ function authoredWorker(profile, opts) {
210
+ const model = profile.model?.default ?? opts.cfg.model;
211
+ const executorFactory = (spec, ctx) => {
212
+ let artifact;
213
+ const executionId = ctx.node?.nodeId ?? `authored-router-${profile.name}`;
214
+ const attemptId = ctx.node?.attemptId ?? newExecutionAttemptId(executionId);
215
+ return gateOnDeliverable(attestRuntimeOwnedExecutor({
216
+ runtime: "router",
217
+ async execute(_t, signal) {
218
+ const res = await routerChatWithUsage({
219
+ ...opts.cfg,
220
+ model
221
+ }, [{
222
+ role: "system",
223
+ content: profile.prompt.systemPrompt
224
+ }, {
225
+ role: "user",
226
+ content: opts.taskPrompt
227
+ }], {
228
+ temperature: opts.temperature ?? .4,
229
+ ...signal ? { signal } : {}
230
+ });
231
+ artifact = {
232
+ outRef: contentAddress(res.content),
233
+ out: res.content,
234
+ spent: {
235
+ iterations: 1,
236
+ tokens: res.usage ?? {
237
+ input: 0,
238
+ output: 0
239
+ },
240
+ usd: res.costUsd ?? 0,
241
+ ms: 0
242
+ }
243
+ };
244
+ return artifact;
245
+ },
246
+ teardown: () => Promise.resolve({ destroyed: true }),
247
+ resultArtifact: () => {
248
+ if (!artifact) throw new Error("authoredWorker: resultArtifact read before execute");
249
+ return artifact;
250
+ }
251
+ }, {
252
+ effectiveProfile: spec.profile,
253
+ backend: "router",
254
+ model: {
255
+ status: "known",
256
+ id: model
257
+ },
258
+ execution: {
259
+ kind: "request",
260
+ id: executionId
261
+ },
262
+ materializer: "authored-router-prompt",
263
+ plan: {
264
+ kind: "authored-router-completion",
265
+ model,
266
+ temperature: opts.temperature ?? .4,
267
+ taskPrompt: opts.taskPrompt
268
+ }
269
+ }, {
270
+ attemptId,
271
+ binding: {
272
+ endpoint: opts.cfg.routerBaseUrl,
273
+ executionId,
274
+ model
275
+ },
276
+ descriptor: {
277
+ kind: "router-request",
278
+ transport: "http",
279
+ backend: "router"
280
+ }
281
+ }), opts.deliverable);
282
+ };
283
+ const spec = {
284
+ profile,
285
+ harness: null,
286
+ executorFactory
287
+ };
288
+ return {
289
+ name: profile.name,
290
+ act: async () => "",
291
+ executorSpec: spec
292
+ };
293
+ }
294
+ /** Default thresholds for `ProfileRichnessThresholds` — 600 chars / 6 lines minimum system prompt. */
295
+ const defaultProfileRichnessThresholds = {
296
+ minSystemPromptChars: 600,
297
+ minSystemPromptLines: 6
298
+ };
299
+ /** Read the system prompt from any authored shape: canonical `prompt.systemPrompt`, the sandbox
300
+ * `prompt.system` convention, or a bare-string `prompt`. */
301
+ function resolveSystemPrompt(profile) {
302
+ const pr = profile.prompt;
303
+ if (typeof pr === "string") return pr;
304
+ if (pr && typeof pr === "object") {
305
+ const o = pr;
306
+ if (typeof o.systemPrompt === "string") return o.systemPrompt;
307
+ if (typeof o.system === "string") return o.system;
308
+ }
309
+ return "";
310
+ }
311
+ /** OBSERVE one authored `AgentProfile` and score its richness (no judge verdict is read). The task
312
+ * context (`needsMcp`) lets a domain say "this work needs a data/tool MCP" so a missing MCP counts. */
313
+ function assessAuthoredProfile(profile, opts) {
314
+ const th = {
315
+ ...defaultProfileRichnessThresholds,
316
+ ...opts?.thresholds ?? {}
317
+ };
318
+ const systemPrompt = resolveSystemPrompt(profile);
319
+ const trimmed = systemPrompt.trim();
320
+ const systemPromptChars = trimmed.length;
321
+ const systemPromptLines = trimmed ? trimmed.split("\n").filter((l) => l.trim().length > 0).length : 0;
322
+ const sentenceCount = trimmed ? (trimmed.match(/[.!?](\s|$)/g) ?? []).length || (trimmed ? 1 : 0) : 0;
323
+ const hasDescription = typeof profile.description === "string" && profile.description.trim().length > 0;
324
+ const tools = profile.tools;
325
+ const hasTools = !!tools && Object.keys(tools).length > 0;
326
+ const skills = profile.resources?.skills;
327
+ const hasSkills = Array.isArray(skills) && skills.length > 0;
328
+ const mcp = profile.mcp;
329
+ const hasMcp = !!mcp && Object.keys(mcp).length > 0;
330
+ const subagents = profile.subagents;
331
+ const hasSubagents = !!subagents && Object.keys(subagents).length > 0;
332
+ const reasons = [];
333
+ const promptThin = systemPromptChars < th.minSystemPromptChars || systemPromptLines < th.minSystemPromptLines;
334
+ if (promptThin) reasons.push(`system prompt is thin (${systemPromptChars} chars, ${systemPromptLines} lines; need ≥${th.minSystemPromptChars} chars and ≥${th.minSystemPromptLines} lines)`);
335
+ if (!hasTools) reasons.push("no tools granted (a worker can only act through the tools you grant it)");
336
+ if (!hasSkills) reasons.push("no skills attached (no reusable how-to notes injected)");
337
+ if (opts?.needsMcp && !hasMcp) reasons.push("no MCP server, but the task needs data/tool access");
338
+ const signals = [
339
+ !promptThin,
340
+ hasTools,
341
+ hasSkills,
342
+ hasDescription,
343
+ opts?.needsMcp ? hasMcp : true
344
+ ];
345
+ const richness = signals.filter(Boolean).length / signals.length;
346
+ const thin = promptThin || !hasTools && !hasSkills && !hasMcp;
347
+ return {
348
+ name: profile.name ?? "worker",
349
+ systemPrompt,
350
+ systemPromptChars,
351
+ systemPromptLines,
352
+ sentenceCount,
353
+ hasDescription,
354
+ hasTools,
355
+ hasSkills,
356
+ hasMcp,
357
+ hasSubagents,
358
+ richness,
359
+ thin,
360
+ reasons
361
+ };
362
+ }
363
+ /** Turn a {@link ProfileRichness} verdict into a bus-routable `AnalystFinding` (area `profile-quality`).
364
+ * Severity scales with thinness; the recommended action names the MISSING lever so the supervisor can
365
+ * re-author. `subject` = the worker name so per-worker findings diff cleanly across re-authors. */
366
+ function profileRichnessFinding(richness, opts) {
367
+ const analyst_id = opts?.analystId ?? "profile-richness";
368
+ const subject = richness.name;
369
+ const claim = richness.thin ? `Worker "${richness.name}" was authored as a THIN profile: ${richness.reasons.join("; ")}.` : `Worker "${richness.name}" was authored as a rich profile (richness ${(richness.richness * 100).toFixed(0)}%).`;
370
+ return makeFinding({
371
+ analyst_id,
372
+ severity: richness.thin ? richness.richness < .25 ? "high" : "medium" : "info",
373
+ area: "profile-quality",
374
+ claim,
375
+ subject,
376
+ confidence: .9,
377
+ evidence_refs: [{
378
+ kind: "metric",
379
+ uri: `profile:${subject}`,
380
+ excerpt: `chars=${richness.systemPromptChars} lines=${richness.systemPromptLines} tools=${richness.hasTools} skills=${richness.hasSkills} mcp=${richness.hasMcp} richness=${richness.richness.toFixed(2)}`
381
+ }],
382
+ ...richness.thin ? { recommended_action: `Re-author "${richness.name}" with: ${richness.reasons.join("; ")}.` } : {},
383
+ id_basis: computeFindingId({
384
+ analyst_id,
385
+ area: "profile-quality",
386
+ subject,
387
+ claim: `richness:${richness.thin ? "thin" : "rich"}`
388
+ })
389
+ });
390
+ }
391
+ //#endregion
392
+ //#region src/runtime/supervise/model-policy.ts
87
393
  /**
88
394
  * Throw a `ConfigError` when `allowed` is set, `model` is defined, and `model` is not a
89
395
  * member of `allowed`. No-op when `allowed` is unset (the unrestricted default) or when
@@ -93,6 +399,14 @@ function assertModelAllowed(model, allowed) {
93
399
  if (!allowed || model === void 0) return;
94
400
  if (!allowed.includes(model)) throw new ConfigError(`model ${JSON.stringify(model)} is not in the allowed set ${JSON.stringify([...allowed])}`);
95
401
  }
402
+ /** Check every canonical model-bearing field in a complete profile, including the models a
403
+ * backend may select for cheap work, named subagents, or modes. */
404
+ function assertProfileModelsAllowed(profile, allowed) {
405
+ assertModelAllowed(profile.model?.default, allowed);
406
+ assertModelAllowed(profile.model?.small, allowed);
407
+ for (const subagent of Object.values(profile.subagents ?? {})) assertModelAllowed(subagent.model, allowed);
408
+ for (const mode of Object.values(profile.modes ?? {})) assertModelAllowed(mode.model, allowed);
409
+ }
96
410
  //#endregion
97
411
  //#region src/runtime/supervise/otel-spans.ts
98
412
  /**
@@ -282,6 +596,12 @@ function createSupervisorSpanRecorder(opts) {
282
596
  } },
283
597
  traceId,
284
598
  rootSpanId,
599
+ workerTrace(spawningNodeId) {
600
+ return {
601
+ traceId,
602
+ parentSpanId: spanIdOf.get(spawningNodeId) ?? rootSpanId
603
+ };
604
+ },
285
605
  async finish(outcome) {
286
606
  if (finished) return;
287
607
  finished = true;
@@ -397,59 +717,96 @@ function truncate(value) {
397
717
  }
398
718
  //#endregion
399
719
  //#region src/runtime/supervise/coordination-log.ts
400
- /** Should this bus event be persisted? Questions and findings ARE the prior context a resumed
401
- * driver needs; answers fold their status; everything else has a better ledger or none. */
720
+ /**
721
+ * Durable side-log for coordination evidence the spawn journal does not own: questions, analyst
722
+ * findings, answer decisions, authorized continuation receipts, delivery-attempt markers, and
723
+ * delivery outcomes. A durable run
724
+ * (`supervise({ runDir })`) appends them as they publish and loads them on resume, so a restarted
725
+ * coordinator retains the exact evidence produced by prior processes.
726
+ *
727
+ * Answer down-events also fold status on load: a question answered before the crash reloads as
728
+ * `answered`, not as a re-blocking `open`. Settled events are skipped (the spawn journal is their
729
+ * ledger). A receipt followed by an attempt but no outcome proves the process died in the delivery
730
+ * window; that outcome remains unknown and no prior instruction is auto-delivered.
731
+ *
732
+ * JSONL, one fsynced record per event, keyed by `runId` — several runs may share one log file
733
+ * exactly as they share one spawn-journal file.
734
+ *
735
+ * @experimental
736
+ */
737
+ /** Persist prior context plus exact continuation authorization, attempt, and result evidence.
738
+ * Settlements have their own journal. */
402
739
  function persisted(event) {
403
- return event.type === "question" || event.type === "finding" || event.type === "answer";
740
+ return event.type !== "settled";
404
741
  }
405
742
  /** FS-backed `CoordinationLog`: append-only JSONL, fsynced per record. */
406
743
  var FileCoordinationLog = class {
407
744
  path;
745
+ appendTail = Promise.resolve();
408
746
  constructor(path) {
409
747
  this.path = path;
410
748
  }
411
- async append(runId, event, at) {
412
- if (!persisted(event)) return;
749
+ async append(runId, record, ownerId) {
750
+ if (!persisted(record.event)) return;
751
+ const append = this.appendTail.then(() => this.appendRecord(runId, record, ownerId));
752
+ this.appendTail = append.catch(() => void 0);
753
+ return append;
754
+ }
755
+ async appendRecord(runId, busRecord, ownerId) {
413
756
  const fs = await import("node:fs/promises");
414
757
  const path = await import("node:path");
415
758
  await fs.mkdir(path.dirname(this.path), { recursive: true });
416
759
  const record = {
417
760
  runId,
418
- at,
419
- event
761
+ ...ownerId !== void 0 ? { ownerId } : {},
762
+ ...busRecord
420
763
  };
764
+ const needsSeparator = await prepareJsonlAppend(this.path);
421
765
  const fh = await fs.open(this.path, "a");
422
766
  try {
423
- await fh.write(`${JSON.stringify(record)}\n`);
767
+ await writeAllBytes(fh, `${needsSeparator ? "\n" : ""}${JSON.stringify(record)}\n`);
424
768
  await fh.sync();
425
769
  } finally {
426
770
  await fh.close();
427
771
  }
428
772
  }
429
- async load(runId) {
773
+ async load(runId, ownerId) {
430
774
  const fs = await import("node:fs/promises");
431
775
  let text;
432
776
  try {
433
777
  text = await fs.readFile(this.path, "utf8");
434
778
  } catch (err) {
435
- if (isNoEntError(err)) return {
436
- questions: [],
437
- findings: []
438
- };
779
+ if (isNoEntError(err)) return emptyPriorCoordination(ownerId);
439
780
  throw err;
440
781
  }
441
782
  const byId = /* @__PURE__ */ new Map();
442
783
  const findings = [];
443
- for (const line of text.split("\n")) {
444
- if (line.length === 0) continue;
445
- const record = JSON.parse(line);
446
- if (record.runId !== runId) continue;
784
+ const continuations = [];
785
+ const deliveryEvidence = [];
786
+ const records = [];
787
+ let legacySeq = 0;
788
+ for (const stored of parseCommittedJsonLines(text, this.path)) {
789
+ if (stored.runId !== runId) continue;
790
+ if (ownerId !== void 0 && stored.ownerId !== ownerId) continue;
791
+ const record = "seq" in stored ? {
792
+ seq: stored.seq,
793
+ at: stored.at,
794
+ priority: stored.priority,
795
+ event: stored.event
796
+ } : {
797
+ seq: legacySeq++,
798
+ at: Date.parse(stored.at),
799
+ priority: 0,
800
+ event: stored.event
801
+ };
802
+ records.push(record);
447
803
  const ev = record.event;
804
+ if (ev.type === "delivery-attempt" || ev.type === "steer" || ev.type === "answer") deliveryEvidence.push(ev);
448
805
  if (ev.type === "question") byId.set(ev.question.id, ev.question);
449
806
  else if (ev.type === "finding") findings.push(ev.finding);
450
807
  else if (ev.type === "answer") {
451
808
  const prior = byId.get(ev.questionId);
452
- if (prior) byId.set(ev.questionId, {
809
+ if (prior && ev.down.delivered) byId.set(ev.questionId, {
453
810
  ...prior,
454
811
  status: "answered",
455
812
  decision: {
@@ -458,14 +815,28 @@ var FileCoordinationLog = class {
458
815
  by: "prior-run"
459
816
  }
460
817
  });
461
- }
818
+ } else if (ev.type === "instruction") continuations.push(ev.instruction);
462
819
  }
463
820
  return {
821
+ ...ownerId !== void 0 ? { ownerId } : {},
464
822
  questions: [...byId.values()],
465
- findings
823
+ findings,
824
+ continuations,
825
+ deliveryEvidence,
826
+ records
466
827
  };
467
828
  }
468
829
  };
830
+ function emptyPriorCoordination(ownerId) {
831
+ return {
832
+ ...ownerId !== void 0 ? { ownerId } : {},
833
+ questions: [],
834
+ findings: [],
835
+ continuations: [],
836
+ deliveryEvidence: [],
837
+ records: []
838
+ };
839
+ }
469
840
  function isNoEntError(err) {
470
841
  return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
471
842
  }
@@ -1556,9 +1927,10 @@ function createInbox() {
1556
1927
  return {
1557
1928
  deliver(msg) {
1558
1929
  const m = parseDown(msg);
1559
- if (!m) return;
1930
+ if (!m) return false;
1560
1931
  pending.push(m);
1561
1932
  if (m.interrupt && live && !live.signal.aborted) live.abort();
1933
+ return true;
1562
1934
  },
1563
1935
  drain() {
1564
1936
  return pending.splice(0, pending.length);
@@ -2215,8 +2587,8 @@ function sandboxSessionTraceSource(box, sessionId, opts = {}) {
2215
2587
  * | `profile.prompt.systemPrompt` | honored — prepended to the task text (pi RPC takes no separate system-prompt channel) |
2216
2588
  * | `profile.mcp` | honored — written to this execution's own file and passed as `--mcp-config` for `pi-mcp-adapter`; see `pi-mcp.ts` |
2217
2589
  * | `profile.extensions.pi.load` | honored — lowered to `--no-extensions` + `--extension <abs>` |
2218
- * | `profile.prompt.instructions` | DROPPEDfold into `systemPrompt` before calling |
2219
- * | `profile.model` | DROPPED — the seam's `model` is the only model channel; a profile that disagrees with the seam is silently overridden by the seam |
2590
+ * | `profile.prompt.instructions` | honoredappended to the system prompt, one per line |
2591
+ * | `profile.model.default` | honoredoverrides the seam's `model`; the seam is the fallback for profiles that select none |
2220
2592
  * | `profile.model.reasoningEffort` | DROPPED — no `--thinking` flag is emitted, so pi's configured `defaultThinkingLevel` applies |
2221
2593
  * | `profile.tools` | DROPPED — no `--no-tools` / allow-deny mapping; pi runs its full builtin tool set |
2222
2594
  * | `profile.permissions` | DROPPED |
@@ -2237,11 +2609,17 @@ const PI_RUNTIME = "pi";
2237
2609
  const piSeamKey = "pi";
2238
2610
  /** Build the `Executor` for one pi worker. Registered as runtime `'pi'`. */
2239
2611
  const piExecutor = (spec, ctx) => {
2240
- const seam = readPiSeam(ctx);
2612
+ const seam = {
2613
+ ...readPiSeam(ctx),
2614
+ ...spec.profile.model?.default ? { model: spec.profile.model.default } : {}
2615
+ };
2616
+ const traceEnv = workerTraceEnv(ctx);
2241
2617
  const inbox = createInbox();
2242
2618
  const activity = createActivityLog(seam.activityWindow ?? 12);
2243
2619
  const runId = `pi-${spec.profile.name ?? "worker"}-${Date.now()}`;
2244
2620
  const trace = createPushTraceSource({ runId });
2621
+ const executionId = ctx.node?.nodeId ?? `pi-run-${randomUUID()}`;
2622
+ const attemptId = ctx.node?.attemptId ?? newExecutionAttemptId(executionId);
2245
2623
  const derived = [];
2246
2624
  const controller = new AbortController();
2247
2625
  const cascade = () => controller.abort();
@@ -2254,7 +2632,7 @@ const piExecutor = (spec, ctx) => {
2254
2632
  proc: void 0,
2255
2633
  artifact: void 0
2256
2634
  };
2257
- return {
2635
+ const executor = {
2258
2636
  runtime: "pi",
2259
2637
  deliver: (m) => inbox.deliver(m),
2260
2638
  progress: () => ({
@@ -2271,6 +2649,7 @@ const piExecutor = (spec, ctx) => {
2271
2649
  signal,
2272
2650
  controller,
2273
2651
  seam,
2652
+ traceEnv,
2274
2653
  spec,
2275
2654
  runId,
2276
2655
  inbox,
@@ -2294,6 +2673,44 @@ const piExecutor = (spec, ctx) => {
2294
2673
  return state.artifact;
2295
2674
  }
2296
2675
  };
2676
+ if (ctx.node === void 0) return executor;
2677
+ return attestRuntimeOwnedExecutor(executor, {
2678
+ effectiveProfile: spec.profile,
2679
+ backend: "pi",
2680
+ model: seam.model ? {
2681
+ status: "known",
2682
+ id: seam.model
2683
+ } : {
2684
+ status: "unknown",
2685
+ reason: "pi selected its configured default model"
2686
+ },
2687
+ execution: {
2688
+ kind: "run",
2689
+ id: executionId
2690
+ },
2691
+ materializer: "pi-rpc-agent-profile",
2692
+ plan: {
2693
+ kind: "pi-rpc-session",
2694
+ bin: seam.bin ?? "pi",
2695
+ args: seam.args ?? [],
2696
+ cwd: seam.cwd ?? null,
2697
+ model: seam.model ?? null,
2698
+ turnTimeoutMs: seam.turnTimeoutMs ?? null
2699
+ }
2700
+ }, {
2701
+ attemptId,
2702
+ binding: {
2703
+ executionId,
2704
+ bin: seam.bin ?? "pi",
2705
+ cwd: seam.cwd ?? null,
2706
+ model: seam.model ?? null
2707
+ },
2708
+ descriptor: {
2709
+ kind: "pi-rpc-run",
2710
+ transport: "process",
2711
+ backend: "pi"
2712
+ }
2713
+ });
2297
2714
  };
2298
2715
  /**
2299
2716
  * One pi RPC session, run to `agent_settled`. Every steer delivered while the turn is in flight is
@@ -2310,6 +2727,7 @@ async function* streamPiSession(args) {
2310
2727
  };
2311
2728
  let usd = 0;
2312
2729
  let usdKnown = true;
2730
+ let tokensKnown = true;
2313
2731
  throwIfAborted(args.signal);
2314
2732
  throwIfAborted(args.controller.signal);
2315
2733
  const piMcp = preparePiMcp(args.spec.profile, {
@@ -2329,7 +2747,7 @@ async function* streamPiSession(args) {
2329
2747
  }
2330
2748
  let proc;
2331
2749
  try {
2332
- proc = spawnPi(seam, piMcp.args);
2750
+ proc = spawnPi(seam, piMcp.args, args.traceEnv);
2333
2751
  } catch (spawnFailure) {
2334
2752
  piMcp.mount?.cleanup();
2335
2753
  throw spawnFailure;
@@ -2376,7 +2794,7 @@ async function* streamPiSession(args) {
2376
2794
  };
2377
2795
  args.signal.addEventListener("abort", abortAll, { once: true });
2378
2796
  args.controller.signal.addEventListener("abort", abortAll, { once: true });
2379
- const system = args.spec.profile.prompt?.systemPrompt;
2797
+ const system = [args.spec.profile.prompt?.systemPrompt, ...args.spec.profile.prompt?.instructions ?? []].filter((line) => typeof line === "string" && line.trim().length > 0).join("\n");
2380
2798
  const opening = system ? `${system}\n\n${taskText(args.task)}` : taskText(args.task);
2381
2799
  const deadline = seam.turnTimeoutMs ? Date.now() + seam.turnTimeoutMs : void 0;
2382
2800
  const sendPrompt = (message, streamingBehavior) => {
@@ -2406,6 +2824,7 @@ async function* streamPiSession(args) {
2406
2824
  }
2407
2825
  const projected = projectPiEvent(ev, args, tokens, pendingTools);
2408
2826
  if (projected.assistant) lastAssistant = projected.assistant;
2827
+ if (projected.tokensUnknown) tokensKnown = false;
2409
2828
  for (const usage of projected.events) {
2410
2829
  if (usage.kind === "cost") {
2411
2830
  usd += usage.usd;
@@ -2459,6 +2878,7 @@ async function* streamPiSession(args) {
2459
2878
  const spent = {
2460
2879
  iterations: state.turns,
2461
2880
  tokens,
2881
+ ...tokensKnown ? {} : { tokensKnown: false },
2462
2882
  usd,
2463
2883
  ...usdKnown ? {} : { usdKnown: false },
2464
2884
  ms: Date.now() - started
@@ -2562,9 +2982,11 @@ function projectPiEvent(ev, args, tokens, pendingTools) {
2562
2982
  });
2563
2983
  out.push({ kind: "iteration" });
2564
2984
  const assistant = readAssistantOutcome(ev.message);
2985
+ const tokensUnknown = !usage || usage.tokensKnown === false;
2565
2986
  return {
2566
2987
  events: out,
2567
- ...assistant ? { assistant } : {}
2988
+ ...assistant ? { assistant } : {},
2989
+ ...tokensUnknown ? { tokensUnknown: true } : {}
2568
2990
  };
2569
2991
  }
2570
2992
  return { events: out };
@@ -2577,14 +2999,18 @@ function readUsage(message) {
2577
2999
  const usage = message.usage;
2578
3000
  if (!usage || typeof usage !== "object") return void 0;
2579
3001
  const u = usage;
2580
- const input = num(u.prompt_tokens) ?? (num(u.input) ?? num(u.inputTokens) ?? 0) + (num(u.cacheRead) ?? num(u.cache_read_input_tokens) ?? num(u.cacheReadInputTokens) ?? 0) + (num(u.cacheWrite) ?? num(u.cache_creation_input_tokens) ?? num(u.cacheCreationInputTokens) ?? 0);
2581
- const output = num(u.output) ?? num(u.outputTokens) ?? num(u.completion_tokens) ?? 0;
3002
+ const promptTokens = num(u.prompt_tokens);
3003
+ const freshInput = num(u.input) ?? num(u.inputTokens);
3004
+ const outputRaw = num(u.output) ?? num(u.outputTokens) ?? num(u.completion_tokens);
3005
+ const input = promptTokens ?? (freshInput ?? 0) + (num(u.cacheRead) ?? num(u.cache_read_input_tokens) ?? num(u.cacheReadInputTokens) ?? 0) + (num(u.cacheWrite) ?? num(u.cache_creation_input_tokens) ?? num(u.cacheCreationInputTokens) ?? 0);
3006
+ const output = outputRaw ?? 0;
2582
3007
  const costRaw = u.cost;
2583
3008
  const reportedUsd = num(costRaw) ?? (costRaw && typeof costRaw === "object" ? num(costRaw.total) ?? num(costRaw.totalCost) : void 0);
2584
3009
  return {
2585
3010
  input,
2586
3011
  output,
2587
- ...reportedUsd !== void 0 && reportedUsd > 0 ? { usd: reportedUsd } : {}
3012
+ ...reportedUsd !== void 0 && reportedUsd > 0 ? { usd: reportedUsd } : {},
3013
+ tokensKnown: promptTokens !== void 0 || freshInput !== void 0 || outputRaw !== void 0
2588
3014
  };
2589
3015
  }
2590
3016
  function readAssistantOutcome(message) {
@@ -2649,8 +3075,14 @@ function taskText(task) {
2649
3075
  * the profile-derived extension flags (`--no-extensions` / `--extension`). Seam args go LAST so an
2650
3076
  * operator's explicit flag wins over a derived one under pi's last-flag-wins parsing; RPC mode has
2651
3077
  * no positional prompt, so nothing here has to precede an argument.
3078
+ *
3079
+ * `traceEnv` is the inherited `TRACE_ID` / `PARENT_SPAN_ID` pair (empty when the run records no
3080
+ * spans). It sits ABOVE the supervisor's ambient `process.env` — a supervisor that was itself
3081
+ * launched as someone's worker holds ids describing ITS place in an outer trace, which are the
3082
+ * wrong parent for this child — and BELOW `seam.env`, so an operator who sets either id explicitly
3083
+ * still wins. See `worker-trace.ts` for the full precedence rule.
2652
3084
  */
2653
- function spawnPi(seam, profileArgs = []) {
3085
+ function spawnPi(seam, profileArgs = [], traceEnv = {}) {
2654
3086
  const bin = seam.bin ?? "pi";
2655
3087
  const argv = ["--mode", "rpc"];
2656
3088
  if (seam.model) {
@@ -2664,6 +3096,7 @@ function spawnPi(seam, profileArgs = []) {
2664
3096
  ...seam.cwd ? { cwd: seam.cwd } : {},
2665
3097
  env: {
2666
3098
  ...process.env,
3099
+ ...traceEnv,
2667
3100
  ...seam.env ?? {}
2668
3101
  },
2669
3102
  stdio: [
@@ -2810,7 +3243,10 @@ function createSteerableSandboxSession(args) {
2810
3243
  profile: args.profile,
2811
3244
  taskToPrompt: args.taskToPrompt,
2812
3245
  name: args.profile.name ?? String(args.harness),
2813
- sandboxOverrides: { backend: { type: args.harness } }
3246
+ sandboxOverrides: {
3247
+ backend: { type: args.harness },
3248
+ ...args.traceEnv && Object.keys(args.traceEnv).length > 0 ? { env: args.traceEnv } : {}
3249
+ }
2814
3250
  };
2815
3251
  const promptOptions = readPromptOptions(args.loopCtx);
2816
3252
  const started = now();
@@ -3009,34 +3445,38 @@ function readPromptOptions(loopCtx) {
3009
3445
  * Build a worktree-CLI leaf `Executor`. Per-spawn (a fresh worktree + abort + teardown each), so a
3010
3446
  * fanout of N profiles = N parallel worktrees that never clobber each other.
3011
3447
  *
3012
- * Fail-loud: an empty `repoRoot`/`harness`/`taskPrompt` throws at construction. `resultArtifact()`
3013
- * before `execute()` resolves throws.
3448
+ * Fail-loud: an empty `repoRoot`/`harness` or an explicitly empty `taskPrompt` throws at
3449
+ * construction. Calling `execute(undefined, signal)` without a configured prompt throws before a
3450
+ * worktree is created. `resultArtifact()` before `execute()` resolves throws.
3014
3451
  *
3015
3452
  * @experimental
3016
3453
  */
3017
3454
  function createWorktreeCliExecutor(options) {
3018
3455
  if (!options.repoRoot) throw new ValidationError("createWorktreeCliExecutor: repoRoot required");
3019
3456
  if (!options.harness) throw new ValidationError("createWorktreeCliExecutor: harness required");
3020
- if (typeof options.taskPrompt !== "string" || options.taskPrompt.length === 0) throw new ValidationError("createWorktreeCliExecutor: taskPrompt required");
3457
+ if (options.taskPrompt !== void 0 && (typeof options.taskPrompt !== "string" || options.taskPrompt.length === 0)) throw new ValidationError("createWorktreeCliExecutor: taskPrompt required");
3021
3458
  if (options.codexReproducible && options.harness !== "codex") throw new ValidationError("createWorktreeCliExecutor: codexReproducible requires harness \"codex\"");
3022
3459
  if (options.codexReproducible && options.budgetExempt === true) throw new ValidationError("createWorktreeCliExecutor: codexReproducible cannot be budgetExempt");
3023
3460
  if (options.codexReadDeniedPaths !== void 0 && !options.codexReproducible) throw new ValidationError("createWorktreeCliExecutor: codexReadDeniedPaths requires codexReproducible");
3024
3461
  const runId = options.runId ?? randomUUID();
3462
+ const attemptId = options.executionAttemptId ?? newExecutionAttemptId(runId);
3025
3463
  const controller = new AbortController();
3026
3464
  const budgetExempt = options.budgetExempt ?? !options.codexReproducible;
3027
3465
  let run;
3028
3466
  let artifact;
3029
- return {
3467
+ const profilePlan = worktreeProfileExecutionPlan(options.profile, options.harness);
3468
+ return attestRuntimeOwnedExecutor({
3030
3469
  runtime: "cli",
3031
3470
  budgetExempt,
3032
- async execute(_task, signal) {
3471
+ async execute(task, signal) {
3033
3472
  const linked = linkSignals$1(signal, controller.signal);
3034
3473
  const started = Date.now();
3474
+ const taskPrompt = executionTaskPrompt(task, options.taskPrompt);
3035
3475
  run = await runWorktreeHarness({
3036
3476
  repoRoot: options.repoRoot,
3037
3477
  profile: options.profile,
3038
3478
  harness: options.harness,
3039
- taskPrompt: options.taskPrompt,
3479
+ taskPrompt,
3040
3480
  runId,
3041
3481
  ...options.baseRef ? { baseRef: options.baseRef } : {},
3042
3482
  ...options.testCmd !== void 0 ? { testCmd: options.testCmd } : {},
@@ -3091,7 +3531,65 @@ function createWorktreeCliExecutor(options) {
3091
3531
  if (!artifact) throw new ValidationError("createWorktreeCliExecutor: resultArtifact() read before execute() resolved");
3092
3532
  return artifact;
3093
3533
  }
3094
- };
3534
+ }, {
3535
+ effectiveProfile: options.profile,
3536
+ backend: `cli-worktree:${options.harness}`,
3537
+ model: options.profile.model?.default ? {
3538
+ status: "known",
3539
+ id: options.profile.model.default
3540
+ } : {
3541
+ status: "unknown",
3542
+ reason: `${options.harness} selected its configured default model`
3543
+ },
3544
+ execution: {
3545
+ kind: "worktree-run",
3546
+ id: runId
3547
+ },
3548
+ materializer: "agent-profile-worktree-plan",
3549
+ plan: {
3550
+ kind: "worktree-cli",
3551
+ profilePlan,
3552
+ harness: options.harness,
3553
+ baseRef: options.baseRef ?? "HEAD",
3554
+ harnessTimeoutMs: options.harnessTimeoutMs ?? null,
3555
+ codexReproducible: options.codexReproducible === true,
3556
+ codexReadDeniedPaths: options.codexReadDeniedPaths ?? [],
3557
+ testCmd: options.testCmd ?? null,
3558
+ typecheckCmd: options.typecheckCmd ?? null,
3559
+ checkTimeoutMs: options.checkTimeoutMs ?? null,
3560
+ checkOutputCap: options.checkOutputCap ?? 16e3
3561
+ }
3562
+ }, {
3563
+ attemptId,
3564
+ binding: {
3565
+ repoRoot: options.repoRoot,
3566
+ runId,
3567
+ harness: options.harness,
3568
+ model: options.profile.model?.default ?? null,
3569
+ baseRef: options.baseRef ?? "HEAD"
3570
+ },
3571
+ descriptor: {
3572
+ kind: "worktree-cli-run",
3573
+ transport: "process",
3574
+ backend: options.harness
3575
+ }
3576
+ });
3577
+ }
3578
+ /** A scoped execution task is authoritative. The configured prompt remains only as the
3579
+ * unambiguous direct-call default for existing `execute(undefined, signal)` consumers. */
3580
+ function executionTaskPrompt(task, configuredPrompt) {
3581
+ if (task === void 0) {
3582
+ if (configuredPrompt !== void 0) return configuredPrompt;
3583
+ throw new ValidationError("createWorktreeCliExecutor: execute task required when taskPrompt is not configured");
3584
+ }
3585
+ if (typeof task === "string") return task;
3586
+ try {
3587
+ const encoded = JSON.stringify(task);
3588
+ if (encoded !== void 0) return encoded;
3589
+ } catch (error) {
3590
+ throw new ValidationError("createWorktreeCliExecutor: execute task must be JSON-serializable", { cause: error });
3591
+ }
3592
+ throw new ValidationError("createWorktreeCliExecutor: execute task must be JSON-serializable");
3095
3593
  }
3096
3594
  /** Link two abort signals into one that fires when either does. Returns `undefined` when neither
3097
3595
  * is present so the harness runner gets no signal at all. */
@@ -3178,7 +3676,7 @@ function zeroSpend() {
3178
3676
  */
3179
3677
  const routerInlineExecutor = (spec, ctx) => {
3180
3678
  const seam = readSeam(ctx, routerSeamKey, "router/inline");
3181
- const model = seam.model ?? spec.profile.model?.default;
3679
+ const model = spec.profile.model?.default ?? seam.model;
3182
3680
  if (!model) throw new ValidationError("routerInlineExecutor: no model — set RouterSeam.model or AgentProfile.model.default");
3183
3681
  if (!seam.routerBaseUrl || !seam.routerKey) throw new ValidationError("routerInlineExecutor: RouterSeam.routerBaseUrl + routerKey required");
3184
3682
  const controller = new AbortController();
@@ -3188,7 +3686,9 @@ const routerInlineExecutor = (spec, ctx) => {
3188
3686
  abortIfSignalled();
3189
3687
  if (!ctx.signal.aborted) ctx.signal.addEventListener("abort", abortIfSignalled, { once: true });
3190
3688
  let artifact;
3191
- return {
3689
+ const executionId = ctx.node?.nodeId ?? `router-request-${randomUUID()}`;
3690
+ const attemptId = ctx.node?.attemptId ?? newExecutionAttemptId(executionId);
3691
+ return attestRuntimeOwnedExecutor({
3192
3692
  runtime: "router",
3193
3693
  async execute(task, signal) {
3194
3694
  const messages = taskToMessages(task, spec);
@@ -3206,6 +3706,8 @@ const routerInlineExecutor = (spec, ctx) => {
3206
3706
  output: r.usage.output
3207
3707
  } : zeroTokenUsage(),
3208
3708
  usd: r.costUsd ?? 0,
3709
+ ...r.usage ? {} : { tokensKnown: false },
3710
+ ...r.costUsd === void 0 ? { usdKnown: false } : {},
3209
3711
  ms: Date.now() - started
3210
3712
  };
3211
3713
  const out = { content: r.content };
@@ -3230,7 +3732,35 @@ const routerInlineExecutor = (spec, ctx) => {
3230
3732
  spent: artifact.spent
3231
3733
  };
3232
3734
  }
3233
- };
3735
+ }, {
3736
+ effectiveProfile: spec.profile,
3737
+ backend: "router",
3738
+ model: {
3739
+ status: "known",
3740
+ id: model
3741
+ },
3742
+ execution: {
3743
+ kind: "request",
3744
+ id: executionId
3745
+ },
3746
+ materializer: "router-prompt-model",
3747
+ plan: {
3748
+ kind: "openai-chat-completion",
3749
+ model
3750
+ }
3751
+ }, {
3752
+ attemptId,
3753
+ binding: {
3754
+ endpoint: seam.routerBaseUrl,
3755
+ executionId,
3756
+ model
3757
+ },
3758
+ descriptor: {
3759
+ kind: "router-request",
3760
+ transport: "http",
3761
+ backend: "router"
3762
+ }
3763
+ });
3234
3764
  };
3235
3765
  const routerToolsSeamKey = "router-tools";
3236
3766
  /**
@@ -3239,7 +3769,7 @@ const routerToolsSeamKey = "router-tools";
3239
3769
  */
3240
3770
  const routerToolsInlineExecutor = (spec, ctx) => {
3241
3771
  const seam = readSeam(ctx, routerToolsSeamKey, "router-tools");
3242
- const model = seam.model ?? spec.profile.model?.default;
3772
+ const model = spec.profile.model?.default ?? seam.model;
3243
3773
  if (!model) throw new ValidationError("routerToolsInlineExecutor: no model — set RouterToolsSeam.model or AgentProfile.model.default");
3244
3774
  if (!seam.routerBaseUrl || !seam.routerKey) throw new ValidationError("routerToolsInlineExecutor: RouterToolsSeam.routerBaseUrl + routerKey required");
3245
3775
  const maxTurns = seam.maxTurns ?? 200;
@@ -3251,13 +3781,16 @@ const routerToolsInlineExecutor = (spec, ctx) => {
3251
3781
  if (!ctx.signal.aborted) ctx.signal.addEventListener("abort", abortIfSignalled, { once: true });
3252
3782
  const inbox = createInbox();
3253
3783
  let artifact;
3254
- return {
3784
+ const executionId = ctx.node?.nodeId ?? `router-tools-run-${randomUUID()}`;
3785
+ const attemptId = ctx.node?.attemptId ?? newExecutionAttemptId(executionId);
3786
+ return attestRuntimeOwnedExecutor({
3255
3787
  runtime: "router",
3256
3788
  deliver: (m) => inbox.deliver(m),
3257
3789
  async execute(task, signal) {
3258
3790
  const started = Date.now();
3259
3791
  const messages = [...taskToMessages(task, spec)];
3260
3792
  const tokens = zeroTokenUsage();
3793
+ let tokensKnown = true;
3261
3794
  let turns = 0;
3262
3795
  let lastText = "";
3263
3796
  const flush = () => {
@@ -3308,7 +3841,7 @@ const routerToolsInlineExecutor = (spec, ctx) => {
3308
3841
  if (u && typeof u.prompt_tokens === "number" && typeof u.completion_tokens === "number") {
3309
3842
  tokens.input += u.prompt_tokens;
3310
3843
  tokens.output += u.completion_tokens;
3311
- }
3844
+ } else tokensKnown = false;
3312
3845
  const msg = data.choices?.[0]?.message;
3313
3846
  if (msg?.content) lastText = msg.content;
3314
3847
  const toolCalls = msg?.tool_calls ?? [];
@@ -3370,11 +3903,14 @@ const routerToolsInlineExecutor = (spec, ctx) => {
3370
3903
  } catch {}
3371
3904
  }
3372
3905
  }
3373
- const usd = isModelPriced(model) ? estimateCost(tokens.input, tokens.output, model) : 0;
3906
+ const priced = isModelPriced(model);
3907
+ const usd = priced ? estimateCost(tokens.input, tokens.output, model) : 0;
3374
3908
  const spent = {
3375
3909
  iterations: turns,
3376
3910
  tokens,
3911
+ ...tokensKnown ? {} : { tokensKnown: false },
3377
3912
  usd,
3913
+ ...!priced || !tokensKnown ? { usdKnown: false } : {},
3378
3914
  ms: Date.now() - started
3379
3915
  };
3380
3916
  const out = { content: lastText };
@@ -3399,7 +3935,37 @@ const routerToolsInlineExecutor = (spec, ctx) => {
3399
3935
  spent: artifact.spent
3400
3936
  };
3401
3937
  }
3402
- };
3938
+ }, {
3939
+ effectiveProfile: spec.profile,
3940
+ backend: "router-tools",
3941
+ model: {
3942
+ status: "known",
3943
+ id: model
3944
+ },
3945
+ execution: {
3946
+ kind: "run",
3947
+ id: executionId
3948
+ },
3949
+ materializer: "router-tools-prompt-model",
3950
+ plan: {
3951
+ kind: "openai-tool-loop",
3952
+ model,
3953
+ maxTurns,
3954
+ tools: seam.tools
3955
+ }
3956
+ }, {
3957
+ attemptId,
3958
+ binding: {
3959
+ endpoint: seam.routerBaseUrl,
3960
+ executionId,
3961
+ model
3962
+ },
3963
+ descriptor: {
3964
+ kind: "router-tool-loop",
3965
+ transport: "http",
3966
+ backend: "router-tools"
3967
+ }
3968
+ });
3403
3969
  };
3404
3970
  /**
3405
3971
  * COMPOSES `runAgentRounds` as a single-task leaf: one box, a refine driver bounded to
@@ -3420,6 +3986,7 @@ const sandboxExecutor = (spec, ctx) => {
3420
3986
  if (!seam.sandboxClient || typeof seam.sandboxClient.create !== "function") throw new ValidationError("sandboxExecutor: SandboxSeam.sandboxClient.create required");
3421
3987
  const maxIterations = seam.maxIterations ?? 1;
3422
3988
  if (!Number.isFinite(maxIterations) || maxIterations <= 0) throw new ValidationError("sandboxExecutor: maxIterations must be > 0");
3989
+ const traceEnv = workerTraceEnv(ctx);
3423
3990
  const controller = new AbortController();
3424
3991
  const abortIfSignalled = () => {
3425
3992
  if (ctx.signal.aborted) controller.abort();
@@ -3427,6 +3994,43 @@ const sandboxExecutor = (spec, ctx) => {
3427
3994
  abortIfSignalled();
3428
3995
  if (!ctx.signal.aborted) ctx.signal.addEventListener("abort", abortIfSignalled, { once: true });
3429
3996
  let artifact;
3997
+ const executionId = ctx.node?.nodeId ?? `sandbox-run-${randomUUID()}`;
3998
+ const attemptId = ctx.node?.attemptId ?? newExecutionAttemptId(executionId);
3999
+ const sandboxMaterialization = {
4000
+ effectiveProfile: spec.profile,
4001
+ backend: harness,
4002
+ model: spec.profile.model?.default ? {
4003
+ status: "known",
4004
+ id: spec.profile.model.default
4005
+ } : {
4006
+ status: "unknown",
4007
+ reason: "sandbox harness selected its default model"
4008
+ },
4009
+ execution: {
4010
+ kind: "run",
4011
+ id: executionId
4012
+ },
4013
+ materializer: "sandbox-agent-profile",
4014
+ plan: {
4015
+ kind: "sandbox-agent-rounds",
4016
+ harness,
4017
+ maxIterations,
4018
+ steering: seam.steering !== void 0
4019
+ }
4020
+ };
4021
+ const sandboxBinding = {
4022
+ attemptId,
4023
+ binding: {
4024
+ executionId,
4025
+ harness,
4026
+ model: spec.profile.model?.default ?? null
4027
+ },
4028
+ descriptor: {
4029
+ kind: "sandbox-run",
4030
+ transport: "sandbox",
4031
+ backend: harness
4032
+ }
4033
+ };
3430
4034
  if (seam.steering) {
3431
4035
  const inbox = createInbox();
3432
4036
  const session = createSteerableSandboxSession({
@@ -3438,9 +4042,10 @@ const sandboxExecutor = (spec, ctx) => {
3438
4042
  taskToPrompt: (t) => taskToPrompt(t),
3439
4043
  options: seam.steering,
3440
4044
  ...seam.loopCtx ? { loopCtx: seam.loopCtx } : {},
4045
+ ...Object.keys(traceEnv).length > 0 ? { traceEnv } : {},
3441
4046
  contentRef
3442
4047
  });
3443
- return {
4048
+ return attestRuntimeOwnedExecutor({
3444
4049
  runtime: "sandbox",
3445
4050
  deliver: (m) => inbox.deliver(m),
3446
4051
  progress: () => session.progress(),
@@ -3458,13 +4063,13 @@ const sandboxExecutor = (spec, ctx) => {
3458
4063
  if (!a) throw new ValidationError("sandboxExecutor(steering): resultArtifact() read before stream drained");
3459
4064
  return a;
3460
4065
  }
3461
- };
4066
+ }, sandboxMaterialization, sandboxBinding);
3462
4067
  }
3463
4068
  const output = { parse(events) {
3464
4069
  return { events };
3465
4070
  } };
3466
4071
  const driver = singleShotDriver(maxIterations);
3467
- return {
4072
+ return attestRuntimeOwnedExecutor({
3468
4073
  runtime: "sandbox",
3469
4074
  execute(task, signal) {
3470
4075
  return streamSandboxLeaf({
@@ -3478,6 +4083,7 @@ const sandboxExecutor = (spec, ctx) => {
3478
4083
  maxIterations,
3479
4084
  controller,
3480
4085
  loopCtx: seam.loopCtx,
4086
+ traceEnv,
3481
4087
  onArtifact: (a) => {
3482
4088
  artifact = a;
3483
4089
  }
@@ -3491,7 +4097,7 @@ const sandboxExecutor = (spec, ctx) => {
3491
4097
  if (!artifact) throw new ValidationError("sandboxExecutor: resultArtifact() read before stream drained");
3492
4098
  return artifact;
3493
4099
  }
3494
- };
4100
+ }, sandboxMaterialization, sandboxBinding);
3495
4101
  };
3496
4102
  async function* streamSandboxLeaf(args) {
3497
4103
  const linked = new AbortController();
@@ -3505,7 +4111,10 @@ async function* streamSandboxLeaf(args) {
3505
4111
  profile: args.spec.profile,
3506
4112
  taskToPrompt: (t) => taskToPrompt(t),
3507
4113
  name: args.spec.profile.name ?? args.harness,
3508
- sandboxOverrides: { backend: { type: args.harness } }
4114
+ sandboxOverrides: {
4115
+ backend: { type: args.harness },
4116
+ ...Object.keys(args.traceEnv).length > 0 ? { env: args.traceEnv } : {}
4117
+ }
3509
4118
  };
3510
4119
  const started = Date.now();
3511
4120
  const loopOptions = {
@@ -3524,8 +4133,10 @@ async function* streamSandboxLeaf(args) {
3524
4133
  };
3525
4134
  try {
3526
4135
  const result = await runAgentRounds(loopOptions);
4136
+ const failure = failedRound(result);
4137
+ if (failure) throw failure;
3527
4138
  const out = result.winner?.output ?? { events: [] };
3528
- const verdict = result.winner?.verdict;
4139
+ const verdict = result.winner?.verdict ?? leafVerdict(result);
3529
4140
  const spent = {
3530
4141
  iterations: result.iterations.length,
3531
4142
  tokens: {
@@ -3559,16 +4170,45 @@ async function* streamSandboxLeaf(args) {
3559
4170
  args.controller.signal.removeEventListener("abort", cascade);
3560
4171
  }
3561
4172
  }
4173
+ /** The loop's own failure, when NO iteration produced an output: the first error it
4174
+ * recorded, renamed so the settled worker names the leaf it died in. `undefined`
4175
+ * when any iteration produced an output — a partly-failed round still has material
4176
+ * to settle on. */
4177
+ function failedRound(result) {
4178
+ if (result.iterations.length === 0) return void 0;
4179
+ if (result.iterations.some((iteration) => iteration.output !== void 0)) return void 0;
4180
+ const first = result.iterations.find((iteration) => iteration.error)?.error;
4181
+ if (!first) return void 0;
4182
+ return new Error(`sandboxExecutor: agent round failed — ${first.message}`, { cause: first });
4183
+ }
4184
+ /**
4185
+ * The leaf's OWN verdict, for a round the loop scored no validator against.
4186
+ *
4187
+ * `settled ⟺ delivered` is written by the completion oracle, and a caller that
4188
+ * passes one keeps it: `gateOnDeliverable` wraps this executor and overrides
4189
+ * `valid` from its check. This is the sandbox backend's structural answer for a
4190
+ * run with no oracle at all — without it nothing ever writes `valid`, no settled
4191
+ * child is ever DELIVERED, and the finalizer has nothing to select no matter how
4192
+ * well the worker ran. Structural, never self-reported: the harness completed a
4193
+ * round and returned an output artifact, or it did not.
4194
+ */
4195
+ function leafVerdict(result) {
4196
+ if (result.winner?.output === void 0) return void 0;
4197
+ return {
4198
+ valid: true,
4199
+ score: 1
4200
+ };
4201
+ }
3562
4202
  /**
3563
4203
  * Spawns a subprocess (`bin` + `args`). It cannot account tokens, so it is
3564
- * `budgetExempt: true`: its spend is NOT metered against the conserved pool and
3565
- * its iterations are EXCLUDED from the equal-k arms by construction (the
3566
- * resolver/equal-k path checks `budgetExempt`). teardown is SIGTERM → SIGKILL
4204
+ * `budgetExempt: true`: it remains usable as a direct executor, while budgeted supervision
4205
+ * refuses it before process execution because the CLI exposes no usage receipt. teardown is SIGTERM → SIGKILL
3567
4206
  * with a grace window. Streaming: yields one `iteration` event on clean exit.
3568
4207
  */
3569
4208
  const cliExecutor = (_spec, ctx) => {
3570
4209
  const seam = readSeam(ctx, cliSeamKey, "cli");
3571
4210
  if (!seam.bin) throw new ValidationError("cliExecutor: CliSeam.bin required");
4211
+ const traceEnv = workerTraceEnv(ctx);
3572
4212
  const controller = new AbortController();
3573
4213
  const abortIfSignalled = () => {
3574
4214
  if (ctx.signal.aborted) controller.abort();
@@ -3577,13 +4217,16 @@ const cliExecutor = (_spec, ctx) => {
3577
4217
  if (!ctx.signal.aborted) ctx.signal.addEventListener("abort", abortIfSignalled, { once: true });
3578
4218
  let proc;
3579
4219
  let artifact;
3580
- return {
4220
+ const executionId = ctx.node?.nodeId ?? `cli-process-${randomUUID()}`;
4221
+ const attemptId = ctx.node?.attemptId ?? newExecutionAttemptId(executionId);
4222
+ return attestRuntimeOwnedExecutor({
3581
4223
  runtime: "cli",
3582
4224
  budgetExempt: true,
3583
4225
  execute(task, signal) {
3584
4226
  return streamCliLeaf({
3585
4227
  task,
3586
4228
  signal,
4229
+ traceEnv,
3587
4230
  seam,
3588
4231
  controller,
3589
4232
  onProc: (p) => {
@@ -3603,7 +4246,39 @@ const cliExecutor = (_spec, ctx) => {
3603
4246
  if (!artifact) throw new ValidationError("cliExecutor: resultArtifact() read before stream drained");
3604
4247
  return artifact;
3605
4248
  }
3606
- };
4249
+ }, {
4250
+ effectiveProfile: _spec.profile,
4251
+ backend: "cli",
4252
+ model: {
4253
+ status: "unknown",
4254
+ reason: "raw subprocess has no model identity contract"
4255
+ },
4256
+ execution: {
4257
+ kind: "process-attempt",
4258
+ id: executionId
4259
+ },
4260
+ materializer: "raw-cli-stdin",
4261
+ plan: {
4262
+ kind: "raw-cli-process",
4263
+ bin: seam.bin,
4264
+ args: seam.args ?? [],
4265
+ cwd: seam.cwd ?? null,
4266
+ envOverrides: seam.env ?? {},
4267
+ ambientEnvironment: "inherited"
4268
+ }
4269
+ }, {
4270
+ attemptId,
4271
+ binding: {
4272
+ executionId,
4273
+ bin: seam.bin,
4274
+ cwd: seam.cwd ?? null
4275
+ },
4276
+ descriptor: {
4277
+ kind: "cli-process",
4278
+ transport: "process",
4279
+ backend: "cli"
4280
+ }
4281
+ });
3607
4282
  };
3608
4283
  async function* streamCliLeaf(args) {
3609
4284
  const prompt = taskToPrompt(args.task);
@@ -3611,6 +4286,7 @@ async function* streamCliLeaf(args) {
3611
4286
  ...args.seam.cwd ? { cwd: args.seam.cwd } : {},
3612
4287
  env: {
3613
4288
  ...process.env,
4289
+ ...args.traceEnv,
3614
4290
  ...args.seam.env ?? {}
3615
4291
  },
3616
4292
  stdio: [
@@ -3691,33 +4367,34 @@ function killWithGrace(proc, grace) {
3691
4367
  * - STEERABLE: the down-leg `inbox` is drained at each turn boundary; a queued
3692
4368
  * steer becomes the next turn's prompt on the same session, and the worker can't
3693
4369
  * settle while a steer it never read is pending (the sandbox/router contract).
3694
- * - ABORT: the caller signal + teardown fold into the per-turn fetch signal; a
3695
- * forceful (`interrupt`) steer aborts the in-flight turn so the worker re-plans.
4370
+ * - ABORT: reader abort only detaches HTTP. Interrupt/teardown then call the
4371
+ * bridge's explicit cancel operation and wait for the owned run to terminate.
3696
4372
  *
3697
4373
  * Reports REAL usage when the bridge surfaces it, never a fabricated cost.
3698
4374
  */
3699
- /** Resolve the bridge wire model for this spawn: a per-create `backend` override
3700
- * (harness + model) wins over the seam default, encoded as `${harness}/${model}`.
3701
- * Absent an override the seam `model` is used verbatim. */
3702
- function bridgeCellModel(seamModel, ctx) {
4375
+ /** Resolve the bridge wire model for this spawn. Per-create matrix settings win, then the
4376
+ * canonical profile's harness/model preferences, then the bridge's configured fallback. */
4377
+ function bridgeCellModel(seamModel, ctx, profile) {
3703
4378
  const backend = ctx.seams.createOptions?.backend;
3704
- const harness = backend?.type;
3705
- const model = backend?.model?.model;
4379
+ const profileHarness = profile.harness === "cli-base" ? void 0 : profile.harness;
4380
+ const harness = backend?.type ?? profileHarness;
4381
+ const model = backend?.model?.model ?? profile.model?.default;
3706
4382
  if (!harness && !model) return seamModel;
3707
- const h = harness ?? "";
3708
- const m = model ?? seamModel;
3709
- if (!h) return m;
3710
- return m.startsWith(`${h}/`) ? m : `${h}/${m}`;
4383
+ if (!harness) return model;
4384
+ if (model) return model.startsWith(`${harness}/`) ? model : `${harness}/${model}`;
4385
+ return seamModel?.startsWith(`${harness}/`) ? seamModel : void 0;
3711
4386
  }
3712
4387
  const bridgeExecutor = (spec, ctx) => {
3713
4388
  const base = readSeam(ctx, bridgeSeamKey, "bridge");
4389
+ const effectiveProfile = agentProfileSchema.parse(mergeAgentProfiles(spec.profile, base.agentProfile) ?? spec.profile);
3714
4390
  const seam = {
3715
4391
  ...base,
3716
- model: bridgeCellModel(base.model, ctx)
4392
+ model: bridgeCellModel(base.model, ctx, effectiveProfile)
3717
4393
  };
3718
- if (!seam.bridgeUrl || !seam.bridgeBearer || !seam.model) throw new ValidationError("bridgeExecutor: BridgeSeam.bridgeUrl + bridgeBearer + model required");
4394
+ if (!seam.bridgeUrl || !seam.bridgeBearer || !seam.model) throw new ValidationError("bridgeExecutor: bridgeUrl + bridgeBearer and a profile or bridge model are required");
3719
4395
  const maxTurns = seam.maxTurns ?? 200;
3720
4396
  const sessionId = seam.sessionId ?? `bridge-${spec.profile.name ?? "worker"}-${randomUUID()}`;
4397
+ const attemptId = ctx.node?.attemptId ?? newExecutionAttemptId(sessionId);
3721
4398
  const controller = new AbortController();
3722
4399
  const abortIfSignalled = () => {
3723
4400
  if (ctx.signal.aborted) controller.abort();
@@ -3726,27 +4403,31 @@ const bridgeExecutor = (spec, ctx) => {
3726
4403
  if (!ctx.signal.aborted) ctx.signal.addEventListener("abort", abortIfSignalled, { once: true });
3727
4404
  const inbox = createInbox();
3728
4405
  let artifact;
3729
- return {
4406
+ const activeRuns = /* @__PURE__ */ new Map();
4407
+ return attestRuntimeOwnedExecutor({
3730
4408
  runtime: "cli",
3731
4409
  deliver: (m) => inbox.deliver(m),
3732
4410
  execute(task, signal) {
3733
4411
  return streamBridgeSession({
3734
4412
  task,
3735
4413
  signal,
3736
- spec,
4414
+ profile: effectiveProfile,
3737
4415
  seam,
3738
4416
  sessionId,
3739
4417
  maxTurns,
3740
4418
  inbox,
3741
4419
  controller,
4420
+ activeRuns,
3742
4421
  onArtifact: (a) => {
3743
4422
  artifact = a;
3744
4423
  }
3745
4424
  });
3746
4425
  },
3747
- teardown(_grace) {
4426
+ async teardown(grace) {
3748
4427
  controller.abort();
3749
- return Promise.resolve({ destroyed: true });
4428
+ const remaining = [...activeRuns.values()].filter((run) => !run.terminal);
4429
+ if (remaining.length === 0) return { destroyed: true };
4430
+ return { destroyed: (await Promise.all(remaining.map((run) => cancelBridgeRunToTerminal(seam, run, grace)))).every(Boolean) };
3750
4431
  },
3751
4432
  resultArtifact() {
3752
4433
  if (!artifact) throw new ValidationError("bridgeExecutor: resultArtifact() read before stream drained");
@@ -3755,7 +4436,40 @@ const bridgeExecutor = (spec, ctx) => {
3755
4436
  spent: artifact.spent
3756
4437
  };
3757
4438
  }
3758
- };
4439
+ }, {
4440
+ effectiveProfile,
4441
+ backend: "bridge",
4442
+ model: {
4443
+ status: "known",
4444
+ id: seam.model
4445
+ },
4446
+ execution: {
4447
+ kind: "session",
4448
+ id: sessionId
4449
+ },
4450
+ materializer: "cli-bridge-agent-profile",
4451
+ plan: {
4452
+ kind: "cli-bridge-session",
4453
+ cwd: seam.cwd ?? null,
4454
+ maxTurns,
4455
+ timeoutMs: seam.timeoutMs ?? null,
4456
+ streaming: true
4457
+ }
4458
+ }, {
4459
+ attemptId,
4460
+ binding: {
4461
+ bridgeUrl: seam.bridgeUrl,
4462
+ cwd: seam.cwd ?? null,
4463
+ effectiveProfile,
4464
+ model: seam.model,
4465
+ sessionId
4466
+ },
4467
+ descriptor: {
4468
+ kind: "bridge-session",
4469
+ transport: "http",
4470
+ backend: "bridge"
4471
+ }
4472
+ });
3759
4473
  };
3760
4474
  /**
3761
4475
  * One resumable cli-bridge session, run as a streamed turn loop. Turn 0 sends the
@@ -3769,12 +4483,13 @@ async function* streamBridgeSession(args) {
3769
4483
  const started = Date.now();
3770
4484
  const external = mergeAbortSignals(args.signal, args.controller.signal);
3771
4485
  const tokens = zeroTokenUsage();
4486
+ let tokensKnown = true;
3772
4487
  let usd = 0;
4488
+ let usdKnown = true;
3773
4489
  let turns = 0;
3774
4490
  let lastText = "";
3775
4491
  const toolCalls = [];
3776
4492
  let nextPrompt = taskToPrompt(args.task);
3777
- const system = args.spec.profile.prompt?.systemPrompt;
3778
4493
  for (let t = 0; t < args.maxTurns; t += 1) {
3779
4494
  const pending = inbox.drain();
3780
4495
  if (pending.length) {
@@ -3783,10 +4498,6 @@ async function* streamBridgeSession(args) {
3783
4498
  }
3784
4499
  if (nextPrompt === void 0) break;
3785
4500
  const messages = [];
3786
- if (t === 0 && typeof system === "string" && system.length > 0) messages.push({
3787
- role: "system",
3788
- content: system
3789
- });
3790
4501
  messages.push({
3791
4502
  role: "user",
3792
4503
  content: nextPrompt
@@ -3798,45 +4509,46 @@ async function* streamBridgeSession(args) {
3798
4509
  if (external.aborted) turnController.abort();
3799
4510
  else external.addEventListener("abort", abortTurn);
3800
4511
  interruptSig.addEventListener("abort", abortTurn, { once: true });
3801
- const timer = seam.timeoutMs ? setTimeout(abortTurn, seam.timeoutMs) : void 0;
4512
+ let timedOut = false;
4513
+ const timer = seam.timeoutMs ? setTimeout(() => {
4514
+ timedOut = true;
4515
+ abortTurn();
4516
+ }, seam.timeoutMs) : void 0;
3802
4517
  const cleanup = () => {
3803
4518
  external.removeEventListener("abort", abortTurn);
3804
4519
  if (timer) clearTimeout(timer);
3805
4520
  };
3806
- let res;
3807
- try {
3808
- res = await bridgeStreamPost(seam.bridgeUrl, {
3809
- bearer: seam.bridgeBearer,
3810
- sessionId: args.sessionId,
3811
- body: {
3812
- model: seam.model,
3813
- stream: true,
3814
- session_id: args.sessionId,
3815
- ...seam.cwd ? { cwd: seam.cwd } : {},
3816
- ...seam.agentProfile ? { agent_profile: seam.agentProfile } : {},
3817
- messages
3818
- },
3819
- signal: turnController.signal
3820
- });
3821
- } catch (e) {
3822
- cleanup();
3823
- if (e instanceof DOMException && e.name === "AbortError" && interruptSig.aborted && !args.signal.aborted && !args.controller.signal.aborted) continue;
3824
- throw e;
3825
- }
3826
- if (!res.ok) {
3827
- cleanup();
3828
- throw new ValidationError(`bridgeExecutor: bridge ${res.status}: ${(await res.text()).slice(0, 300)}`);
3829
- }
3830
- if (!res.body) {
3831
- cleanup();
3832
- throw new ValidationError("bridgeExecutor: bridge response had no body to stream");
3833
- }
4521
+ const activeRun = {
4522
+ id: `bridge-run-${randomUUID()}`,
4523
+ lastEventId: 0,
4524
+ terminal: false
4525
+ };
4526
+ args.activeRuns.set(activeRun.id, activeRun);
4527
+ const requestBody = {
4528
+ model: seam.model,
4529
+ stream: true,
4530
+ run_id: activeRun.id,
4531
+ session_id: args.sessionId,
4532
+ ...seam.cwd ? { cwd: seam.cwd } : {},
4533
+ agent_profile: args.profile,
4534
+ messages
4535
+ };
3834
4536
  let turnText = "";
4537
+ let turnTokensKnown = false;
4538
+ let turnUsdKnown = false;
4539
+ let interrupted = false;
3835
4540
  try {
3836
- for await (const chunk of parseSseChatStream(res.body)) {
4541
+ for await (const chunk of streamDurableBridgeRun({
4542
+ seam,
4543
+ sessionId: args.sessionId,
4544
+ body: requestBody,
4545
+ signal: turnController.signal,
4546
+ run: activeRun
4547
+ })) {
3837
4548
  if (chunk.content) turnText += chunk.content;
3838
4549
  if (chunk.toolCall) toolCalls.push(chunk.toolCall);
3839
4550
  if (chunk.usage) {
4551
+ turnTokensKnown = true;
3840
4552
  tokens.input += chunk.usage.input;
3841
4553
  tokens.output += chunk.usage.output;
3842
4554
  yield {
@@ -3845,26 +4557,43 @@ async function* streamBridgeSession(args) {
3845
4557
  output: chunk.usage.output
3846
4558
  };
3847
4559
  }
3848
- if (typeof chunk.cost === "number" && chunk.cost > 0) {
3849
- usd += chunk.cost;
3850
- yield {
3851
- kind: "cost",
3852
- usd: chunk.cost
3853
- };
4560
+ if (typeof chunk.cost === "number") {
4561
+ turnUsdKnown = true;
4562
+ if (chunk.cost > 0) {
4563
+ usd += chunk.cost;
4564
+ yield {
4565
+ kind: "cost",
4566
+ usd: chunk.cost
4567
+ };
4568
+ }
3854
4569
  }
3855
4570
  }
4571
+ } catch (error) {
4572
+ if (interruptSig.aborted && !args.signal.aborted && !args.controller.signal.aborted) {
4573
+ if (!await cancelBridgeRunToTerminal(seam, activeRun, "infinity", external)) throw new ValidationError(`bridgeExecutor: interrupted run ${activeRun.id} did not reach terminal state`);
4574
+ interrupted = true;
4575
+ } else {
4576
+ if (timedOut && !activeRun.terminal) await requestBridgeRunCancellation(seam, activeRun, 0);
4577
+ throw error;
4578
+ }
3856
4579
  } finally {
3857
4580
  cleanup();
3858
4581
  }
4582
+ if (interruptSig.aborted && !args.signal.aborted && !args.controller.signal.aborted) interrupted = true;
3859
4583
  turns += 1;
4584
+ if (!turnTokensKnown) tokensKnown = false;
4585
+ if (!turnUsdKnown) usdKnown = false;
3860
4586
  yield { kind: "iteration" };
3861
- if (turnText) lastText = turnText;
4587
+ if (!interrupted && turnText) lastText = turnText;
4588
+ if (interrupted) continue;
3862
4589
  if (inbox.pending() === 0) break;
3863
4590
  }
3864
4591
  const spent = {
3865
4592
  iterations: turns,
3866
4593
  tokens,
4594
+ ...tokensKnown ? {} : { tokensKnown: false },
3867
4595
  usd,
4596
+ ...usdKnown ? {} : { usdKnown: false },
3868
4597
  ms: Date.now() - started
3869
4598
  };
3870
4599
  const out = {
@@ -3881,6 +4610,69 @@ async function* streamBridgeSession(args) {
3881
4610
  spent
3882
4611
  });
3883
4612
  }
4613
+ const BRIDGE_MAX_RECONNECTS = 3;
4614
+ const BRIDGE_CANCEL_LONG_POLL_MS = 3e4;
4615
+ const BRIDGE_BRUTAL_KILL_WAIT_MS = 150;
4616
+ /**
4617
+ * Drain one server-owned bridge run. A transport loss replays from the last
4618
+ * contiguous event id under the SAME run id and request bytes. No unnumbered,
4619
+ * duplicate, or skipped event is accepted: an exact replay contract that
4620
+ * cannot prove continuity fails instead of returning a plausible partial answer.
4621
+ */
4622
+ async function* streamDurableBridgeRun(args) {
4623
+ let reconnects = 0;
4624
+ let pendingUpstreamError;
4625
+ for (;;) {
4626
+ let res;
4627
+ try {
4628
+ res = await bridgeStreamPost(args.seam.bridgeUrl, {
4629
+ bearer: args.seam.bridgeBearer,
4630
+ sessionId: args.sessionId,
4631
+ runId: args.run.id,
4632
+ afterEventId: args.run.lastEventId,
4633
+ body: args.body,
4634
+ signal: args.signal
4635
+ });
4636
+ } catch (error) {
4637
+ if (args.signal.aborted) throw error;
4638
+ if (reconnects >= BRIDGE_MAX_RECONNECTS) throw new ValidationError(`bridgeExecutor: run ${args.run.id} disconnected before terminal acknowledgement after ${reconnects + 1} attempts: ${errorMessage$1(error)}`);
4639
+ reconnects += 1;
4640
+ continue;
4641
+ }
4642
+ if (!res.ok) throw new ValidationError(`bridgeExecutor: bridge ${res.status}: ${(await res.text()).slice(0, 300)}`);
4643
+ if (!res.body) throw new ValidationError("bridgeExecutor: bridge response had no body to stream");
4644
+ assertBridgeResponseIdentity(res, args.run);
4645
+ let sawDone = false;
4646
+ try {
4647
+ for await (const event of parseSseChatStream(res.body)) {
4648
+ if (event.kind === "done") {
4649
+ sawDone = true;
4650
+ break;
4651
+ }
4652
+ const expected = args.run.lastEventId + 1;
4653
+ if (event.id !== expected) throw new ValidationError(`bridgeExecutor: run ${args.run.id} replay gap: expected event ${expected}, received ${event.id}`);
4654
+ args.run.lastEventId = event.id;
4655
+ if (event.error) pendingUpstreamError = event.error;
4656
+ if (event.chunk) yield event.chunk;
4657
+ }
4658
+ } catch (error) {
4659
+ if (args.signal.aborted) throw error;
4660
+ if (error instanceof ValidationError) throw error;
4661
+ if (reconnects >= BRIDGE_MAX_RECONNECTS) throw new ValidationError(`bridgeExecutor: run ${args.run.id} stream disconnected before terminal acknowledgement after ${reconnects + 1} attempts: ${errorMessage$1(error)}`);
4662
+ reconnects += 1;
4663
+ continue;
4664
+ }
4665
+ if (sawDone) {
4666
+ args.run.terminal = true;
4667
+ if (pendingUpstreamError) throw pendingUpstreamError;
4668
+ return;
4669
+ }
4670
+ if (pendingUpstreamError) throw pendingUpstreamError;
4671
+ if (args.signal.aborted) throw new DOMException("bridgeExecutor: turn aborted", "AbortError");
4672
+ if (reconnects >= BRIDGE_MAX_RECONNECTS) throw new ValidationError(`bridgeExecutor: run ${args.run.id} ended without terminal acknowledgement after ${reconnects + 1} attempts`);
4673
+ reconnects += 1;
4674
+ }
4675
+ }
3884
4676
  /**
3885
4677
  * POST one streamed turn to the cli-bridge over the `node:http(s)` core client
3886
4678
  * instead of global `fetch`. The bridge runs a harness CLI and streams SSE only
@@ -3908,15 +4700,22 @@ function bridgeStreamPost(url, args) {
3908
4700
  "content-type": "application/json",
3909
4701
  authorization: `Bearer ${args.bearer}`,
3910
4702
  "x-session-id": args.sessionId,
4703
+ "x-run-id": args.runId,
4704
+ ...args.afterEventId > 0 ? { "last-event-id": String(args.afterEventId) } : {},
3911
4705
  "content-length": Buffer.byteLength(payload)
3912
4706
  },
3913
4707
  timeout: 0
3914
4708
  }, (res) => {
4709
+ response = res;
4710
+ res.once("close", () => args.signal.removeEventListener("abort", onAbort));
3915
4711
  const status = res.statusCode ?? 0;
4712
+ const ok = status >= 200 && status < 300;
4713
+ const body = Readable.toWeb(res);
3916
4714
  resolve({
3917
- ok: status >= 200 && status < 300,
4715
+ ok,
3918
4716
  status,
3919
- body: Readable.toWeb(res),
4717
+ headers: res.headers,
4718
+ body,
3920
4719
  text: async () => {
3921
4720
  const chunks = [];
3922
4721
  for await (const c of res) chunks.push(c);
@@ -3924,8 +4723,10 @@ function bridgeStreamPost(url, args) {
3924
4723
  }
3925
4724
  });
3926
4725
  });
4726
+ let response;
3927
4727
  const onAbort = () => {
3928
4728
  req.destroy(new DOMException("bridgeExecutor: turn aborted", "AbortError"));
4729
+ if (response && "destroy" in response && typeof response.destroy === "function") response.destroy(new DOMException("bridgeExecutor: turn aborted", "AbortError"));
3929
4730
  };
3930
4731
  if (args.signal.aborted) onAbort();
3931
4732
  else args.signal.addEventListener("abort", onAbort, { once: true });
@@ -3933,16 +4734,109 @@ function bridgeStreamPost(url, args) {
3933
4734
  args.signal.removeEventListener("abort", onAbort);
3934
4735
  reject(e);
3935
4736
  });
3936
- req.on("close", () => args.signal.removeEventListener("abort", onAbort));
4737
+ req.on("close", () => {
4738
+ if (!response) args.signal.removeEventListener("abort", onAbort);
4739
+ });
3937
4740
  req.write(payload);
3938
4741
  req.end();
3939
4742
  });
3940
4743
  }
4744
+ function bridgeHeader(headers, name) {
4745
+ const raw = headers[name.toLowerCase()];
4746
+ if (Array.isArray(raw)) return raw.length === 1 ? raw[0] : void 0;
4747
+ return raw;
4748
+ }
4749
+ function assertBridgeResponseIdentity(response, run) {
4750
+ assertBridgeIdentityHeaders(response.headers, run);
4751
+ }
4752
+ function assertBridgeIdentityHeaders(headers, run) {
4753
+ const responseRunId = bridgeHeader(headers, "x-run-id");
4754
+ if (responseRunId !== run.id) throw new ValidationError(`bridgeExecutor: bridge run identity mismatch: expected ${run.id}, received ${responseRunId ?? "missing"}`);
4755
+ const digest = bridgeHeader(headers, "x-run-request-digest");
4756
+ if (!digest || !/^sha256:[a-f0-9]{64}$/u.test(digest)) throw new ValidationError("bridgeExecutor: bridge response omitted a valid request digest");
4757
+ if (run.requestDigest !== void 0 && run.requestDigest !== digest) throw new ValidationError(`bridgeExecutor: bridge request digest changed for run ${run.id}: expected ${run.requestDigest}, received ${digest}`);
4758
+ run.requestDigest = digest;
4759
+ }
4760
+ /** Explicitly cancel one server-owned run and long-poll for its terminal snapshot. */
4761
+ function bridgeCancelPost(seam, run, waitMs) {
4762
+ const target = new URL(`${seam.bridgeUrl.replace(/\/$/, "")}/v1/runs/${encodeURIComponent(run.id)}/cancel`);
4763
+ target.searchParams.set("wait_ms", String(waitMs));
4764
+ const requestFn = target.protocol === "https:" ? request$1 : request;
4765
+ return new Promise((resolve, reject) => {
4766
+ const req = requestFn(target, {
4767
+ method: "POST",
4768
+ headers: {
4769
+ authorization: `Bearer ${seam.bridgeBearer}`,
4770
+ "x-run-id": run.id,
4771
+ "content-length": "0"
4772
+ },
4773
+ timeout: 0
4774
+ }, (res) => {
4775
+ (async () => {
4776
+ const chunks = [];
4777
+ for await (const chunk of res) chunks.push(Buffer.from(chunk));
4778
+ resolve({
4779
+ status: res.statusCode ?? 0,
4780
+ headers: res.headers,
4781
+ text: Buffer.concat(chunks).toString("utf8")
4782
+ });
4783
+ })().catch(reject);
4784
+ });
4785
+ req.on("error", reject);
4786
+ req.end();
4787
+ });
4788
+ }
4789
+ async function requestBridgeRunCancellation(seam, run, waitMs) {
4790
+ if (run.terminal) return true;
4791
+ if (run.cancelInFlight) return run.cancelInFlight;
4792
+ const work = (async () => {
4793
+ const response = await bridgeCancelPost(seam, run, waitMs);
4794
+ if (response.status === 404) throw new ValidationError(`bridgeExecutor: bridge no longer knows run ${run.id}; terminal state is unproven`);
4795
+ if (response.status !== 200 && response.status !== 202) throw new ValidationError(`bridgeExecutor: cancel ${run.id} returned ${response.status}: ${response.text.slice(0, 300)}`);
4796
+ assertBridgeIdentityHeaders(response.headers, run);
4797
+ let parsed;
4798
+ try {
4799
+ parsed = JSON.parse(response.text);
4800
+ } catch {
4801
+ throw new ValidationError(`bridgeExecutor: cancel ${run.id} returned invalid JSON`);
4802
+ }
4803
+ if (parsed.run?.id !== run.id || parsed.run.requestDigest !== run.requestDigest || typeof parsed.terminal !== "boolean" || typeof parsed.run.terminal !== "boolean" || parsed.terminal !== parsed.run.terminal) throw new ValidationError(`bridgeExecutor: cancel ${run.id} returned an inconsistent terminal snapshot`);
4804
+ if (response.status === 200 && parsed.terminal === true) {
4805
+ run.terminal = true;
4806
+ return true;
4807
+ }
4808
+ if (response.status === 202 && parsed.terminal === false) return false;
4809
+ throw new ValidationError(`bridgeExecutor: cancel ${run.id} status ${response.status} disagreed with terminal=${String(parsed.terminal)}`);
4810
+ })();
4811
+ run.cancelInFlight = work;
4812
+ try {
4813
+ return await work;
4814
+ } finally {
4815
+ if (run.cancelInFlight === work) run.cancelInFlight = void 0;
4816
+ }
4817
+ }
4818
+ async function cancelBridgeRunToTerminal(seam, run, grace, stopSignal) {
4819
+ if (run.terminal) return true;
4820
+ const deadline = grace === "infinity" ? void 0 : Date.now() + (grace === "brutalKill" ? BRIDGE_BRUTAL_KILL_WAIT_MS : Math.max(0, grace));
4821
+ let first = true;
4822
+ for (;;) {
4823
+ const remaining = deadline === void 0 ? BRIDGE_CANCEL_LONG_POLL_MS : deadline - Date.now();
4824
+ if (!first && remaining <= 0) return false;
4825
+ if (!first && stopSignal?.aborted) return false;
4826
+ if (await requestBridgeRunCancellation(seam, run, Math.max(0, Math.min(stopSignal ? 1e3 : BRIDGE_CANCEL_LONG_POLL_MS, deadline === void 0 ? remaining : Math.max(0, remaining))))) return true;
4827
+ first = false;
4828
+ if (deadline !== void 0 && Date.now() >= deadline) return false;
4829
+ await new Promise((resolve) => setTimeout(resolve, 10));
4830
+ }
4831
+ }
4832
+ function errorMessage$1(error) {
4833
+ return error instanceof Error ? error.message : String(error);
4834
+ }
3941
4835
  /**
3942
4836
  * Parse cli-bridge's OpenAI-compatible SSE stream into normalized chunks. Each
3943
- * `data:` line is an OpenAI chat-completion chunk (`choices[].delta`); `[DONE]`
3944
- * and SSE comments (`:` keepalives) terminate/skip. Mirrors how `streamSandboxLeaf`
3945
- * folds a box's event stream same `UsageEvent` currency, different wire shape.
4837
+ * `data:` line is an OpenAI chat-completion chunk (`choices[].delta`). Every
4838
+ * run-owned frame, including an id-only comment, is returned so the caller can
4839
+ * prove a contiguous replay sequence. Transport keepalives have no id and are ignored.
3946
4840
  */
3947
4841
  async function* parseSseChatStream(body) {
3948
4842
  const reader = body.getReader();
@@ -3953,18 +4847,18 @@ async function* parseSseChatStream(body) {
3953
4847
  const { done, value } = await reader.read();
3954
4848
  if (done) break;
3955
4849
  buf += decoder.decode(value, { stream: true });
3956
- let sep = buf.indexOf("\n\n");
3957
- while (sep !== -1) {
3958
- const frame = buf.slice(0, sep);
3959
- buf = buf.slice(sep + 2);
3960
- const chunk = parseSseFrame(frame);
3961
- if (chunk === "done") return;
3962
- if (chunk) yield chunk;
3963
- sep = buf.indexOf("\n\n");
4850
+ let separator = /\r?\n\r?\n/u.exec(buf);
4851
+ while (separator) {
4852
+ const frame = buf.slice(0, separator.index);
4853
+ buf = buf.slice(separator.index + separator[0].length);
4854
+ const event = parseSseFrame(frame);
4855
+ if (event) yield event;
4856
+ separator = /\r?\n\r?\n/u.exec(buf);
3964
4857
  }
3965
4858
  }
4859
+ buf += decoder.decode();
3966
4860
  const tail = parseSseStreamTail(buf);
3967
- if (tail !== void 0 && tail !== "done") yield tail;
4861
+ if (tail !== void 0) yield tail;
3968
4862
  } finally {
3969
4863
  reader.releaseLock();
3970
4864
  }
@@ -3986,25 +4880,41 @@ function parseSseStreamTail(buf) {
3986
4880
  }
3987
4881
  if (parsed.error) throw new ValidationError(`bridgeExecutor: bridge upstream error: ${parsed.error.message ?? parsed.error.type ?? "unknown"}`);
3988
4882
  }
3989
- /** Parse one SSE frame (possibly multi-line `data:`/comment) into a chunk, `'done'`,
3990
- * or undefined (comment/keepalive/empty). */
4883
+ /** Parse one SSE frame into a numbered run event, terminal marker, or unnumbered keepalive. */
3991
4884
  function parseSseFrame(frame) {
3992
4885
  const dataLines = [];
4886
+ let id;
3993
4887
  for (const rawLine of frame.split("\n")) {
3994
4888
  const line = rawLine.replace(/\r$/, "");
3995
4889
  if (!line || line.startsWith(":")) continue;
4890
+ if (line.startsWith("id:")) {
4891
+ const rawId = line.slice(3).trim();
4892
+ if (!/^[1-9][0-9]*$/u.test(rawId)) throw new ValidationError(`bridgeExecutor: invalid SSE event id ${JSON.stringify(rawId)}`);
4893
+ const parsedId = Number(rawId);
4894
+ if (!Number.isSafeInteger(parsedId)) throw new ValidationError(`bridgeExecutor: SSE event id exceeds safe integer range`);
4895
+ id = parsedId;
4896
+ continue;
4897
+ }
3996
4898
  if (line.startsWith("data:")) dataLines.push(line.slice(5).trimStart());
3997
4899
  }
3998
- if (dataLines.length === 0) return void 0;
4900
+ if (dataLines.length === 0) return id === void 0 ? void 0 : {
4901
+ kind: "event",
4902
+ id
4903
+ };
3999
4904
  const data = dataLines.join("\n");
4000
- if (data === "[DONE]") return "done";
4905
+ if (data === "[DONE]") return { kind: "done" };
4001
4906
  let parsed;
4002
4907
  try {
4003
4908
  parsed = JSON.parse(data);
4004
4909
  } catch {
4005
- return;
4910
+ throw new ValidationError("bridgeExecutor: bridge emitted a non-JSON SSE data frame");
4006
4911
  }
4007
- if (parsed.error) throw new ValidationError(`bridgeExecutor: bridge stream error: ${parsed.error.message ?? parsed.error.type ?? "unknown"}`);
4912
+ if (id === void 0) throw new ValidationError("bridgeExecutor: bridge emitted an unnumbered run event");
4913
+ if (parsed.error) return {
4914
+ kind: "event",
4915
+ id,
4916
+ error: new ValidationError(`bridgeExecutor: bridge stream error: ${parsed.error.message ?? parsed.error.type ?? "unknown"}`)
4917
+ };
4008
4918
  const out = {};
4009
4919
  const choice = parsed.choices?.[0];
4010
4920
  const content = choice?.delta?.content ?? choice?.message?.content;
@@ -4017,7 +4927,11 @@ function parseSseFrame(frame) {
4017
4927
  output: u.completion_tokens ?? 0
4018
4928
  };
4019
4929
  if (typeof u?.cost === "number") out.cost = u.cost;
4020
- return Object.keys(out).length > 0 ? out : void 0;
4930
+ return {
4931
+ kind: "event",
4932
+ id,
4933
+ ...Object.keys(out).length > 0 ? { chunk: out } : {}
4934
+ };
4021
4935
  }
4022
4936
  function bridgeWorktreeExecutor(spec, ctx, seam) {
4023
4937
  const bridge = seam.bridge;
@@ -4025,6 +4939,9 @@ function bridgeWorktreeExecutor(spec, ctx, seam) {
4025
4939
  if (!bridge.bridgeUrl || !bridge.bridgeBearer) throw new ValidationError("cliWorktreeExecutor: bridge.bridgeUrl + bridge.bridgeBearer required");
4026
4940
  const runId = seam.runId ?? randomUUID();
4027
4941
  const sessionId = bridge.sessionId ?? `bridge-worktree-${runId}`;
4942
+ const attemptId = ctx.node?.attemptId ?? newExecutionAttemptId(runId);
4943
+ const effectiveProfile = agentProfileSchema.parse(mergeAgentProfiles(spec.profile, bridge.agentProfile) ?? spec.profile);
4944
+ const model = bridgeCellModel(bridge.model, ctx, effectiveProfile);
4028
4945
  const controller = new AbortController();
4029
4946
  const pending = [];
4030
4947
  let inner;
@@ -4049,11 +4966,11 @@ function bridgeWorktreeExecutor(spec, ctx, seam) {
4049
4966
  }
4050
4967
  pending.push(msg);
4051
4968
  };
4052
- return {
4969
+ return attestRuntimeOwnedExecutor({
4053
4970
  runtime: "cli",
4054
4971
  budgetExempt: seam.budgetExempt ?? false,
4055
4972
  deliver,
4056
- execute(_task, signal) {
4973
+ execute(task, signal) {
4057
4974
  return (async function* bridgeWorktreeStream() {
4058
4975
  const started = Date.now();
4059
4976
  const linked = mergeAbortSignals(signal, controller.signal);
@@ -4069,10 +4986,10 @@ function bridgeWorktreeExecutor(spec, ctx, seam) {
4069
4986
  const bridgeSeam = {
4070
4987
  bridgeUrl: bridge.bridgeUrl,
4071
4988
  bridgeBearer: bridge.bridgeBearer,
4072
- model: resolveBridgeWorktreeModel(spec, bridge),
4073
4989
  cwd: worktree.path,
4074
4990
  sessionId,
4075
- ...bridge.agentProfile ? { agentProfile: bridge.agentProfile } : { agentProfile: spec.profile },
4991
+ ...bridge.model ? { model: bridge.model } : {},
4992
+ ...bridge.agentProfile ? { agentProfile: bridge.agentProfile } : {},
4076
4993
  ...bridge.timeoutMs !== void 0 ? { timeoutMs: bridge.timeoutMs } : {},
4077
4994
  ...bridge.maxTurns !== void 0 ? { maxTurns: bridge.maxTurns } : {}
4078
4995
  };
@@ -4086,8 +5003,8 @@ function bridgeWorktreeExecutor(spec, ctx, seam) {
4086
5003
  };
4087
5004
  inner = bridgeExecutor(spec, bridgeCtx);
4088
5005
  for (const msg of pending.splice(0)) inner.deliver?.(msg);
4089
- const run = inner.execute(seam.taskPrompt, linked);
4090
- if (isAsyncIterable(run)) {
5006
+ const run = inner.execute(task, linked);
5007
+ if (isAsyncIterable$1(run)) {
4091
5008
  for await (const event of run) yield event;
4092
5009
  bridgeArtifact = inner.resultArtifact();
4093
5010
  } else bridgeArtifact = await run;
@@ -4153,13 +5070,48 @@ function bridgeWorktreeExecutor(spec, ctx, seam) {
4153
5070
  if (!artifact) throw new ValidationError("cliWorktreeExecutor: bridge resultArtifact() read before stream drained");
4154
5071
  return artifact;
4155
5072
  }
4156
- };
4157
- }
4158
- function resolveBridgeWorktreeModel(spec, bridge) {
4159
- if (bridge.model) return bridge.model;
4160
- const model = spec.profile.model?.default;
4161
- if (typeof model === "string" && model.length > 0) return model;
4162
- throw new ValidationError("cliWorktreeExecutor: bridge.model or AgentProfile.model.default required");
5073
+ }, {
5074
+ effectiveProfile,
5075
+ backend: "bridge-worktree",
5076
+ model: model ? {
5077
+ status: "known",
5078
+ id: model
5079
+ } : {
5080
+ status: "unknown",
5081
+ reason: "bridge worktree profile did not select a model"
5082
+ },
5083
+ execution: {
5084
+ kind: "worktree-session",
5085
+ id: `${runId}:${sessionId}`
5086
+ },
5087
+ materializer: "bridge-worktree-agent-profile",
5088
+ plan: {
5089
+ kind: "bridge-worktree-session",
5090
+ runId,
5091
+ sessionId,
5092
+ baseRef: seam.baseRef ?? "HEAD",
5093
+ model: model ?? null,
5094
+ testCmd: seam.testCmd ?? null,
5095
+ typecheckCmd: seam.typecheckCmd ?? null,
5096
+ checkTimeoutMs: seam.checkTimeoutMs ?? seam.harnessTimeoutMs ?? bridge.timeoutMs ?? 300 * 1e3,
5097
+ checkOutputCap: seam.checkOutputCap ?? 16e3
5098
+ }
5099
+ }, {
5100
+ attemptId,
5101
+ binding: {
5102
+ bridgeUrl: bridge.bridgeUrl,
5103
+ effectiveProfile,
5104
+ model: model ?? null,
5105
+ repoRoot: seam.repoRoot,
5106
+ runId,
5107
+ sessionId
5108
+ },
5109
+ descriptor: {
5110
+ kind: "bridge-worktree-session",
5111
+ transport: "http",
5112
+ backend: "bridge-worktree"
5113
+ }
5114
+ });
4163
5115
  }
4164
5116
  function bridgeOutputText(out) {
4165
5117
  if (typeof out === "string") return out;
@@ -4173,7 +5125,7 @@ function bridgeOutputText(out) {
4173
5125
  return String(out);
4174
5126
  }
4175
5127
  }
4176
- function isAsyncIterable(value) {
5128
+ function isAsyncIterable$1(value) {
4177
5129
  return value !== null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function";
4178
5130
  }
4179
5131
  /**
@@ -4183,14 +5135,14 @@ function isAsyncIterable(value) {
4183
5135
  */
4184
5136
  const cliWorktreeExecutor = (spec, ctx) => {
4185
5137
  const seam = readSeam(ctx, cliWorktreeSeamKey, "cli-worktree");
4186
- if (!seam.repoRoot || !seam.taskPrompt) throw new ValidationError("cliWorktreeExecutor: CliWorktreeSeam.repoRoot + taskPrompt required");
5138
+ if (!seam.repoRoot) throw new ValidationError("cliWorktreeExecutor: CliWorktreeSeam.repoRoot required");
4187
5139
  if (seam.bridge) return bridgeWorktreeExecutor(spec, ctx, seam);
4188
5140
  if (!seam.harness) throw new ValidationError("cliWorktreeExecutor: CliWorktreeSeam.harness required when bridge is not set");
4189
5141
  return createWorktreeCliExecutor({
4190
5142
  repoRoot: seam.repoRoot,
4191
5143
  profile: spec.profile,
4192
5144
  harness: seam.harness,
4193
- taskPrompt: seam.taskPrompt,
5145
+ ...seam.taskPrompt !== void 0 ? { taskPrompt: seam.taskPrompt } : {},
4194
5146
  ...seam.runId ? { runId: seam.runId } : {},
4195
5147
  ...seam.baseRef ? { baseRef: seam.baseRef } : {},
4196
5148
  ...seam.harnessTimeoutMs !== void 0 ? { harnessTimeoutMs: seam.harnessTimeoutMs } : {},
@@ -4202,9 +5154,110 @@ const cliWorktreeExecutor = (spec, ctx) => {
4202
5154
  ...seam.checkOutputCap !== void 0 ? { checkOutputCap: seam.checkOutputCap } : {},
4203
5155
  ...seam.runGit ? { runGit: seam.runGit } : {},
4204
5156
  ...seam.runCommand ? { runCommand: seam.runCommand } : {},
4205
- ...seam.budgetExempt !== void 0 ? { budgetExempt: seam.budgetExempt } : {}
5157
+ ...seam.budgetExempt !== void 0 ? { budgetExempt: seam.budgetExempt } : {},
5158
+ ...ctx.node?.attemptId !== void 0 ? { executionAttemptId: ctx.node.attemptId } : {}
4206
5159
  });
4207
5160
  };
5161
+ /** Capture one public executor configuration at its call boundary. All data that selects policy,
5162
+ * model, process, limits, profile overlays, or backend behavior is detached and deeply frozen.
5163
+ * Explicit service/function fields remain live by reference because they are executable ports,
5164
+ * not portable configuration. */
5165
+ function snapshotExecutorConfig(config) {
5166
+ switch (config.backend) {
5167
+ case "router-tools": {
5168
+ const { executeToolCall, onToolStep, ...decisionData } = config;
5169
+ const snapshot = detachedSnapshot(decisionData, "createExecutor router-tools config");
5170
+ return Object.freeze({
5171
+ ...snapshot,
5172
+ executeToolCall,
5173
+ ...onToolStep === void 0 ? {} : { onToolStep }
5174
+ });
5175
+ }
5176
+ case "cli-worktree": {
5177
+ const { runGit, runCommand, ...decisionData } = config;
5178
+ const snapshot = detachedSnapshot(decisionData, "createExecutor cli-worktree config");
5179
+ return Object.freeze({
5180
+ ...snapshot,
5181
+ ...runGit === void 0 ? {} : { runGit },
5182
+ ...runCommand === void 0 ? {} : { runCommand }
5183
+ });
5184
+ }
5185
+ case "provider": {
5186
+ const { provider, registry, taskToTurn, ...decisionData } = config;
5187
+ const snapshot = detachedSnapshot(decisionData, "createExecutor provider config");
5188
+ const resolvedProvider = resolveAgentEnvironmentProvider(provider, registry);
5189
+ return Object.freeze({
5190
+ ...snapshot,
5191
+ provider: resolvedProvider,
5192
+ ...taskToTurn === void 0 ? {} : { taskToTurn }
5193
+ });
5194
+ }
5195
+ case "sandbox": {
5196
+ const { sandboxClient, loopCtx, ...decisionData } = config;
5197
+ if (loopCtx === void 0) {
5198
+ const snapshot = detachedSnapshot(decisionData, "createExecutor sandbox config");
5199
+ return Object.freeze({
5200
+ ...snapshot,
5201
+ sandboxClient
5202
+ });
5203
+ }
5204
+ const { hooks, traceEmitter, onSandboxEvent, runHandle, ...loopDecisionData } = loopCtx;
5205
+ const snapshot = detachedSnapshot({
5206
+ ...decisionData,
5207
+ loopCtx: loopDecisionData
5208
+ }, "createExecutor sandbox config");
5209
+ const loopSnapshot = snapshot.loopCtx;
5210
+ return Object.freeze({
5211
+ ...snapshot,
5212
+ sandboxClient,
5213
+ loopCtx: Object.freeze({
5214
+ ...loopSnapshot,
5215
+ ...hooks === void 0 ? {} : { hooks },
5216
+ ...traceEmitter === void 0 ? {} : { traceEmitter },
5217
+ ...onSandboxEvent === void 0 ? {} : { onSandboxEvent },
5218
+ ...runHandle === void 0 ? {} : { runHandle }
5219
+ })
5220
+ });
5221
+ }
5222
+ case "router":
5223
+ case "bridge":
5224
+ case "cli":
5225
+ case "pi": return detachedSnapshot(config, `createExecutor ${config.backend} config`);
5226
+ }
5227
+ }
5228
+ /** A backend config reused for multiple workers/managers cannot pin execution identity or carry a
5229
+ * profile overlay applied after Scope hashed the authored profile. Direct single-execution
5230
+ * `createExecutor` calls may still use those fields. */
5231
+ function captureReusableExecutorConfig(config, context) {
5232
+ const captured = snapshotExecutorConfig(config);
5233
+ if ((captured.backend === "bridge" ? captured.agentProfile : captured.backend === "cli-worktree" ? captured.bridge?.agentProfile : void 0) !== void 0) throw new ValidationError(`${context}: backend agentProfile overlays are not allowed because they change the effective profile after spawn identity is fixed`);
5234
+ const fixedIdentity = captured.backend === "bridge" && captured.sessionId !== void 0 ? "sessionId" : captured.backend === "cli-worktree" && captured.runId !== void 0 ? "runId" : captured.backend === "cli-worktree" && captured.bridge?.sessionId !== void 0 ? "bridge.sessionId" : void 0;
5235
+ if (fixedIdentity !== void 0) throw new ValidationError(`${context}: fixed ${fixedIdentity} is not allowed on a reusable backend; let each execution derive an isolated id`);
5236
+ return captured;
5237
+ }
5238
+ /** Bind one already-captured reusable backend to the durable identity of the execution that will
5239
+ * use it. Stateful bridge backends need an explicit external id: a random default isolates two
5240
+ * siblings but cannot reconnect a replacement process to the same harness session. Non-stateful
5241
+ * backends carry no external execution id and are returned unchanged. */
5242
+ function bindReusableExecutorExecutionId(captured, executionId) {
5243
+ if (typeof executionId !== "string" || executionId.length === 0) throw new ValidationError("bindReusableExecutorExecutionId: executionId must be a non-empty string");
5244
+ switch (captured.backend) {
5245
+ case "bridge": return Object.freeze({
5246
+ ...captured,
5247
+ sessionId: executionId
5248
+ });
5249
+ case "cli-worktree": return Object.freeze({
5250
+ ...captured,
5251
+ runId: executionId
5252
+ });
5253
+ case "router":
5254
+ case "router-tools":
5255
+ case "cli":
5256
+ case "provider":
5257
+ case "pi":
5258
+ case "sandbox": return captured;
5259
+ }
5260
+ }
4208
5261
  /**
4209
5262
  * The single built-in executor factory. Picks a leaf backend by data (`config.backend`),
4210
5263
  * injects the matching seam, and delegates to that backend's built-in implementation.
@@ -4214,8 +5267,10 @@ const cliWorktreeExecutor = (spec, ctx) => {
4214
5267
  * `UsageEvent` reporting channel.
4215
5268
  */
4216
5269
  function createExecutor(config) {
5270
+ const captured = snapshotExecutorConfig(config);
4217
5271
  return (spec, ctx) => {
4218
- const { backend, ...seam } = config;
5272
+ const { backend, ...seamData } = captured;
5273
+ const seam = Object.freeze(seamData);
4219
5274
  const seamed = {
4220
5275
  ...ctx,
4221
5276
  seams: {
@@ -4223,7 +5278,7 @@ function createExecutor(config) {
4223
5278
  [backend]: seam
4224
5279
  }
4225
5280
  };
4226
- switch (config.backend) {
5281
+ switch (captured.backend) {
4227
5282
  case "router": return routerInlineExecutor(spec, seamed);
4228
5283
  case "router-tools": return routerToolsInlineExecutor(spec, seamed);
4229
5284
  case "bridge": return bridgeExecutor(spec, seamed);
@@ -4232,10 +5287,41 @@ function createExecutor(config) {
4232
5287
  case "pi": return piExecutor(spec, seamed);
4233
5288
  case "provider": {
4234
5289
  const providerSeam = readSeam(seamed, providerSeamKey, "provider");
4235
- return providerAsExecutor(resolveAgentEnvironmentProvider(providerSeam.provider, providerSeam.registry), providerSeam)(spec, seamed);
5290
+ const provider = resolveAgentEnvironmentProvider(providerSeam.provider, providerSeam.registry);
5291
+ if (providerSeam.steering) {
5292
+ if (providerSeam.taskToTurn) throw new ValidationError("createExecutor(provider, steering): taskToTurn is not representable by the text-only steerable session");
5293
+ if (providerSeam.destroyOnSettle === false) throw new ValidationError("createExecutor(provider, steering): destroyOnSettle=false conflicts with the session-owned environment lifecycle");
5294
+ const harness = requiredProviderProfileHarness(spec, providerSeam);
5295
+ const sandboxClient = providerAsSandboxClient(provider, {
5296
+ defaults: {
5297
+ ...providerSeam.defaults ?? {},
5298
+ signal: seamed.signal
5299
+ },
5300
+ requireTerminalEvent: providerSeam.requireTerminalEvent,
5301
+ requireSession: true
5302
+ });
5303
+ const providerCtx = {
5304
+ ...seamed,
5305
+ seams: {
5306
+ ...seamed.seams,
5307
+ [sandboxSeamKey]: {
5308
+ sandboxClient,
5309
+ steering: providerSeam.steering
5310
+ }
5311
+ }
5312
+ };
5313
+ return {
5314
+ ...sandboxExecutor({
5315
+ ...spec,
5316
+ harness
5317
+ }, providerCtx),
5318
+ runtime: providerSeam.runtime ?? provider.name
5319
+ };
5320
+ }
5321
+ return providerAsExecutor(provider, providerSeam)(spec, seamed);
4236
5322
  }
4237
5323
  case "sandbox": {
4238
- const harness = spec.harness ?? config.harness ?? null;
5324
+ const harness = spec.harness ?? captured.harness ?? null;
4239
5325
  return sandboxExecutor({
4240
5326
  ...spec,
4241
5327
  harness
@@ -4244,6 +5330,13 @@ function createExecutor(config) {
4244
5330
  }
4245
5331
  };
4246
5332
  }
5333
+ function requiredProviderProfileHarness(spec, seam) {
5334
+ const harness = spec.profile.harness;
5335
+ if (harness === void 0) throw new ValidationError("createExecutor(provider, steering): AgentProfile.harness is required");
5336
+ if (spec.harness != null && spec.harness !== harness) throw new ValidationError(`createExecutor(provider, steering): AgentSpec.harness "${spec.harness}" conflicts with AgentProfile.harness "${harness}"`);
5337
+ if (seam.defaults?.backend !== void 0 && seam.defaults.backend !== harness) throw new ValidationError(`createExecutor(provider, steering): provider default backend "${seam.defaults.backend}" conflicts with AgentProfile.harness "${harness}"`);
5338
+ return harness;
5339
+ }
4247
5340
  /**
4248
5341
  * The open resolver/registry. Pre-registers the three built-ins under their
4249
5342
  * runtime tags (`'router'`, `'sandbox'`, `'cli'`) and accepts `register(name,
@@ -4251,8 +5344,8 @@ function createExecutor(config) {
4251
5344
  * without touching the registry at all. NOT a closed switch; registration + BYO
4252
5345
  * ARE the extension points.
4253
5346
  *
4254
- * `resolve` precedence (frozen in `ExecutorRegistry`): a BYO `spec.executor` →
4255
- * `harness === null` → the `'router'` factory; else a registered factory for the
5347
+ * `resolve` precedence (frozen in `ExecutorRegistry`): a BYO `spec.executorFactory` →
5348
+ * `spec.executor` → `harness === null` → the `'router'` factory; else a registered factory for the
4256
5349
  * harness-derived runtime (`'sandbox'` for any `BackendType`); else fail loud.
4257
5350
  */
4258
5351
  function createExecutorRegistry() {
@@ -4268,6 +5361,10 @@ function createExecutorRegistry() {
4268
5361
  factories.set(runtime, factory);
4269
5362
  },
4270
5363
  resolve(spec) {
5364
+ if (spec.executorFactory) return {
5365
+ succeeded: true,
5366
+ value: spec.executorFactory
5367
+ };
4271
5368
  if (spec.executor) {
4272
5369
  const byo = spec.executor;
4273
5370
  return {
@@ -4321,11 +5418,11 @@ function taskToPrompt(task) {
4321
5418
  }
4322
5419
  return JSON.stringify(task);
4323
5420
  }
4324
- /** Router messages from the opaque task + the profile's system prompt, when set. */
5421
+ /** Router messages from the opaque task + every portable profile prompt instruction. */
4325
5422
  function taskToMessages(task, spec) {
4326
5423
  const messages = [];
4327
- const system = spec.profile.prompt?.systemPrompt;
4328
- if (typeof system === "string" && system.length > 0) messages.push({
5424
+ const system = [spec.profile.prompt?.systemPrompt, ...spec.profile.prompt?.instructions ?? []].filter((line) => typeof line === "string" && line.trim().length > 0).join("\n");
5425
+ if (system.length > 0) messages.push({
4329
5426
  role: "system",
4330
5427
  content: system
4331
5428
  });
@@ -4423,8 +5520,9 @@ function createInMemoryRunContext(opts = {}) {
4423
5520
  * back on `Scope.resume` (rehydrated by `replaySpawnTree`) instead of being re-executed.
4424
5521
  *
4425
5522
  * Layout: `${dir}/spawn-journal.jsonl` (one JSONL record per event), `${dir}/blobs/` (one
4426
- * content-addressed JSON file per settled result), and `${dir}/coordination-log.jsonl` (questions
4427
- * + findings, replayed into a resumed driver). The directory is created on first write.
5523
+ * content-addressed JSON file per settled result), and `${dir}/coordination-log.jsonl`
5524
+ * (questions, findings, answer decisions, and authorized continuation receipts retained as
5525
+ * evidence). The directory is created on first write.
4428
5526
  *
4429
5527
  * Opt-in by construction — `createInMemoryRunContext()` is unchanged and stays the default, so no
4430
5528
  * existing consumer writes to disk or resumes unless it asks for this.
@@ -4482,168 +5580,6 @@ function watchTrace(source, opts = {}) {
4482
5580
  });
4483
5581
  }
4484
5582
  //#endregion
4485
- //#region src/runtime/supervise/dispatch.ts
4486
- /**
4487
- *
4488
- * `rollingDispatch` — the REFILLING dispatch policy over a `Scope`. It keeps `width` children in
4489
- * flight and admits the next queued unit of work the instant one settles, instead of waiting for
4490
- * a whole round to drain (`fanout`) or for a driver to decide again (`spawn → await → spawn`).
4491
- *
4492
- * The gap it closes: `fanout` opens every item at once and then drains — one round, no refill —
4493
- * and a driver brain's manual loop opens one worker per model turn. Between those two there was
4494
- * nothing that holds N slots full, which is why a 5-worker run can peak at 2 live workers and sit
4495
- * ~50% idle. This is a policy over the EXISTING `Scope.spawn` / `Scope.next` primitives: it adds
4496
- * no second admission path, so the conserved budget pool stays the only fence on total work and
4497
- * `width` is only a fence on simultaneous work.
4498
- *
4499
- * Fail-closed by construction: an admission rejection (`budget-exhausted` / `depth-exceeded`) is
4500
- * recorded and STOPS further admission — the loop then drains what is already live and returns.
4501
- * It never retries a rejected spawn against the same pool, and it never spawns past `width`.
4502
- *
4503
- * ── The concurrency-cap ledger (read this before adding a fourth cap) ──────────────────────────
4504
- *
4505
- * Three unrelated caps bound "how much runs at once" in this stack, at three different layers.
4506
- * They are NOT aware of each other, and the smallest one silently wins:
4507
- *
4508
- * 1. `CoordinationToolsOptions.maxLiveWorkers` (`src/mcp/tools/coordination.ts`) — supervisor
4509
- * level. How many workers may be spawned-but-not-settled at once; `spawn_agent` fails closed
4510
- * with `error: 'max-live-workers'` past it. Unset by default ⇒ NO cap at this layer.
4511
- * 2. `SandboxLineage`'s `maxConcurrency` / `DEFAULT_FORK_CONCURRENCY = 4`
4512
- * (`src/runtime/sandbox-lineage.ts`) — kernel level. How many BOXES one `runAgentRounds` fork wave
4513
- * provisions at once. It bounds a single leaf's fanout, not the supervisor's worker count.
4514
- * 3. A host's own live-box governor (e.g. the kernel's `ComputeGovernor`, `maxSandboxes = 4`) — fleet
4515
- * level. How many sandboxes may exist across the whole host process.
4516
- *
4517
- * The honest effective limit on simultaneous WORKERS is the minimum of the caps that apply to the
4518
- * worker layer — (1) and (3). (2) is a different unit (boxes per fork wave inside one leaf) and
4519
- * must not be min'd into it, or a 4-way fork inside one worker reads as a 4-worker ceiling.
4520
- * `effectiveConcurrency` computes that minimum in one place so a host derives ONE number and
4521
- * passes it to BOTH `maxLiveWorkers` and this dispatcher's `width`, instead of leaving a fleet
4522
- * governor of 4 and an unset worker fence as unrelated numbers.
4523
- *
4524
- * ── Why this is not a copy of the kernel's batch loop ──────────────────────────────────────────
4525
- *
4526
- * `runBatch` (`src/runtime/run-loop.ts`) runs the same hold-N-slots-full shape over the KERNEL's
4527
- * substrate: bare promises in a `Set`, raced with `Promise.race`, bounded by `maxConcurrency`.
4528
- * This one runs it over the SUPERVISOR's substrate — `Scope.spawn`'s atomic reservation against
4529
- * the conserved pool, `Scope.next`'s journaled settlement cursor, and the blob store behind each
4530
- * result. Neither can be expressed in the other's terms without dragging its whole substrate
4531
- * along: the kernel loop has no budget to reserve and no cursor to order settlements by, and this
4532
- * one cannot race raw promises because a settlement is only real once it is journaled. The shape
4533
- * repeating across the two deliberate layers is resonance, not duplication — do not "unify" them
4534
- * into a shared helper that would have to know about both.
4535
- *
4536
- * @experimental
4537
- */
4538
- /**
4539
- * Run the refilling dispatch loop over `scope` until the queue is dry (or a stop fires) and every
4540
- * admitted child has settled. Returns the settlements in cursor order plus the admission ledger.
4541
- *
4542
- * The loop is: fill free slots from `nextUnit` → `await scope.next()` → deliver the settlement →
4543
- * refill → repeat. Because the refill happens immediately after each settlement rather than after
4544
- * a whole round, a slow child never idles the other slots.
4545
- */
4546
- async function rollingDispatch(scope, opts) {
4547
- if (!Number.isInteger(opts.width) || opts.width < 1) throw new ValidationError(`rollingDispatch: width must be a positive integer, got ${String(opts.width)}`);
4548
- const settled = [];
4549
- const rejected = [];
4550
- const live = /* @__PURE__ */ new Set();
4551
- let admitted = 0;
4552
- let peakLive = 0;
4553
- let queueDry = false;
4554
- let stopReason = "drained";
4555
- const fill = async () => {
4556
- while (live.size < opts.width) {
4557
- if (queueDry) return;
4558
- if (scope.signal.aborted) {
4559
- stopReason = "aborted";
4560
- queueDry = true;
4561
- return;
4562
- }
4563
- if (opts.shouldStop?.() === true) {
4564
- stopReason = "stopped";
4565
- queueDry = true;
4566
- return;
4567
- }
4568
- const unit = await opts.nextUnit();
4569
- if (unit === void 0) {
4570
- queueDry = true;
4571
- return;
4572
- }
4573
- const res = scope.spawn(unit.agent, unit.task, unit.opts);
4574
- if (!res.ok) {
4575
- rejected.push(`${unit.opts.label}: ${res.reason}`);
4576
- stopReason = "not-admitted";
4577
- queueDry = true;
4578
- return;
4579
- }
4580
- live.add(res.handle.id);
4581
- admitted += 1;
4582
- if (live.size > peakLive) peakLive = live.size;
4583
- }
4584
- };
4585
- await fill();
4586
- while (live.size > 0) {
4587
- const s = await scope.next();
4588
- if (s === null) break;
4589
- live.delete(s.handle.id);
4590
- settled.push(s);
4591
- await opts.onSettled?.(s);
4592
- await fill();
4593
- }
4594
- return {
4595
- settled,
4596
- admitted,
4597
- rejected,
4598
- stopReason,
4599
- peakLive
4600
- };
4601
- }
4602
- /**
4603
- * Free worker slots under a simultaneity cap: `cap - live`, floored at 0, or `null` when there is
4604
- * no cap (the conserved pool is then the only fence and "free slots" is not a finite number).
4605
- * The one place the answer is computed, so the driver-facing tool payload and a dispatcher agree.
4606
- */
4607
- function freeSlots(liveCount, cap) {
4608
- if (cap === void 0 || cap <= 0) return null;
4609
- return Math.max(0, cap - liveCount);
4610
- }
4611
- /**
4612
- * The ONE honest effective limit on simultaneous workers: the minimum of the caps that actually
4613
- * bound the worker layer. Ignores unset/non-positive caps; returns `undefined` when no cap applies
4614
- * (uncapped — the conserved pool remains the only fence).
4615
- *
4616
- * Deliberately does NOT fold in `SandboxLineage`'s fork concurrency: that bounds boxes inside ONE
4617
- * leaf's fork wave, a different unit. Folding it in would report a 4-worker ceiling for what is
4618
- * really a 4-box fanout inside a single worker.
4619
- *
4620
- * Use it once, at the top of a run, and pass the result to BOTH `maxLiveWorkers` and a
4621
- * dispatcher's `width` — that is what turns three unrelated numbers into one.
4622
- */
4623
- function effectiveConcurrency(caps) {
4624
- const applicable = [caps.maxLiveWorkers, caps.maxSandboxes].filter((c) => typeof c === "number" && c > 0);
4625
- if (applicable.length === 0) return void 0;
4626
- return Math.min(...applicable);
4627
- }
4628
- /** Convenience: a `DispatchUnit` factory over a fixed array of tasks, for the common case where
4629
- * the queue is known up front and only the refill behavior is wanted. */
4630
- function queueOf(units, budget) {
4631
- let i = 0;
4632
- return () => {
4633
- const u = units[i];
4634
- if (u === void 0) return void 0;
4635
- i += 1;
4636
- return {
4637
- agent: u.agent,
4638
- task: u.task,
4639
- opts: {
4640
- budget,
4641
- label: u.label
4642
- }
4643
- };
4644
- };
4645
- }
4646
- //#endregion
4647
5583
  //#region src/runtime/supervise/event-bus.ts
4648
5584
  /** Create the child→parent coordination bus: one typed pipe for settled outputs, questions, and analyst findings, with a priority-ordered pull queue and a pass-through subscribe lane. */
4649
5585
  function createEventBus(now = Date.now) {
@@ -4651,7 +5587,9 @@ function createEventBus(now = Date.now) {
4651
5587
  const log = [];
4652
5588
  const subscribers = [];
4653
5589
  const byKind = {};
5590
+ const staged = /* @__PURE__ */ new WeakMap();
4654
5591
  let seq = 0;
5592
+ let published = 0;
4655
5593
  let pulled = 0;
4656
5594
  const matches = (r, kinds) => !kinds || kinds.includes(r.event.type);
4657
5595
  const bestIndex = (kinds) => {
@@ -4669,16 +5607,19 @@ function createEventBus(now = Date.now) {
4669
5607
  };
4670
5608
  return {
4671
5609
  async publish(event, opts) {
4672
- const record = {
5610
+ const record = staged.get(event) ?? {
4673
5611
  seq: seq++,
4674
5612
  at: now(),
4675
5613
  priority: opts?.priority ?? 0,
4676
5614
  event
4677
5615
  };
5616
+ staged.set(event, record);
5617
+ for (const handler of subscribers) await handler(record);
5618
+ staged.delete(event);
4678
5619
  if (opts?.queue !== false) queue.push(record);
4679
5620
  log.push(record);
5621
+ published += 1;
4680
5622
  byKind[event.type] = (byKind[event.type] ?? 0) + 1;
4681
- for (const handler of subscribers) await handler(record);
4682
5623
  return record;
4683
5624
  },
4684
5625
  pull(kinds) {
@@ -4702,7 +5643,7 @@ function createEventBus(now = Date.now) {
4702
5643
  },
4703
5644
  stats() {
4704
5645
  return {
4705
- published: seq,
5646
+ published,
4706
5647
  pulled,
4707
5648
  byKind: { ...byKind }
4708
5649
  };
@@ -4910,14 +5851,6 @@ function spawnProfileArg() {
4910
5851
  }).properties));
4911
5852
  return spawnProfileArgCache;
4912
5853
  }
4913
- /** Freeze a JSON-Schema tree. The derived schema is plain JSON data with no cycles. */
4914
- function deepFreeze(value) {
4915
- if (value && typeof value === "object" && !Object.isFrozen(value)) {
4916
- Object.freeze(value);
4917
- for (const nested of Object.values(value)) deepFreeze(nested);
4918
- }
4919
- return value;
4920
- }
4921
5854
  /** Build the driver's MCP tools over a live scope. */
4922
5855
  function createCoordinationTools(opts) {
4923
5856
  const deliverable = opts.deliverable;
@@ -4930,23 +5863,76 @@ function createCoordinationTools(opts) {
4930
5863
  const questionPolicy = opts.questionPolicy ?? "auto";
4931
5864
  const completedKeys = /* @__PURE__ */ new Set();
4932
5865
  const keyByWorker = /* @__PURE__ */ new Map();
5866
+ let unkeyedAssignmentOrdinal = nextUnkeyedAssignmentOrdinal(opts.scope);
4933
5867
  for (const [key, prior] of opts.scope.resume?.keys ?? []) if (prior.state === "completed") completedKeys.add(key);
4934
- for (const s of opts.scope.resume?.settled ?? []) ledger.push(s.kind === "done" ? {
4935
- id: s.handle.id,
4936
- status: "done",
4937
- score: s.verdict?.score ?? 0,
4938
- valid: s.verdict?.valid ?? false,
4939
- outRef: s.outRef
4940
- } : {
4941
- id: s.handle.id,
4942
- status: "down",
4943
- reason: s.reason
4944
- });
5868
+ const nodeForWorker = (id) => opts.scope.view.nodes.find((node) => node.id === id) ?? opts.scope.resume?.view.nodes.find((node) => node.id === id);
5869
+ const projectSettled = (settled, resumed = false) => {
5870
+ const node = nodeForWorker(settled.handle.id);
5871
+ const assignmentId = settled.handle.assignmentId ?? node?.assignmentId;
5872
+ const identity = settled.handle.identity ?? node?.identity;
5873
+ const materialization = settled.handle.materialization ?? node?.materialization;
5874
+ const executionBindings = settled.handle.executionBindings ?? node?.executionBindings;
5875
+ const settledAt = settled.settledAt ?? node?.settledAt;
5876
+ const trace = settled.trace ?? node?.trace ?? {
5877
+ status: "unavailable",
5878
+ reason: "legacy-settlement-without-trace-evidence"
5879
+ };
5880
+ const common = {
5881
+ id: settled.handle.id,
5882
+ ...assignmentId === void 0 ? {} : { assignmentId },
5883
+ ...identity === void 0 ? {} : { identity },
5884
+ ...materialization === void 0 ? {} : { materialization },
5885
+ ...executionBindings === void 0 ? {} : { executionBindings },
5886
+ ...settledAt === void 0 ? {} : { settledAt },
5887
+ trace,
5888
+ ...resumed ? { resumed: true } : {}
5889
+ };
5890
+ return deepFreezeDetached(settled.kind === "done" ? {
5891
+ ...common,
5892
+ status: "done",
5893
+ spent: settled.spent,
5894
+ ...settled.verdict?.score === void 0 ? {} : { score: settled.verdict.score },
5895
+ ...settled.verdict?.valid === void 0 ? {} : { valid: settled.verdict.valid },
5896
+ outRef: settled.outRef
5897
+ } : {
5898
+ ...common,
5899
+ status: "down",
5900
+ ...node?.spent === void 0 ? {} : { spent: node.spent },
5901
+ reason: settled.reason
5902
+ });
5903
+ };
5904
+ const resumedWorkers = [];
5905
+ for (const s of opts.scope.resume?.settled ?? []) {
5906
+ const worker = projectSettled(s, true);
5907
+ resumedWorkers.push(worker);
5908
+ ledger.push(worker);
5909
+ }
4945
5910
  const bus = createEventBus();
4946
5911
  if (opts.onEvent) {
4947
5912
  const cb = opts.onEvent;
4948
- bus.subscribe((rec) => cb(rec.event));
4949
- }
5913
+ bus.subscribe((rec) => cb(rec.event, rec));
5914
+ }
5915
+ const resumeEvents = opts.replaySettlements ? resumedWorkers.map((worker) => deepFreezeDetached({
5916
+ type: "settled",
5917
+ worker
5918
+ })) : [];
5919
+ let resumeEventIndex = 0;
5920
+ let readyInFlight;
5921
+ const ready = () => {
5922
+ if (resumeEventIndex >= resumeEvents.length) return Promise.resolve();
5923
+ if (readyInFlight) return readyInFlight;
5924
+ readyInFlight = (async () => {
5925
+ while (resumeEventIndex < resumeEvents.length) {
5926
+ const event = resumeEvents[resumeEventIndex];
5927
+ if (!event) break;
5928
+ await bus.publish(event);
5929
+ resumeEventIndex += 1;
5930
+ }
5931
+ })().finally(() => {
5932
+ readyInFlight = void 0;
5933
+ });
5934
+ return readyInFlight;
5935
+ };
4950
5936
  const urgencyPriority = (u) => u === "blocks-run" ? 20 : u === "blocks-step" ? 10 : 0;
4951
5937
  const str = (v, field) => {
4952
5938
  if (typeof v !== "string" || v.length === 0) throw new Error(`coordination tools: "${field}" must be a non-empty string`);
@@ -4969,12 +5955,14 @@ function createCoordinationTools(opts) {
4969
5955
  const maxTokens = field("maxTokens");
4970
5956
  const maxUsd = field("maxUsd");
4971
5957
  const deadlineMs = field("deadlineMs");
4972
- return {
5958
+ const merged = {
4973
5959
  maxIterations: maxIterations ?? base.maxIterations,
4974
5960
  maxTokens: maxTokens ?? base.maxTokens,
4975
5961
  ...(maxUsd ?? base.maxUsd) === void 0 ? {} : { maxUsd: maxUsd ?? base.maxUsd },
4976
5962
  ...(deadlineMs ?? base.deadlineMs) === void 0 ? {} : { deadlineMs: deadlineMs ?? base.deadlineMs }
4977
5963
  };
5964
+ assertValidBudget(merged, "coordination tools: budget");
5965
+ return merged;
4978
5966
  };
4979
5967
  const level = (v) => {
4980
5968
  if (v === "worker" || v === "driver" || v === "loop") return v;
@@ -4984,43 +5972,27 @@ function createCoordinationTools(opts) {
4984
5972
  if (v === "continue-without" || v === "blocks-step" || v === "blocks-run") return v;
4985
5973
  throw new Error("coordination tools: \"urgency\" must be continue-without, blocks-step, or blocks-run");
4986
5974
  };
4987
- const recordSettled = (s) => {
4988
- const settledAt = Date.now();
5975
+ const commitSettled = (s, w) => {
4989
5976
  const settledKey = keyByWorker.get(s.handle.id);
4990
5977
  if (settledKey !== void 0 && s.kind === "done") completedKeys.add(settledKey);
4991
- const w = s.kind === "done" ? {
4992
- id: s.handle.id,
4993
- status: "done",
4994
- score: s.verdict?.score ?? 0,
4995
- valid: s.verdict?.valid ?? false,
4996
- outRef: s.outRef,
4997
- settledAt
4998
- } : {
4999
- id: s.handle.id,
5000
- status: "down",
5001
- reason: s.reason,
5002
- settledAt
5003
- };
5004
5978
  ledger.push(w);
5005
5979
  unwatchWorker(w.id);
5006
- return w;
5007
5980
  };
5008
- const drainSettlement = async () => {
5009
- const s = await opts.scope.next();
5010
- if (!s) return false;
5011
- const w = recordSettled(s);
5012
- await bus.publish({
5013
- type: "settled",
5014
- worker: w
5015
- });
5016
- if (w.status === "done" && w.outRef && opts.analysts && opts.analyzeOnSettle?.length) {
5017
- const trace = await opts.blobs.get(w.outRef);
5981
+ let pendingSettlement;
5982
+ const flushPendingSettlement = async () => {
5983
+ const pending = pendingSettlement;
5984
+ if (!pending) return false;
5985
+ await bus.publish(pending.event);
5986
+ commitSettled(pending.settled, pending.worker);
5987
+ pendingSettlement = void 0;
5988
+ if (pending.analyze && pending.worker.status === "done" && pending.worker.trace.status === "available" && opts.analysts && opts.analyzeOnSettle?.length) {
5989
+ const trace = await workerTraceAnalysisStore(pending.worker.trace, opts.blobs);
5018
5990
  for (const analyst of opts.analyzeOnSettle) {
5019
5991
  const findings = await opts.analysts.run(analyst, trace);
5020
5992
  await bus.publish({
5021
5993
  type: "finding",
5022
5994
  finding: {
5023
- fromWorker: w.id,
5995
+ fromWorker: pending.worker.id,
5024
5996
  analyst,
5025
5997
  findings
5026
5998
  }
@@ -5029,16 +6001,41 @@ function createCoordinationTools(opts) {
5029
6001
  }
5030
6002
  return true;
5031
6003
  };
6004
+ const drainSettlement = async () => {
6005
+ if (!pendingSettlement) {
6006
+ const settled = await opts.scope.next();
6007
+ if (!settled) return false;
6008
+ const worker = projectSettled(settled);
6009
+ pendingSettlement = {
6010
+ settled,
6011
+ worker,
6012
+ event: deepFreezeDetached({
6013
+ type: "settled",
6014
+ worker
6015
+ }),
6016
+ analyze: true
6017
+ };
6018
+ }
6019
+ return flushPendingSettlement();
6020
+ };
5032
6021
  const drainResolved = async () => {
5033
6022
  let drained = 0;
5034
6023
  for (;;) {
5035
- const s = await opts.scope.nextResolved();
5036
- if (!s) return drained;
5037
- const w = recordSettled(s);
5038
- await bus.publish({
5039
- type: "settled",
5040
- worker: w
5041
- });
6024
+ if (!pendingSettlement) {
6025
+ const settled = await opts.scope.nextResolved();
6026
+ if (!settled) return drained;
6027
+ const worker = projectSettled(settled);
6028
+ pendingSettlement = {
6029
+ settled,
6030
+ worker,
6031
+ event: deepFreezeDetached({
6032
+ type: "settled",
6033
+ worker
6034
+ }),
6035
+ analyze: false
6036
+ };
6037
+ }
6038
+ await flushPendingSettlement();
5042
6039
  drained += 1;
5043
6040
  }
5044
6041
  };
@@ -5052,21 +6049,100 @@ function createCoordinationTools(opts) {
5052
6049
  down
5053
6050
  }, { queue: false });
5054
6051
  }
6052
+ const authorizeInstruction = (kind, workerId, instruction, interrupt, questionId) => {
6053
+ const workerIdentity = opts.scope.view.nodes.find((node) => node.id === workerId)?.identity;
6054
+ let authorizedInstruction = instruction;
6055
+ if (opts.authorizeDownMessage) {
6056
+ if (workerIdentity === void 0) throw new Error(`coordination tools: cannot authorize ${kind} for worker ${JSON.stringify(workerId)} without durable identity`);
6057
+ const decision = deepFreezeDetached(opts.authorizeDownMessage(deepFreezeDetached({
6058
+ kind,
6059
+ workerId,
6060
+ workerIdentity,
6061
+ instruction,
6062
+ interrupt,
6063
+ ...questionId !== void 0 ? { questionId } : {}
6064
+ })));
6065
+ if (typeof decision !== "object" || decision === null || Array.isArray(decision) || typeof decision.instruction !== "string" || decision.instruction.length === 0) throw new Error("coordination tools: authorizeDownMessage must return an instruction");
6066
+ authorizedInstruction = decision.instruction;
6067
+ }
6068
+ return deepFreezeDetached({
6069
+ receiptId: randomUUID(),
6070
+ kind,
6071
+ toWorker: workerId,
6072
+ instruction: authorizedInstruction,
6073
+ instructionDigest: canonicalCandidateDigest(authorizedInstruction),
6074
+ ...workerIdentity !== void 0 ? { workerIdentity } : {},
6075
+ interrupt,
6076
+ ...questionId !== void 0 ? { questionId } : {}
6077
+ });
6078
+ };
6079
+ /** Publish before `scope.send`: an awaited durable subscriber therefore commits the exact bytes
6080
+ * before the worker can observe them. */
6081
+ const recordInstruction = async (instruction) => {
6082
+ await bus.publish({
6083
+ type: "instruction",
6084
+ instruction
6085
+ }, { queue: false });
6086
+ };
6087
+ /** Commit delivery intent after the authorization receipt and before `Scope.send`. An attempt with
6088
+ * no matching outcome after a crash is explicitly unknown and must never be replayed. */
6089
+ const recordDeliveryAttempt = async (instruction) => {
6090
+ const attempt = deepFreezeDetached({
6091
+ receiptId: instruction.receiptId,
6092
+ kind: instruction.kind,
6093
+ toWorker: instruction.toWorker,
6094
+ instructionDigest: instruction.instructionDigest,
6095
+ interrupt: instruction.interrupt,
6096
+ ...instruction.questionId !== void 0 ? { questionId: instruction.questionId } : {}
6097
+ });
6098
+ await bus.publish({
6099
+ type: "delivery-attempt",
6100
+ attempt
6101
+ }, { queue: false });
6102
+ return attempt;
6103
+ };
6104
+ const deliveryOutcome = (workerId, delivered) => {
6105
+ if (delivered) return "delivered";
6106
+ if (opts.scope.signal.aborted) return "scope-stopped";
6107
+ const node = opts.scope.view.nodes.find((candidate) => candidate.id === workerId);
6108
+ if (!node) return "unknown-worker";
6109
+ if (!isLive(node.status)) return "already-settled";
6110
+ return "runtime-has-no-inbox";
6111
+ };
6112
+ const attemptDelivery = async (instruction, message) => {
6113
+ await recordDeliveryAttempt(instruction);
6114
+ let delivered = false;
6115
+ let outcome;
6116
+ let error;
6117
+ try {
6118
+ delivered = opts.scope.send(instruction.toWorker, message);
6119
+ outcome = deliveryOutcome(instruction.toWorker, delivered);
6120
+ } catch (cause) {
6121
+ outcome = "runtime-error";
6122
+ error = cause instanceof Error ? cause.message : String(cause);
6123
+ }
6124
+ const down = deepFreezeDetached({
6125
+ receiptId: instruction.receiptId,
6126
+ toWorker: instruction.toWorker,
6127
+ instruction: instruction.instruction,
6128
+ instructionDigest: instruction.instructionDigest,
6129
+ delivered,
6130
+ outcome,
6131
+ ...error !== void 0 ? { error } : {}
6132
+ });
6133
+ if (instruction.kind === "answer") await sendDown("answer", down, str(instruction.questionId, "questionId"));
6134
+ else await sendDown("steer", down);
6135
+ if (error !== void 0) throw new Error(`coordination tools: delivery failed: ${error}`);
6136
+ return down;
6137
+ };
5055
6138
  const projectEvent = (ev) => {
5056
6139
  if (ev.type === "settled") {
5057
- const w = ev.worker;
5058
- return w.status === "done" ? {
5059
- type: "settled",
5060
- settled: w.id,
5061
- status: "done",
5062
- score: w.score,
5063
- valid: w.valid,
5064
- outRef: w.outRef
5065
- } : {
6140
+ const { id, status, ...evidence } = ev.worker;
6141
+ return {
5066
6142
  type: "settled",
5067
- settled: w.id,
5068
- status: "down",
5069
- reason: w.reason
6143
+ settled: id,
6144
+ status,
6145
+ ...evidence
5070
6146
  };
5071
6147
  }
5072
6148
  if (ev.type === "question") return {
@@ -5082,12 +6158,25 @@ function createCoordinationTools(opts) {
5082
6158
  ...ev.down,
5083
6159
  questionId: ev.questionId
5084
6160
  };
6161
+ if (ev.type === "instruction") return {
6162
+ type: "instruction",
6163
+ ...ev.instruction
6164
+ };
6165
+ if (ev.type === "delivery-attempt") return {
6166
+ type: "delivery-attempt",
6167
+ ...ev.attempt
6168
+ };
5085
6169
  return {
5086
6170
  type: ev.type,
5087
6171
  ...ev.down
5088
6172
  };
5089
6173
  };
5090
- const nextQuestionId = (from) => `${from}:q${questionSeq++}`;
6174
+ const nextQuestionId = (from) => {
6175
+ for (;;) {
6176
+ const id = `${from}:q${questionSeq++}`;
6177
+ if (!questions.some((question) => question.id === id)) return id;
6178
+ }
6179
+ };
5091
6180
  const normalizeQuestion = (q, fallbackFrom) => {
5092
6181
  const from = str(q.from ?? fallbackFrom, "from");
5093
6182
  return {
@@ -5155,13 +6244,30 @@ function createCoordinationTools(opts) {
5155
6244
  };
5156
6245
  const maxLiveWorkers = opts.maxLiveWorkers;
5157
6246
  const isLive = (status) => status !== "done" && status !== "failed" && status !== "cancelled";
5158
- const liveWorkerCount = () => opts.scope.view.nodes.filter((n) => isLive(n.status)).length;
5159
- const liveSnapshot = () => opts.scope.view.nodes.filter((n) => isLive(n.status)).map((n) => ({
5160
- id: n.id,
5161
- status: n.status,
5162
- spent: n.spent
5163
- }));
5164
- const freeWorkerSlots = () => freeSlots(liveWorkerCount(), maxLiveWorkers);
6247
+ const localLiveWorkerCount = () => opts.scope.view.nodes.filter((n) => isLive(n.status)).length;
6248
+ const sharedWorkerCapacity = () => {
6249
+ return opts.scope.workerCapacity;
6250
+ };
6251
+ const usesTreeWideLimit = () => {
6252
+ const capacity = sharedWorkerCapacity();
6253
+ return capacity !== void 0 && capacity.freeSlots !== null;
6254
+ };
6255
+ const liveWorkerCount = () => usesTreeWideLimit() ? sharedWorkerCapacity()?.live ?? localLiveWorkerCount() : localLiveWorkerCount();
6256
+ const projectNodeEvidence = (node, resumed = false) => ({
6257
+ id: node.id,
6258
+ status: node.status,
6259
+ ...node.assignmentId === void 0 ? {} : { assignmentId: node.assignmentId },
6260
+ ...node.identity === void 0 ? {} : { identity: node.identity },
6261
+ ...node.materialization === void 0 ? {} : { materialization: node.materialization },
6262
+ ...node.executionBindings === void 0 ? {} : { executionBindings: node.executionBindings },
6263
+ spent: node.spent,
6264
+ ...node.settledAt === void 0 ? {} : { settledAt: node.settledAt },
6265
+ ...node.outRef === void 0 ? {} : { outRef: node.outRef },
6266
+ ...node.trace === void 0 ? {} : { trace: node.trace },
6267
+ ...resumed ? { resumed: true } : {}
6268
+ });
6269
+ const liveSnapshot = () => opts.scope.view.nodes.filter((n) => isLive(n.status)).map((n) => projectNodeEvidence(n));
6270
+ const freeWorkerSlots = () => usesTreeWideLimit() ? sharedWorkerCapacity()?.freeSlots ?? null : freeSlots(localLiveWorkerCount(), maxLiveWorkers);
5165
6271
  const readProgress = (id) => {
5166
6272
  const scope = opts.scope;
5167
6273
  if (typeof scope.progress !== "function") return void 0;
@@ -5262,10 +6368,22 @@ function createCoordinationTools(opts) {
5262
6368
  type: "object",
5263
6369
  description: "Optional per-spawn budget that merges over the per-worker default (per field). Only set the ceilings this sub-task needs raised; the conserved pool still fences.",
5264
6370
  properties: {
5265
- maxIterations: { type: "number" },
5266
- maxTokens: { type: "number" },
5267
- maxUsd: { type: "number" },
5268
- deadlineMs: { type: "number" }
6371
+ maxIterations: {
6372
+ type: "number",
6373
+ minimum: 0
6374
+ },
6375
+ maxTokens: {
6376
+ type: "number",
6377
+ minimum: 0
6378
+ },
6379
+ maxUsd: {
6380
+ type: "number",
6381
+ minimum: 0
6382
+ },
6383
+ deadlineMs: {
6384
+ type: "number",
6385
+ minimum: 0
6386
+ }
5269
6387
  }
5270
6388
  }
5271
6389
  },
@@ -5274,28 +6392,47 @@ function createCoordinationTools(opts) {
5274
6392
  handler: (raw) => {
5275
6393
  const a = obj(raw);
5276
6394
  const key = a.key === void 0 ? void 0 : str(a.key, "key");
5277
- if (!(key !== void 0 && completedKeys.has(key)) && maxLiveWorkers !== void 0 && maxLiveWorkers > 0 && liveWorkerCount() >= maxLiveWorkers) return Promise.resolve({
6395
+ if (!(key !== void 0 && completedKeys.has(key)) && !usesTreeWideLimit() && maxLiveWorkers !== void 0 && maxLiveWorkers > 0 && liveWorkerCount() >= maxLiveWorkers) return Promise.resolve({
5278
6396
  error: "max-live-workers",
5279
6397
  live: liveWorkerCount(),
5280
6398
  freeSlots: freeWorkerSlots()
5281
6399
  });
5282
- const agent = opts.makeWorkerAgent(a.profile);
5283
- const budget = a.budget === void 0 ? opts.perWorker : mergeBudget(opts.perWorker, a.budget);
5284
- const res = opts.scope.spawn(agent, a.task, {
6400
+ const parsedProfile = agentProfileSchema.safeParse(a.profile);
6401
+ if (!parsedProfile.success) return Promise.resolve({
6402
+ error: "invalid-profile",
6403
+ issues: parsedProfile.error.issues.map((issue) => ({
6404
+ path: issue.path.join("."),
6405
+ message: issue.message
6406
+ }))
6407
+ });
6408
+ const profile = deepFreezeDetached(parsedProfile.data);
6409
+ const task = deepFreezeDetached(a.task);
6410
+ const label = typeof a.label === "string" ? a.label : "worker";
6411
+ const budget = Object.freeze(a.budget === void 0 ? opts.perWorker : mergeBudget(opts.perWorker, a.budget));
6412
+ const assignmentId = key !== void 0 ? `key:${key}` : `ordinal:${unkeyedAssignmentOrdinal++}`;
6413
+ const context = Object.freeze({
6414
+ assignmentId,
6415
+ parentNodeId: opts.scope.view.root,
6416
+ budget,
6417
+ task,
6418
+ label,
6419
+ ...key !== void 0 ? { key } : {}
6420
+ });
6421
+ const res = opts.scope.spawn(() => opts.makeWorkerAgent(profile, context), task, {
5285
6422
  budget,
5286
- label: typeof a.label === "string" ? a.label : "worker",
6423
+ label,
6424
+ assignmentId,
5287
6425
  ...key !== void 0 ? { key } : {}
5288
6426
  });
5289
6427
  if (res.ok && res.prior?.state === "completed") {
5290
6428
  const s = res.prior.settled;
5291
6429
  if (key !== void 0) completedKeys.add(key);
6430
+ const { id, status, resumed: _resumed, ...evidence } = projectSettled(s);
5292
6431
  return Promise.resolve({
5293
- workerId: s.handle.id,
6432
+ workerId: id,
5294
6433
  resumed: "completed",
5295
- status: "done",
5296
- score: s.verdict?.score ?? 0,
5297
- valid: s.verdict?.valid ?? false,
5298
- outRef: s.outRef,
6434
+ status,
6435
+ ...evidence,
5299
6436
  live: liveWorkerCount(),
5300
6437
  freeSlots: freeWorkerSlots()
5301
6438
  });
@@ -5311,6 +6448,10 @@ function createCoordinationTools(opts) {
5311
6448
  } : {};
5312
6449
  return Promise.resolve(res.ok ? {
5313
6450
  workerId: res.handle.id,
6451
+ assignmentId: res.handle.assignmentId ?? assignmentId,
6452
+ ...res.handle.identity === void 0 ? {} : { identity: res.handle.identity },
6453
+ ...res.handle.materialization === void 0 ? {} : { materialization: res.handle.materialization },
6454
+ ...res.handle.executionBindings === void 0 ? {} : { executionBindings: res.handle.executionBindings },
5314
6455
  live: liveWorkerCount(),
5315
6456
  freeSlots: freeWorkerSlots(),
5316
6457
  ...priorHistory
@@ -5338,19 +6479,16 @@ function createCoordinationTools(opts) {
5338
6479
  if (!resumed) return { error: `unknown workerId ${JSON.stringify(id)}` };
5339
6480
  const output = resumed.outRef ? await opts.blobs.get(resumed.outRef) : void 0;
5340
6481
  return {
5341
- status: resumed.status,
5342
- spent: resumed.spent,
6482
+ ...projectNodeEvidence(resumed, true),
5343
6483
  outRef: resumed.outRef ?? null,
5344
6484
  output: output ?? null,
5345
- progress: null,
5346
- resumed: true
6485
+ progress: null
5347
6486
  };
5348
6487
  }
5349
6488
  const output = node.outRef ? await opts.blobs.get(node.outRef) : void 0;
5350
6489
  const progress = readProgress(id);
5351
6490
  return {
5352
- status: node.status,
5353
- spent: node.spent,
6491
+ ...projectNodeEvidence(node),
5354
6492
  outRef: node.outRef ?? null,
5355
6493
  output: output ?? null,
5356
6494
  progress: progress ?? null
@@ -5380,24 +6518,20 @@ function createCoordinationTools(opts) {
5380
6518
  const workerId = str(a.workerId, "workerId");
5381
6519
  const instruction = str(a.instruction, "instruction");
5382
6520
  const interrupt = a.interrupt === true;
5383
- const delivered = opts.scope.send(workerId, {
5384
- steer: instruction,
6521
+ const authorized = authorizeInstruction("steer", workerId, instruction, interrupt);
6522
+ await recordInstruction(authorized);
6523
+ const delivery = await attemptDelivery(authorized, {
6524
+ steer: authorized.instruction,
5385
6525
  interrupt
5386
6526
  });
5387
- await sendDown("steer", {
5388
- toWorker: workerId,
5389
- instruction,
5390
- delivered
5391
- });
5392
- if (delivered) return {
5393
- delivered,
6527
+ if (delivery.delivered) return {
6528
+ delivered: true,
5394
6529
  progress: readProgress(workerId) ?? null
5395
6530
  };
5396
- const progress = readProgress(workerId);
5397
6531
  return {
5398
- delivered,
5399
- reason: !progress ? "unknown-worker" : !progress.live ? "already-settled" : "runtime-has-no-inbox",
5400
- progress: progress ?? null
6532
+ delivered: false,
6533
+ reason: delivery.outcome,
6534
+ progress: readProgress(workerId) ?? null
5401
6535
  };
5402
6536
  }
5403
6537
  },
@@ -5479,25 +6613,24 @@ function createCoordinationTools(opts) {
5479
6613
  const questionId = str(a.questionId, "questionId");
5480
6614
  if (typeof a.answer === "string" && a.answer.length > 0) {
5481
6615
  const answer = a.answer;
5482
- const question = decideQuestion(questionId, {
5483
- kind: "answer",
5484
- answer,
5485
- by: typeof a.by === "string" && a.by.length > 0 ? a.by : "user"
5486
- });
5487
- const interrupt = question.urgency === "blocks-run" || question.urgency === "blocks-step";
5488
- const delivered = opts.scope.send(question.from, {
5489
- answer,
6616
+ const pendingQuestion = questions.find((question) => question.id === questionId);
6617
+ if (pendingQuestion === void 0) throw new Error(`unknown questionId ${JSON.stringify(questionId)}`);
6618
+ const interrupt = pendingQuestion.urgency === "blocks-run" || pendingQuestion.urgency === "blocks-step";
6619
+ const authorized = authorizeInstruction("answer", pendingQuestion.from, answer, interrupt, questionId);
6620
+ await recordInstruction(authorized);
6621
+ const delivery = await attemptDelivery(authorized, {
6622
+ answer: authorized.instruction,
5490
6623
  questionId,
5491
6624
  interrupt
5492
6625
  });
5493
- await sendDown("answer", {
5494
- toWorker: question.from,
5495
- instruction: answer,
5496
- delivered
5497
- }, questionId);
5498
6626
  return {
5499
- question,
5500
- delivered
6627
+ question: delivery.delivered ? decideQuestion(questionId, {
6628
+ kind: "answer",
6629
+ answer: authorized.instruction,
6630
+ by: typeof a.by === "string" && a.by.length > 0 ? a.by : "user"
6631
+ }) : pendingQuestion,
6632
+ delivered: delivery.delivered,
6633
+ ...delivery.delivered ? {} : { reason: delivery.outcome }
5501
6634
  };
5502
6635
  }
5503
6636
  if (typeof a.deferReason === "string" && a.deferReason.length > 0) return Promise.resolve({ question: decideQuestion(questionId, {
@@ -5663,16 +6796,29 @@ function createCoordinationTools(opts) {
5663
6796
  handler: async (raw) => {
5664
6797
  const a = obj(raw);
5665
6798
  const id = str(a.workerId, "workerId");
5666
- const node = opts.scope.view.nodes.find((n) => n.id === id);
6799
+ const node = nodeForWorker(id);
5667
6800
  if (!node) return { error: `unknown workerId ${JSON.stringify(id)}` };
5668
- if (!node.outRef) return { error: `worker ${JSON.stringify(id)} has not settled — no trace to analyze yet` };
5669
- const trace = await opts.blobs.get(node.outRef);
5670
- return { findings: await opts.analysts?.run(str(a.kind, "kind"), trace) };
6801
+ if (isLive(node.status)) return { error: `worker ${JSON.stringify(id)} has not settled — no trace to analyze yet` };
6802
+ const trace = ledger.find((worker) => worker.id === id)?.trace ?? node.trace ?? {
6803
+ status: "unavailable",
6804
+ reason: "legacy-settlement-without-trace-evidence"
6805
+ };
6806
+ let store;
6807
+ try {
6808
+ store = await workerTraceAnalysisStore(trace, opts.blobs);
6809
+ } catch (error) {
6810
+ return {
6811
+ error: error instanceof Error ? error.message : String(error),
6812
+ trace
6813
+ };
6814
+ }
6815
+ return { findings: await opts.analysts?.run(str(a.kind, "kind"), store) };
5671
6816
  }
5672
6817
  });
5673
6818
  }
5674
6819
  return {
5675
6820
  tools,
6821
+ ready,
5676
6822
  history: () => bus.history(),
5677
6823
  raiseFinding: (finding) => bus.publish({
5678
6824
  type: "finding",
@@ -5687,6 +6833,31 @@ function createCoordinationTools(opts) {
5687
6833
  drainResolved
5688
6834
  };
5689
6835
  }
6836
+ function nextUnkeyedAssignmentOrdinal(scope) {
6837
+ let next = 0;
6838
+ const views = [scope.resume?.view, scope.view];
6839
+ for (const view of views) {
6840
+ if (view === void 0) continue;
6841
+ for (const node of view.nodes) {
6842
+ const match = /^ordinal:(\d+)$/.exec(node.assignmentId ?? "");
6843
+ if (match === null) continue;
6844
+ const ordinal = Number(match[1]);
6845
+ if (!Number.isSafeInteger(ordinal)) throw new Error(`coordination: durable assignment id '${node.assignmentId}' exceeds the safe ordinal range`);
6846
+ next = Math.max(next, ordinal + 1);
6847
+ }
6848
+ }
6849
+ if (!Number.isSafeInteger(next)) throw new Error("coordination: durable assignment ordinal space is exhausted");
6850
+ return next;
6851
+ }
6852
+ function deepFreezeDetached(value) {
6853
+ return deepFreeze(structuredClone(value));
6854
+ }
6855
+ function deepFreeze(value, seen = /* @__PURE__ */ new Set()) {
6856
+ if (value === null || typeof value !== "object" || seen.has(value)) return value;
6857
+ seen.add(value);
6858
+ for (const child of Object.values(value)) deepFreeze(child, seen);
6859
+ return Object.freeze(value);
6860
+ }
5690
6861
  //#endregion
5691
6862
  //#region src/runtime/anytime.ts
5692
6863
  /**
@@ -6106,10 +7277,11 @@ const runawayTripwireTurns = 2e3;
6106
7277
  * overspend usd up to the turn tripwire). */
6107
7278
  function poolStarved(scope, perWorker) {
6108
7279
  const b = scope.budget;
6109
- if (b.reservedTokens > 0) return false;
7280
+ if (scope.view.inFlight > 0 || scope.view.waiting > 0) return false;
6110
7281
  const tokenStarved = b.tokensLeft < perWorker.maxTokens;
6111
- const usdStarved = b.usdCapped && b.usdLeft <= 0;
6112
- return tokenStarved || usdStarved;
7282
+ const iterationStarved = b.iterationsLeft <= 0;
7283
+ const usdStarved = b.usdCapped && (b.usdLeft <= 0 || perWorker.maxUsd !== void 0 && b.usdLeft < perWorker.maxUsd);
7284
+ return tokenStarved || iterationStarved || usdStarved;
6113
7285
  }
6114
7286
  /** The absolute wall-clock deadline (when the root set one) has passed. */
6115
7287
  function deadlinePassed(scope, now) {
@@ -6142,17 +7314,29 @@ function driverAgent(opts) {
6142
7314
  if ((opts.extraTools?.length ?? 0) > 0 && typeof opts.executeExtraTool !== "function") throw new ValidationError("driverAgent: extraTools requires executeExtraTool (how to run a work-tool call)");
6143
7315
  if ((opts.analyzeOnSettle?.length ?? 0) > 0 && !opts.analysts) throw new ValidationError("driverAgent: analyzeOnSettle requires analysts (the lens registry the kinds resolve against)");
6144
7316
  const reserved = new Set(coordinationVerbNames);
6145
- for (const t of opts.extraTools ?? []) if (reserved.has(t.name)) throw new ValidationError(`driverAgent: extra work tool "${t.name}" collides with a coordination verb`);
7317
+ for (const tool of opts.nodeTools ?? []) {
7318
+ if (reserved.has(tool.name)) throw new ValidationError(`driverAgent: node tool "${tool.name}" collides with a coordination verb or another node tool`);
7319
+ reserved.add(tool.name);
7320
+ }
7321
+ for (const t of opts.extraTools ?? []) {
7322
+ if (reserved.has(t.name)) throw new ValidationError(`driverAgent: extra work tool "${t.name}" collides with a coordination verb or node tool`);
7323
+ reserved.add(t.name);
7324
+ }
6146
7325
  if (opts.maxTurns !== void 0 && opts.maxTurns < 0) throw new ValidationError("driverAgent: maxTurns must be >= 0 (0 lifts the turn cap; bounds become the conserved pool + deadline + abort)");
6147
7326
  const maxTurns = opts.maxTurns === 0 ? runawayTripwireTurns : opts.maxTurns ?? 16;
6148
7327
  const now = opts.now ?? Date.now;
7328
+ const inbox = opts.inbox ?? createInbox();
6149
7329
  return {
6150
7330
  name: opts.name,
7331
+ deliver(message) {
7332
+ return inbox.deliver(message);
7333
+ },
6151
7334
  async act(task, scope) {
6152
7335
  const coord = createCoordinationTools({
6153
7336
  scope,
6154
7337
  blobs: opts.blobs,
6155
7338
  makeWorkerAgent: opts.makeWorkerAgent,
7339
+ ...opts.authorizeDownMessage ? { authorizeDownMessage: opts.authorizeDownMessage } : {},
6156
7340
  perWorker: opts.perWorker,
6157
7341
  ...opts.deliverable ? { deliverable: opts.deliverable } : {},
6158
7342
  ...opts.maxLiveWorkers !== void 0 ? { maxLiveWorkers: opts.maxLiveWorkers } : {},
@@ -6161,28 +7345,41 @@ function driverAgent(opts) {
6161
7345
  ...opts.watchWorkers ? { watchWorkers: opts.watchWorkers } : {},
6162
7346
  ...opts.stallAfterMs !== void 0 ? { stallAfterMs: opts.stallAfterMs } : {},
6163
7347
  ...opts.onEvent ? { onEvent: opts.onEvent } : {},
7348
+ ...opts.replaySettlements ? { replaySettlements: true } : {},
6164
7349
  ...opts.priorCoordination?.questions.length ? { priorQuestions: opts.priorCoordination.questions } : {}
6165
7350
  });
7351
+ await coord.ready();
6166
7352
  for (const w of scope.resume?.waits ?? []) {
6167
7353
  const rearmed = scope.wait(w.spec, { label: w.label });
6168
7354
  if (!rearmed.ok) throw new RuntimeRunStateError(`driverAgent: cannot re-arm resumed wait '${w.label}' (${rearmed.reason})`);
6169
7355
  }
6170
- const byName = new Map(coord.tools.map((t) => [t.name, t]));
6171
- const toolSpecs = [...coord.tools.map((t) => ({
6172
- type: "function",
6173
- function: {
6174
- name: t.name,
6175
- description: t.description,
6176
- parameters: t.inputSchema
6177
- }
6178
- })), ...(opts.extraTools ?? []).map((t) => ({
6179
- type: "function",
6180
- function: {
6181
- name: t.name,
6182
- description: t.description,
6183
- parameters: t.parameters
6184
- }
6185
- }))];
7356
+ const byName = new Map([...coord.tools, ...opts.nodeTools ?? []].map((t) => [t.name, t]));
7357
+ const toolSpecs = [
7358
+ ...coord.tools.map((t) => ({
7359
+ type: "function",
7360
+ function: {
7361
+ name: t.name,
7362
+ description: t.description,
7363
+ parameters: t.inputSchema
7364
+ }
7365
+ })),
7366
+ ...(opts.nodeTools ?? []).map((t) => ({
7367
+ type: "function",
7368
+ function: {
7369
+ name: t.name,
7370
+ description: t.description,
7371
+ parameters: t.inputSchema
7372
+ }
7373
+ })),
7374
+ ...(opts.extraTools ?? []).map((t) => ({
7375
+ type: "function",
7376
+ function: {
7377
+ name: t.name,
7378
+ description: t.description,
7379
+ parameters: t.parameters
7380
+ }
7381
+ }))
7382
+ ];
6186
7383
  const system = typeof opts.systemPrompt === "function" ? opts.systemPrompt(task) : opts.systemPrompt;
6187
7384
  const tracker = opts.stopRule ? createProgressTracker({ now }) : void 0;
6188
7385
  let progressStopReason;
@@ -6262,20 +7459,32 @@ function driverAgent(opts) {
6262
7459
  ...scope.resume ? [{
6263
7460
  role: "user",
6264
7461
  content: resumeBrief(scope.resume, opts.priorCoordination)
7462
+ }] : hasPriorCoordination(opts.priorCoordination) ? [{
7463
+ role: "user",
7464
+ content: priorCoordinationBrief(opts.priorCoordination)
6265
7465
  }] : []
6266
7466
  ],
6267
7467
  maxTurns,
6268
- hooks: { stopBefore: () => {
6269
- if (coord.isStopped() || scope.signal.aborted || poolStarved(scope, opts.perWorker) || deadlinePassed(scope, now)) return true;
6270
- if (!opts.stopRule || !tracker) return false;
6271
- const decision = progressStop(tracker, opts.stopRule, coord, scope, now, opts.stallAfterMs);
6272
- if (!decision.stop) return false;
6273
- if (progressStopReason === void 0) {
6274
- progressStopReason = decision.reason;
6275
- opts.onProgressStop?.(decision.reason);
7468
+ hooks: {
7469
+ beforeTurn: (_turn, messages) => {
7470
+ const pending = inbox.drain();
7471
+ if (pending.length > 0) messages.push({
7472
+ role: "user",
7473
+ content: inbox.fold(pending)
7474
+ });
7475
+ },
7476
+ stopBefore: () => {
7477
+ if (coord.isStopped() || scope.signal.aborted || poolStarved(scope, opts.perWorker) || deadlinePassed(scope, now)) return true;
7478
+ if (!opts.stopRule || !tracker) return false;
7479
+ const decision = progressStop(tracker, opts.stopRule, coord, scope, now, opts.stallAfterMs);
7480
+ if (!decision.stop) return false;
7481
+ if (progressStopReason === void 0) {
7482
+ progressStopReason = decision.reason;
7483
+ opts.onProgressStop?.(decision.reason);
7484
+ }
7485
+ return true;
6276
7486
  }
6277
- return true;
6278
- } }
7487
+ }
6279
7488
  });
6280
7489
  await coord.drainResolved();
6281
7490
  const submitted = coord.submittedResult();
@@ -6292,8 +7501,9 @@ function driverAgent(opts) {
6292
7501
  /**
6293
7502
  * The factual context a resumed driver starts from — everything the durable stores prove about
6294
7503
  * the prior process(es): committed settlements, per-key states (completed / lost / failed),
6295
- * re-armed waits, carried-over questions and findings, and the spend already paid. Injected as
6296
- * the brain's first user-context on a resumed run so it continues from the unresolved work.
7504
+ * re-armed waits, carried-over questions/findings/continuation receipts, and spend already paid.
7505
+ * Injected as the brain's first user-context on a resumed run so it continues from unresolved work;
7506
+ * old continuation receipts are evidence and are never auto-delivered.
6297
7507
  */
6298
7508
  function resumeBrief(resume, prior) {
6299
7509
  const lines = [
@@ -6313,13 +7523,36 @@ function resumeBrief(resume, prior) {
6313
7523
  if (lost.length > 0) lines.push("", "Keys LOST in flight with the prior process — this is the unresolved work; spawn_agent with the same key starts a fresh attempt:", ...lost.map(([k, v]) => `- ${k} (prior attempt ${v.id}, ${v.label})`));
6314
7524
  if (failed.length > 0) lines.push("", "Keys whose prior attempt FAILED (settled down) — spawn_agent with the same key retries:", ...failed.map(([k, v]) => `- ${k} (prior attempt ${v.id}, ${v.label})`));
6315
7525
  if (resume.waits.length > 0) lines.push("", "Pending waits RE-ARMED on their original deadlines (they settle through await_event):", ...resume.waits.map((w) => `- ${w.label} (${w.spec.kind})`));
6316
- const openQuestions = (prior?.questions ?? []).filter((q) => q.status === "open" || q.status === "escalated");
6317
- if (openQuestions.length > 0) lines.push("", "Questions carried over, still undecided (answer_question decides them; list_questions shows all):", ...openQuestions.map((q) => `- [${q.id}] from=${q.from}, urgency=${q.urgency}: ${q.question}`));
6318
- if ((prior?.findings.length ?? 0) > 0) lines.push("", "Analyst findings from the prior process:", ...(prior?.findings ?? []).map((f) => `- ${f.analyst} on ${f.fromWorker}: ${safeJson(f.findings)}`));
7526
+ appendPriorCoordination(lines, prior);
6319
7527
  const spent = resume.priorSpend;
6320
7528
  lines.push("", "Budget the run ALREADY spent before this process (it counts toward the run total):", `- child work: tokens in=${spent.childWork.tokens.input} out=${spent.childWork.tokens.output}, usd=${spent.childWork.usd}, iterations=${spent.childWork.iterations}`, `- driver inference: tokens in=${spent.driverInference.tokens.input} out=${spent.driverInference.tokens.output}, usd=${spent.driverInference.usd}`);
6321
7529
  return lines.join("\n");
6322
7530
  }
7531
+ function hasPriorCoordination(prior) {
7532
+ return prior !== void 0 && (prior.questions.length > 0 || prior.findings.length > 0 || prior.continuations.length > 0 || prior.deliveryEvidence.length > 0);
7533
+ }
7534
+ function priorCoordinationBrief(prior) {
7535
+ const lines = [
7536
+ "PRIOR COORDINATION EVIDENCE: this logical supervisor ran in an earlier process.",
7537
+ "Use the evidence below as context. Never auto-deliver an old continuation; issue a new",
7538
+ "authorized instruction only when current live state still warrants it."
7539
+ ];
7540
+ appendPriorCoordination(lines, prior);
7541
+ return lines.join("\n");
7542
+ }
7543
+ function appendPriorCoordination(lines, prior) {
7544
+ const openQuestions = (prior?.questions ?? []).filter((q) => q.status === "open" || q.status === "escalated");
7545
+ if (openQuestions.length > 0) lines.push("", "Questions carried over, still undecided (answer_question decides them; list_questions shows all):", ...openQuestions.map((q) => `- [${q.id}] from=${q.from}, urgency=${q.urgency}: ${q.question}`));
7546
+ if ((prior?.findings.length ?? 0) > 0) lines.push("", "Analyst findings from the prior process:", ...(prior?.findings ?? []).map((f) => `- ${f.analyst} on ${f.fromWorker}: ${safeJson(f.findings)}`));
7547
+ if ((prior?.continuations.length ?? 0) > 0) {
7548
+ const attempts = new Set((prior?.deliveryEvidence ?? []).filter((event) => event.type === "delivery-attempt").map((event) => event.attempt.receiptId));
7549
+ const outcomes = new Map((prior?.deliveryEvidence ?? []).filter((event) => event.type === "steer" || event.type === "answer").map((event) => [event.down.receiptId, event.down.outcome]));
7550
+ lines.push("", "Authorized continuations committed by the prior process (evidence only; never replayed automatically):", ...(prior?.continuations ?? []).map((continuation) => {
7551
+ const delivery = outcomes.get(continuation.receiptId) ?? (attempts.has(continuation.receiptId) ? "unknown-after-crash" : "not-attempted-before-crash");
7552
+ return `- receipt=${continuation.receiptId}, ${continuation.kind} → ${continuation.toWorker}, instruction=${continuation.instructionDigest}, delivery=${delivery}`;
7553
+ }));
7554
+ }
7555
+ }
6323
7556
  /** Run a work tool. A throw is data to the driver (it can recover next turn), not a crash — fold
6324
7557
  * the error back as a string result. null/undefined passes through (the caller treats it as "not
6325
7558
  * handled" and falls to the coordination dispatch). */
@@ -7217,203 +8450,6 @@ function canonicalize(value) {
7217
8450
  return out;
7218
8451
  }
7219
8452
  //#endregion
7220
- //#region src/runtime/supervise/authoring.ts
7221
- /**
7222
- *
7223
- * The supervisor's intelligence is AUTHORING the agents it spawns — not pressing buttons.
7224
- *
7225
- * Every agent here is three things: instructions (system prompt), tools, and a model — its
7226
- * `AgentProfile`. The supervisor's job is to WRITE those profiles: read the task, decompose it,
7227
- * and for each sub-task author a tailored worker recipe. `supervisorInstructions` is the how-to the
7228
- * supervisor reads (its system prompt); `authoredWorker` builds a worker AGENT from a profile the
7229
- * supervisor authored — the authored systemPrompt + model shape the worker's call.
7230
- *
7231
- * The skill is the single OPTIMIZABLE surface: edit it → the supervisor designs better agents.
7232
- * That is the self-improvement lever (the prompt/skill lever), not the execution plumbing.
7233
- *
7234
- * @experimental
7235
- */
7236
- /** Narrow an untyped `spawn_agent` profile argument to an `AuthoredProfile`, or null if the
7237
- * supervisor failed to author one (empty/placeholder profile — a skill violation worth catching). */
7238
- function asAuthoredProfile(raw) {
7239
- const p = raw;
7240
- if (!p || typeof p.systemPrompt !== "string" || p.systemPrompt.trim().length === 0) return null;
7241
- return {
7242
- name: typeof p.name === "string" && p.name.length > 0 ? p.name : "worker",
7243
- systemPrompt: p.systemPrompt,
7244
- ...typeof p.model === "string" ? { model: p.model } : {}
7245
- };
7246
- }
7247
- /** The supervisor SKILL — the how-to the supervisor reads (its system prompt). THE optimizable
7248
- * surface: editing this changes how the supervisor designs every agent it spawns. */
7249
- function supervisorInstructions(opts) {
7250
- return [
7251
- "You are a SUPERVISOR. You do NOT do the work yourself — your job is to DESIGN and DRIVE specialist worker agents.",
7252
- "",
7253
- "For the task you are given:",
7254
- "1. DECOMPOSE it into the smallest set of sub-tasks a single focused worker can each deliver.",
7255
- "2. For EACH sub-task, AUTHOR a worker by calling spawn_agent with a COMPLETE `profile`:",
7256
- " • name: a short id for the worker.",
7257
- " • systemPrompt: rich, specific instructions for THIS sub-task — tell the worker exactly what to produce, how to use its tools fully, and what \"done\" means. Never a one-liner; write the prompt a power-user would write.",
7258
- " • model: the model best suited to this sub-task (omit to use the default).",
7259
- " NEVER spawn a worker with an empty profile. The quality of the worker IS the quality of the profile you write.",
7260
- "3. await_event (kinds:['settled']) to collect each worker. Its result says valid:true only if the deployable check passed.",
7261
- "4. If a worker did NOT deliver, AUTHOR A NEW worker whose systemPrompt names the SPECIFIC failure and how to fix it — never just retry the same prompt.",
7262
- "5. Stop (reply with no tool call) once the work is delivered. You cannot declare done yourself — only a delivered (valid:true) worker counts.",
7263
- ...opts?.goal ? ["", `The goal: ${opts.goal}`] : []
7264
- ].join("\n");
7265
- }
7266
- /** Build a worker AGENT from a profile the supervisor authored: the authored `systemPrompt` +
7267
- * `model` shape the worker's one model call; the deliverable gates settlement (valid ⟺ delivered). */
7268
- function authoredWorker(profile, opts) {
7269
- let artifact;
7270
- const model = profile.model ?? opts.cfg.model;
7271
- const gated = gateOnDeliverable({
7272
- runtime: "router",
7273
- async execute(_t, signal) {
7274
- const res = await routerChatWithUsage({
7275
- ...opts.cfg,
7276
- model
7277
- }, [{
7278
- role: "system",
7279
- content: profile.systemPrompt
7280
- }, {
7281
- role: "user",
7282
- content: opts.taskPrompt
7283
- }], {
7284
- temperature: opts.temperature ?? .4,
7285
- ...signal ? { signal } : {}
7286
- });
7287
- artifact = {
7288
- outRef: contentAddress(res.content),
7289
- out: res.content,
7290
- spent: {
7291
- iterations: 1,
7292
- tokens: res.usage ?? {
7293
- input: 0,
7294
- output: 0
7295
- },
7296
- usd: res.costUsd ?? 0,
7297
- ms: 0
7298
- }
7299
- };
7300
- return artifact;
7301
- },
7302
- teardown: () => Promise.resolve({ destroyed: true }),
7303
- resultArtifact: () => {
7304
- if (!artifact) throw new Error("authoredWorker: resultArtifact read before execute");
7305
- return artifact;
7306
- }
7307
- }, opts.deliverable);
7308
- const spec = {
7309
- profile: { name: profile.name },
7310
- harness: null,
7311
- executor: gated
7312
- };
7313
- return {
7314
- name: profile.name,
7315
- act: async () => "",
7316
- executorSpec: spec
7317
- };
7318
- }
7319
- /** Default thresholds for `ProfileRichnessThresholds` — 600 chars / 6 lines minimum system prompt. */
7320
- const defaultProfileRichnessThresholds = {
7321
- minSystemPromptChars: 600,
7322
- minSystemPromptLines: 6
7323
- };
7324
- /** Read the system prompt from any authored shape: canonical `prompt.systemPrompt`, the sandbox
7325
- * `prompt.system` convention, or a bare-string `prompt`. */
7326
- function resolveSystemPrompt(profile) {
7327
- const pr = profile.prompt;
7328
- if (typeof pr === "string") return pr;
7329
- if (pr && typeof pr === "object") {
7330
- const o = pr;
7331
- if (typeof o.systemPrompt === "string") return o.systemPrompt;
7332
- if (typeof o.system === "string") return o.system;
7333
- }
7334
- return "";
7335
- }
7336
- /** OBSERVE one authored `AgentProfile` and score its richness (no judge verdict is read). The task
7337
- * context (`needsMcp`) lets a domain say "this work needs a data/tool MCP" so a missing MCP counts. */
7338
- function assessAuthoredProfile(profile, opts) {
7339
- const th = {
7340
- ...defaultProfileRichnessThresholds,
7341
- ...opts?.thresholds ?? {}
7342
- };
7343
- const systemPrompt = resolveSystemPrompt(profile);
7344
- const trimmed = systemPrompt.trim();
7345
- const systemPromptChars = trimmed.length;
7346
- const systemPromptLines = trimmed ? trimmed.split("\n").filter((l) => l.trim().length > 0).length : 0;
7347
- const sentenceCount = trimmed ? (trimmed.match(/[.!?](\s|$)/g) ?? []).length || (trimmed ? 1 : 0) : 0;
7348
- const hasDescription = typeof profile.description === "string" && profile.description.trim().length > 0;
7349
- const tools = profile.tools;
7350
- const hasTools = !!tools && Object.keys(tools).length > 0;
7351
- const skills = profile.resources?.skills;
7352
- const hasSkills = Array.isArray(skills) && skills.length > 0;
7353
- const mcp = profile.mcp;
7354
- const hasMcp = !!mcp && Object.keys(mcp).length > 0;
7355
- const subagents = profile.subagents;
7356
- const hasSubagents = !!subagents && Object.keys(subagents).length > 0;
7357
- const reasons = [];
7358
- const promptThin = systemPromptChars < th.minSystemPromptChars || systemPromptLines < th.minSystemPromptLines;
7359
- if (promptThin) reasons.push(`system prompt is thin (${systemPromptChars} chars, ${systemPromptLines} lines; need ≥${th.minSystemPromptChars} chars and ≥${th.minSystemPromptLines} lines)`);
7360
- if (!hasTools) reasons.push("no tools granted (a worker can only act through the tools you grant it)");
7361
- if (!hasSkills) reasons.push("no skills attached (no reusable how-to notes injected)");
7362
- if (opts?.needsMcp && !hasMcp) reasons.push("no MCP server, but the task needs data/tool access");
7363
- const signals = [
7364
- !promptThin,
7365
- hasTools,
7366
- hasSkills,
7367
- hasDescription,
7368
- opts?.needsMcp ? hasMcp : true
7369
- ];
7370
- const richness = signals.filter(Boolean).length / signals.length;
7371
- const thin = promptThin || !hasTools && !hasSkills && !hasMcp;
7372
- return {
7373
- name: profile.name ?? "worker",
7374
- systemPrompt,
7375
- systemPromptChars,
7376
- systemPromptLines,
7377
- sentenceCount,
7378
- hasDescription,
7379
- hasTools,
7380
- hasSkills,
7381
- hasMcp,
7382
- hasSubagents,
7383
- richness,
7384
- thin,
7385
- reasons
7386
- };
7387
- }
7388
- /** Turn a {@link ProfileRichness} verdict into a bus-routable `AnalystFinding` (area `profile-quality`).
7389
- * Severity scales with thinness; the recommended action names the MISSING lever so the supervisor can
7390
- * re-author. `subject` = the worker name so per-worker findings diff cleanly across re-authors. */
7391
- function profileRichnessFinding(richness, opts) {
7392
- const analyst_id = opts?.analystId ?? "profile-richness";
7393
- const subject = richness.name;
7394
- const claim = richness.thin ? `Worker "${richness.name}" was authored as a THIN profile: ${richness.reasons.join("; ")}.` : `Worker "${richness.name}" was authored as a rich profile (richness ${(richness.richness * 100).toFixed(0)}%).`;
7395
- return makeFinding({
7396
- analyst_id,
7397
- severity: richness.thin ? richness.richness < .25 ? "high" : "medium" : "info",
7398
- area: "profile-quality",
7399
- claim,
7400
- subject,
7401
- confidence: .9,
7402
- evidence_refs: [{
7403
- kind: "metric",
7404
- uri: `profile:${subject}`,
7405
- excerpt: `chars=${richness.systemPromptChars} lines=${richness.systemPromptLines} tools=${richness.hasTools} skills=${richness.hasSkills} mcp=${richness.hasMcp} richness=${richness.richness.toFixed(2)}`
7406
- }],
7407
- ...richness.thin ? { recommended_action: `Re-author "${richness.name}" with: ${richness.reasons.join("; ")}.` } : {},
7408
- id_basis: computeFindingId({
7409
- analyst_id,
7410
- area: "profile-quality",
7411
- subject,
7412
- claim: `richness:${richness.thin ? "thin" : "rich"}`
7413
- })
7414
- });
7415
- }
7416
- //#endregion
7417
8453
  //#region src/runtime/supervise/delegate.ts
7418
8454
  /**
7419
8455
  *
@@ -7442,15 +8478,15 @@ const defaultDelegateBudget = {
7442
8478
  maxIterations: 50,
7443
8479
  maxTokens: 2e5
7444
8480
  };
7445
- /** Build the DEFAULT authoring supervisor profile: a router-brained supervisor (`harness: null`)
8481
+ /** Build the DEFAULT authoring supervisor profile: a router-brained supervisor (`harness: cli-base`)
7446
8482
  * whose standing instruction IS the authoring-agent-profiles skill, so it decomposes the intent and
7447
8483
  * AUTHORS a worker profile per sub-task. No worker profile is baked in here. */
7448
8484
  function authoringSupervisorProfile(model, override) {
7449
8485
  return {
7450
8486
  name: override?.name ?? "delegate-supervisor",
7451
- harness: null,
7452
- ...model ? { model } : {},
7453
- systemPrompt: override?.systemPrompt ?? supervisorInstructions()
8487
+ harness: "cli-base",
8488
+ ...model ? { model: { default: model } } : {},
8489
+ prompt: { systemPrompt: override?.systemPrompt ?? supervisorInstructions() }
7454
8490
  };
7455
8491
  }
7456
8492
  /**
@@ -7535,11 +8571,19 @@ function validateDelegateArgs(raw) {
7535
8571
  * conserved `spentTotal`, so the agent always learns the cost — even on a no-winner, never a faked
7536
8572
  * output and never a fabricated zero spend. */
7537
8573
  function toDelegateResult(result) {
7538
- if (result.kind === "no-winner") return {
7539
- status: "no-winner",
7540
- reason: result.reason,
7541
- spentTotal: result.spentTotal
7542
- };
8574
+ if (result.kind === "no-winner") {
8575
+ const rejection = result.error;
8576
+ const error = typeof rejection?.name === "string" && typeof rejection.message === "string" ? {
8577
+ name: rejection.name,
8578
+ message: rejection.message
8579
+ } : void 0;
8580
+ return {
8581
+ status: "no-winner",
8582
+ reason: result.reason,
8583
+ ...error ? { error } : {},
8584
+ spentTotal: result.spentTotal
8585
+ };
8586
+ }
7543
8587
  return {
7544
8588
  status: "winner",
7545
8589
  out: result.out,
@@ -8299,6 +9343,7 @@ async function serveCoordinationMcp(opts) {
8299
9343
  scope: opts.scope,
8300
9344
  blobs: opts.blobs,
8301
9345
  makeWorkerAgent: opts.makeWorkerAgent,
9346
+ ...opts.authorizeDownMessage ? { authorizeDownMessage: opts.authorizeDownMessage } : {},
8302
9347
  perWorker: opts.perWorker,
8303
9348
  ...opts.deliverable ? { deliverable: opts.deliverable } : {},
8304
9349
  ...opts.maxLiveWorkers !== void 0 ? { maxLiveWorkers: opts.maxLiveWorkers } : {},
@@ -8308,11 +9353,13 @@ async function serveCoordinationMcp(opts) {
8308
9353
  ...opts.watchWorkers ? { watchWorkers: opts.watchWorkers } : {},
8309
9354
  ...opts.stallAfterMs !== void 0 ? { stallAfterMs: opts.stallAfterMs } : {},
8310
9355
  ...opts.onEvent ? { onEvent: opts.onEvent } : {},
9356
+ ...opts.replaySettlements ? { replaySettlements: true } : {},
8311
9357
  ...opts.questionPolicy ? { questionPolicy: opts.questionPolicy } : {},
8312
9358
  ...opts.priorQuestions?.length ? { priorQuestions: opts.priorQuestions } : {}
8313
9359
  });
9360
+ await coord.ready();
8314
9361
  const mcp = createMcpServer({
8315
- extraTools: coord.tools,
9362
+ extraTools: [...coord.tools, ...opts.nodeTools ?? []],
8316
9363
  serverName: "coordination"
8317
9364
  });
8318
9365
  const server = createServer((req, res) => {
@@ -8484,45 +9531,81 @@ function assertCoordinationBinding(binding) {
8484
9531
  }
8485
9532
  /** Build a supervisor `Agent` from its profile: the brain resolves from `profile.harness` (backend-as-data), the same resolution rule as every worker. */
8486
9533
  function supervisorAgent(profile, deps) {
8487
- const name = profile.name ?? "supervisor";
8488
- const harness = profile.harness ?? null;
8489
- const profilePrompt = resolveSupervisorSystemPrompt(profile);
9534
+ const stableProfile = detachedSnapshot(profile, "supervisorAgent profile");
9535
+ const resolveTools = deps.resolveSupervisorTools;
9536
+ const observeNodeEvent = deps.observeNodeEvent;
9537
+ const nodeContextSeed = deps.nodeContext === void 0 ? void 0 : detachedSnapshot(deps.nodeContext, "supervisorAgent node context");
9538
+ if ((resolveTools || observeNodeEvent) && !nodeContextSeed) throw new ValidationError("supervisorAgent: nodeContext is required with resolveSupervisorTools or observeNodeEvent");
9539
+ const name = stableProfile.name ?? "supervisor";
9540
+ const harness = stableProfile.harness === void 0 || stableProfile.harness === null || stableProfile.harness === "cli-base" ? null : stableProfile.harness;
9541
+ const profilePrompt = resolveSupervisorSystemPrompt(stableProfile);
8490
9542
  const coordination = deps.coordination ? { ...deps.coordination } : void 0;
8491
9543
  assertCoordinationBinding(coordination);
8492
9544
  if (harness === null && coordination !== void 0) throw new ConfigError("supervisorAgent: coordination binding is only meaningful for a harness-brained supervisor (profile.harness set). A router-brained supervisor calls the coordination verbs in process and serves no MCP, so this binding would be silently ignored.");
8493
- if (harness !== null && deps.compaction) throw new ValidationError("supervisorAgent: compaction is only supported for router-brained supervisors (profile.harness null)");
8494
- if (harness === null) return driverAgent({
8495
- name,
8496
- brain: deps.brain ?? routerBrainFromProfile(profile, deps),
8497
- blobs: deps.blobs,
8498
- makeWorkerAgent: deps.makeWorkerAgent,
8499
- perWorker: deps.perWorker,
8500
- systemPrompt: resolveSupervisorSystemPrompt(profile, defaultSupervisorPrompt) ?? defaultSupervisorPrompt,
8501
- ...deps.deliverable ? { deliverable: deps.deliverable } : {},
8502
- ...deps.maxLiveWorkers !== void 0 ? { maxLiveWorkers: deps.maxLiveWorkers } : {},
8503
- ...deps.extraTools ? { extraTools: deps.extraTools } : {},
8504
- ...deps.executeExtraTool ? { executeExtraTool: deps.executeExtraTool } : {},
8505
- ...deps.analysts ? { analysts: deps.analysts } : {},
8506
- ...deps.analyzeOnSettle ? { analyzeOnSettle: deps.analyzeOnSettle } : {},
8507
- ...deps.watchWorkers ? { watchWorkers: deps.watchWorkers } : {},
8508
- ...deps.stallAfterMs !== void 0 ? { stallAfterMs: deps.stallAfterMs } : {},
8509
- ...deps.stopRule ? { stopRule: deps.stopRule } : {},
8510
- ...deps.onProgressStop ? { onProgressStop: deps.onProgressStop } : {},
8511
- ...deps.maxTurns !== void 0 ? { maxTurns: deps.maxTurns } : {},
8512
- ...deps.compaction ? { compaction: deps.compaction } : {},
8513
- ...deps.onEvent ? { onEvent: deps.onEvent } : {},
8514
- ...deps.priorCoordination ? { priorCoordination: deps.priorCoordination } : {},
8515
- ...deps.finalizer ? { finalizer: deps.finalizer } : {}
8516
- });
9545
+ if (harness !== null && deps.compaction) throw new ValidationError("supervisorAgent: compaction is only supported for router-brained supervisors (profile.harness omitted or cli-base)");
9546
+ if (harness === null) {
9547
+ const brain = deps.brain ?? routerBrainFromProfile(stableProfile, deps);
9548
+ const inbox = createInbox();
9549
+ const build = (priorCoordination, nodeTools, onEvent) => driverAgent({
9550
+ name,
9551
+ brain,
9552
+ blobs: deps.blobs,
9553
+ makeWorkerAgent: deps.makeWorkerAgent,
9554
+ ...deps.authorizeDownMessage ? { authorizeDownMessage: deps.authorizeDownMessage } : {},
9555
+ perWorker: deps.perWorker,
9556
+ systemPrompt: resolveSupervisorSystemPrompt(stableProfile, defaultSupervisorPrompt) ?? defaultSupervisorPrompt,
9557
+ ...deps.deliverable ? { deliverable: deps.deliverable } : {},
9558
+ ...nodeTools?.length ? { nodeTools } : {},
9559
+ ...deps.maxLiveWorkers !== void 0 ? { maxLiveWorkers: deps.maxLiveWorkers } : {},
9560
+ ...deps.extraTools ? { extraTools: deps.extraTools } : {},
9561
+ ...deps.executeExtraTool ? { executeExtraTool: deps.executeExtraTool } : {},
9562
+ ...deps.analysts ? { analysts: deps.analysts } : {},
9563
+ ...deps.analyzeOnSettle ? { analyzeOnSettle: deps.analyzeOnSettle } : {},
9564
+ ...deps.watchWorkers ? { watchWorkers: deps.watchWorkers } : {},
9565
+ ...deps.stallAfterMs !== void 0 ? { stallAfterMs: deps.stallAfterMs } : {},
9566
+ ...deps.stopRule ? { stopRule: deps.stopRule } : {},
9567
+ ...deps.onProgressStop ? { onProgressStop: deps.onProgressStop } : {},
9568
+ ...deps.maxTurns !== void 0 ? { maxTurns: deps.maxTurns } : {},
9569
+ ...deps.compaction ? { compaction: deps.compaction } : {},
9570
+ ...onEvent ? { onEvent } : {},
9571
+ ...deps.replaySettlements ? { replaySettlements: true } : {},
9572
+ ...priorCoordination ? { priorCoordination } : {},
9573
+ ...deps.finalizer ? { finalizer: deps.finalizer } : {},
9574
+ inbox
9575
+ });
9576
+ if (!deps.loadPriorCoordination && !resolveTools && !observeNodeEvent) return build(deps.priorCoordination, void 0, deps.onEvent);
9577
+ return {
9578
+ name,
9579
+ deliver(message) {
9580
+ return inbox.deliver(message);
9581
+ },
9582
+ async act(task, scope) {
9583
+ const context = nodeContextSeed ? supervisorNodeContext(nodeContextSeed, stableProfile, task, scope) : void 0;
9584
+ const priorCoordination = await deps.loadPriorCoordination?.();
9585
+ const nodeTools = resolveTools && context ? await bindSupervisorTools(resolveTools, context, scope.signal) : void 0;
9586
+ const onEvent = bindSupervisorNodeObserver(context, observeNodeEvent, deps.onEvent);
9587
+ return build(priorCoordination, nodeTools, onEvent).act(task, scope);
9588
+ }
9589
+ };
9590
+ }
8517
9591
  const driveHarness = deps.driveHarness;
8518
9592
  if (!driveHarness) throw new ValidationError(`supervisorAgent: profile.harness="${harness}" needs deps.driveHarness (how to run the harness with the coordination MCP mounted)`);
8519
- return {
9593
+ const deliver = driveHarness.deliver?.bind(driveHarness);
9594
+ const externalAgent = {
8520
9595
  name,
9596
+ ...deliver ? { deliver(message) {
9597
+ return deliver(message);
9598
+ } } : {},
8521
9599
  async act(task, scope) {
9600
+ const context = nodeContextSeed ? supervisorNodeContext(nodeContextSeed, stableProfile, task, scope) : void 0;
9601
+ const priorCoordination = deps.loadPriorCoordination ? await deps.loadPriorCoordination() : deps.priorCoordination;
9602
+ const nodeTools = resolveTools && context ? await bindSupervisorTools(resolveTools, context, scope.signal) : void 0;
9603
+ const onEvent = bindSupervisorNodeObserver(context, observeNodeEvent, deps.onEvent);
8522
9604
  const mcp = await serveCoordinationMcp({
8523
9605
  scope,
8524
9606
  blobs: deps.blobs,
8525
9607
  makeWorkerAgent: deps.makeWorkerAgent,
9608
+ ...deps.authorizeDownMessage ? { authorizeDownMessage: deps.authorizeDownMessage } : {},
8526
9609
  perWorker: deps.perWorker,
8527
9610
  ...coordination?.host !== void 0 ? { host: coordination.host } : {},
8528
9611
  ...coordination?.port !== void 0 ? { port: coordination.port } : {},
@@ -8533,17 +9616,24 @@ function supervisorAgent(profile, deps) {
8533
9616
  ...deps.analyzeOnSettle ? { analyzeOnSettle: deps.analyzeOnSettle } : {},
8534
9617
  ...deps.watchWorkers ? { watchWorkers: deps.watchWorkers } : {},
8535
9618
  ...deps.stallAfterMs !== void 0 ? { stallAfterMs: deps.stallAfterMs } : {},
8536
- ...deps.onEvent ? { onEvent: deps.onEvent } : {},
8537
- ...deps.priorCoordination?.questions.length ? { priorQuestions: deps.priorCoordination.questions } : {}
9619
+ ...onEvent ? { onEvent } : {},
9620
+ ...deps.replaySettlements ? { replaySettlements: true } : {},
9621
+ ...priorCoordination?.questions.length ? { priorQuestions: priorCoordination.questions } : {},
9622
+ ...nodeTools?.length ? { nodeTools } : {}
8538
9623
  });
8539
9624
  try {
8540
9625
  try {
8541
9626
  await driveHarness({
8542
- profile,
9627
+ profile: stableProfile,
8543
9628
  ...profilePrompt !== void 0 ? { systemPrompt: profilePrompt } : {},
8544
9629
  task,
8545
9630
  scope,
8546
- coordinationMcpUrl: mcp.url
9631
+ coordinationMcpUrl: mcp.url,
9632
+ coordinationTools: (nodeTools ?? []).map(({ name, description, inputSchema }) => ({
9633
+ name,
9634
+ description,
9635
+ inputSchema
9636
+ }))
8547
9637
  });
8548
9638
  } catch (error) {
8549
9639
  if (!mcp.submittedResult()) throw error;
@@ -8562,9 +9652,57 @@ function supervisorAgent(profile, deps) {
8562
9652
  }
8563
9653
  }
8564
9654
  };
9655
+ const runtime = runtimeOwnedScopeOwnerRuntime(driveHarness);
9656
+ return runtime === void 0 ? externalAgent : attestRuntimeOwnedScopeOwner(externalAgent, runtime);
9657
+ }
9658
+ function supervisorNodeContext(seed, profile, task, scope) {
9659
+ return detachedSnapshot({
9660
+ ...seed,
9661
+ nodeId: scope.view.root,
9662
+ profile,
9663
+ task
9664
+ }, "supervisorAgent trusted node context");
9665
+ }
9666
+ async function bindSupervisorTools(resolveTools, context, signal) {
9667
+ const resolved = await resolveTools(context);
9668
+ if (!Array.isArray(resolved)) throw new ValidationError("supervisorAgent: resolveSupervisorTools must return an array");
9669
+ const invocationContext = Object.freeze({
9670
+ ...context,
9671
+ signal
9672
+ });
9673
+ const names = new Set(coordinationVerbNames);
9674
+ return Object.freeze(resolved.map((rawTool, index) => {
9675
+ if (typeof rawTool !== "object" || rawTool === null || Array.isArray(rawTool)) throw new ValidationError(`supervisorAgent: resolved tool at index ${index} must be a descriptor`);
9676
+ const { name, description, inputSchema, handler } = rawTool;
9677
+ if (typeof name !== "string" || name.length === 0) throw new ValidationError(`supervisorAgent: resolved tool at index ${index} needs a non-empty name`);
9678
+ if (names.has(name)) throw new ValidationError(`supervisorAgent: resolved tool "${name}" collides with a coordination verb or another resolved tool`);
9679
+ names.add(name);
9680
+ if (typeof description !== "string" || description.length === 0) throw new ValidationError(`supervisorAgent: resolved tool "${name}" needs a description`);
9681
+ if (typeof inputSchema !== "object" || inputSchema === null || Array.isArray(inputSchema)) throw new ValidationError(`supervisorAgent: resolved tool "${name}" needs an inputSchema`);
9682
+ if (typeof handler !== "function") throw new ValidationError(`supervisorAgent: resolved tool "${name}" needs a handler`);
9683
+ const descriptor = detachedSnapshot({
9684
+ name,
9685
+ description,
9686
+ inputSchema
9687
+ }, `supervisorAgent resolved tool ${JSON.stringify(name)}`);
9688
+ return Object.freeze({
9689
+ ...descriptor,
9690
+ handler: (raw) => handler(detachedSnapshot(raw, `supervisorAgent tool ${JSON.stringify(name)} input`), invocationContext)
9691
+ });
9692
+ }));
9693
+ }
9694
+ function bindSupervisorNodeObserver(context, observeNodeEvent, onEvent) {
9695
+ if (!observeNodeEvent && !onEvent) return void 0;
9696
+ return async (event, record) => {
9697
+ if (observeNodeEvent) {
9698
+ if (!context) throw new ValidationError("supervisorAgent: observeNodeEvent has no trusted node context");
9699
+ await observeNodeEvent(context, event, record);
9700
+ }
9701
+ await onEvent?.(event, record);
9702
+ };
8565
9703
  }
8566
9704
  function routerBrainFromProfile(profile, deps) {
8567
- if (!deps.router) throw new ValidationError("supervisorAgent: a router-brained supervisor (harness null) needs deps.router (or deps.brain)");
9705
+ if (!deps.router) throw new ValidationError("supervisorAgent: a router-brained supervisor (harness omitted or cli-base) needs deps.router (or deps.brain)");
8568
9706
  const modelId = resolveSupervisorModelId(profile);
8569
9707
  return routerBrain({
8570
9708
  ...deps.router,
@@ -8573,32 +9711,314 @@ function routerBrainFromProfile(profile, deps) {
8573
9711
  }
8574
9712
  //#endregion
8575
9713
  //#region src/runtime/supervise/supervise.ts
8576
- /** Build the worker seam from a backend (WHERE workers run) + an optional completion oracle (the
8577
- * deliverable check that makes "settled delivered" true the guard against "ran but didn't
8578
- * deliver"). The ONE place a backend becomes a spawnable worker. */
8579
- function workerFromBackend(backend, deliverable) {
8580
- return (rawProfile) => {
8581
- const p = rawProfile ?? {};
8582
- const name = typeof p.name === "string" && p.name.length > 0 ? p.name : "worker";
8583
- const spec = {
8584
- profile: rawProfile,
8585
- harness: null
8586
- };
8587
- const ctx = {
8588
- signal: new AbortController().signal,
8589
- seams: {}
9714
+ /**
9715
+ * `supervise` the one-call "just invoke the supervisor". Builds + runs a supervisor from its
9716
+ * profile with sensible defaults, so the common case is `supervise(profile, task, { backend, budget })`
9717
+ * instead of hand-wiring `blobs` / `perWorker` / `journal` / `executors` / `maxDepth`. The raw seams
9718
+ * (`supervisorAgent` + `createSupervisor().run`) stay available for power use.
9719
+ *
9720
+ * `workerFromBackend` derives the worker seam (`makeWorkerAgent`) from a backend config + an optional
9721
+ * completion oracle — so "where the workers run" is one data choice, not a hand-rolled factory.
9722
+ */
9723
+ /**
9724
+ * Build the worker seam from a backend (WHERE workers run) + an optional completion oracle (the
9725
+ * deliverable check that makes "settled ⟺ delivered" true — the guard against "ran but didn't
9726
+ * deliver"). The ONE place a backend becomes a spawnable worker.
9727
+ *
9728
+ * `seams` exists because this path builds the leaf executor EAGERLY and hands it back as a BYO
9729
+ * `executorSpec.executor`. The registry resolves a BYO executor without ever consulting the
9730
+ * per-child `ExecutorContext` the `Scope` seeds, so anything the scope would have supplied is
9731
+ * invisible here and has to be passed in. It is a FUNCTION because it is resolved once per worker
9732
+ * construction, so a caller may hand back something the run only learns later — which is exactly how
9733
+ * `supervise()` gives a traced run's workers their trace context without ordering the span recorder
9734
+ * ahead of the worker seam.
9735
+ */
9736
+ function workerFromBackend(backend, deliverable, seams) {
9737
+ const capturedBackend = captureReusableExecutorConfig(backend, "workerFromBackend");
9738
+ const unscopedNamespace = randomUUID();
9739
+ let unscopedOrdinal = 0;
9740
+ return (rawProfile, spawnContext) => {
9741
+ const parsed = agentProfileSchema.safeParse(canonicalizeAuthoredProfile(rawProfile));
9742
+ if (!parsed.success) throw new ValidationError(`workerFromBackend: invalid AgentProfile: ${parsed.error.message}`);
9743
+ const profile = parsed.data;
9744
+ assertBackendProfileMaterialization(profile, capturedBackend, "workerFromBackend");
9745
+ const name = profile.name ?? "worker";
9746
+ const assignmentId = spawnContext?.assignmentId ?? `unscoped:${unscopedNamespace}:${unscopedOrdinal++}`;
9747
+ const baseFactory = createExecutor(bindReusableExecutorExecutionId(capturedBackend, externalExecutionId("supervised-worker", { assignmentId })));
9748
+ const executorFactory = (spec, ctx) => {
9749
+ const extraSeams = seams?.();
9750
+ const built = baseFactory(spec, extraSeams === void 0 ? ctx : {
9751
+ ...ctx,
9752
+ seams: {
9753
+ ...extraSeams,
9754
+ ...ctx.seams
9755
+ }
9756
+ });
9757
+ return deliverable ? gateOnDeliverable(built, deliverable) : built;
8590
9758
  };
8591
- const built = createExecutor(backend)(spec, ctx);
8592
- const executor = deliverable ? gateOnDeliverable(built, deliverable) : built;
8593
9759
  return {
8594
9760
  name,
8595
9761
  act: async () => "",
8596
9762
  executorSpec: {
8597
- ...spec,
8598
- executor
9763
+ profile,
9764
+ harness: null,
9765
+ executorFactory,
9766
+ ...spawnContext?.execution ? { execution: spawnContext.execution } : {}
9767
+ }
9768
+ };
9769
+ };
9770
+ }
9771
+ function externalExecutionId(kind, identity) {
9772
+ return `${kind}-${canonicalCandidateDigest({
9773
+ kind,
9774
+ identity
9775
+ }).slice(7)}`;
9776
+ }
9777
+ function backendProfileMaterialization(backend) {
9778
+ switch (backend.backend) {
9779
+ case "bridge":
9780
+ case "sandbox":
9781
+ case "provider": return fullProfileMaterialization;
9782
+ case "cli-worktree": return backend.bridge ? fullProfileMaterialization : worktreeCliProfileMaterialization;
9783
+ case "router":
9784
+ case "router-tools":
9785
+ case "pi": return promptModelProfileMaterialization;
9786
+ case "cli": return controlProfileMaterialization;
9787
+ }
9788
+ }
9789
+ function assertProfileContract(profile, contract, context) {
9790
+ assertProfileMaterialization({
9791
+ contract,
9792
+ changedAxes: profileMaterializationAxes(profile),
9793
+ context
9794
+ });
9795
+ }
9796
+ function assertBackendProfileMaterialization(profile, backend, context) {
9797
+ assertProfileContract(profile, backendProfileMaterialization(backend), context);
9798
+ }
9799
+ /**
9800
+ * The ROOT router-brained supervisor's materialization claim. The router arm consumes the
9801
+ * identity fields, the resolved system prompt (`systemPrompt` + `prompt.instructions` +
9802
+ * `resources.instructions`), and the resolved model id (`model.default`); the remaining model
9803
+ * HINTS (`small`, `provider`, `reasoningEffort`, `metadata`) are accepted as documented-unhonored
9804
+ * router-arm material (`supervisorAgent`'s contract table states each one), so a canonical
9805
+ * profile carrying ordinary hints is not refused. Every behavioral axis — tools, permissions,
9806
+ * MCP, hooks, modes, subagents, file resources — still fails loud before any compute.
9807
+ */
9808
+ const routerSupervisorProfileMaterialization = defineProfileMaterializationContract({
9809
+ name: "router-supervisor-execution",
9810
+ axes: [
9811
+ "name",
9812
+ "description",
9813
+ "version",
9814
+ "tags",
9815
+ "systemPrompt",
9816
+ "instructions",
9817
+ "resourceInstructions",
9818
+ "modelDefault",
9819
+ "modelSmall",
9820
+ "modelProvider",
9821
+ "modelReasoningEffort",
9822
+ "modelMetadata",
9823
+ "harness",
9824
+ "metadata"
9825
+ ]
9826
+ });
9827
+ const coordinationMcpAlias = "agent-runtime-coordination";
9828
+ const defaultAllowedMcpHosts = [];
9829
+ Object.freeze(defaultAllowedMcpHosts);
9830
+ /** Manager-authored profiles are untrusted until product policy says otherwise. Remote MCP and
9831
+ * ambient connection grants therefore fail closed by default, in addition to local MCP and hooks. */
9832
+ const DEFAULT_AUTHORED_PROFILE_SECURITY_POLICY = Object.freeze({
9833
+ allowLocalMcp: false,
9834
+ allowHooks: false,
9835
+ allowedMcpHosts: defaultAllowedMcpHosts,
9836
+ allowConnections: false
9837
+ });
9838
+ function isExternalSupervisor(profile) {
9839
+ return profile.harness !== void 0 && profile.harness !== "cli-base";
9840
+ }
9841
+ function automaticDriverBackendSupported(backend) {
9842
+ return backend.backend === "bridge";
9843
+ }
9844
+ function backendProfileOverlays(backend) {
9845
+ if (!backend) return [];
9846
+ if (backend.backend === "bridge" && backend.agentProfile) return [backend.agentProfile];
9847
+ if (backend.backend === "cli-worktree" && backend.bridge?.agentProfile) return [backend.bridge.agentProfile];
9848
+ return [];
9849
+ }
9850
+ /** Run a harness-brained manager through the same executor factory as its children. The manager's
9851
+ * full profile is preserved, the live coordination server is added under one reserved alias, and
9852
+ * every streamed turn is charged to the manager's scope before it may continue. */
9853
+ function driveHarnessFromBackend(backend, executionId, now = Date.now) {
9854
+ const boundBackend = bindReusableExecutorExecutionId(captureReusableExecutorConfig(backend, "driveHarnessFromBackend"), executionId);
9855
+ const baseFactory = createExecutor(boundBackend);
9856
+ let activeExecutor;
9857
+ const drive = async ({ profile, task, scope, coordinationMcpUrl, coordinationTools }) => {
9858
+ const initialBudget = scope.budget;
9859
+ if (!(scope.view.inFlight > 0 || scope.view.waiting > 0) && (initialBudget.tokensLeft <= 0 || initialBudget.iterationsLeft <= 0 || initialBudget.usdCapped && initialBudget.usdLeft <= 0 || initialBudget.deadlineMs > 0 && now() >= initialBudget.deadlineMs)) throw new ValidationError("driveHarnessFromBackend: supervisor budget exhausted");
9860
+ const canonicalDriverProfile = agentProfileSchema.parse(profile);
9861
+ if (canonicalDriverProfile.mcp?.[coordinationMcpAlias] !== void 0) throw new ValidationError(`driveHarnessFromBackend: profile MCP alias ${JSON.stringify(coordinationMcpAlias)} is reserved`);
9862
+ const effectiveProfile = agentProfileSchema.parse({
9863
+ ...canonicalDriverProfile,
9864
+ mcp: {
9865
+ ...canonicalDriverProfile.mcp,
9866
+ [coordinationMcpAlias]: {
9867
+ transport: "http",
9868
+ url: coordinationMcpUrl
9869
+ }
8599
9870
  }
9871
+ });
9872
+ const stableCoordinationTools = detachedSnapshot(coordinationTools, "driveHarnessFromBackend coordination tools");
9873
+ const spec = {
9874
+ profile: effectiveProfile,
9875
+ harness: boundBackend.backend === "sandbox" ? effectiveProfile.harness ?? boundBackend.harness ?? null : null
9876
+ };
9877
+ const executor = baseFactory(spec, {
9878
+ signal: scope.signal,
9879
+ node: scopeOwnerExecutorNodeContext(scope),
9880
+ seams: {}
9881
+ });
9882
+ activeExecutor = executor;
9883
+ let completed = false;
9884
+ let started = false;
9885
+ let terminalAccountingCaptured = false;
9886
+ let pendingUsage = [];
9887
+ let teardownStarted = false;
9888
+ const deadlineAtMs = scope.budget.deadlineMs || void 0;
9889
+ const teardownOnce = async (grace) => {
9890
+ if (teardownStarted) return;
9891
+ teardownStarted = true;
9892
+ await teardownExecutor(executor, grace, deadlineAtMs, now);
9893
+ };
9894
+ const meterPending = async () => {
9895
+ if (pendingUsage.length === 0) return;
9896
+ const batch = pendingUsage;
9897
+ pendingUsage = [];
9898
+ await scope.meter(spendFromUsageEvents(batch), {
9899
+ role: "driver",
9900
+ runtime: executor.runtime
9901
+ });
9902
+ const budget = scope.budget;
9903
+ if (budget.tokensLeft <= 0 || budget.usdCapped && budget.usdLeft <= 0 || budget.deadlineMs > 0 && now() >= budget.deadlineMs) throw new ValidationError("driveHarnessFromBackend: supervisor budget exhausted");
8600
9904
  };
9905
+ let failed = false;
9906
+ let failure;
9907
+ try {
9908
+ const declaration = runtimeOwnedExecutorMaterialization(executor);
9909
+ const executionBinding = runtimeOwnedExecutorExecutionBinding(executor);
9910
+ if (declaration === void 0 || executionBinding === void 0) throw new ValidationError(`driveHarnessFromBackend: built-in runtime ${JSON.stringify(executor.runtime)} has no trusted materialization declaration or execution binding`);
9911
+ await recordScopeOwnerMaterialization(scope, executor.runtime, {
9912
+ ...declaration,
9913
+ effectiveProfile: canonicalDriverProfile,
9914
+ platformAttachments: { [coordinationMcpAlias]: {
9915
+ kind: "coordination-mcp",
9916
+ transport: "http",
9917
+ tools: stableCoordinationTools
9918
+ } }
9919
+ }, {
9920
+ ...executionBinding,
9921
+ binding: {
9922
+ stableBinding: executionBinding.binding,
9923
+ platformAttachments: { [coordinationMcpAlias]: {
9924
+ transport: "http",
9925
+ url: coordinationMcpUrl
9926
+ } }
9927
+ },
9928
+ descriptor: {
9929
+ ...executionBinding.descriptor,
9930
+ coordination: true
9931
+ }
9932
+ });
9933
+ if (executor.budgetExempt) throw new ValidationError(`driveHarnessFromBackend: runtime ${JSON.stringify(executor.runtime)} does not report usage and cannot drive a budgeted supervisor`);
9934
+ started = true;
9935
+ const run = executor.execute(task, scope.signal);
9936
+ if (isAsyncIterable(run)) {
9937
+ for await (const event of run) if (event.kind === "iteration") await meterPending();
9938
+ else pendingUsage.push(event);
9939
+ await meterPending();
9940
+ const artifact = executor.resultArtifact();
9941
+ terminalAccountingCaptured = true;
9942
+ if (artifact.spent.tokensKnown === false || artifact.spent.usdKnown === false) await scope.meter({
9943
+ iterations: 0,
9944
+ tokens: {
9945
+ input: 0,
9946
+ output: 0
9947
+ },
9948
+ ...artifact.spent.tokensKnown === false ? { tokensKnown: false } : {},
9949
+ usd: 0,
9950
+ ...artifact.spent.usdKnown === false ? { usdKnown: false } : {},
9951
+ ms: 0
9952
+ }, {
9953
+ role: "driver",
9954
+ runtime: executor.runtime,
9955
+ telemetry: "unknown"
9956
+ });
9957
+ } else {
9958
+ const artifact = await run;
9959
+ terminalAccountingCaptured = true;
9960
+ await scope.meter({
9961
+ ...artifact.spent,
9962
+ iterations: 0
9963
+ }, {
9964
+ role: "driver",
9965
+ runtime: executor.runtime
9966
+ });
9967
+ }
9968
+ completed = true;
9969
+ } catch (error) {
9970
+ failed = true;
9971
+ failure = error;
9972
+ } finally {
9973
+ try {
9974
+ await meterPending();
9975
+ } catch (error) {
9976
+ if (!failed) {
9977
+ failed = true;
9978
+ failure = error;
9979
+ }
9980
+ }
9981
+ if (failed && started && !terminalAccountingCaptured) try {
9982
+ await scope.meter({
9983
+ iterations: 0,
9984
+ tokens: {
9985
+ input: 0,
9986
+ output: 0
9987
+ },
9988
+ tokensKnown: false,
9989
+ usd: 0,
9990
+ usdKnown: false,
9991
+ ms: 0
9992
+ }, {
9993
+ role: "driver",
9994
+ runtime: executor.runtime,
9995
+ telemetry: "unknown-after-failure"
9996
+ });
9997
+ } catch (error) {
9998
+ const budget = scope.budget;
9999
+ if (budget.tokensKnown !== false || budget.usdCapped && budget.usdKnown !== false) failure = error;
10000
+ }
10001
+ try {
10002
+ await teardownOnce(completed ? DEFAULT_SUCCESSFUL_SHUTDOWN_MS : "brutalKill");
10003
+ } catch (error) {
10004
+ if (!failed) {
10005
+ failed = true;
10006
+ failure = error;
10007
+ }
10008
+ }
10009
+ if (activeExecutor === executor) activeExecutor = void 0;
10010
+ }
10011
+ if (failed) throw failure;
8601
10012
  };
10013
+ drive.deliver = (message) => {
10014
+ const deliver = activeExecutor?.deliver;
10015
+ if (!deliver) return false;
10016
+ return deliver.call(activeExecutor, message) !== false;
10017
+ };
10018
+ return attestRuntimeOwnedScopeOwner(drive, "cli");
10019
+ }
10020
+ function isAsyncIterable(value) {
10021
+ return value !== null && typeof value === "object" && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
8602
10022
  }
8603
10023
  /** Resolve one option that may be given as a value OR as a name into `opts.registry`. Both failure
8604
10024
  * modes name the option, the requested name, and the table it was looked up in — a typo must not
@@ -8612,93 +10032,489 @@ function resolveNamed(option, table, value, registry) {
8612
10032
  if (entry === void 0) throw new ConfigError(`supervise: opts.${option} = ${JSON.stringify(value)} is not in opts.registry.${table} — the table resolved no entry under that name`);
8613
10033
  return entry;
8614
10034
  }
8615
- /** A quarter of the token pool per worker → ~4 workers fit before `poolStarved` halts spawning. */
10035
+ function captureDeliverable(deliverable, context) {
10036
+ if (typeof deliverable !== "object" || deliverable === null || Array.isArray(deliverable)) throw new ValidationError(`${context}: deliverable must be an object`);
10037
+ if (typeof deliverable.check !== "function") throw new ValidationError(`${context}: deliverable.check must be a function`);
10038
+ return Object.freeze({
10039
+ ...detachedSnapshot({ describe: deliverable.describe }, `${context} configuration`),
10040
+ check: deliverable.check
10041
+ });
10042
+ }
10043
+ /** Capture the public one-call configuration before any asynchronous work starts. Decision data is
10044
+ * detached and frozen; executable ports are copied as the exact references selected at intake.
10045
+ * Service internals intentionally remain live, while replacing a callback/service on the caller's
10046
+ * mutable options object can no longer change an in-flight run. */
10047
+ function captureSuperviseOptions(opts) {
10048
+ const { backend, driverBackend, deliverable, resolveDeliverable, router, compaction, watchWorkers, analysts, makeWorkerAgent, blobs, journal, probes, registry, hooks, otel, authorizeSpawn, authorizeMessage, isDriverProfile, brain, driveHarness, resolveDriveHarness, resolveSupervisorTools, onCoordinationEvent, executeExtraTool, stopRule, onProgressStop, finalizer, now, signal, rootHandle, ...decisionData } = opts;
10049
+ const capturedData = detachedSnapshot(decisionData, "supervise options");
10050
+ const capturedBackend = backend === void 0 ? void 0 : snapshotExecutorConfig(backend);
10051
+ const capturedDriverBackend = driverBackend === void 0 ? void 0 : snapshotExecutorConfig(driverBackend);
10052
+ const capturedDeliverable = deliverable === void 0 || typeof deliverable === "string" ? deliverable : captureDeliverable(deliverable, "supervise deliverable");
10053
+ const capturedRouter = router === void 0 ? void 0 : (() => {
10054
+ const { complete, ...routerData } = router;
10055
+ return Object.freeze({
10056
+ ...detachedSnapshot(routerData, "supervise router configuration"),
10057
+ ...complete === void 0 ? {} : { complete }
10058
+ });
10059
+ })();
10060
+ const capturedCompaction = compaction === void 0 ? void 0 : (() => {
10061
+ const { distill, estimateTokens, onCompact, ...compactionData } = compaction;
10062
+ return Object.freeze({
10063
+ ...detachedSnapshot(compactionData, "supervise compaction configuration"),
10064
+ ...distill === void 0 ? {} : { distill },
10065
+ ...estimateTokens === void 0 ? {} : { estimateTokens },
10066
+ ...onCompact === void 0 ? {} : { onCompact }
10067
+ });
10068
+ })();
10069
+ const capturedWatchWorkers = watchWorkers === void 0 ? void 0 : Object.freeze({
10070
+ ...detachedSnapshot({ maxFindingsPerWorker: watchWorkers.maxFindingsPerWorker }, "supervise worker-watch configuration"),
10071
+ ...watchWorkers.detectors === void 0 ? {} : { detectors: Object.freeze([...watchWorkers.detectors]) }
10072
+ });
10073
+ const capturedAnalysts = analysts === void 0 || typeof analysts === "string" ? analysts : Object.freeze({
10074
+ kinds: detachedSnapshot(analysts.kinds, "supervise analyst kinds"),
10075
+ run: analysts.run
10076
+ });
10077
+ return Object.freeze({
10078
+ ...capturedData,
10079
+ ...capturedBackend === void 0 ? {} : { backend: capturedBackend },
10080
+ ...capturedDriverBackend === void 0 ? {} : { driverBackend: capturedDriverBackend },
10081
+ ...capturedDeliverable === void 0 ? {} : { deliverable: capturedDeliverable },
10082
+ ...resolveDeliverable === void 0 ? {} : { resolveDeliverable },
10083
+ ...capturedRouter === void 0 ? {} : { router: capturedRouter },
10084
+ ...capturedCompaction === void 0 ? {} : { compaction: capturedCompaction },
10085
+ ...capturedWatchWorkers === void 0 ? {} : { watchWorkers: capturedWatchWorkers },
10086
+ ...capturedAnalysts === void 0 ? {} : { analysts: capturedAnalysts },
10087
+ ...makeWorkerAgent === void 0 ? {} : { makeWorkerAgent },
10088
+ ...blobs === void 0 ? {} : { blobs },
10089
+ ...journal === void 0 ? {} : { journal },
10090
+ ...probes === void 0 ? {} : { probes },
10091
+ ...authorizeSpawn === void 0 ? {} : { authorizeSpawn },
10092
+ ...authorizeMessage === void 0 ? {} : { authorizeMessage },
10093
+ ...isDriverProfile === void 0 ? {} : { isDriverProfile },
10094
+ ...brain === void 0 ? {} : { brain },
10095
+ ...driveHarness === void 0 ? {} : { driveHarness },
10096
+ ...resolveDriveHarness === void 0 ? {} : { resolveDriveHarness },
10097
+ ...resolveSupervisorTools === void 0 ? {} : { resolveSupervisorTools },
10098
+ ...onCoordinationEvent === void 0 ? {} : { onCoordinationEvent },
10099
+ ...executeExtraTool === void 0 ? {} : { executeExtraTool },
10100
+ ...stopRule === void 0 ? {} : { stopRule },
10101
+ ...onProgressStop === void 0 ? {} : { onProgressStop },
10102
+ ...finalizer === void 0 ? {} : { finalizer },
10103
+ ...now === void 0 ? {} : { now },
10104
+ ...signal === void 0 ? {} : { signal },
10105
+ ...rootHandle === void 0 ? {} : { rootHandle },
10106
+ ...registry === void 0 ? {} : { registry },
10107
+ ...hooks === void 0 ? {} : { hooks },
10108
+ ...otel === void 0 ? {} : { otel }
10109
+ });
10110
+ }
10111
+ /** A quarter of token and optional dollar capacity per worker; nested managers partition again. */
8616
10112
  function defaultPerWorker(budget) {
8617
10113
  return {
8618
- maxIterations: budget.maxIterations,
8619
- maxTokens: Math.max(1, Math.floor(budget.maxTokens / 4))
10114
+ maxIterations: Math.max(1, Math.floor(budget.maxIterations / 4)),
10115
+ maxTokens: Math.max(1, Math.floor(budget.maxTokens / 4)),
10116
+ ...budget.maxUsd !== void 0 ? { maxUsd: budget.maxUsd / 4 } : {}
8620
10117
  };
8621
10118
  }
10119
+ function freezeDetached(value) {
10120
+ return detachedSnapshot(value, "supervise");
10121
+ }
10122
+ function freezeDetachedProfile(value) {
10123
+ return freezeDetached(agentProfileSchema.parse(value));
10124
+ }
10125
+ /**
10126
+ * Map the two loose `SupervisorProfile` spellings onto their canonical `AgentProfile` form before
10127
+ * the strict schema parse, so both documented spellings run the SAME canonical pipeline and share
10128
+ * one identity digest:
10129
+ * - a string `model` IS `model.default`;
10130
+ * - a top-level `systemPrompt` IS `prompt.systemPrompt` (two disagreeing values are a fault);
10131
+ * - `harness: null` selects the router brain, which canonically is an ABSENT harness.
10132
+ * A canonical profile passes through byte-identical; every other field is left for the schema to
10133
+ * accept or refuse.
10134
+ */
10135
+ function canonicalSupervisorProfileInput(profile) {
10136
+ if (typeof profile !== "object" || profile === null) return profile;
10137
+ const { harness, model, systemPrompt, prompt, ...rest } = profile;
10138
+ const promptSystem = prompt?.systemPrompt;
10139
+ if (systemPrompt !== void 0 && promptSystem !== void 0 && systemPrompt !== promptSystem) throw new ValidationError("supervise: profile.prompt.systemPrompt and profile.systemPrompt are both set and differ — they are the same standing instruction, so keep exactly one");
10140
+ const canonicalPrompt = systemPrompt !== void 0 ? {
10141
+ ...prompt,
10142
+ systemPrompt
10143
+ } : prompt;
10144
+ return {
10145
+ ...rest,
10146
+ ...harness === null || harness === void 0 ? {} : { harness },
10147
+ ...model === void 0 ? {} : { model: typeof model === "string" ? { default: model } : model },
10148
+ ...canonicalPrompt === void 0 ? {} : { prompt: canonicalPrompt }
10149
+ };
10150
+ }
10151
+ function canonicalExecution(profile, task, rawExecution, context) {
10152
+ const execution = rawExecution === void 0 ? void 0 : freezeDetached(rawExecution);
10153
+ if (execution !== void 0) {
10154
+ if (typeof execution !== "object" || execution === null || Array.isArray(execution)) throw new ValidationError(`${context}: execution must be an object`);
10155
+ const unknown = Object.keys(execution).filter((key) => key !== "candidateDigest" && key !== "correlation");
10156
+ if (unknown.length > 0) throw new ValidationError(`${context}: unknown execution fields: ${unknown.join(", ")}`);
10157
+ }
10158
+ const identity = deriveNodeExecutionIdentity({
10159
+ profile,
10160
+ execution
10161
+ }, task);
10162
+ if (!identity?.profileDigest || !identity.taskDigest) throw new ValidationError(`${context}: profile and task must be finite, acyclic canonical JSON for durable identity`);
10163
+ const ref = identity.candidateDigest || identity.correlation ? Object.freeze({
10164
+ ...identity.candidateDigest ? { candidateDigest: identity.candidateDigest } : {},
10165
+ ...identity.correlation ? { correlation: identity.correlation } : {}
10166
+ }) : void 0;
10167
+ return {
10168
+ identity,
10169
+ ...ref ? { ref } : {}
10170
+ };
10171
+ }
10172
+ function rootCoordinationOwner(identity) {
10173
+ return canonicalCandidateDigest({
10174
+ kind: "supervisor-root",
10175
+ identity
10176
+ });
10177
+ }
10178
+ function childCoordinationOwner(parentOwnerId, identity, context, depth) {
10179
+ return canonicalCandidateDigest({
10180
+ kind: "supervisor-child",
10181
+ parentOwnerId,
10182
+ identity,
10183
+ assignment: {
10184
+ id: context.assignmentId,
10185
+ label: context.label,
10186
+ key: context.key ?? null,
10187
+ depth
10188
+ }
10189
+ });
10190
+ }
10191
+ function supervisionRunNamespace(runDir, runId) {
10192
+ return canonicalCandidateDigest(runDir === void 0 ? {
10193
+ kind: "supervise-ephemeral-run",
10194
+ runId,
10195
+ nonce: randomUUID()
10196
+ } : {
10197
+ kind: "supervise-durable-run",
10198
+ runId,
10199
+ runDir: resolve(runDir)
10200
+ });
10201
+ }
10202
+ function workerAssignmentNamespace(runNamespace, parentOwnerId, assignmentId) {
10203
+ return canonicalCandidateDigest({
10204
+ kind: "supervise-worker-assignment",
10205
+ runNamespace,
10206
+ parentOwnerId,
10207
+ assignmentId
10208
+ });
10209
+ }
10210
+ /** Hash only durable coordination meaning. Bus sequence/timestamp are delivery metadata and a
10211
+ * resumed projection's marker describes the reader, not the original settlement. */
10212
+ function coordinationEventId(context, event) {
10213
+ const durableEvent = event.type === "settled" && event.worker.resumed === true ? (() => {
10214
+ const { resumed: _resumed, ...worker } = event.worker;
10215
+ return {
10216
+ type: "settled",
10217
+ worker
10218
+ };
10219
+ })() : event;
10220
+ return canonicalCandidateDigest({
10221
+ kind: "supervise-coordination-event",
10222
+ runNamespace: context.runNamespace,
10223
+ ownerId: context.ownerId,
10224
+ event: detachedSnapshot(durableEvent, "supervise coordination event identity")
10225
+ });
10226
+ }
8622
10227
  /** One-call supervisor: build + run a supervisor from its profile with sensible defaults; the raw `supervisorAgent` + `createSupervisor().run` seams stay available for power use. */
8623
10228
  function supervise(profile, task, opts) {
8624
- const backendModel = opts.backend?.model;
8625
- assertModelAllowed(opts.router?.model, opts.allowedModels);
8626
- assertModelAllowed(resolveSupervisorModelId(profile), opts.allowedModels);
8627
- assertModelAllowed(typeof backendModel === "string" ? backendModel : void 0, opts.allowedModels);
8628
- const deliverable = resolveNamed("deliverable", "deliverables", opts.deliverable, opts.registry?.deliverables);
8629
- const finalizer = resolveNamed("finalizer", "finalizers", opts.finalizer, opts.registry?.finalizers);
8630
- const analysts = resolveNamed("analysts", "analysts", opts.analysts, opts.registry?.analysts);
8631
- const probes = resolveNamed("probes", "probes", opts.probes, opts.registry?.probes);
8632
- assertCoordinationBinding(opts.coordination);
8633
- const ctx = opts.runDir !== void 0 ? createFileRunContext(opts.runDir, { withDriver: true }) : createInMemoryRunContext({ withDriver: true });
8634
- const blobs = opts.blobs ?? ctx.blobs;
8635
- const perWorker = opts.perWorker ?? defaultPerWorker(opts.budget);
8636
- let makeWorkerAgent = opts.makeWorkerAgent;
10229
+ const options = captureSuperviseOptions(opts);
10230
+ assertValidBudget(options.budget, "supervise budget");
10231
+ const parsedProfile = agentProfileSchema.safeParse(canonicalSupervisorProfileInput(profile));
10232
+ if (!parsedProfile.success) throw new ValidationError(`supervise: invalid AgentProfile: ${parsedProfile.error.message}`);
10233
+ const canonicalProfile = freezeDetachedProfile(parsedProfile.data);
10234
+ const canonicalTask = freezeDetached(task);
10235
+ if (options.makeWorkerAgent && options.authorizeSpawn) throw new ValidationError("supervise: authorizeSpawn cannot be combined with caller-owned makeWorkerAgent; wrap and authorize the custom factory explicitly or use backend-derived workers");
10236
+ if (options.makeWorkerAgent && options.resolveDeliverable) throw new ValidationError("supervise: resolveDeliverable applies only to backend-derived workers; wrap a caller-owned makeWorkerAgent with its completion checks explicitly");
10237
+ const authorizeDownFor = (parent, depth) => {
10238
+ if (!options.authorizeSpawn && !options.authorizeMessage) return void 0;
10239
+ return (input) => {
10240
+ if (!options.authorizeMessage) throw new ValidationError("supervise: authorizeMessage is required before steer_agent or answer_question when authorizeSpawn is enabled");
10241
+ return freezeDetached(options.authorizeMessage(freezeDetached({
10242
+ ...input,
10243
+ parent,
10244
+ depth
10245
+ })));
10246
+ };
10247
+ };
10248
+ const rootExecution = canonicalExecution(canonicalProfile, canonicalTask, options.execution, "supervise root");
10249
+ const backendModel = options.backend?.model;
10250
+ const driverBackendModel = options.driverBackend?.model;
10251
+ if ([...backendProfileOverlays(options.backend), ...backendProfileOverlays(options.driverBackend)].length > 0) throw new ValidationError("supervise: backend agentProfile overlays are not allowed because they run after spawn authorization; merge the overlay into the exact profile before calling supervise");
10252
+ assertModelAllowed(options.router?.model, options.allowedModels);
10253
+ assertProfileModelsAllowed(canonicalProfile, options.allowedModels);
10254
+ assertModelAllowed(typeof backendModel === "string" ? backendModel : void 0, options.allowedModels);
10255
+ assertModelAllowed(typeof driverBackendModel === "string" ? driverBackendModel : void 0, options.allowedModels);
10256
+ const deliverable = resolveNamed("deliverable", "deliverables", options.deliverable, options.registry?.deliverables);
10257
+ const finalizer = resolveNamed("finalizer", "finalizers", options.finalizer, options.registry?.finalizers);
10258
+ const analysts = resolveNamed("analysts", "analysts", options.analysts, options.registry?.analysts);
10259
+ const probes = resolveNamed("probes", "probes", options.probes, options.registry?.probes);
10260
+ assertCoordinationBinding(options.coordination);
10261
+ const ctx = options.runDir !== void 0 ? createFileRunContext(options.runDir, { withDriver: true }) : createInMemoryRunContext({ withDriver: true });
10262
+ const blobs = options.blobs ?? ctx.blobs;
10263
+ const perWorker = options.perWorker ?? defaultPerWorker(options.budget);
10264
+ assertValidBudget(perWorker, "supervise perWorker");
10265
+ const journal = options.journal ?? ctx.journal;
10266
+ const runId = options.runId ?? "supervise";
10267
+ const runNamespace = supervisionRunNamespace(options.runDir, runId);
10268
+ const log = ctx.coordinationLog;
10269
+ const rootOwnerId = rootCoordinationOwner(rootExecution.identity);
10270
+ const observeNodeEvent = options.onCoordinationEvent ? async (context, event, record) => {
10271
+ await options.onCoordinationEvent?.(context, coordinationEventId(context, event), record);
10272
+ } : void 0;
10273
+ const managerBackend = options.driverBackend ?? options.backend;
10274
+ if (options.driveHarness && options.resolveDriveHarness) throw new ValidationError("supervise: provide driveHarness or resolveDriveHarness, not both");
10275
+ const driverMaterialization = Boolean(options.driveHarness || options.resolveDriveHarness) ? options.driveHarnessMaterialization ?? fullProfileMaterialization : managerBackend && automaticDriverBackendSupported(managerBackend) ? backendProfileMaterialization(managerBackend) : void 0;
10276
+ if (isExternalSupervisor(canonicalProfile) && !options.driveHarness && !options.resolveDriveHarness && (!managerBackend || !automaticDriverBackendSupported(managerBackend))) throw new ValidationError(`supervise: external supervisor profile.harness=${JSON.stringify(canonicalProfile.harness)} requires a local bridge driverBackend, an explicit driveHarness, or resolveDriveHarness with reachable coordination transport`);
10277
+ const harnessClaims = /* @__PURE__ */ new WeakMap();
10278
+ const claimDriveHarness = (rawHarness, ownerId) => {
10279
+ if (typeof rawHarness !== "function") throw new ValidationError("supervise: resolveDriveHarness must return a DriveHarness function");
10280
+ const harness = rawHarness;
10281
+ const deliver = harness.deliver;
10282
+ if (deliver !== void 0 && typeof deliver !== "function") throw new ValidationError("supervise: driveHarness.deliver must be a function when provided");
10283
+ const claim = harnessClaims.get(harness);
10284
+ const conflictingOwner = claim ? [...claim.owners].find((claimedOwner) => claimedOwner !== ownerId) : void 0;
10285
+ const steerable = typeof deliver === "function";
10286
+ if (conflictingOwner !== void 0 && (steerable || claim?.steerable === true)) throw new ValidationError(`supervise: steerable driveHarness is already bound to manager owner ${JSON.stringify(conflictingOwner)}; resolveDriveHarness must return a distinct steerable instance for owner ${JSON.stringify(ownerId)}`);
10287
+ if (claim) {
10288
+ claim.owners.add(ownerId);
10289
+ claim.steerable ||= steerable;
10290
+ } else harnessClaims.set(harness, {
10291
+ owners: /* @__PURE__ */ new Set([ownerId]),
10292
+ steerable
10293
+ });
10294
+ return harness;
10295
+ };
10296
+ const driveHarnessForOwner = (context) => {
10297
+ if (options.resolveDriveHarness) return claimDriveHarness(options.resolveDriveHarness(context), context.ownerId);
10298
+ if (options.driveHarness) return claimDriveHarness(options.driveHarness, context.ownerId);
10299
+ return managerBackend && automaticDriverBackendSupported(managerBackend) ? driveHarnessFromBackend(managerBackend, externalExecutionId("supervised-manager", {
10300
+ runNamespace,
10301
+ ownerId: context.ownerId
10302
+ }), options.now ?? Date.now) : void 0;
10303
+ };
10304
+ const rootDriveHarness = isExternalSupervisor(canonicalProfile) ? driveHarnessForOwner(freezeDetached({
10305
+ runId,
10306
+ runNamespace,
10307
+ ownerId: rootOwnerId,
10308
+ depth: 0,
10309
+ identity: rootExecution.identity,
10310
+ profile: canonicalProfile,
10311
+ task: canonicalTask
10312
+ })) : void 0;
10313
+ const rootOwnerRuntime = !isExternalSupervisor(canonicalProfile) || rootDriveHarness === void 0 ? void 0 : runtimeOwnedScopeOwnerRuntime(rootDriveHarness);
10314
+ assertProfileContract(canonicalProfile, isExternalSupervisor(canonicalProfile) ? driverMaterialization : options.brain ? promptControlProfileMaterialization : routerSupervisorProfileMaterialization, "supervise root");
10315
+ const now = options.now ?? Date.now;
10316
+ let spans;
10317
+ let makeWorkerAgent = options.makeWorkerAgent;
8637
10318
  if (!makeWorkerAgent) {
8638
- if (!opts.backend) throw new ValidationError("supervise: provide opts.backend (where workers run) or opts.makeWorkerAgent");
8639
- makeWorkerAgent = workerFromBackend(opts.backend, deliverable);
10319
+ if (!options.backend) throw new ValidationError("supervise: provide opts.backend (where workers run) or opts.makeWorkerAgent");
10320
+ const makeLeaf = workerFromBackend(options.backend, deliverable);
10321
+ const securityPolicy = options.profileSecurity ?? DEFAULT_AUTHORED_PROFILE_SECURITY_POLICY;
10322
+ const makeRecursiveWorkerFor = (parent, parentIdentity, depth, parentOwnerId) => {
10323
+ const makeRecursiveWorker = (authoredProfile, spawnContext) => {
10324
+ if (!spawnContext) throw new ValidationError("supervise: backend-derived workers require spawn context");
10325
+ const input = freezeDetachedProfile(authoredProfile);
10326
+ const authorizationInput = Object.freeze({
10327
+ profile: input,
10328
+ parent,
10329
+ parentIdentity,
10330
+ parentNodeId: spawnContext.parentNodeId,
10331
+ assignmentId: spawnContext.assignmentId,
10332
+ task: spawnContext.task,
10333
+ budget: spawnContext.budget,
10334
+ label: spawnContext.label,
10335
+ ...spawnContext.key !== void 0 ? { key: spawnContext.key } : {},
10336
+ depth
10337
+ });
10338
+ const decision = options.authorizeSpawn ? freezeDetached(options.authorizeSpawn(authorizationInput)) : Object.freeze({
10339
+ profile: input,
10340
+ ...spawnContext.execution ? { execution: spawnContext.execution } : {}
10341
+ });
10342
+ if (typeof decision !== "object" || decision === null || Array.isArray(decision)) throw new ValidationError("supervise: authorizeSpawn must return an AuthorizedSpawn");
10343
+ const authorized = freezeDetachedProfile(decision.profile);
10344
+ const childExecution = canonicalExecution(authorized, spawnContext.task, decision.execution, `supervise spawn ${JSON.stringify(spawnContext.label)}`);
10345
+ const authorizedContext = Object.freeze({
10346
+ ...spawnContext,
10347
+ ...childExecution.ref ? { execution: childExecution.ref } : {}
10348
+ });
10349
+ const postAuthorizationContext = freezeDetached({
10350
+ profile: authorized,
10351
+ parent,
10352
+ parentIdentity,
10353
+ execution: childExecution.identity,
10354
+ parentNodeId: spawnContext.parentNodeId,
10355
+ assignmentId: spawnContext.assignmentId,
10356
+ task: spawnContext.task,
10357
+ budget: spawnContext.budget,
10358
+ label: spawnContext.label,
10359
+ ...spawnContext.key !== void 0 ? { key: spawnContext.key } : {},
10360
+ depth
10361
+ });
10362
+ const security = validateAgentProfileSecurity(authorized, securityPolicy);
10363
+ if (!security.ok) throw new ValidationError(`supervise: spawned AgentProfile refused: ${security.issues.filter((issue) => issue.level === "error").map((issue) => `${issue.code}${issue.path ? ` at ${issue.path}` : ""}`).join(", ")}`);
10364
+ assertProfileModelsAllowed(authorized, options.allowedModels);
10365
+ let isDriver;
10366
+ if (options.isDriverProfile) {
10367
+ const driverDecision = options.isDriverProfile(postAuthorizationContext);
10368
+ if (typeof driverDecision !== "boolean") throw new ValidationError("supervise: isDriverProfile must return a boolean");
10369
+ isDriver = driverDecision;
10370
+ } else isDriver = authorized.metadata?.role === "driver";
10371
+ if (!isDriver) {
10372
+ const selectedDeliverable = options.resolveDeliverable?.(postAuthorizationContext);
10373
+ const leafDeliverable = selectedDeliverable === void 0 ? deliverable : captureDeliverable(selectedDeliverable, `supervise deliverable for ${JSON.stringify(spawnContext.label)}`);
10374
+ return (leafDeliverable === deliverable ? makeLeaf : workerFromBackend(options.backend, leafDeliverable))(authorized, Object.freeze({
10375
+ ...authorizedContext,
10376
+ assignmentId: workerAssignmentNamespace(runNamespace, parentOwnerId, spawnContext.assignmentId)
10377
+ }));
10378
+ }
10379
+ const ownerId = childCoordinationOwner(parentOwnerId, childExecution.identity, spawnContext, depth);
10380
+ const nestedDriveHarness = isExternalSupervisor(authorized) ? driveHarnessForOwner(freezeDetached({
10381
+ runId,
10382
+ runNamespace,
10383
+ ownerId,
10384
+ depth,
10385
+ identity: childExecution.identity,
10386
+ assignmentId: spawnContext.assignmentId,
10387
+ profile: authorized,
10388
+ task: spawnContext.task
10389
+ })) : void 0;
10390
+ if (isExternalSupervisor(authorized) && !nestedDriveHarness) throw new ValidationError(`supervise: authored external supervisor profile.harness=${JSON.stringify(authorized.harness)} requires a local bridge driverBackend, an explicit driveHarness, or resolveDriveHarness with reachable coordination transport`);
10391
+ assertProfileContract(authorized, isExternalSupervisor(authorized) ? driverMaterialization : promptModelProfileMaterialization, `supervise driver ${JSON.stringify(spawnContext.label)}`);
10392
+ const childFactory = makeRecursiveWorkerFor(authorized, childExecution.identity, depth + 1, ownerId);
10393
+ const nestedPerWorker = defaultPerWorker(spawnContext.budget);
10394
+ const authorizeNestedMessage = authorizeDownFor(authorized, depth + 1);
10395
+ return driverChild(authorized, supervisorAgent(authorized, {
10396
+ blobs,
10397
+ makeWorkerAgent: childFactory,
10398
+ ...authorizeNestedMessage ? { authorizeDownMessage: authorizeNestedMessage } : {},
10399
+ perWorker: nestedPerWorker,
10400
+ ...options.router ? { router: options.router } : {},
10401
+ ...nestedDriveHarness ? { driveHarness: nestedDriveHarness } : {},
10402
+ nodeContext: {
10403
+ runId,
10404
+ runNamespace,
10405
+ ownerId,
10406
+ depth,
10407
+ identity: childExecution.identity,
10408
+ assignmentId: spawnContext.assignmentId
10409
+ },
10410
+ ...options.resolveSupervisorTools ? { resolveSupervisorTools: options.resolveSupervisorTools } : {},
10411
+ ...observeNodeEvent ? {
10412
+ observeNodeEvent,
10413
+ replaySettlements: true
10414
+ } : {},
10415
+ ...analysts ? { analysts } : {},
10416
+ ...options.analyzeOnSettle ? { analyzeOnSettle: options.analyzeOnSettle } : {},
10417
+ ...options.watchWorkers ? { watchWorkers: options.watchWorkers } : {},
10418
+ ...options.stallAfterMs !== void 0 ? { stallAfterMs: options.stallAfterMs } : {},
10419
+ ...options.stopRule ? { stopRule: options.stopRule } : {},
10420
+ ...options.onProgressStop ? { onProgressStop: options.onProgressStop } : {},
10421
+ ...options.maxTurns !== void 0 ? { maxTurns: options.maxTurns } : {},
10422
+ ...options.compaction ? { compaction: options.compaction } : {},
10423
+ ...log ? {
10424
+ onEvent: (_event, record) => log.append(runId, record, ownerId),
10425
+ loadPriorCoordination: () => log.load(runId, ownerId)
10426
+ } : {},
10427
+ ...finalizer ? { finalizer } : {}
10428
+ }), journal, childExecution.ref);
10429
+ };
10430
+ return makeRecursiveWorker;
10431
+ };
10432
+ makeWorkerAgent = makeRecursiveWorkerFor(canonicalProfile, rootExecution.identity, 1, rootOwnerId);
8640
10433
  }
8641
10434
  const workerFactory = makeWorkerAgent;
8642
- const runId = opts.runId ?? "supervise";
8643
- const log = ctx.coordinationLog;
8644
- const now = opts.now ?? Date.now;
8645
10435
  const start = async () => {
8646
- const priorCoordination = log ? await log.load(runId) : void 0;
8647
- const agent = supervisorAgent(profile, {
10436
+ const priorCoordination = log ? await log.load(runId, rootOwnerId) : void 0;
10437
+ const authorizeRootMessage = authorizeDownFor(canonicalProfile, 1);
10438
+ const agent = supervisorAgent(canonicalProfile, {
8648
10439
  blobs,
8649
10440
  makeWorkerAgent: workerFactory,
10441
+ ...authorizeRootMessage ? { authorizeDownMessage: authorizeRootMessage } : {},
8650
10442
  perWorker,
10443
+ ...log ? { onEvent: (_event, record) => log.append(runId, record, rootOwnerId) } : {},
8651
10444
  ...deliverable ? { deliverable } : {},
8652
- ...log ? { onEvent: (ev) => log.append(runId, ev, new Date(now()).toISOString()) } : {},
8653
- ...priorCoordination && (priorCoordination.questions.length > 0 || priorCoordination.findings.length > 0) ? { priorCoordination } : {},
10445
+ ...priorCoordination && (priorCoordination.questions.length > 0 || priorCoordination.findings.length > 0 || priorCoordination.continuations.length > 0 || priorCoordination.deliveryEvidence.length > 0) ? { priorCoordination } : {},
8654
10446
  ...finalizer ? { finalizer } : {},
8655
- ...opts.coordination ? { coordination: opts.coordination } : {},
8656
- ...opts.maxLiveWorkers !== void 0 ? { maxLiveWorkers: opts.maxLiveWorkers } : {},
8657
- ...opts.router ? { router: opts.router } : {},
8658
- ...opts.brain ? { brain: opts.brain } : {},
8659
- ...opts.driveHarness ? { driveHarness: opts.driveHarness } : {},
8660
- ...opts.extraTools ? { extraTools: opts.extraTools } : {},
8661
- ...opts.executeExtraTool ? { executeExtraTool: opts.executeExtraTool } : {},
10447
+ ...options.coordination ? { coordination: options.coordination } : {},
10448
+ ...options.maxLiveWorkers !== void 0 ? { maxLiveWorkers: options.maxLiveWorkers } : {},
10449
+ ...options.router ? { router: options.router } : {},
10450
+ ...options.brain ? { brain: options.brain } : {},
10451
+ ...rootDriveHarness ? { driveHarness: rootDriveHarness } : {},
10452
+ nodeContext: {
10453
+ runId,
10454
+ runNamespace,
10455
+ ownerId: rootOwnerId,
10456
+ depth: 0,
10457
+ identity: rootExecution.identity
10458
+ },
10459
+ ...options.resolveSupervisorTools ? { resolveSupervisorTools: options.resolveSupervisorTools } : {},
10460
+ ...observeNodeEvent ? {
10461
+ observeNodeEvent,
10462
+ replaySettlements: true
10463
+ } : {},
10464
+ ...options.extraTools ? { extraTools: options.extraTools } : {},
10465
+ ...options.executeExtraTool ? { executeExtraTool: options.executeExtraTool } : {},
8662
10466
  ...analysts ? { analysts } : {},
8663
- ...opts.analyzeOnSettle ? { analyzeOnSettle: opts.analyzeOnSettle } : {},
8664
- ...opts.watchWorkers ? { watchWorkers: opts.watchWorkers } : {},
8665
- ...opts.stallAfterMs !== void 0 ? { stallAfterMs: opts.stallAfterMs } : {},
8666
- ...opts.stopRule ? { stopRule: opts.stopRule } : {},
8667
- ...opts.onProgressStop ? { onProgressStop: opts.onProgressStop } : {},
8668
- ...opts.maxTurns !== void 0 ? { maxTurns: opts.maxTurns } : {},
8669
- ...opts.compaction ? { compaction: opts.compaction } : {}
10467
+ ...options.analyzeOnSettle ? { analyzeOnSettle: options.analyzeOnSettle } : {},
10468
+ ...options.watchWorkers ? { watchWorkers: options.watchWorkers } : {},
10469
+ ...options.stallAfterMs !== void 0 ? { stallAfterMs: options.stallAfterMs } : {},
10470
+ ...options.stopRule ? { stopRule: options.stopRule } : {},
10471
+ ...options.onProgressStop ? { onProgressStop: options.onProgressStop } : {},
10472
+ ...options.maxTurns !== void 0 ? { maxTurns: options.maxTurns } : {},
10473
+ ...options.compaction ? { compaction: options.compaction } : {}
8670
10474
  });
8671
- const spans = opts.otel ? createSupervisorSpanRecorder({
10475
+ spans = options.otel ? createSupervisorSpanRecorder({
8672
10476
  runId,
8673
- ...opts.otel,
10477
+ ...options.otel,
8674
10478
  now
8675
10479
  }) : void 0;
8676
- const hooks = spans ? composeRuntimeHooks(opts.hooks, spans.hooks) : opts.hooks;
8677
- const run = createSupervisor().run(agent, task, {
8678
- budget: opts.budget,
10480
+ const recorder = spans;
10481
+ const hooks = recorder ? composeRuntimeHooks(options.hooks, recorder.hooks) : options.hooks;
10482
+ const supervisor = createSupervisor();
10483
+ if (options.rootHandle) supervisor.attach(options.rootHandle);
10484
+ const run = supervisor.run(agent, canonicalTask, {
10485
+ budget: options.budget,
8679
10486
  runId,
8680
- journal: opts.journal ?? ctx.journal,
10487
+ journal,
8681
10488
  blobs,
8682
10489
  executors: ctx.executors,
8683
- maxDepth: opts.maxDepth ?? 8,
10490
+ rootIdentity: rootExecution.identity,
10491
+ ...rootOwnerRuntime === void 0 ? {} : { rootMaterialization: {
10492
+ runtime: rootOwnerRuntime,
10493
+ declaration: "deferred",
10494
+ authoredProfile: canonicalProfile
10495
+ } },
10496
+ maxDepth: options.maxDepth ?? 8,
10497
+ ...options.maxLiveWorkers !== void 0 ? { maxLiveWorkers: options.maxLiveWorkers } : {},
8684
10498
  ...probes ? { probes } : {},
8685
10499
  ...ctx.resume === true ? { resume: true } : {},
8686
- ...opts.now ? { now: opts.now } : {},
8687
- ...hooks ? { hooks } : {}
10500
+ ...options.now ? { now: options.now } : {},
10501
+ ...options.signal ? { signal: options.signal } : {},
10502
+ ...hooks ? { hooks } : {},
10503
+ ...recorder ? { workerTrace: recorder.workerTrace } : {}
8688
10504
  });
8689
- if (!spans) return run;
10505
+ if (!recorder) return run;
8690
10506
  try {
8691
10507
  const result = await run;
8692
- await spans.finish({ result });
10508
+ await recorder.finish({ result });
8693
10509
  return result;
8694
10510
  } catch (error) {
8695
- await spans.finish({ error });
10511
+ await recorder.finish({ error });
8696
10512
  throw error;
8697
10513
  }
8698
10514
  };
8699
10515
  return start();
8700
10516
  }
8701
10517
  //#endregion
8702
- export { InMemoryDelegationStore as $, FileCoordinationLog as $t, DELEGATE_INPUT_SCHEMA as A, createWorktreeCliExecutor as At, profileRichnessFinding as B, PI_MCP_ADAPTER_ENV as Bt, validateDelegateUiAuditArgs as C, defaultToolDetectors as Ct, createDelegateFeedbackHandler as D, cliWorktreeExecutor as Dt, DELEGATE_FEEDBACK_TOOL_NAME as E, createInMemoryRunContext as Et, delegate as F, piSeamKey as Ft, DELEGATION_TRACE_MAX_SPANS as G, createInbox as Gt, DelegationTaskQueue as H, buildPiMcpServers as Ht, asAuthoredProfile as I, createPushTraceSource as It, composeLoopTraceEmitters as J, runAgentRounds as Jt, buildDelegationTraceSpans as K, createSandboxForSpec as Kt, assessAuthoredProfile as L, decodeToolPart as Lt, createDelegateHandler as M, createSteerableSandboxSession as Mt, validateDelegateArgs as N, PI_RUNTIME as Nt, validateDelegateFeedbackArgs as O, createExecutor as Ot, defaultDelegateBudget as P, piExecutor as Pt, FileDelegationStore as Q, acquireSandbox as Qt, authoredWorker as R, sandboxSessionTraceSource as Rt, createDelegateUiAuditHandler as S, rollingDispatch as St, DELEGATE_FEEDBACK_INPUT_SCHEMA as T, createFileRunContext as Tt, hashIdempotencyInput as U, piMcpAdapterAvailable as Ut, supervisorInstructions as V, PI_MCP_CONFIG_FLAG as Vt, DELEGATION_TRACE_MAX_BYTES as W, preparePiMcp as Wt, DelegationPersistenceError as X, createSandboxLineage as Xt, createDelegationTraceCollector as Y, runLoop as Yt, DelegationStateCorruptError as Z, probeSandboxCapabilities as Zt, createDelegationHistoryHandler as _, createCoordinationTools as _t, supervisorAgent as a, allWorkersStalled as at, DELEGATE_UI_AUDIT_INPUT_SCHEMA as b, freeSlots as bt, createMcpServer as c, noProgressFor as ct, DELEGATION_STATUS_TOOL_NAME as d, anytimeReport as dt, createSupervisorSpanRecorder as en, InMemoryFeedbackStore as et, createDelegationStatusHandler as f, areaUnderCurve as ft, DELEGATION_HISTORY_TOOL_NAME as g, DEFAULT_AWAIT_EVENT_TIMEOUT_MS as gt, DELEGATION_HISTORY_INPUT_SCHEMA as h, renderAnytimeTable as ht, resolveSupervisorProfile as i, allOf as it, DELEGATE_TOOL_NAME as j, DEFAULT_SANDBOX_STEERING_MAX_TURNS as jt, DELEGATE_DESCRIPTION as k, createExecutorRegistry as kt, DELEGATION_STATUS_DESCRIPTION as l, plateau as lt, DELEGATION_HISTORY_DESCRIPTION as m, plateauLength as mt, workerFromBackend as n, gateOnDeliverable as nn, driverAgent as nt, serveCoordinationMcp as o, anyOf as ot, validateDelegationStatusArgs as p, bestSoFar as pt, capDelegationTrace as q, defaultSelectWinner as qt, assertCoordinationBinding as r, finalizeBestDelivered as rt, createInProcessTransport as s, createProgressTracker as st, supervise as t, assertModelAllowed as tn, eventToSnapshot as tt, DELEGATION_STATUS_INPUT_SCHEMA as u, sampleFromSettled as ut, validateDelegationHistoryArgs as v, createEventBus as vt, DELEGATE_FEEDBACK_DESCRIPTION as w, watchTrace as wt, DELEGATE_UI_AUDIT_TOOL_NAME as x, queueOf as xt, DELEGATE_UI_AUDIT_DESCRIPTION as y, effectiveConcurrency as yt, defaultProfileRichnessThresholds as z, PI_MCP_ADAPTER as zt };
10518
+ export { allOf as $, profileRichnessFinding as $t, DELEGATE_DESCRIPTION as A, PI_MCP_ADAPTER as At, DELEGATION_TRACE_MAX_SPANS as B, runLoop as Bt, createDelegateUiAuditHandler as C, createSteerableSandboxSession as Ct, DELEGATE_FEEDBACK_TOOL_NAME as D, createPushTraceSource as Dt, DELEGATE_FEEDBACK_INPUT_SCHEMA as E, piSeamKey as Et, defaultDelegateBudget as F, preparePiMcp as Ft, DelegationPersistenceError as G, createSupervisorSpanRecorder as Gt, capDelegationTrace as H, probeSandboxCapabilities as Ht, delegate as I, createInbox as It, InMemoryDelegationStore as J, asAuthoredProfile as Jt, DelegationStateCorruptError as K, assertModelAllowed as Kt, DelegationTaskQueue as L, createSandboxForSpec as Lt, DELEGATE_TOOL_NAME as M, PI_MCP_CONFIG_FLAG as Mt, createDelegateHandler as N, buildPiMcpServers as Nt, createDelegateFeedbackHandler as O, decodeToolPart as Ot, validateDelegateArgs as P, piMcpAdapterAvailable as Pt, finalizeBestDelivered as Q, defaultProfileRichnessThresholds as Qt, hashIdempotencyInput as R, defaultSelectWinner as Rt, DELEGATE_UI_AUDIT_TOOL_NAME as S, DEFAULT_SANDBOX_STEERING_MAX_TURNS as St, DELEGATE_FEEDBACK_DESCRIPTION as T, piExecutor as Tt, composeLoopTraceEmitters as U, acquireSandbox as Ut, buildDelegationTraceSpans as V, createSandboxLineage as Vt, createDelegationTraceCollector as W, FileCoordinationLog as Wt, eventToSnapshot as X, authoredWorker as Xt, InMemoryFeedbackStore as Y, assessAuthoredProfile as Yt, driverAgent as Z, canonicalizeAuthoredProfile as Zt, DELEGATION_HISTORY_TOOL_NAME as _, createInMemoryRunContext as _t, resolveSupervisorProfile as a, sampleFromSettled as at, DELEGATE_UI_AUDIT_DESCRIPTION as b, createExecutorRegistry as bt, createInProcessTransport as c, bestSoFar as ct, DELEGATION_STATUS_INPUT_SCHEMA as d, DEFAULT_AWAIT_EVENT_TIMEOUT_MS as dt, supervisorInstructions as en, allWorkersStalled as et, DELEGATION_STATUS_TOOL_NAME as f, createCoordinationTools as ft, DELEGATION_HISTORY_INPUT_SCHEMA as g, createFileRunContext as gt, DELEGATION_HISTORY_DESCRIPTION as h, watchTrace as ht, assertCoordinationBinding as i, plateau as it, DELEGATE_INPUT_SCHEMA as j, PI_MCP_ADAPTER_ENV as jt, validateDelegateFeedbackArgs as k, sandboxSessionTraceSource as kt, createMcpServer as l, plateauLength as lt, validateDelegationStatusArgs as m, defaultToolDetectors as mt, supervise as n, createProgressTracker as nt, supervisorAgent as o, anytimeReport as ot, createDelegationStatusHandler as p, createEventBus as pt, FileDelegationStore as q, assertProfileModelsAllowed as qt, workerFromBackend as r, noProgressFor as rt, serveCoordinationMcp as s, areaUnderCurve as st, DEFAULT_AUTHORED_PROFILE_SECURITY_POLICY as t, gateOnDeliverable as tn, anyOf as tt, DELEGATION_STATUS_DESCRIPTION as u, renderAnytimeTable as ut, createDelegationHistoryHandler as v, cliWorktreeExecutor as vt, validateDelegateUiAuditArgs as w, PI_RUNTIME as wt, DELEGATE_UI_AUDIT_INPUT_SCHEMA as x, createWorktreeCliExecutor as xt, validateDelegationHistoryArgs as y, createExecutor as yt, DELEGATION_TRACE_MAX_BYTES as z, runAgentRounds as zt };
8703
10519
 
8704
- //# sourceMappingURL=supervise-B7TIJR3D.js.map
10520
+ //# sourceMappingURL=supervise-U7_K5yuV.js.map