@tangle-network/agent-runtime 0.111.0 → 0.112.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 (43) hide show
  1. package/dist/{activation-CsuHCZVN.js → activation-Cdc_tRNR.js} +2 -2
  2. package/dist/{activation-CsuHCZVN.js.map → activation-Cdc_tRNR.js.map} +1 -1
  3. package/dist/agent.d.ts +1 -1
  4. package/dist/agent.js +2 -2
  5. package/dist/{environment-provider-CTEMEP9u.d.ts → environment-provider-Cl97VeCv.d.ts} +43 -2
  6. package/dist/environment-provider.d.ts +1 -1
  7. package/dist/{improvement-cycle-ryAyCLKN.js → improvement-cycle-BCjD-g_C.js} +3 -3
  8. package/dist/{improvement-cycle-ryAyCLKN.js.map → improvement-cycle-BCjD-g_C.js.map} +1 -1
  9. package/dist/{index-DlLPNELY.d.ts → index-B0sAaAO_.d.ts} +144 -17
  10. package/dist/{index-BmI2uxy5.d.ts → index-B6glsqBp.d.ts} +3 -3
  11. package/dist/{index-sLuBoGud.d.ts → index-C9vg2af7.d.ts} +4 -4
  12. package/dist/index.d.ts +5 -5
  13. package/dist/index.js +7 -7
  14. package/dist/intelligence.d.ts +1 -1
  15. package/dist/intelligence.js +2 -2
  16. package/dist/kernel.d.ts +3 -3
  17. package/dist/kernel.js +5 -5
  18. package/dist/{knowledge-DBNAteaC.js → knowledge-In_1LsHg.js} +3 -3
  19. package/dist/{knowledge-DBNAteaC.js.map → knowledge-In_1LsHg.js.map} +1 -1
  20. package/dist/knowledge.d.ts +1 -1
  21. package/dist/knowledge.js +1 -1
  22. package/dist/{loop-runner-bin-vRo5TZt_.d.ts → loop-runner-bin-CHnWCyiB.d.ts} +3 -3
  23. package/dist/{loop-runner-bin-BLOckrqT.js → loop-runner-bin-DF98VMqr.js} +3 -3
  24. package/dist/{loop-runner-bin-BLOckrqT.js.map → loop-runner-bin-DF98VMqr.js.map} +1 -1
  25. package/dist/loop-runner-bin.d.ts +1 -1
  26. package/dist/loop-runner-bin.js +1 -1
  27. package/dist/mcp/bin.js +1 -1
  28. package/dist/mcp/index.d.ts +1 -1
  29. package/dist/mcp/index.js +4 -4
  30. package/dist/{openai-tools-st-hERvA.js → openai-tools-g5FS2twc.js} +2 -2
  31. package/dist/{openai-tools-st-hERvA.js.map → openai-tools-g5FS2twc.js.map} +1 -1
  32. package/dist/primeintellect/index.d.ts +1 -1
  33. package/dist/{runtime-fwz-erxT.js → runtime-6sL2vhTQ.js} +4 -4
  34. package/dist/{runtime-fwz-erxT.js.map → runtime-6sL2vhTQ.js.map} +1 -1
  35. package/dist/{structural-rollout-CgnNy7_4.js → structural-rollout-D5GbH3cy.js} +2 -2
  36. package/dist/{structural-rollout-CgnNy7_4.js.map → structural-rollout-D5GbH3cy.js.map} +1 -1
  37. package/dist/{supervise-CeZtA1wu.js → supervise-6jSTe0kO.js} +322 -30
  38. package/dist/supervise-6jSTe0kO.js.map +1 -0
  39. package/dist/{supervisor-ByCPHcp9.js → supervisor-B4hOPKJV.js} +48 -6
  40. package/dist/{supervisor-ByCPHcp9.js.map → supervisor-B4hOPKJV.js.map} +1 -1
  41. package/dist/testing.js +8 -8
  42. package/package.json +1 -1
  43. package/dist/supervise-CeZtA1wu.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  import { c as RuntimeRunStateError, i as ConfigError, o as NotFoundError, t as AgentEvalError$1, u as ValidationError } from "./errors-DEAvWQPy.js";
2
2
  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
3
  import { a as contentAddress, i as InMemorySpawnJournal, n as FileSpawnJournal, r as InMemoryResultBlobStore, t as FileResultBlobStore } from "./spawn-journal-DLhnom3e.js";
4
- import { A as createWorktree, C as routerChatWithUsage, D as runWorktreeChecks, O as runWorktreeHarness, T as runBrainLoop, a as runFinalizer, i as pickBestDelivered, j as removeWorktree, k as captureWorktreeDiff, l as withDriverExecutor, n as bestDelivered, o as runTree, t as createSupervisor, x as routerBrain, y as createActivityLog } from "./supervisor-ByCPHcp9.js";
4
+ import { A as createWorktree, C as routerChatWithUsage, D as runWorktreeChecks, O as runWorktreeHarness, T as runBrainLoop, a as runFinalizer, i as pickBestDelivered, j as removeWorktree, k as captureWorktreeDiff, l as withDriverExecutor, n as bestDelivered, o as runTree, t as createSupervisor, x as routerBrain, y as createActivityLog } from "./supervisor-B4hOPKJV.js";
5
5
  import { i as notifyRuntimeHookEvent } from "./runtime-hooks-C7iJOWm3.js";
6
6
  import { a as notifySandboxEventObserver, n as extractLlmCallEvent } from "./sandbox-events-DeI5xX8P.js";
7
7
  import { i as resolveAgentEnvironmentProvider, n as providerAsExecutor, s as buildBackendOptions } from "./environment-provider-BsHpW4Dp.js";
@@ -9,6 +9,7 @@ import { r as buildLoopSpanNodes } from "./otel-export-D34IQW1C.js";
9
9
  import { t as createStdioToolServer } from "./tool-server-RcWgLIsL.js";
10
10
  import { n as UI_LENSES } from "./substrate-B0TYNrXn.js";
11
11
  import { argHash, computeFindingId, errorStreakDetector, estimateCost, isModelPriced, makeFinding, observeAll, repeatedActionDetector } from "@tangle-network/agent-eval";
12
+ import { agentProfileSchema } from "@tangle-network/agent-interface";
12
13
  import { randomUUID } from "node:crypto";
13
14
  import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
14
15
  import path, { dirname } from "node:path";
@@ -3956,6 +3957,15 @@ function createEventBus(now = Date.now) {
3956
3957
  }
3957
3958
  //#endregion
3958
3959
  //#region src/mcp/tools/coordination.ts
3960
+ /**
3961
+ *
3962
+ * MCP binding for a live `Scope`. A sandbox driver gets the same small verbs
3963
+ * the in-process driver has: spawn, observe, await, steer, ask/answer, analyze,
3964
+ * and stop. Settled outputs remain Scope artifacts; product code can project
3965
+ * them into any UI/report envelope it needs.
3966
+ *
3967
+ * @experimental
3968
+ */
3959
3969
  /** Default ceiling for a single `await_event` block (ms). Chosen well under any reasonable remote
3960
3970
  * MCP client request timeout so the call returns a `pending` liveness snapshot instead of erroring;
3961
3971
  * the supervisor re-polls until the worker settles. */
@@ -3981,6 +3991,179 @@ const idArg = {
3981
3991
  type: "string",
3982
3992
  description: "The workerId returned by spawn_agent."
3983
3993
  };
3994
+ /**
3995
+ * Strip zod's object-KEY CODEC artifact from a derived JSON Schema, at every depth.
3996
+ *
3997
+ * `z.record(z.string(), …)` converts to `propertyNames: { type: 'string', pattern:
3998
+ * '^u(?:[0-9a-f]{4})*$' }` — a marker of the lossy key round-trip, not a constraint anything
3999
+ * enforces: `agentProfileSchema.safeParse({ name: 'r', tools: { bash: true, Read: false } })`
4000
+ * succeeds with those plain keys. Published verbatim it reads to a model as "every key must be a
4001
+ * run of hex quads", and the model either emits hex-encoded garbage keys or drops the field —
4002
+ * on `tools`, `permissions`, `metadata`, `mcp`, `mcp.*.env`, and `model.metadata`, which is most
4003
+ * of what a parent actually configures.
4004
+ *
4005
+ * Every `propertyNames` in the canonical profile schema is this artifact (25 of 25 at Interface
4006
+ * 0.40), and the canonical schema constrains no key by pattern, so dropping the keyword outright
4007
+ * loses nothing real and cannot be defeated by zod changing the encoding's exact regex.
4008
+ *
4009
+ * Rebuilds rather than mutates: the canonical conversion output must stay untouched for callers
4010
+ * that compare against it.
4011
+ */
4012
+ const stripKeyCodecArtifacts = (node) => {
4013
+ if (Array.isArray(node)) return node.map(stripKeyCodecArtifacts);
4014
+ if (!node || typeof node !== "object") return node;
4015
+ return Object.fromEntries(Object.entries(node).filter(([key]) => key !== "propertyNames").map(([key, value]) => [key, stripKeyCodecArtifacts(value)]));
4016
+ };
4017
+ /** The canonical profile fields a spawning parent actually sets on a child, in the order a reader
4018
+ * needs them, each with the description published alongside it. Everything else stays legal to
4019
+ * pass — see {@link deriveSpawnProfileArg}.
4020
+ *
4021
+ * Why these eleven, with the measured numbers (serialized JSON bytes, Interface 0.40). The
4022
+ * canonical `properties` map is 10629 bytes, against 2424 bytes for every argument of every other
4023
+ * coordination tool COMBINED — publishing it whole makes one parameter four times the rest of the
4024
+ * surface a driver re-reads each turn. Of the seven omitted fields (tags, connections, subagents,
4025
+ * hooks, modes, confidential, extensions) none is something a parent hands a worker; `permissions`
4026
+ * (321 bytes) IS, so it is published — a child that must not touch the network or the filesystem
4027
+ * is fenced there and nowhere else. `mcp` (2663 bytes) and `resources` (3122 bytes) are the two a
4028
+ * parent is least likely to author inline and were together 85% of the published cost, so they
4029
+ * carry a brief shape plus a description naming the full form instead of the canonical sub-tree. */
4030
+ const spawnProfileFields = [
4031
+ {
4032
+ name: "name",
4033
+ description: "Short identifier for this child, e.g. \"researcher\" or \"patch-writer\". A child normally sets it to its role; it shows up in traces and worker labels."
4034
+ },
4035
+ {
4036
+ name: "description",
4037
+ description: "One line saying what this child is for. Read by humans and by a parent listing its workers."
4038
+ },
4039
+ {
4040
+ name: "version",
4041
+ description: "Optional version string for this profile, so two revisions of the same role are distinguishable in evidence. A child usually omits it."
4042
+ },
4043
+ {
4044
+ name: "harness",
4045
+ description: "Which coding backend runs the child. Omit to inherit the run default; set it only when this child needs a specific backend (e.g. a long refactor on \"claude-code\")."
4046
+ },
4047
+ {
4048
+ name: "model",
4049
+ description: "Model routing: `default` model id, optional `small` for cheap sub-calls, `provider`, and `reasoningEffort`. A child typically sets `default` and `reasoningEffort` — raise effort for a hard reasoning task, lower it for bulk mechanical work."
4050
+ },
4051
+ {
4052
+ name: "prompt",
4053
+ description: "The child's standing instructions: `systemPrompt` (who it is and how it works) and `instructions` (durable rules). This is the role; the separate `task` argument carries what to do right now. A child with no systemPrompt has no role — always set one."
4054
+ },
4055
+ {
4056
+ name: "tools",
4057
+ description: "Per-tool on/off map keyed by tool name, e.g. `{ \"bash\": true, \"webfetch\": false }`. Omit to inherit the backend's default tool set; set it to narrow a child to the tools its task needs. Keys are plain tool names."
4058
+ },
4059
+ {
4060
+ name: "permissions",
4061
+ description: "Per-tool permission decisions: each tool name maps to \"allow\", \"deny\", or \"ask\", or to a nested map of finer-grained rules. This is where a parent fences a child it does not fully trust — a read-only child denies write and network tools here, not in `tools`."
4062
+ },
4063
+ {
4064
+ name: "mcp",
4065
+ description: "MCP tool servers to mount for the child, keyed by server name. Brief form: each value is either `{ transport: \"stdio\", command, args?, env?, cwd? }` or `{ transport: \"sse\" | \"http\", url, headers? }`. A child normally sets this only when it needs a tool server the task requires; the canonical AgentProfile schema carries the full form (secret-ref values for env/headers, per-server metadata) and governs validation.",
4066
+ brief: {
4067
+ type: "object",
4068
+ additionalProperties: { type: "object" }
4069
+ }
4070
+ },
4071
+ {
4072
+ name: "resources",
4073
+ description: "Files, tools, skills, and agents materialized into the child workspace before it starts. Brief form: `{ files?, tools?, skills?, agents? }`, each an array whose entries are `{ kind: \"inline\", name, content }` or `{ kind: \"github\", repository?, path, ref? }` (`files` entries wrap that as `{ path, resource, executable? }`). A child typically gets `files` for seed inputs and `skills` for a procedure it must follow; the canonical AgentProfile schema carries the full form and governs validation.",
4074
+ brief: {
4075
+ type: "object",
4076
+ properties: {
4077
+ files: {
4078
+ type: "array",
4079
+ items: { type: "object" }
4080
+ },
4081
+ tools: {
4082
+ type: "array",
4083
+ items: { type: "object" }
4084
+ },
4085
+ skills: {
4086
+ type: "array",
4087
+ items: { type: "object" }
4088
+ },
4089
+ agents: {
4090
+ type: "array",
4091
+ items: { type: "object" }
4092
+ }
4093
+ },
4094
+ additionalProperties: true
4095
+ }
4096
+ },
4097
+ {
4098
+ name: "metadata",
4099
+ description: "Free-form key/value bag carried with the profile (plain string keys). Use it for run bookkeeping a reader will want later; it does not change how the child executes."
4100
+ }
4101
+ ];
4102
+ /**
4103
+ * Build the published shape of `spawn_agent`'s `profile` argument from the canonical
4104
+ * `agentProfileSchema` conversion's `properties` map, so it cannot drift from the profile the
4105
+ * runtime materializes.
4106
+ *
4107
+ * DEGRADES, never throws. A canonical field that is absent — renamed or removed upstream — is
4108
+ * simply omitted from the published shape, and a canonical schema that is no longer an object
4109
+ * publishes no properties at all. This function is reached from a statically-imported module, so a
4110
+ * throw here bricks `import '@tangle-network/agent-runtime/kernel'` for every consumer over an
4111
+ * upstream rename that costs them, at worst, one advisory field. The drift itself is still caught
4112
+ * loudly — as a test assertion in `tests/kernel/coordination.test.ts`, in CI, where it is our
4113
+ * problem rather than at a consumer's import, where it is theirs.
4114
+ *
4115
+ * Permissive on purpose: `additionalProperties: true` with no `required` list, so every canonical
4116
+ * field this shape omits stays legal to pass. This tool layer performs no profile validation.
4117
+ *
4118
+ * @internal exported for the drift and degradation tests; not part of the package's public API.
4119
+ */
4120
+ function deriveSpawnProfileArg(canonicalProperties) {
4121
+ const published = [];
4122
+ for (const field of spawnProfileFields) {
4123
+ const canonical = canonicalProperties?.[field.name];
4124
+ if (canonical === void 0) continue;
4125
+ const shape = field.brief ?? stripKeyCodecArtifacts(canonical);
4126
+ published.push([field.name, {
4127
+ ...shape,
4128
+ description: field.description
4129
+ }]);
4130
+ }
4131
+ return {
4132
+ type: "object",
4133
+ description: "The child agent profile to run — this is the shape the DEFAULT worker seam accepts; a run wired with a custom makeWorkerAgent may accept a different one. The properties below are derived from the canonical AgentProfile schema and reduced to what a spawning parent sets (`mcp` and `resources` in a brief form); every other canonical field — tags, connections, subagents, hooks, modes, confidential, extensions — may still be passed. This tool does not validate the profile: the canonical AgentProfile schema governs validation downstream.",
4134
+ properties: Object.fromEntries(published),
4135
+ additionalProperties: true
4136
+ };
4137
+ }
4138
+ spawnProfileFields.map((f) => f.name);
4139
+ let spawnProfileArgCache;
4140
+ /** The published `profile` shape, computed on FIRST tool-definition access and memoized — not at
4141
+ * module load. The conversion walks the whole canonical profile tree, and the strip walk rebuilds
4142
+ * it: 3.5ms on the first `createCoordinationTools`, 0.017ms on every later one (measured, Interface
4143
+ * 0.40, node 24). `src/runtime/index.ts` imports this module statically, so paying that at import
4144
+ * taxes every consumer of the kernel entrypoint — including the ones that never build a
4145
+ * coordination toolbox. The memo keeps it at once per process for the ones that do.
4146
+ *
4147
+ * Conversion choices. `io: 'input'` is the CALLER's view — pre-default, pre-transform — which is
4148
+ * what a spawning parent may pass, not what the runtime ends up holding. `unrepresentable: 'any'`
4149
+ * keeps the conversion total: the canonical schema contains transforms with no JSON Schema form,
4150
+ * and zod's default is to throw on them, which would leave the tool with no published shape. */
4151
+ function spawnProfileArg() {
4152
+ if (!spawnProfileArgCache) spawnProfileArgCache = deepFreeze(deriveSpawnProfileArg(agentProfileSchema.toJSONSchema({
4153
+ io: "input",
4154
+ target: "draft-07",
4155
+ unrepresentable: "any"
4156
+ }).properties));
4157
+ return spawnProfileArgCache;
4158
+ }
4159
+ /** Freeze a JSON-Schema tree. The derived schema is plain JSON data with no cycles. */
4160
+ function deepFreeze(value) {
4161
+ if (value && typeof value === "object" && !Object.isFrozen(value)) {
4162
+ Object.freeze(value);
4163
+ for (const nested of Object.values(value)) deepFreeze(nested);
4164
+ }
4165
+ return value;
4166
+ }
3984
4167
  /** Build the driver's MCP tools over a live scope. */
3985
4168
  function createCoordinationTools(opts) {
3986
4169
  const deliverable = opts.deliverable;
@@ -4311,7 +4494,7 @@ function createCoordinationTools(opts) {
4311
4494
  inputSchema: {
4312
4495
  type: "object",
4313
4496
  properties: {
4314
- profile: { description: "The worker/driver profile to run." },
4497
+ profile: spawnProfileArg(),
4315
4498
  task: { description: "The task the worker should perform." },
4316
4499
  label: {
4317
4500
  type: "string",
@@ -7340,9 +7523,21 @@ function createInProcessTransport() {
7340
7523
  *
7341
7524
  * @experimental
7342
7525
  */
7526
+ /** Hosts that reach only this machine, including the IPv4-mapped and bracketed IPv6 spellings a
7527
+ * caller may pass through from config. A name that is not recognizably loopback counts as REMOTE:
7528
+ * whether it resolves to a loopback interface is not knowable here, and the safe direction of that
7529
+ * doubt is "exposed". */
7530
+ function isLoopbackHost(host) {
7531
+ const h = host.trim().toLowerCase().replace(/^\[/, "").replace(/\]$/, "");
7532
+ if (h === "localhost" || h === "::1" || h === "0:0:0:0:0:0:0:1" || h === "::ffff:127.0.0.1") return true;
7533
+ return /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(h);
7534
+ }
7343
7535
  /** Stand up the coordination MCP over a live scope. The HOST address is `127.0.0.1` (the bridge runs
7344
- * opencode locally, same host); pass `host` to bind elsewhere when the harness is remote. */
7536
+ * opencode locally, same host); pass `host` to bind elsewhere when the harness is remote — a
7537
+ * non-loopback host additionally requires `allowUnauthenticatedRemote`. */
7345
7538
  async function serveCoordinationMcp(opts) {
7539
+ const host = opts.host ?? "127.0.0.1";
7540
+ if (!isLoopbackHost(host) && opts.allowUnauthenticatedRemote !== true) throw new ConfigError(`coordination host=${JSON.stringify(host)} is not a loopback address and the coordination MCP has no authentication: any client that can reach the port could call spawn_agent/steer_agent and spend this run's budget. Bind a loopback host ("127.0.0.1", "localhost", "::1"), or set allowUnauthenticatedRemote: true to accept that exposure explicitly.`);
7346
7541
  const coord = createCoordinationTools({
7347
7542
  scope: opts.scope,
7348
7543
  blobs: opts.blobs,
@@ -7363,7 +7558,6 @@ async function serveCoordinationMcp(opts) {
7363
7558
  extraTools: coord.tools,
7364
7559
  serverName: "coordination"
7365
7560
  });
7366
- const host = opts.host ?? "127.0.0.1";
7367
7561
  const server = createServer((req, res) => {
7368
7562
  if (req.method !== "POST") {
7369
7563
  res.writeHead(405, { allow: "POST" });
@@ -7423,21 +7617,6 @@ async function serveCoordinationMcp(opts) {
7423
7617
  }
7424
7618
  //#endregion
7425
7619
  //#region src/runtime/supervise/supervisor-agent.ts
7426
- /**
7427
- * `supervisorAgent` — build a supervisor `Agent` FROM its profile. The brain is resolved from
7428
- * `profile.harness` exactly as `createExecutor({ backend })` resolves a worker: backend-as-data,
7429
- * no hand-built brain. The supervisor stops being special — it's one profile, materialized by the
7430
- * same resolution rule as every other agent.
7431
- *
7432
- * - `harness` null/undefined → the in-process router tool-loop: `driverAgent` over the
7433
- * canonical `ToolLoopChat`, built by `routerBrain` from the profile's model + the router seam.
7434
- * - `harness` a coding CLI (`claude-code`/`opencode`/`codex`/…) → a SANDBOXED harness drives the
7435
- * coordination verbs: `serveCoordinationMcp` exposes spawn/await/steer/stop over the live scope,
7436
- * and the caller's `driveHarness` runs the harness with that MCP mounted. The harness IS the brain.
7437
- *
7438
- * Both arms spawn children through the SAME `makeWorkerAgent` seam and apply the SAME independent
7439
- * deliverable check to direct submissions. Raw driver prose is never eligible.
7440
- */
7441
7620
  /** The standing strategy a router-brained supervisor runs with when its profile names no
7442
7621
  * `systemPrompt`. The brain's competence IS this prompt: without it the brain has the coordination
7443
7622
  * verbs but no policy for WHEN to use them, and either over-spawns or stalls. A profile may override
@@ -7459,11 +7638,101 @@ const defaultSupervisorPrompt = [
7459
7638
  "Wait on real signals (await a settle, answer a blocking question), integrate the result, and stop",
7460
7639
  "as soon as the deliverable is met."
7461
7640
  ].join("\n");
7641
+ /** Longest prompt excerpt an error message may carry. A supervisor system prompt is routinely
7642
+ * thousands of characters; two of them interpolated whole turn a configuration fault into an
7643
+ * unreadable wall, so a fault reports each prompt's LENGTH plus a leading excerpt instead. */
7644
+ const PROMPT_EXCERPT_CHARS = 60;
7645
+ /** `<n> chars starting "<first 60>…"` — enough to tell two prompts apart without printing either. */
7646
+ function describePrompt(value) {
7647
+ const head = value.slice(0, PROMPT_EXCERPT_CHARS);
7648
+ return `${value.length} chars starting ${JSON.stringify(head)}${value.length > PROMPT_EXCERPT_CHARS ? "…" : ""}`;
7649
+ }
7650
+ /**
7651
+ * The instruction lines a canonical `resources.instructions` contributes. A plain string and an
7652
+ * `inline` resource are their own text; a `github` reference names bytes that live elsewhere and
7653
+ * cannot be fetched while building a supervisor synchronously — that fails loud rather than
7654
+ * dropping instructions the profile says the agent runs under (the same rule
7655
+ * `improve()`'s memory surface applies to the same field).
7656
+ */
7657
+ function resourceInstructionLines(instructions) {
7658
+ if (instructions === void 0) return [];
7659
+ if (typeof instructions === "string") return instructions.length > 0 ? [instructions] : [];
7660
+ if (instructions.kind === "inline") return instructions.content.length > 0 ? [instructions.content] : [];
7661
+ throw new ConfigError(`supervisorAgent: profile.resources.instructions is a github resource reference (${JSON.stringify(instructions.path)}), which cannot be fetched while the supervisor is built — pass the instruction text as a string or an inline resource`);
7662
+ }
7663
+ /**
7664
+ * The standing instruction both arms run under, assembled from every canonical spelling that
7665
+ * carries one: the system prompt (`prompt.systemPrompt` or the top-level `systemPrompt`), then the
7666
+ * `prompt.instructions` lines, then `resources.instructions` — each on its own line, in that order.
7667
+ * `undefined` only when the profile names none at all.
7668
+ *
7669
+ * Two disagreeing system prompts throw: they are the same standing instruction in two spellings, so
7670
+ * picking one silently changes what the supervisor runs and there is no defensible winner.
7671
+ */
7672
+ function resolveSupervisorSystemPrompt(profile, activePrompt) {
7673
+ const promptSystem = profile.prompt?.systemPrompt;
7674
+ const topSystem = profile.systemPrompt;
7675
+ if (promptSystem !== void 0 && topSystem !== void 0 && promptSystem !== topSystem) throw new ValidationError(`supervisorAgent: profile.prompt.systemPrompt and profile.systemPrompt are both set and differ — they are the same standing instruction, so keep exactly one (prompt.systemPrompt: ${describePrompt(promptSystem)}; systemPrompt: ${describePrompt(topSystem)})`);
7676
+ const base = promptSystem ?? topSystem ?? activePrompt;
7677
+ const lines = [...profile.prompt?.instructions ?? [], ...resourceInstructionLines(profile.resources?.instructions)];
7678
+ if (lines.length === 0) return base;
7679
+ return (base !== void 0 ? [base, ...lines] : lines).join("\n");
7680
+ }
7681
+ /**
7682
+ * The router model id, or `undefined` when the profile names none. A string `model` IS the id; an
7683
+ * object `model` is canonical model hints and `default` is the id. `AgentProfileModelHints.default`
7684
+ * is OPTIONAL upstream (`{ provider: 'anthropic' }` is a valid canonical profile), so hints without
7685
+ * a resolvable id are the documented "profile names no model" case: the router config's own model
7686
+ * applies, exactly as when `model` is absent.
7687
+ */
7688
+ function resolveSupervisorModelId(profile) {
7689
+ if (typeof profile.model === "string") return profile.model;
7690
+ const fromHints = profile.model?.default;
7691
+ return typeof fromHints === "string" && fromHints.length > 0 ? fromHints : void 0;
7692
+ }
7693
+ /**
7694
+ * Reduce either profile spelling — a hand-written `SupervisorProfile` or a canonical `AgentProfile`
7695
+ * — to the scalars the brain arms consume:
7696
+ *
7697
+ * - `modelId`: a string `model` verbatim, else `model.default`. Absent or unresolvable → the
7698
+ * router config's own model applies unchanged.
7699
+ * - `systemPrompt`: the system prompt plus the `prompt.instructions` and `resources.instructions`
7700
+ * lines, one per line.
7701
+ *
7702
+ * `supervisorAgent` resolves each piece only where it is consumed (the model id on the router arm
7703
+ * only); this whole-profile reduction is the caller-facing view of the same rules.
7704
+ */
7705
+ function resolveSupervisorProfile(profile) {
7706
+ const systemPrompt = resolveSupervisorSystemPrompt(profile);
7707
+ const modelId = resolveSupervisorModelId(profile);
7708
+ return {
7709
+ name: profile.name ?? "supervisor",
7710
+ harness: profile.harness ?? null,
7711
+ ...modelId !== void 0 ? { modelId } : {},
7712
+ ...systemPrompt !== void 0 ? { systemPrompt } : {}
7713
+ };
7714
+ }
7715
+ /**
7716
+ * Fail closed on a non-loopback coordination bind. `serveCoordinationMcp` mounts spawn_agent /
7717
+ * steer_agent / stop with NO authentication of any kind (it is a bare JSON-RPC-over-HTTP handler),
7718
+ * so a non-loopback bind lets anyone who can reach the port spawn agents and spend the run's
7719
+ * conserved budget. There is no token to require yet, so the only honest options are loopback or an
7720
+ * explicit, recorded acknowledgment — never a silent bind.
7721
+ */
7722
+ function assertCoordinationBinding(binding) {
7723
+ const host = binding?.host;
7724
+ if (host === void 0 || isLoopbackHost(host)) return;
7725
+ if (binding?.allowUnauthenticatedRemote === true) return;
7726
+ throw new ConfigError(`supervisorAgent: coordination.host=${JSON.stringify(host)} is not a loopback address and the coordination MCP has no authentication: any client that can reach the port could call spawn_agent/steer_agent and spend this run's budget. Bind a loopback host ("127.0.0.1", "localhost", "::1"), or set coordination.allowUnauthenticatedRemote: true to accept that exposure explicitly.`);
7727
+ }
7462
7728
  /** Build a supervisor `Agent` from its profile: the brain resolves from `profile.harness` (backend-as-data), the same resolution rule as every worker. */
7463
7729
  function supervisorAgent(profile, deps) {
7464
7730
  const name = profile.name ?? "supervisor";
7465
- const systemPrompt = profile.systemPrompt ?? defaultSupervisorPrompt;
7466
7731
  const harness = profile.harness ?? null;
7732
+ const profilePrompt = resolveSupervisorSystemPrompt(profile);
7733
+ const coordination = deps.coordination ? { ...deps.coordination } : void 0;
7734
+ assertCoordinationBinding(coordination);
7735
+ 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.");
7467
7736
  if (harness !== null && deps.compaction) throw new ValidationError("supervisorAgent: compaction is only supported for router-brained supervisors (profile.harness null)");
7468
7737
  if (harness === null) return driverAgent({
7469
7738
  name,
@@ -7471,7 +7740,7 @@ function supervisorAgent(profile, deps) {
7471
7740
  blobs: deps.blobs,
7472
7741
  makeWorkerAgent: deps.makeWorkerAgent,
7473
7742
  perWorker: deps.perWorker,
7474
- systemPrompt,
7743
+ systemPrompt: resolveSupervisorSystemPrompt(profile, defaultSupervisorPrompt) ?? defaultSupervisorPrompt,
7475
7744
  ...deps.deliverable ? { deliverable: deps.deliverable } : {},
7476
7745
  ...deps.maxLiveWorkers !== void 0 ? { maxLiveWorkers: deps.maxLiveWorkers } : {},
7477
7746
  ...deps.extraTools ? { extraTools: deps.extraTools } : {},
@@ -7498,6 +7767,9 @@ function supervisorAgent(profile, deps) {
7498
7767
  blobs: deps.blobs,
7499
7768
  makeWorkerAgent: deps.makeWorkerAgent,
7500
7769
  perWorker: deps.perWorker,
7770
+ ...coordination?.host !== void 0 ? { host: coordination.host } : {},
7771
+ ...coordination?.port !== void 0 ? { port: coordination.port } : {},
7772
+ ...coordination?.allowUnauthenticatedRemote === true ? { allowUnauthenticatedRemote: true } : {},
7501
7773
  ...deps.deliverable ? { deliverable: deps.deliverable } : {},
7502
7774
  ...deps.maxLiveWorkers !== void 0 ? { maxLiveWorkers: deps.maxLiveWorkers } : {},
7503
7775
  ...deps.analysts ? { analysts: deps.analysts } : {},
@@ -7511,6 +7783,7 @@ function supervisorAgent(profile, deps) {
7511
7783
  try {
7512
7784
  await driveHarness({
7513
7785
  profile,
7786
+ ...profilePrompt !== void 0 ? { systemPrompt: profilePrompt } : {},
7514
7787
  task,
7515
7788
  scope,
7516
7789
  coordinationMcpUrl: mcp.url
@@ -7535,9 +7808,10 @@ function supervisorAgent(profile, deps) {
7535
7808
  }
7536
7809
  function routerBrainFromProfile(profile, deps) {
7537
7810
  if (!deps.router) throw new ValidationError("supervisorAgent: a router-brained supervisor (harness null) needs deps.router (or deps.brain)");
7811
+ const modelId = resolveSupervisorModelId(profile);
7538
7812
  return routerBrain({
7539
7813
  ...deps.router,
7540
- model: profile.model ?? deps.router.model
7814
+ ...modelId !== void 0 ? { model: modelId } : {}
7541
7815
  });
7542
7816
  }
7543
7817
  //#endregion
@@ -7569,6 +7843,18 @@ function workerFromBackend(backend, deliverable) {
7569
7843
  };
7570
7844
  };
7571
7845
  }
7846
+ /** Resolve one option that may be given as a value OR as a name into `opts.registry`. Both failure
7847
+ * modes name the option, the requested name, and the table it was looked up in — a typo must not
7848
+ * degrade into a silently unconfigured run (which for `deliverable` means "no run can ever
7849
+ * deliver"). A resolver port cannot enumerate its names, so the message names the table instead of
7850
+ * listing what was in it. */
7851
+ function resolveNamed(option, table, value, registry) {
7852
+ if (typeof value !== "string") return value;
7853
+ if (!registry) throw new ConfigError(`supervise: opts.${option} = ${JSON.stringify(value)} names a registry entry, but no opts.registry.${table} was provided to resolve it against`);
7854
+ const entry = registry.resolve(value);
7855
+ 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`);
7856
+ return entry;
7857
+ }
7572
7858
  /** A quarter of the token pool per worker → ~4 workers fit before `poolStarved` halts spawning. */
7573
7859
  function defaultPerWorker(budget) {
7574
7860
  return {
@@ -7580,15 +7866,20 @@ function defaultPerWorker(budget) {
7580
7866
  function supervise(profile, task, opts) {
7581
7867
  const backendModel = opts.backend?.model;
7582
7868
  assertModelAllowed(opts.router?.model, opts.allowedModels);
7583
- assertModelAllowed(profile.model, opts.allowedModels);
7869
+ assertModelAllowed(resolveSupervisorModelId(profile), opts.allowedModels);
7584
7870
  assertModelAllowed(typeof backendModel === "string" ? backendModel : void 0, opts.allowedModels);
7871
+ const deliverable = resolveNamed("deliverable", "deliverables", opts.deliverable, opts.registry?.deliverables);
7872
+ const finalizer = resolveNamed("finalizer", "finalizers", opts.finalizer, opts.registry?.finalizers);
7873
+ const analysts = resolveNamed("analysts", "analysts", opts.analysts, opts.registry?.analysts);
7874
+ const probes = resolveNamed("probes", "probes", opts.probes, opts.registry?.probes);
7875
+ assertCoordinationBinding(opts.coordination);
7585
7876
  const ctx = opts.runDir !== void 0 ? createFileRunContext(opts.runDir, { withDriver: true }) : createInMemoryRunContext({ withDriver: true });
7586
7877
  const blobs = opts.blobs ?? ctx.blobs;
7587
7878
  const perWorker = opts.perWorker ?? defaultPerWorker(opts.budget);
7588
7879
  let makeWorkerAgent = opts.makeWorkerAgent;
7589
7880
  if (!makeWorkerAgent) {
7590
7881
  if (!opts.backend) throw new ValidationError("supervise: provide opts.backend (where workers run) or opts.makeWorkerAgent");
7591
- makeWorkerAgent = workerFromBackend(opts.backend, opts.deliverable);
7882
+ makeWorkerAgent = workerFromBackend(opts.backend, deliverable);
7592
7883
  }
7593
7884
  const workerFactory = makeWorkerAgent;
7594
7885
  const runId = opts.runId ?? "supervise";
@@ -7600,17 +7891,18 @@ function supervise(profile, task, opts) {
7600
7891
  blobs,
7601
7892
  makeWorkerAgent: workerFactory,
7602
7893
  perWorker,
7603
- ...opts.deliverable ? { deliverable: opts.deliverable } : {},
7894
+ ...deliverable ? { deliverable } : {},
7604
7895
  ...log ? { onEvent: (ev) => log.append(runId, ev, new Date(now()).toISOString()) } : {},
7605
7896
  ...priorCoordination && (priorCoordination.questions.length > 0 || priorCoordination.findings.length > 0) ? { priorCoordination } : {},
7606
- ...opts.finalizer ? { finalizer: opts.finalizer } : {},
7897
+ ...finalizer ? { finalizer } : {},
7898
+ ...opts.coordination ? { coordination: opts.coordination } : {},
7607
7899
  ...opts.maxLiveWorkers !== void 0 ? { maxLiveWorkers: opts.maxLiveWorkers } : {},
7608
7900
  ...opts.router ? { router: opts.router } : {},
7609
7901
  ...opts.brain ? { brain: opts.brain } : {},
7610
7902
  ...opts.driveHarness ? { driveHarness: opts.driveHarness } : {},
7611
7903
  ...opts.extraTools ? { extraTools: opts.extraTools } : {},
7612
7904
  ...opts.executeExtraTool ? { executeExtraTool: opts.executeExtraTool } : {},
7613
- ...opts.analysts ? { analysts: opts.analysts } : {},
7905
+ ...analysts ? { analysts } : {},
7614
7906
  ...opts.analyzeOnSettle ? { analyzeOnSettle: opts.analyzeOnSettle } : {},
7615
7907
  ...opts.watchWorkers ? { watchWorkers: opts.watchWorkers } : {},
7616
7908
  ...opts.stallAfterMs !== void 0 ? { stallAfterMs: opts.stallAfterMs } : {},
@@ -7626,7 +7918,7 @@ function supervise(profile, task, opts) {
7626
7918
  blobs,
7627
7919
  executors: ctx.executors,
7628
7920
  maxDepth: opts.maxDepth ?? 8,
7629
- ...opts.probes ? { probes: opts.probes } : {},
7921
+ ...probes ? { probes } : {},
7630
7922
  ...ctx.resume === true ? { resume: true } : {},
7631
7923
  ...opts.now ? { now: opts.now } : {}
7632
7924
  });
@@ -7634,6 +7926,6 @@ function supervise(profile, task, opts) {
7634
7926
  return start();
7635
7927
  }
7636
7928
  //#endregion
7637
- export { eventToSnapshot as $, createDelegateHandler as A, createSteerableSandboxSession as At, DelegationTaskQueue as B, runAgentRounds as Bt, DELEGATE_FEEDBACK_INPUT_SCHEMA as C, createFileRunContext as Ct, DELEGATE_DESCRIPTION as D, createExecutorRegistry as Dt, validateDelegateFeedbackArgs as E, createExecutor as Et, assessAuthoredProfile as F, decodeToolPart as Ft, capDelegationTrace as G, FileCoordinationLog as Gt, DELEGATION_TRACE_MAX_BYTES as H, createSandboxLineage as Ht, authoredWorker as I, sandboxSessionTraceSource as It, DelegationPersistenceError as J, composeLoopTraceEmitters as K, assertModelAllowed as Kt, defaultProfileRichnessThresholds as L, createInbox as Lt, defaultDelegateBudget as M, piExecutor as Mt, delegate as N, piSeamKey as Nt, DELEGATE_INPUT_SCHEMA as O, createWorktreeCliExecutor as Ot, asAuthoredProfile as P, createPushTraceSource as Pt, InMemoryFeedbackStore as Q, profileRichnessFinding as R, createSandboxForSpec as Rt, DELEGATE_FEEDBACK_DESCRIPTION as S, watchTrace as St, createDelegateFeedbackHandler as T, cliWorktreeExecutor as Tt, DELEGATION_TRACE_MAX_SPANS as U, probeSandboxCapabilities as Ut, hashIdempotencyInput as V, runLoop as Vt, buildDelegationTraceSpans as W, acquireSandbox as Wt, FileDelegationStore as X, DelegationStateCorruptError as Y, InMemoryDelegationStore as Z, DELEGATE_UI_AUDIT_DESCRIPTION as _, effectiveConcurrency as _t, createInProcessTransport as a, createProgressTracker as at, createDelegateUiAuditHandler as b, rollingDispatch as bt, DELEGATION_STATUS_INPUT_SCHEMA as c, sampleFromSettled as ct, validateDelegationStatusArgs as d, bestSoFar as dt, driverAgent as et, DELEGATION_HISTORY_DESCRIPTION as f, plateauLength as ft, validateDelegationHistoryArgs as g, createEventBus as gt, createDelegationHistoryHandler as h, createCoordinationTools as ht, serveCoordinationMcp as i, anyOf as it, validateDelegateArgs as j, PI_RUNTIME as jt, DELEGATE_TOOL_NAME as k, DEFAULT_SANDBOX_STEERING_MAX_TURNS as kt, DELEGATION_STATUS_TOOL_NAME as l, anytimeReport as lt, DELEGATION_HISTORY_TOOL_NAME as m, DEFAULT_AWAIT_EVENT_TIMEOUT_MS as mt, workerFromBackend as n, allOf as nt, createMcpServer as o, noProgressFor as ot, DELEGATION_HISTORY_INPUT_SCHEMA as p, renderAnytimeTable as pt, createDelegationTraceCollector as q, gateOnDeliverable as qt, supervisorAgent as r, allWorkersStalled as rt, DELEGATION_STATUS_DESCRIPTION as s, plateau as st, supervise as t, finalizeBestDelivered as tt, createDelegationStatusHandler as u, areaUnderCurve as ut, DELEGATE_UI_AUDIT_INPUT_SCHEMA as v, freeSlots as vt, DELEGATE_FEEDBACK_TOOL_NAME as w, createInMemoryRunContext as wt, validateDelegateUiAuditArgs as x, defaultToolDetectors as xt, DELEGATE_UI_AUDIT_TOOL_NAME as y, queueOf as yt, supervisorInstructions as z, defaultSelectWinner as zt };
7929
+ export { InMemoryDelegationStore as $, DELEGATE_INPUT_SCHEMA as A, createWorktreeCliExecutor as At, profileRichnessFinding as B, createSandboxForSpec 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, probeSandboxCapabilities as Gt, DelegationTaskQueue as H, runAgentRounds as Ht, asAuthoredProfile as I, createPushTraceSource as It, composeLoopTraceEmitters as J, assertModelAllowed as Jt, buildDelegationTraceSpans as K, acquireSandbox 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, authoredWorker as R, sandboxSessionTraceSource as Rt, createDelegateUiAuditHandler as S, rollingDispatch as St, DELEGATE_FEEDBACK_INPUT_SCHEMA as T, createFileRunContext as Tt, hashIdempotencyInput as U, runLoop as Ut, supervisorInstructions as V, defaultSelectWinner as Vt, DELEGATION_TRACE_MAX_BYTES as W, createSandboxLineage as Wt, DelegationPersistenceError as X, createDelegationTraceCollector as Y, gateOnDeliverable as Yt, DelegationStateCorruptError as Z, 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, 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, driverAgent as nt, serveCoordinationMcp as o, anyOf as ot, validateDelegationStatusArgs as p, bestSoFar as pt, capDelegationTrace as q, FileCoordinationLog as qt, assertCoordinationBinding as r, finalizeBestDelivered as rt, createInProcessTransport as s, createProgressTracker as st, supervise as t, 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, createInbox as zt };
7638
7930
 
7639
- //# sourceMappingURL=supervise-CeZtA1wu.js.map
7931
+ //# sourceMappingURL=supervise-6jSTe0kO.js.map