@tangle-network/agent-runtime 0.317.0 → 0.319.3
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.
- package/dist/{activation-CvdE2HIU.js → activation-ClcJ6wO1.js} +3 -3
- package/dist/{activation-CvdE2HIU.js.map → activation-ClcJ6wO1.js.map} +1 -1
- package/dist/{activation-BFDmjaKP.d.ts → activation-OColGsfd.d.ts} +2 -2
- package/dist/agent.d.ts +3 -3
- package/dist/agent.js +3 -3
- package/dist/{bundle-RgHpAFDY.js → bundle-Cw-QdGmH.js} +2 -2
- package/dist/{bundle-RgHpAFDY.js.map → bundle-Cw-QdGmH.js.map} +1 -1
- package/dist/candidate-execution/index.d.ts +40 -3
- package/dist/candidate-execution/index.js +86 -7
- package/dist/candidate-execution/index.js.map +1 -1
- package/dist/{coordination-driver-DGhN8GO9.js → coordination-driver-Culvomn2.js} +3 -3
- package/dist/{coordination-driver-DGhN8GO9.js.map → coordination-driver-Culvomn2.js.map} +1 -1
- package/dist/{delegate-B5pmSbQa.js → delegate-CpMbpiIR.js} +2 -2
- package/dist/{delegate-B5pmSbQa.js.map → delegate-CpMbpiIR.js.map} +1 -1
- package/dist/durable.d.ts +1 -1
- package/dist/durable.js +4 -4
- package/dist/{graph-G0j1ysqe.js → graph-DnfSGUM8.js} +5 -5
- package/dist/{graph-G0j1ysqe.js.map → graph-DnfSGUM8.js.map} +1 -1
- package/dist/graph-registry-BuJbzTzF.js +211 -0
- package/dist/graph-registry-BuJbzTzF.js.map +1 -0
- package/dist/{improvement-cycle-D7yR6GC2.js → improvement-cycle-xnQwUaC3.js} +7 -7
- package/dist/{improvement-cycle-D7yR6GC2.js.map → improvement-cycle-xnQwUaC3.js.map} +1 -1
- package/dist/{index-CUh40yUJ.d.ts → index-Da7w2H86.d.ts} +351 -132
- package/dist/index.d.ts +5 -5
- package/dist/index.js +10 -10
- package/dist/intelligence.d.ts +4 -4
- package/dist/intelligence.js +7 -7
- package/dist/kernel.d.ts +3 -2
- package/dist/kernel.js +12 -11
- package/dist/{loop-runner-bin-DQKLUt0l.d.ts → loop-runner-bin-CbBoLC9D.d.ts} +2 -2
- package/dist/{loop-runner-bin-CFVX4oi0.js → loop-runner-bin-uoeGHNZA.js} +3 -3
- package/dist/{loop-runner-bin-CFVX4oi0.js.map → loop-runner-bin-uoeGHNZA.js.map} +1 -1
- package/dist/loop-runner-bin.d.ts +1 -1
- package/dist/loop-runner-bin.js +1 -1
- package/dist/mcp/bin.js +3 -3
- package/dist/mcp/index.d.ts +2 -2
- package/dist/mcp/index.js +6 -6
- package/dist/{model-policy-DhvyZ8-O.js → model-policy-CNe257pB.js} +37 -2
- package/dist/model-policy-CNe257pB.js.map +1 -0
- package/dist/{openai-tools-u3gWBi3x.d.ts → openai-tools-Cu9E1Bda.d.ts} +2 -2
- package/dist/placement.d.ts +1 -1
- package/dist/{prepare-CD9kR0gS.js → prepare-DjCLEN-q.js} +3 -3
- package/dist/prepare-DjCLEN-q.js.map +1 -0
- package/dist/{profile-CHXYmpGd.js → profile-DmVM4Gxb.js} +9 -2
- package/dist/profile-DmVM4Gxb.js.map +1 -0
- package/dist/{profile-materialization-Cca615eu.d.ts → profile-materialization-C5-t3HJ7.d.ts} +14 -3
- package/dist/profiles.d.ts +1 -1
- package/dist/profiles.js +1 -1
- package/dist/{protected-model-port-C9QtEf3y.d.ts → protected-model-port-CQg2gstJ.d.ts} +3 -3
- package/dist/{protected-model-port-B0pHd65J.js → protected-model-port-D1fcnYdj.js} +4 -4
- package/dist/{protected-model-port-B0pHd65J.js.map → protected-model-port-D1fcnYdj.js.map} +1 -1
- package/dist/{provision-supervisor-BQLLrUtn.js → provision-supervisor-DiZTjzdp.js} +5 -5
- package/dist/{provision-supervisor-BQLLrUtn.js.map → provision-supervisor-DiZTjzdp.js.map} +1 -1
- package/dist/{runtime-B9BOFyEp.js → runtime-6qzuLTJ7.js} +514 -277
- package/dist/runtime-6qzuLTJ7.js.map +1 -0
- package/dist/{search-executor-B5ZVFsDV.js → search-executor-DlaLafvy.js} +4 -4
- package/dist/{search-executor-B5ZVFsDV.js.map → search-executor-DlaLafvy.js.map} +1 -1
- package/dist/{server-TwpH9aik.js → server-sLrmWqKw.js} +4 -4
- package/dist/{server-TwpH9aik.js.map → server-sLrmWqKw.js.map} +1 -1
- package/dist/{supervise-CU6AuxWY.js → supervise-D4CnC-cl.js} +5 -5
- package/dist/{supervise-CU6AuxWY.js.map → supervise-D4CnC-cl.js.map} +1 -1
- package/dist/{supervisor-CbFyf48U.js → supervisor-Cqhu3xH-.js} +709 -80
- package/dist/supervisor-Cqhu3xH-.js.map +1 -0
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +14 -14
- package/dist/tool-loop.d.ts +5 -1
- package/dist/tool-loop.js +4 -3
- package/dist/tool-loop.js.map +1 -1
- package/dist/tui/index.d.ts +1 -1
- package/dist/tui/index.js +1 -1
- package/dist/workspace-store/index.d.ts +171 -3
- package/dist/workspace-store/index.js +529 -8
- package/dist/workspace-store/index.js.map +1 -1
- package/dist/{workspace-streams-DkijayqX.js → workspace-streams-DFAhW7hF.js} +300 -42
- package/dist/workspace-streams-DFAhW7hF.js.map +1 -0
- package/dist/{workspace-streams-CpSmt3zx.d.ts → workspace-streams-U6_UfOXu.d.ts} +10 -2
- package/package.json +15 -11
- package/skills/agent-graphs/references/authoring.md +7 -0
- package/skills/codemode/SKILL.md +6 -4
- package/skills/codemode/references/runtime-execution.md +63 -11
- package/skills/graph-designer/SKILL.md +57 -0
- package/skills/profile-authoring/SKILL.md +17 -15
- package/dist/model-policy-DhvyZ8-O.js.map +0 -1
- package/dist/prepare-CD9kR0gS.js.map +0 -1
- package/dist/profile-CHXYmpGd.js.map +0 -1
- package/dist/runtime-B9BOFyEp.js.map +0 -1
- package/dist/supervisor-CbFyf48U.js.map +0 -1
- package/dist/workspace-streams-DkijayqX.js.map +0 -1
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as graphRunsFor, d as recordGraphRun, i as graphRegistry, l as lookupGraph, p as taskShapeDigest, r as graphFromStored, t as digestOfGraph } from "./graph-registry-BuJbzTzF.js";
|
|
2
|
+
import { Bn as InMemoryResultBlobStore, Cn as readPromptOptions, Hn as insideCursorNamespace, It as createWorktreeCliExecutor, Jn as readCommittedJsonLines, Mr as contentAddress, Nt as createExecutor, Ot as verdictFromJudgeScore, Pt as createExecutorRegistry, Qn as isTraceAnalysisStore, Sn as assertBoxlessPromptOptions, Tn as runBrainLoop, Vn as InMemorySpawnJournal, Yn as writeAllBytes, _n as runAgentRounds, aa as detachedSnapshot, ga as notifySandboxEventObserver, hn as defaultSelectWinner, ht as mapExecutorResult, ia as detachedFrozen, j as settledToIteration, mt as gateOnDeliverable, na as executableAgentProfileSnapshot, pt as rollingDispatch, qn as prepareJsonlAppend, r as createSupervisor, ra as executableAgentSpecSnapshot, v as withDriverExecutor, vn as createSandboxLineage, vt as CheckUnavailableError, wn as routerBrain } from "./supervisor-Cqhu3xH-.js";
|
|
2
3
|
import { i as ConfigError, m as ValidationError, n as AnalystError, s as PlannerError } from "./errors-DodWX-cb.js";
|
|
3
|
-
import { B as runAgentic, G as observe, K as renderReport, U as ObservationError, V as sample, X as strategyAuthorMethod, a as reconcileInterruptedSearchCalls, c as searchExecutor, q as profileChatClient, r as dedicatedLane, x as runtimeShipDecision, z as refine } from "./search-executor-
|
|
4
|
-
import {
|
|
5
|
-
import { c as profileModelExecutionSettings, i as concreteModelId, l as profileProviderModel, o as enforceTokenLimits, p as canonicalObservedModelParts, t as assertExecutableAgentProfile } from "./model-policy-
|
|
4
|
+
import { B as runAgentic, G as observe, K as renderReport, U as ObservationError, V as sample, X as strategyAuthorMethod, a as reconcileInterruptedSearchCalls, c as searchExecutor, q as profileChatClient, r as dedicatedLane, x as runtimeShipDecision, z as refine } from "./search-executor-DlaLafvy.js";
|
|
5
|
+
import { A as markPutStreamVerified, J as fnv1a32Hex, L as immutableCandidateValue, N as canonicalCandidateDigest$1, S as captureMaterializedWorkspace, U as chargedTokens, V as addSpend, W as cloneSpend, X as isAbortError, Y as hasCompleteCacheBreakdown, Z as isAsyncIterable, et as randomSuffix, it as stringifySafe, lt as zeroSpend, q as errorMessage, rt as sleep, xt as armDeadlineTimer, y as WorkspaceScanLimitError, z as sha256Bytes$1 } from "./workspace-streams-DFAhW7hF.js";
|
|
6
|
+
import { c as profileModelExecutionSettings, i as concreteModelId, l as profileProviderModel, o as enforceTokenLimits, p as canonicalObservedModelParts, t as assertExecutableAgentProfile } from "./model-policy-CNe257pB.js";
|
|
6
7
|
import { i as notifyRuntimeHookEvent } from "./runtime-hooks-tXpAarhW.js";
|
|
7
8
|
import { i as redactProtectedValue, r as redactProtectedReason } from "./protected-redaction-DylCC_ot.js";
|
|
8
|
-
import { C as createInMemoryRunContext, E as foldCoordinationRecords } from "./coordination-driver-
|
|
9
|
-
import { r as supervise } from "./supervise-
|
|
9
|
+
import { C as createInMemoryRunContext, E as foldCoordinationRecords } from "./coordination-driver-Culvomn2.js";
|
|
10
|
+
import { r as supervise } from "./supervise-D4CnC-cl.js";
|
|
10
11
|
import "./run-layout-DSCWdbX2.js";
|
|
11
|
-
import "./provision-supervisor-
|
|
12
|
-
import "./delegate-
|
|
13
|
-
import "./graph-
|
|
12
|
+
import "./provision-supervisor-DiZTjzdp.js";
|
|
13
|
+
import "./delegate-CpMbpiIR.js";
|
|
14
|
+
import "./graph-DnfSGUM8.js";
|
|
14
15
|
import { agentProfileSchema, canonicalAgentProfileDigest, canonicalCandidateDigest, sha256Bytes, validateAgentProfileSecurity } from "@tangle-network/agent-interface";
|
|
15
16
|
import { CODING_HARNESSES, DEFAULT_TRACE_ANALYST_KINDS, InMemoryTraceStore, OUTPUT_VALUE, benjaminiHochberg, buildTrajectory, computeFindingId as computeFindingId$1, confidenceInterval, createTraceAnalyst, expandProfileAxes, makeFinding as makeFinding$1, pairedBootstrap, paretoFrontier, wilcoxonSignedRank, wilson } from "@tangle-network/agent-eval";
|
|
16
17
|
import { createAgentRunOutcomeTracker } from "@tangle-network/sandbox/runtime";
|
|
@@ -29,7 +30,6 @@ import { defineEvaluationClaim, summarizeEvaluationUnits } from "@tangle-network
|
|
|
29
30
|
import { createInterface } from "node:readline";
|
|
30
31
|
import { pathToFileURL } from "node:url";
|
|
31
32
|
import { gzipSync } from "node:zlib";
|
|
32
|
-
import { createContext, runInContext } from "node:vm";
|
|
33
33
|
import { stuckLoopView, toolWasteView } from "@tangle-network/agent-eval/pipelines";
|
|
34
34
|
//#region src/runtime/tangle-sandbox-exact-process-provider.ts
|
|
35
35
|
const exactProcessProviderMarker = "agent-runtime.exact-process-provider";
|
|
@@ -393,6 +393,165 @@ async function afterAbortCheck(signal, operation) {
|
|
|
393
393
|
return result;
|
|
394
394
|
}
|
|
395
395
|
//#endregion
|
|
396
|
+
//#region src/runtime/http-mcp-client.ts
|
|
397
|
+
/**
|
|
398
|
+
* `connectHttpMcp` — the remote (streamable HTTP) MCP client, sibling of
|
|
399
|
+
* `connectStdioMcp`. Same connection contract (`tools`, `callTool`, `close`),
|
|
400
|
+
* same error semantics (a JSON-RPC error / `isError` result is the agent's
|
|
401
|
+
* `ERROR: …` outcome; a transport fault or timeout throws), no child process —
|
|
402
|
+
* which is the point: this is the MCP path for environments that cannot spawn
|
|
403
|
+
* stdio servers (Workers, browser-context agents, locked-down sandboxes) and
|
|
404
|
+
* for servers that only exist as endpoints (a remote Hindsight, a hosted MCP).
|
|
405
|
+
*
|
|
406
|
+
* Transport: MCP "streamable HTTP" (protocol 2025-03-26 / 2025-06-18). Every
|
|
407
|
+
* request is a POST with `Accept: application/json, text/event-stream`; the
|
|
408
|
+
* server may answer either shape, so both are parsed. A server-assigned
|
|
409
|
+
* `Mcp-Session-Id` response header is captured and replayed on every later
|
|
410
|
+
* request (and the DELETE on close) — stateful servers refuse without it,
|
|
411
|
+
* stateless ones simply never send it.
|
|
412
|
+
*
|
|
413
|
+
* Auth headers can be protected values: they are sent to the server but never
|
|
414
|
+
* allowed back out — error messages and tool results are redacted against the
|
|
415
|
+
* exact protected values, mirroring `connectStdioMcp`'s protectedEnv handling.
|
|
416
|
+
*/
|
|
417
|
+
const HTTP_MCP_PROTOCOL_VERSION = "2025-06-18";
|
|
418
|
+
/** A remote MCP endpoint refused the connection before the handshake completed. */
|
|
419
|
+
var McpConnectFault = class extends Error {
|
|
420
|
+
status;
|
|
421
|
+
constructor(message, status) {
|
|
422
|
+
super(message);
|
|
423
|
+
this.status = status;
|
|
424
|
+
this.name = "McpConnectFault";
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
const SSE_DATA_LINE = /^data:\s?(.*)$/s;
|
|
428
|
+
function parseSseBody(body, wantId) {
|
|
429
|
+
for (const chunk of body.split(/\r?\n\r?\n/)) for (const line of chunk.split(/\r?\n/)) {
|
|
430
|
+
const match = SSE_DATA_LINE.exec(line);
|
|
431
|
+
if (!match) continue;
|
|
432
|
+
try {
|
|
433
|
+
const parsed = JSON.parse(match[1] ?? "");
|
|
434
|
+
if (parsed.id === wantId) return parsed;
|
|
435
|
+
} catch {}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
function redactValuesFrom(text, values) {
|
|
439
|
+
let out = text;
|
|
440
|
+
for (const value of values) if (value.length > 0) out = out.split(value).join("[redacted]");
|
|
441
|
+
return out;
|
|
442
|
+
}
|
|
443
|
+
/** Connect to a remote MCP endpoint: initialize, list tools, return the live connection. */
|
|
444
|
+
async function connectHttpMcp(spec) {
|
|
445
|
+
let endpoint;
|
|
446
|
+
try {
|
|
447
|
+
endpoint = new URL(spec.url);
|
|
448
|
+
} catch {
|
|
449
|
+
throw new ValidationError(`connectHttpMcp: invalid MCP endpoint URL: ${spec.url}`);
|
|
450
|
+
}
|
|
451
|
+
if (endpoint.protocol !== "https:" && endpoint.hostname !== "localhost" && endpoint.hostname !== "127.0.0.1") throw new ValidationError(`connectHttpMcp: refusing non-HTTPS MCP endpoint ${endpoint.origin} (localhost excepted) — a bearer or api key on plain HTTP would cross the network in the clear`);
|
|
452
|
+
const fetchImpl = spec.fetchImpl ?? fetch;
|
|
453
|
+
const timeoutMs = spec.timeoutMs ?? 3e4;
|
|
454
|
+
const protectedValues = Object.values(spec.protectedHeaders ?? {});
|
|
455
|
+
const redact = (text) => redactValuesFrom(text, protectedValues);
|
|
456
|
+
let sessionId;
|
|
457
|
+
let nextId = 1;
|
|
458
|
+
let closed = false;
|
|
459
|
+
const post = async (path, body, method = "POST") => fetchImpl(`${endpoint.origin}${endpoint.pathname}${endpoint.search}${path}`, {
|
|
460
|
+
method,
|
|
461
|
+
headers: {
|
|
462
|
+
accept: "application/json, text/event-stream",
|
|
463
|
+
...body !== void 0 ? { "content-type": "application/json" } : {},
|
|
464
|
+
...sessionId !== void 0 ? { "mcp-session-id": sessionId } : {},
|
|
465
|
+
...body !== void 0 ? { "x-request-id": String(nextId) } : {},
|
|
466
|
+
...spec.headers ?? {},
|
|
467
|
+
...spec.protectedHeaders ?? {}
|
|
468
|
+
},
|
|
469
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
470
|
+
});
|
|
471
|
+
const request = async (method, params) => {
|
|
472
|
+
if (closed) throw new Error("HTTP MCP connection closed");
|
|
473
|
+
const id = nextId++;
|
|
474
|
+
const controller = new AbortController();
|
|
475
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
476
|
+
try {
|
|
477
|
+
const res = await post("", {
|
|
478
|
+
jsonrpc: "2.0",
|
|
479
|
+
id,
|
|
480
|
+
method,
|
|
481
|
+
params
|
|
482
|
+
}, "POST");
|
|
483
|
+
const sessionHeader = res.headers.get("mcp-session-id");
|
|
484
|
+
if (sessionHeader) sessionId = sessionHeader;
|
|
485
|
+
if (!res.ok) {
|
|
486
|
+
const text = redact((await res.text()).slice(0, 500));
|
|
487
|
+
throw new McpConnectFault(`HTTP MCP ${method} failed (${res.status} ${res.statusText}): ${text}`, res.status);
|
|
488
|
+
}
|
|
489
|
+
if ((res.headers.get("content-type") ?? "").includes("text/event-stream")) {
|
|
490
|
+
const parsed = parseSseBody(await res.text(), id);
|
|
491
|
+
if (!parsed) throw new Error(`HTTP MCP ${method}: SSE response carried no JSON-RPC message for request ${id}`);
|
|
492
|
+
return parsed;
|
|
493
|
+
}
|
|
494
|
+
return JSON.parse(await res.text());
|
|
495
|
+
} catch (error) {
|
|
496
|
+
if (error instanceof McpConnectFault) throw error;
|
|
497
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
498
|
+
throw new Error(redact(`HTTP MCP ${method} transport failed: ${reason}`));
|
|
499
|
+
} finally {
|
|
500
|
+
clearTimeout(timer);
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
`${endpoint.origin}${endpoint.pathname}${timeoutMs}`;
|
|
504
|
+
try {
|
|
505
|
+
const init = await request("initialize", {
|
|
506
|
+
protocolVersion: HTTP_MCP_PROTOCOL_VERSION,
|
|
507
|
+
capabilities: {},
|
|
508
|
+
clientInfo: {
|
|
509
|
+
name: "agent-runtime-http-mcp",
|
|
510
|
+
version: "0"
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
if (init.error) throw new McpConnectFault(redact(`initialize errored: ${JSON.stringify(init.error)}`), void 0);
|
|
514
|
+
await post("", {
|
|
515
|
+
jsonrpc: "2.0",
|
|
516
|
+
method: "notifications/initialized"
|
|
517
|
+
}, "POST").catch(() => void 0);
|
|
518
|
+
const list = await request("tools/list", void 0);
|
|
519
|
+
if (list.error) throw new Error(redact(`tools/list errored: ${JSON.stringify(list.error)}`));
|
|
520
|
+
const rawTools = list.result?.tools;
|
|
521
|
+
if (!Array.isArray(rawTools)) throw new Error("tools/list result has no tools array");
|
|
522
|
+
const tools = JSON.parse(redact(JSON.stringify(rawTools)));
|
|
523
|
+
const callTool = async (name, args) => {
|
|
524
|
+
const res = await request("tools/call", {
|
|
525
|
+
name,
|
|
526
|
+
arguments: args
|
|
527
|
+
});
|
|
528
|
+
if (res.error) return `ERROR: ${redact(JSON.stringify(res.error)).slice(0, 300)}`;
|
|
529
|
+
const result = res.result;
|
|
530
|
+
const chunks = result?.content?.map((c) => c.text ?? "");
|
|
531
|
+
const joined = chunks?.join("\n") ?? JSON.stringify(result ?? null);
|
|
532
|
+
const collapsed = chunks?.join("");
|
|
533
|
+
let text = joined;
|
|
534
|
+
if (collapsed !== void 0) {
|
|
535
|
+
const collapsedRedacted = redact(collapsed);
|
|
536
|
+
if (collapsedRedacted !== collapsed) text = collapsedRedacted;
|
|
537
|
+
}
|
|
538
|
+
return redact(result?.isError ? `ERROR: ${text}` : text);
|
|
539
|
+
};
|
|
540
|
+
const close = async () => {
|
|
541
|
+
if (closed) return;
|
|
542
|
+
closed = true;
|
|
543
|
+
await post("", void 0, "DELETE").catch(() => void 0);
|
|
544
|
+
};
|
|
545
|
+
return {
|
|
546
|
+
tools,
|
|
547
|
+
callTool,
|
|
548
|
+
close
|
|
549
|
+
};
|
|
550
|
+
} catch (error) {
|
|
551
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
//#endregion
|
|
396
555
|
//#region src/runtime/key-provider.ts
|
|
397
556
|
/** The env-backed provider: reads the (dotenvx-loaded) process env. Empty /
|
|
398
557
|
* whitespace-only values count as absent — fail loud, not with a blank key. */
|
|
@@ -404,12 +563,23 @@ function envKeyProvider(env = process.env) {
|
|
|
404
563
|
}
|
|
405
564
|
/** The `AgentProfileMcpServer.metadata` key the declarative secret-env map
|
|
406
565
|
* rides under: `{ ENV_VAR_NAME: 'PROVIDER_KEY_NAME' }`. Names only — values
|
|
407
|
-
* are resolved at materialize time and never stored.
|
|
566
|
+
* are resolved at materialize time and never stored.
|
|
567
|
+
*
|
|
568
|
+
* DEPRECATED (2026-10-12): this is the interface <0.40 channel. Author
|
|
569
|
+
* `profile.mcp[key].env.ENV_VAR_NAME = { kind: 'secret-ref', key }` instead —
|
|
570
|
+
* the canonical form since 0.40. The legacy map keeps resolving (profiles
|
|
571
|
+
* are data in the wild and must not break at boot) but every use now warns
|
|
572
|
+
* once per server; removal lands at the next interface major. */
|
|
408
573
|
const mcpSecretEnvMetadataKey = "secretEnv";
|
|
574
|
+
const warnedSecretEnv = /* @__PURE__ */ new Set();
|
|
409
575
|
/** Read (and validate) a server entry's declared secret-env map, if any.
|
|
410
576
|
* Malformed metadata throws — a half-declared secret must never half-boot. */
|
|
411
|
-
function secretEnvOfMcpServer(server) {
|
|
577
|
+
function secretEnvOfMcpServer(server, label = "profile.mcp server") {
|
|
412
578
|
const raw = server.metadata?.[mcpSecretEnvMetadataKey];
|
|
579
|
+
if (raw !== void 0 && !warnedSecretEnv.has(label)) {
|
|
580
|
+
warnedSecretEnv.add(label);
|
|
581
|
+
console.warn(`${label}: metadata.${mcpSecretEnvMetadataKey} is deprecated — author env secret-refs (profile.mcp[key].env.ENV = { kind: 'secret-ref', key }) instead; support is removed at the next interface major`);
|
|
582
|
+
}
|
|
413
583
|
if (raw === void 0 || raw === null) return void 0;
|
|
414
584
|
if (typeof raw !== "object" || Array.isArray(raw)) throw new ValidationError(`secretEnvOfMcpServer: metadata.${mcpSecretEnvMetadataKey} must be an object mapping env var name -> key name`);
|
|
415
585
|
const entries = Object.entries(raw);
|
|
@@ -793,6 +963,34 @@ async function connectStdioMcp(spec) {
|
|
|
793
963
|
* child and expose its tools under `<server>__<tool>` names. The default policy
|
|
794
964
|
* refuses local processes. A profile with no MCP surface returns zero tools.
|
|
795
965
|
*/
|
|
966
|
+
/** Resolve a remote server's `url` + `headers` profile config values into the
|
|
967
|
+
* plain strings + protected headers an HTTP connection needs. Same fail-closed
|
|
968
|
+
* contract as `resolveMcpServerLaunch`: no KeyProvider for a declared secret, or
|
|
969
|
+
* a missing key, aborts the materialization naming the KEY only. */
|
|
970
|
+
async function resolveRemoteMcpHeaders(server, keys, label) {
|
|
971
|
+
if (typeof server.url !== "string" || server.url.trim().length === 0) throw new ValidationError(`${label}: a remote (http/sse) server requires url`);
|
|
972
|
+
const headers = {};
|
|
973
|
+
const protectedHeaders = {};
|
|
974
|
+
for (const [name, value] of Object.entries(server.headers ?? {})) if (value.kind === "public") headers[name] = value.value ?? "";
|
|
975
|
+
else {
|
|
976
|
+
if (!keys) throw new ValidationError(`${label}: header ${name} is a secret-ref but no KeyProvider was supplied — refusing to connect a remote server with unresolvable auth`);
|
|
977
|
+
const secret = await keys.get(value.key ?? "");
|
|
978
|
+
if (secret === void 0) throw new ValidationError(`${label}: the KeyProvider holds no value for '${value.key}' (wanted for header ${name}) — provision the key or drop the header`);
|
|
979
|
+
protectedHeaders[name] = value.format === "bearer" ? `Bearer ${secret}` : secret;
|
|
980
|
+
}
|
|
981
|
+
return {
|
|
982
|
+
url: server.url,
|
|
983
|
+
...Object.keys(headers).length > 0 ? { headers } : {},
|
|
984
|
+
...Object.keys(protectedHeaders).length > 0 ? { protectedHeaders } : {}
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
/**
|
|
988
|
+
* Spawn every enabled stdio server in `profile.mcp` and expose their tools as
|
|
989
|
+
* `<server>__<tool>` behind one route and close facade.
|
|
990
|
+
*
|
|
991
|
+
* Fails closed: a declared server that cannot boot throws, so a profile is never
|
|
992
|
+
* scored as if it had no MCP surface.
|
|
993
|
+
*/
|
|
796
994
|
async function materializeLocalMcp(profile, opts = {}) {
|
|
797
995
|
const security = validateAgentProfileSecurity(profile, opts.profileSecurityPolicy);
|
|
798
996
|
if (!security.ok) throw new ValidationError(`materializeLocalMcp: profile host execution refused: ${security.issues.filter((issue) => issue.level === "error").map((issue) => issue.message).join("; ")}`);
|
|
@@ -807,7 +1005,35 @@ async function materializeLocalMcp(profile, opts = {}) {
|
|
|
807
1005
|
for (const [key, server] of Object.entries(profile.mcp ?? {})) {
|
|
808
1006
|
if (server.enabled === false) continue;
|
|
809
1007
|
const transport = server.transport ?? "stdio";
|
|
810
|
-
if (transport
|
|
1008
|
+
if (transport === "http" || transport === "sse") {
|
|
1009
|
+
const { url, headers, protectedHeaders } = await resolveRemoteMcpHeaders(server, opts.keys, `materializeLocalMcp: profile.mcp['${key}']`);
|
|
1010
|
+
const conn = await connectHttpMcp({
|
|
1011
|
+
url,
|
|
1012
|
+
...headers !== void 0 ? { headers } : {},
|
|
1013
|
+
...protectedHeaders !== void 0 ? { protectedHeaders } : {},
|
|
1014
|
+
...opts.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {}
|
|
1015
|
+
});
|
|
1016
|
+
connections.push(conn);
|
|
1017
|
+
const prefix = key.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1018
|
+
for (const t of conn.tools) {
|
|
1019
|
+
const name = `${prefix}__${t.name.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
|
|
1020
|
+
if (routes.has(name)) throw new ValidationError(`materializeLocalMcp: namespaced tool '${name}' collides across servers — rename the profile.mcp keys`);
|
|
1021
|
+
routes.set(name, {
|
|
1022
|
+
conn,
|
|
1023
|
+
tool: t.name
|
|
1024
|
+
});
|
|
1025
|
+
tools.push({
|
|
1026
|
+
type: "function",
|
|
1027
|
+
function: {
|
|
1028
|
+
name,
|
|
1029
|
+
description: (t.description ?? "").slice(0, 1e3),
|
|
1030
|
+
parameters: sanitizeMcpToolSchema(t.inputSchema)
|
|
1031
|
+
}
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
continue;
|
|
1035
|
+
}
|
|
1036
|
+
if (transport !== "stdio") throw new ValidationError(`materializeLocalMcp: profile.mcp['${key}'] has unsupported transport '${transport}'`);
|
|
811
1037
|
if (!server.command || server.command.trim().length === 0) throw new ValidationError(`materializeLocalMcp: profile.mcp['${key}'] declares a stdio server with no command`);
|
|
812
1038
|
const launch = await resolveMcpServerLaunch(server, opts.keys, `materializeLocalMcp: profile.mcp['${key}']`);
|
|
813
1039
|
const conn = await connectStdioMcp({
|
|
@@ -2745,6 +2971,8 @@ function localSandboxClient(opts) {
|
|
|
2745
2971
|
const r = await runBrainLoop({
|
|
2746
2972
|
chat,
|
|
2747
2973
|
tools: mcp.tools,
|
|
2974
|
+
...opts.codeMode ? { codeMode: opts.codeMode } : {},
|
|
2975
|
+
...popts?.signal ? { signal: popts.signal } : {},
|
|
2748
2976
|
execute: (name, args) => mcp.call(name, args),
|
|
2749
2977
|
initialMessages: [...system ? [{
|
|
2750
2978
|
role: "system",
|
|
@@ -2760,7 +2988,7 @@ function localSandboxClient(opts) {
|
|
|
2760
2988
|
type: "llm_call",
|
|
2761
2989
|
data: {
|
|
2762
2990
|
model,
|
|
2763
|
-
tools: mcp.tools.map((t) => t.function.name),
|
|
2991
|
+
tools: r.modelToolNames ?? mcp.tools.map((t) => t.function.name),
|
|
2764
2992
|
...r.tokensKnown === false ? { tokensKnown: false } : {
|
|
2765
2993
|
tokensIn: r.usage.input,
|
|
2766
2994
|
tokensOut: r.usage.output
|
|
@@ -5953,9 +6181,8 @@ function hashText(value) {
|
|
|
5953
6181
|
/**
|
|
5954
6182
|
* The ONE lint over model-authored source.
|
|
5955
6183
|
*
|
|
5956
|
-
*
|
|
5957
|
-
*
|
|
5958
|
-
* verbs). Both need the same refusals; this module is the single copy both import.
|
|
6184
|
+
* Authored optimization strategies use this static contract lint. General Runtime code-mode
|
|
6185
|
+
* scripts execute in the isolated QuickJS/WASM engine instead of relying on source lint.
|
|
5959
6186
|
*
|
|
5960
6187
|
* A LINT, NOT A SANDBOX — it reads text and cannot constrain what running code does, and trivial
|
|
5961
6188
|
* concatenation defeats any token match. Its only job is refusing the obvious escapes so a typo or
|
|
@@ -6901,276 +7128,183 @@ function chatWorkerSeam(opts) {
|
|
|
6901
7128
|
};
|
|
6902
7129
|
}
|
|
6903
7130
|
//#endregion
|
|
6904
|
-
//#region src/runtime/supervise/
|
|
7131
|
+
//#region src/runtime/supervise/designer-tools.ts
|
|
6905
7132
|
/**
|
|
6906
|
-
*
|
|
6907
|
-
*
|
|
6908
|
-
* expose exactly two tools (`search`, `execute`), and run model-written code whose only intended
|
|
6909
|
-
* capability is the API bindings. One model turn where the tool-calling loop pays one round trip
|
|
6910
|
-
* per call; intermediates live in the program, not the context window.
|
|
7133
|
+
* `graphDesignerExtraTools` — the designer's toolset on the existing
|
|
7134
|
+
* `RunGraphOptions.extraTools` seam.
|
|
6911
7135
|
*
|
|
6912
|
-
*
|
|
6913
|
-
*
|
|
6914
|
-
*
|
|
6915
|
-
*
|
|
6916
|
-
* execution
|
|
6917
|
-
*
|
|
6918
|
-
*
|
|
6919
|
-
* only — your own eval harness, an offline test, a model you control — and is named for what it is:
|
|
6920
|
-
* `node:vm` shares the host realm, so host code is reachable from inside it and it is not a
|
|
6921
|
-
* security boundary. Choosing it for a hostile model is remote code execution, by construction.
|
|
7136
|
+
* A meta-graph designer is an ordinary supervisor ROOT whose ONLY tools are
|
|
7137
|
+
* these three: look up what this task shape has run, run a graph (authored or
|
|
7138
|
+
* replayed — every run recorded, terminal accounting included), and read the
|
|
7139
|
+
* history. The agent authors graphs as DATA (nodes, edges, budget, deliverable
|
|
7140
|
+
* description); execution is ENVIRONMENT-OWNED — the caller closes over how
|
|
7141
|
+
* graphs run (backend/brain/leaf seam) and how the deliverable's check is
|
|
7142
|
+
* re-bound, because oracles are environment, never agent-supplied.
|
|
6922
7143
|
*
|
|
6923
|
-
*
|
|
6924
|
-
*
|
|
6925
|
-
*
|
|
6926
|
-
* journal ("there is no second spawn path"). The model authors a workflow as code at runtime and
|
|
6927
|
-
* the kernel still meters and records every edge of it — a dynamic workflow system, not a bypass.
|
|
6928
|
-
* Verb RESULTS are detached (JSON round-trip) before they re-enter the program, so in-code calls
|
|
6929
|
-
* cannot mutate live coordination state the MCP transport would have copied.
|
|
6930
|
-
*
|
|
6931
|
-
* WHAT STAYS THE MODEL'S: `submit_result`, `stop`, `ask_parent` are never in the API — a program
|
|
6932
|
-
* that could settle the run would be a second brain. `search` names them and says why. Code does
|
|
6933
|
-
* the mechanics; the model keeps the judgment, the same split the sources draw.
|
|
6934
|
-
*
|
|
6935
|
-
* THE GRANT CANNOT DRIFT FROM THE DOCS: `search` renders from `context.coordinationTools()`, the
|
|
6936
|
-
* same descriptor objects the verbs are served from — never prose written beside them.
|
|
7144
|
+
* This is the `measure_rung` pattern from the graph contract generalized: the
|
|
7145
|
+
* root's profile declares the tools; the graph options supply them; nothing
|
|
7146
|
+
* new exists below this line but the registry calls themselves.
|
|
6937
7147
|
*/
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
steer_agent: "steerAgent",
|
|
6943
|
-
observe_agent: "observeAgent",
|
|
6944
|
-
list_questions: "listQuestions",
|
|
6945
|
-
answer_question: "answerQuestion",
|
|
6946
|
-
run_analyst: "runAnalyst",
|
|
6947
|
-
read_journal: "readJournal",
|
|
6948
|
-
define_analyst: "defineAnalyst"
|
|
7148
|
+
const taskShapeSchema = {
|
|
7149
|
+
type: "object",
|
|
7150
|
+
description: "Stable descriptor of this class of work (kind, source, constraints) — the lookup key. Not the payload.",
|
|
7151
|
+
additionalProperties: true
|
|
6949
7152
|
};
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
type: "array",
|
|
6959
|
-
items: { type: "string" }
|
|
6960
|
-
} },
|
|
6961
|
-
required: ["workerIds"]
|
|
6962
|
-
}
|
|
6963
|
-
});
|
|
6964
|
-
/** The manager's own lifecycle verbs — never callable from code; `search` names them and why. */
|
|
6965
|
-
const LIFECYCLE_VERBS = [
|
|
6966
|
-
"submit_result",
|
|
6967
|
-
"stop",
|
|
6968
|
-
"ask_parent"
|
|
6969
|
-
];
|
|
6970
|
-
/** Render a JSON Schema as TypeScript type text. Bounded and structural: enough for tool input
|
|
6971
|
-
* schemas (objects, enums, arrays, unions); anything unrecognized renders `unknown`, never a
|
|
6972
|
-
* guess. Module-level (not root) export: consumed by `renderCodeModeApi` and its tests only. */
|
|
6973
|
-
function renderJsonSchemaType(schema, depth = 0) {
|
|
6974
|
-
if (depth > 6 || typeof schema !== "object" || schema === null) return "unknown";
|
|
6975
|
-
const node = schema;
|
|
6976
|
-
if (node.const !== void 0) return JSON.stringify(node.const);
|
|
6977
|
-
if (Array.isArray(node.enum)) return node.enum.map((value) => JSON.stringify(value)).join(" | ");
|
|
6978
|
-
const variants = node.anyOf ?? node.oneOf;
|
|
6979
|
-
if (Array.isArray(variants)) return variants.map((variant) => renderJsonSchemaType(variant, depth + 1)).join(" | ");
|
|
6980
|
-
const type = Array.isArray(node.type) ? node.type : [node.type];
|
|
6981
|
-
if (type.includes("object") || node.type === void 0 && node.properties !== void 0) {
|
|
6982
|
-
const properties = node.properties ?? {};
|
|
6983
|
-
const required = new Set(Array.isArray(node.required) ? node.required : []);
|
|
6984
|
-
const fields = Object.entries(properties).map(([name, property]) => {
|
|
6985
|
-
const doc = describeSchema(property);
|
|
6986
|
-
const optional = required.has(name) ? "" : "?";
|
|
6987
|
-
return `${doc}${JSON.stringify(name).slice(1, -1)}${optional}: ${renderJsonSchemaType(property, depth + 1)}`;
|
|
6988
|
-
});
|
|
6989
|
-
if (fields.length === 0) return "Record<string, unknown>";
|
|
6990
|
-
const indent = " ".repeat(depth + 1);
|
|
6991
|
-
return `{\n${fields.map((field) => `${indent}${field}`).join("\n")}\n${" ".repeat(depth)}}`;
|
|
6992
|
-
}
|
|
6993
|
-
if (type.includes("array")) return `Array<${renderJsonSchemaType(node.items, depth + 1)}>`;
|
|
6994
|
-
const primitives = type.map((entry) => entry === "integer" ? "number" : typeof entry === "string" ? entry : void 0).filter((entry) => entry === "string" || entry === "number" || entry === "boolean" || entry === "null");
|
|
6995
|
-
return primitives.length > 0 ? primitives.join(" | ") : "unknown";
|
|
6996
|
-
}
|
|
6997
|
-
function describeSchema(schema) {
|
|
6998
|
-
const description = typeof schema === "object" && schema !== null ? schema.description : void 0;
|
|
6999
|
-
if (typeof description !== "string" || description.length === 0) return "";
|
|
7000
|
-
const first = description.split("\n")[0] ?? "";
|
|
7001
|
-
return `/** ${first.length > 140 ? `${first.slice(0, 140)}…` : first} */ `;
|
|
7002
|
-
}
|
|
7003
|
-
/** Render the callable API from tool faces — `declare function` per tool, doc from its own
|
|
7004
|
-
* description. This is the text `search` answers; generated, never hand-written. Module-level
|
|
7005
|
-
* export for tests. */
|
|
7006
|
-
function renderCodeModeApi(tools, query) {
|
|
7007
|
-
const needle = query?.trim().toLowerCase();
|
|
7008
|
-
const blocks = tools.filter((tool) => !needle || tool.name.toLowerCase().includes(needle) || (tool.description ?? "").toLowerCase().includes(needle)).map((tool) => {
|
|
7009
|
-
const doc = (tool.description ?? "").split("\n")[0] ?? "";
|
|
7010
|
-
const args = tool.inputSchema === void 0 ? "unknown" : renderJsonSchemaType(tool.inputSchema);
|
|
7011
|
-
return `/** ${doc} */\ndeclare function ${tool.name}(args: ${args}): Promise<unknown>`;
|
|
7012
|
-
});
|
|
7013
|
-
const header = [
|
|
7014
|
-
"// Call these as `api.<name>(args)` from code passed to `execute`.",
|
|
7015
|
-
"// Results are the same JSON the tools return. Intermediates stay in your program;",
|
|
7016
|
-
"// return only what the next decision needs.",
|
|
7017
|
-
`// NOT callable from code: ${LIFECYCLE_VERBS.join(", ")} — those are your own tools,`,
|
|
7018
|
-
"// because a program that could settle the run would be a second brain."
|
|
7019
|
-
].join("\n");
|
|
7020
|
-
if (blocks.length === 0) return `${header}\n\n// No API member matches ${JSON.stringify(query ?? "")}. Call search with no query for the full API.`;
|
|
7021
|
-
return `${header}\n\n${blocks.join("\n\n")}`;
|
|
7153
|
+
const graphDataSchema = {
|
|
7154
|
+
type: "object",
|
|
7155
|
+
description: "A graph as data: { nodes: [{id, profile}], edges: [{kind, from, to, directive, ...}], budget, deliverable: {describe} }. No check function — the environment binds it.",
|
|
7156
|
+
additionalProperties: true
|
|
7157
|
+
};
|
|
7158
|
+
function asRecord(value, context) {
|
|
7159
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new ValidationError(`${context}: expected an object`);
|
|
7160
|
+
return value;
|
|
7022
7161
|
}
|
|
7023
|
-
/**
|
|
7024
|
-
*
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7031
|
-
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
error: capture("error")
|
|
7052
|
-
});
|
|
7053
|
-
const context = createContext(sandbox, { codeGeneration: {
|
|
7054
|
-
strings: false,
|
|
7055
|
-
wasm: false
|
|
7056
|
-
} });
|
|
7057
|
-
const program = runInContext(`(async () => {\n${code}\n})()`, context);
|
|
7058
|
-
const aborted = new Promise((_resolve, reject) => {
|
|
7059
|
-
if (signal.aborted) reject(abortReason(signal));
|
|
7060
|
-
else signal.addEventListener("abort", () => reject(abortReason(signal)), { once: true });
|
|
7162
|
+
/** The designer's three tools over one registry. Record-every-run is enforced
|
|
7163
|
+
* by construction: running IS recording. */
|
|
7164
|
+
function graphDesignerExtraTools(env) {
|
|
7165
|
+
const registry = graphRegistry(env.registryDir);
|
|
7166
|
+
let runCounter = 0;
|
|
7167
|
+
const runId = env.nextRunId ?? (() => `designer-${++runCounter}`);
|
|
7168
|
+
const runAndRecord = async (taskShape, graph, mode) => {
|
|
7169
|
+
const digest = digestOfGraph(graph);
|
|
7170
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7171
|
+
const result = await env.runGraph(graph);
|
|
7172
|
+
const winner = result.result.kind === "winner";
|
|
7173
|
+
const spent = winner ? result.result.spentTotal : void 0;
|
|
7174
|
+
await recordGraphRun(registry, graph, {
|
|
7175
|
+
graphDigest: digest,
|
|
7176
|
+
taskDigest: taskShapeDigest(taskShape),
|
|
7177
|
+
startedAt,
|
|
7178
|
+
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7179
|
+
outcome: winner ? { kind: "delivered" } : {
|
|
7180
|
+
kind: "no-winner",
|
|
7181
|
+
reason: `mode=${mode} result=${result.result.kind}`
|
|
7182
|
+
},
|
|
7183
|
+
cost: {
|
|
7184
|
+
...spent?.iterations !== void 0 ? { iterations: spent.iterations } : {},
|
|
7185
|
+
...spent?.tokens && typeof spent.tokens === "object" && "input" in spent.tokens ? { tokens: (spent.tokens.input ?? 0) + (spent.tokens.output ?? 0) } : {},
|
|
7186
|
+
...spent?.usd !== void 0 ? { usd: spent.usd } : {}
|
|
7187
|
+
},
|
|
7188
|
+
traversals: result.ledger.length,
|
|
7189
|
+
...result.exhaustedEdges.length > 0 ? { exhaustedEdges: result.exhaustedEdges } : {}
|
|
7061
7190
|
});
|
|
7062
7191
|
return {
|
|
7063
|
-
|
|
7064
|
-
|
|
7192
|
+
runId: runId(),
|
|
7193
|
+
outcome: winner ? "delivered" : `no-winner (${result.result.kind})`,
|
|
7194
|
+
graphDigest: digest,
|
|
7195
|
+
traversals: result.ledger.length,
|
|
7196
|
+
...spent?.iterations !== void 0 ? { iterations: spent.iterations } : {},
|
|
7197
|
+
...spent?.tokens && typeof spent.tokens === "object" && "input" in spent.tokens ? { tokens: (spent.tokens.input ?? 0) + (spent.tokens.output ?? 0) } : {}
|
|
7065
7198
|
};
|
|
7066
|
-
}
|
|
7067
|
-
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
|
|
7078
|
-
|
|
7079
|
-
|
|
7080
|
-
|
|
7081
|
-
|
|
7082
|
-
|
|
7083
|
-
|
|
7084
|
-
|
|
7085
|
-
|
|
7086
|
-
|
|
7087
|
-
|
|
7088
|
-
|
|
7089
|
-
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7095
|
-
|
|
7096
|
-
|
|
7097
|
-
|
|
7098
|
-
|
|
7099
|
-
|
|
7100
|
-
|
|
7101
|
-
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
description: "Substring filter over names and descriptions."
|
|
7118
|
-
} }
|
|
7119
|
-
},
|
|
7120
|
-
handler: async (raw, context) => {
|
|
7121
|
-
const query = typeof raw === "object" && raw !== null ? raw.query : void 0;
|
|
7122
|
-
return renderCodeModeApi(faces(context), typeof query === "string" ? query : void 0);
|
|
7123
|
-
}
|
|
7124
|
-
}, {
|
|
7125
|
-
name: "execute",
|
|
7126
|
-
description: "Run JavaScript against the API from `search`. Write the BODY of an async function: call `api.<name>(args)` (await each call), use loops and Promise.all for fan-out, keep intermediates in variables, `return` only what the next decision needs. `console.log` lines come back beside the result. No imports, no network, no filesystem — the API is the intended capability.",
|
|
7127
|
-
inputSchema: {
|
|
7128
|
-
type: "object",
|
|
7129
|
-
properties: { code: {
|
|
7130
|
-
type: "string",
|
|
7131
|
-
description: "The async function body to run."
|
|
7132
|
-
} },
|
|
7133
|
-
required: ["code"]
|
|
7134
|
-
},
|
|
7135
|
-
handler: async (raw, context) => {
|
|
7136
|
-
const code = typeof raw === "object" && raw !== null ? raw.code : void 0;
|
|
7137
|
-
if (typeof code !== "string" || code.trim().length === 0) throw new ValidationError("code mode: execute needs { code: string }");
|
|
7138
|
-
assertAuthoredCode(code, { context: `code mode (${context.nodeId})` });
|
|
7139
|
-
const execution = new AbortController();
|
|
7140
|
-
let timedOut = false;
|
|
7141
|
-
const onScopeAbort = () => execution.abort(abortReason(context.signal));
|
|
7142
|
-
const clearTimer = timeoutMs === null ? void 0 : armDeadlineTimer(timeoutMs, () => {
|
|
7143
|
-
if (!execution.signal.aborted) {
|
|
7144
|
-
timedOut = true;
|
|
7145
|
-
execution.abort(new ValidationError(`code mode: program timed out after ${timeoutMs}ms`));
|
|
7199
|
+
};
|
|
7200
|
+
const summarize = (row) => ({
|
|
7201
|
+
graphDigest: row.graphDigest.slice(0, 12),
|
|
7202
|
+
outcome: row.outcome.kind,
|
|
7203
|
+
cost: row.cost,
|
|
7204
|
+
finishedAt: row.finishedAt
|
|
7205
|
+
});
|
|
7206
|
+
return {
|
|
7207
|
+
extraTools: [
|
|
7208
|
+
{
|
|
7209
|
+
name: "designer_lookup_graph",
|
|
7210
|
+
description: "Look up what this task shape has run before. Returns replay (a known-good graph — run it verbatim with designer_run_graph, near-zero inference) or author (with the reason), plus the recent history for context.",
|
|
7211
|
+
parameters: {
|
|
7212
|
+
type: "object",
|
|
7213
|
+
properties: { taskShape: taskShapeSchema },
|
|
7214
|
+
required: ["taskShape"],
|
|
7215
|
+
additionalProperties: false
|
|
7216
|
+
}
|
|
7217
|
+
},
|
|
7218
|
+
{
|
|
7219
|
+
name: "designer_run_graph",
|
|
7220
|
+
description: "Run a graph and record it. REPLAY mode: pass the graphDigest from lookup — the stored graph runs verbatim, check re-bound by the environment. AUTHOR mode: pass the graph as data (no check). Every run is recorded with its terminal accounting; the registry is the memory.",
|
|
7221
|
+
parameters: {
|
|
7222
|
+
type: "object",
|
|
7223
|
+
properties: {
|
|
7224
|
+
taskShape: taskShapeSchema,
|
|
7225
|
+
mode: {
|
|
7226
|
+
type: "string",
|
|
7227
|
+
enum: ["replay", "authored"]
|
|
7228
|
+
},
|
|
7229
|
+
graphDigest: {
|
|
7230
|
+
type: "string",
|
|
7231
|
+
description: "Replay mode: the digest lookup returned."
|
|
7232
|
+
},
|
|
7233
|
+
graph: graphDataSchema,
|
|
7234
|
+
mutationNote: {
|
|
7235
|
+
type: "string",
|
|
7236
|
+
description: "Author mode after a failed replay lineage: what the prior record says went wrong and the ONE axis this graph changes."
|
|
7237
|
+
}
|
|
7238
|
+
},
|
|
7239
|
+
required: ["taskShape", "mode"],
|
|
7240
|
+
additionalProperties: false
|
|
7241
|
+
}
|
|
7242
|
+
},
|
|
7243
|
+
{
|
|
7244
|
+
name: "designer_history",
|
|
7245
|
+
description: "Every recorded run for a task shape (or all shapes): graph digest, outcome, cost, finish time. The evidence for improvement decisions.",
|
|
7246
|
+
parameters: {
|
|
7247
|
+
type: "object",
|
|
7248
|
+
properties: { taskShape: taskShapeSchema },
|
|
7249
|
+
additionalProperties: false
|
|
7146
7250
|
}
|
|
7147
|
-
}, true);
|
|
7148
|
-
if (context.signal.aborted) execution.abort(abortReason(context.signal));
|
|
7149
|
-
else context.signal.addEventListener("abort", onScopeAbort, { once: true });
|
|
7150
|
-
const bindings = {};
|
|
7151
|
-
for (const face of faces(context)) {
|
|
7152
|
-
const member = CODE_CALLABLE_VERBS[face.name];
|
|
7153
|
-
if (member === void 0) continue;
|
|
7154
|
-
bindings[face.name] = async (args) => {
|
|
7155
|
-
if (execution.signal.aborted) {
|
|
7156
|
-
if (!timedOut) throw abortReason(execution.signal);
|
|
7157
|
-
throw new ValidationError(`code mode: the execute deadline passed; api.${face.name} is refused so no work outlives the call`);
|
|
7158
|
-
}
|
|
7159
|
-
return detach(await context.verbs[member](args));
|
|
7160
|
-
};
|
|
7161
|
-
}
|
|
7162
|
-
try {
|
|
7163
|
-
return await runner.run({
|
|
7164
|
-
code,
|
|
7165
|
-
bindings,
|
|
7166
|
-
signal: execution.signal
|
|
7167
|
-
});
|
|
7168
|
-
} finally {
|
|
7169
|
-
clearTimer?.();
|
|
7170
|
-
context.signal.removeEventListener("abort", onScopeAbort);
|
|
7171
7251
|
}
|
|
7252
|
+
],
|
|
7253
|
+
executeExtraTool: (name, raw) => {
|
|
7254
|
+
if (name === "designer_lookup_graph") return (async () => {
|
|
7255
|
+
return lookupGraphSyncish(asRecord(asRecord(raw, "designer_lookup_graph").taskShape, "designer_lookup_graph.taskShape"));
|
|
7256
|
+
})();
|
|
7257
|
+
if (name === "designer_history") return (async () => {
|
|
7258
|
+
const args = asRecord(raw ?? {}, "designer_history");
|
|
7259
|
+
const { listGraphRuns } = await import("./graph-registry-BuJbzTzF.js").then((n) => n.o);
|
|
7260
|
+
const all = await listGraphRuns(registry);
|
|
7261
|
+
return { runs: (args.taskShape === void 0 ? all : all.filter((row) => row.taskDigest === taskShapeDigest(asRecord(args.taskShape, "designer_history.taskShape")))).map(summarize) };
|
|
7262
|
+
})();
|
|
7263
|
+
if (name === "designer_run_graph") return (async () => {
|
|
7264
|
+
const args = asRecord(raw, "designer_run_graph");
|
|
7265
|
+
const taskShape = asRecord(args.taskShape, "designer_run_graph.taskShape");
|
|
7266
|
+
const mode = args.mode;
|
|
7267
|
+
if (mode === "replay") {
|
|
7268
|
+
const digest = args.graphDigest;
|
|
7269
|
+
if (typeof digest !== "string" || digest.length === 0) throw new ValidationError("designer_run_graph: replay mode requires graphDigest from lookup");
|
|
7270
|
+
const { loadGraph } = await import("./graph-registry-BuJbzTzF.js").then((n) => n.o);
|
|
7271
|
+
const stored = await loadGraph(registry, digest);
|
|
7272
|
+
if (!stored) throw new ValidationError(`designer_run_graph: no stored graph ${digest.slice(0, 12)} — re-lookup`);
|
|
7273
|
+
const graph = env.bindCheck(graphFromStored(stored, () => {
|
|
7274
|
+
throw new Error("designer: environment did not bind the deliverable check");
|
|
7275
|
+
}));
|
|
7276
|
+
return runAndRecord(taskShape, graph, "replay");
|
|
7277
|
+
}
|
|
7278
|
+
if (mode === "authored") {
|
|
7279
|
+
const graph = asRecord(args.graph, "designer_run_graph.graph");
|
|
7280
|
+
for (const axis of [
|
|
7281
|
+
"nodes",
|
|
7282
|
+
"edges",
|
|
7283
|
+
"budget",
|
|
7284
|
+
"deliverable"
|
|
7285
|
+
]) if (graph[axis] === void 0) throw new ValidationError(`designer_run_graph.graph: ${axis} is required`);
|
|
7286
|
+
return runAndRecord(taskShape, env.bindCheck(graph), "authored");
|
|
7287
|
+
}
|
|
7288
|
+
throw new ValidationError("designer_run_graph: mode must be 'replay' | 'authored'");
|
|
7289
|
+
})();
|
|
7290
|
+
return null;
|
|
7172
7291
|
}
|
|
7173
|
-
}
|
|
7292
|
+
};
|
|
7293
|
+
async function lookupGraphSyncish(taskShape) {
|
|
7294
|
+
const selection = await lookupGraph(registry, taskShapeDigest(taskShape));
|
|
7295
|
+
const history = (await graphRunsFor(registry, taskShapeDigest(taskShape))).map(summarize);
|
|
7296
|
+
if (selection.kind === "replay") return {
|
|
7297
|
+
decision: "replay",
|
|
7298
|
+
reason: `a delivered graph exists (${selection.record.cost.iterations ?? "?"} iterations, ${selection.record.cost.tokens ?? "?"} tokens)`,
|
|
7299
|
+
graphDigest: selection.graph.digest,
|
|
7300
|
+
history
|
|
7301
|
+
};
|
|
7302
|
+
return {
|
|
7303
|
+
decision: "author",
|
|
7304
|
+
reason: selection.reason,
|
|
7305
|
+
history
|
|
7306
|
+
};
|
|
7307
|
+
}
|
|
7174
7308
|
}
|
|
7175
7309
|
//#endregion
|
|
7176
7310
|
//#region src/runtime/supervise/patch-checks.ts
|
|
@@ -7302,6 +7436,109 @@ function signalPass(value, required) {
|
|
|
7302
7436
|
return !required;
|
|
7303
7437
|
}
|
|
7304
7438
|
//#endregion
|
|
7439
|
+
//#region src/runtime/supervise/profile-registry.ts
|
|
7440
|
+
/**
|
|
7441
|
+
* `profile-registry` — named AgentProfiles with run receipts: the missing
|
|
7442
|
+
* bottom layer of the designer's memory.
|
|
7443
|
+
*
|
|
7444
|
+
* The graph registry (#1719) answers "which GRAPH won for this task shape?"
|
|
7445
|
+
* but a profile is reused ACROSS graphs and across products — the same
|
|
7446
|
+
* summarizer, the same referee, the same driver — and "did the v2 prompt
|
|
7447
|
+
* actually improve?" was answerable only per-graph. This module gives named
|
|
7448
|
+
* profiles their own receipt loop in the exact same shape as the graph
|
|
7449
|
+
* registry: profiles content-addressed by the interface's canonical digest,
|
|
7450
|
+
* one JSONL record per run, pickBest by the same documented heuristic.
|
|
7451
|
+
*
|
|
7452
|
+
* A profile record answers the question a prompt change has to answer before
|
|
7453
|
+
* it deserves to exist: same name, new digest — what did each version cost,
|
|
7454
|
+
* and did it deliver? Versions never overwrite (immutability), so old-vs-new
|
|
7455
|
+
* is always a controlled diff, and a product mounting the registry can refuse
|
|
7456
|
+
* a profile revision with no runs behind it.
|
|
7457
|
+
*/
|
|
7458
|
+
const RECORDS_FILE = "profile-records.jsonl";
|
|
7459
|
+
const PROFILES_DIR = "profiles";
|
|
7460
|
+
function assertRecord(record) {
|
|
7461
|
+
if (typeof record.name !== "string" || record.name.trim().length === 0) throw new ValidationError("profile-registry: record.name is required");
|
|
7462
|
+
if (typeof record.profileDigest !== "string" || record.profileDigest.length === 0) throw new ValidationError("profile-registry: record.profileDigest is required");
|
|
7463
|
+
if (record.outcome.kind !== "delivered" && record.outcome.kind !== "failed") throw new ValidationError("profile-registry: record.outcome.kind must be 'delivered' | 'failed'");
|
|
7464
|
+
}
|
|
7465
|
+
/** Open (or lazily create) a profile registry rooted at a workspace directory. */
|
|
7466
|
+
function profileRegistry(root) {
|
|
7467
|
+
if (!root || root.trim().length === 0) throw new ValidationError("profileRegistry: root directory is required");
|
|
7468
|
+
return { root };
|
|
7469
|
+
}
|
|
7470
|
+
async function ensureLayout(reg) {
|
|
7471
|
+
await mkdir(join(reg.root, PROFILES_DIR), { recursive: true });
|
|
7472
|
+
}
|
|
7473
|
+
async function readRecords(reg) {
|
|
7474
|
+
try {
|
|
7475
|
+
return (await readFile(join(reg.root, RECORDS_FILE), "utf8")).split("\n").filter((line) => line.trim().length > 0).map((line) => JSON.parse(line));
|
|
7476
|
+
} catch {
|
|
7477
|
+
return [];
|
|
7478
|
+
}
|
|
7479
|
+
}
|
|
7480
|
+
/** Record one run and persist the exact profile revision beside it. The
|
|
7481
|
+
* record's digest must match the supplied profile — a record always names
|
|
7482
|
+
* the revision that actually ran. The revision file is write-once: a
|
|
7483
|
+
* different profile under the same digest is refused. */
|
|
7484
|
+
async function recordProfileRun(reg, profile, record) {
|
|
7485
|
+
assertRecord(record);
|
|
7486
|
+
if (typeof profile?.name !== "string" || profile.name !== record.name) throw new ValidationError(`profile-registry: the supplied profile's name must equal record.name ('${record.name}')`);
|
|
7487
|
+
const digest = canonicalAgentProfileDigest(profile);
|
|
7488
|
+
if (digest !== record.profileDigest) throw new ValidationError(`profile-registry: record.profileDigest ${record.profileDigest.slice(0, 12)} does not match the supplied profile (${digest.slice(0, 12)}) — record the revision that actually ran`);
|
|
7489
|
+
await ensureLayout(reg);
|
|
7490
|
+
const file = join(reg.root, PROFILES_DIR, `${digest}.json`);
|
|
7491
|
+
try {
|
|
7492
|
+
if (canonicalAgentProfileDigest(JSON.parse(await readFile(file, "utf8"))) !== digest) throw new ValidationError(`profile-registry: revision ${digest.slice(0, 12)} is immutable but its stored copy differs — refusing to overwrite`);
|
|
7493
|
+
} catch (error) {
|
|
7494
|
+
if (!(error instanceof ValidationError)) await writeFile(file, JSON.stringify(profile), "utf8");
|
|
7495
|
+
else throw error;
|
|
7496
|
+
}
|
|
7497
|
+
const deduped = (await readRecords(reg)).filter((row) => !(row.name === record.name && row.profileDigest === record.profileDigest && row.startedAt === record.startedAt));
|
|
7498
|
+
deduped.push(record);
|
|
7499
|
+
await writeFile(join(reg.root, RECORDS_FILE), deduped.map((row) => JSON.stringify(row)).join("\n") + "\n", "utf8");
|
|
7500
|
+
}
|
|
7501
|
+
/** All records for one name, newest last. */
|
|
7502
|
+
async function profileRunsForName(reg, name) {
|
|
7503
|
+
return (await readRecords(reg)).filter((row) => row.name === name);
|
|
7504
|
+
}
|
|
7505
|
+
/** The best revision of a name by the same documented heuristic as the graph
|
|
7506
|
+
* registry: delivered beats failed, then cheaper (tokens, then iterations),
|
|
7507
|
+
* then most recent. This is the answer to "which prompt revision is winning?"
|
|
7508
|
+
* — and every alternative is a controlled diff away (versions never overwrite). */
|
|
7509
|
+
function pickBestProfile(records) {
|
|
7510
|
+
const delivered = records.filter((row) => row.outcome.kind === "delivered");
|
|
7511
|
+
if (delivered.length === 0) return void 0;
|
|
7512
|
+
const better = (a, b) => {
|
|
7513
|
+
const aTokens = a.cost.tokens ?? Number.POSITIVE_INFINITY;
|
|
7514
|
+
const bTokens = b.cost.tokens ?? Number.POSITIVE_INFINITY;
|
|
7515
|
+
if (aTokens !== bTokens) return aTokens < bTokens ? a : b;
|
|
7516
|
+
const aIter = a.cost.iterations ?? Number.POSITIVE_INFINITY;
|
|
7517
|
+
const bIter = b.cost.iterations ?? Number.POSITIVE_INFINITY;
|
|
7518
|
+
if (aIter !== bIter) return aIter < bIter ? a : b;
|
|
7519
|
+
return a.finishedAt >= b.finishedAt ? a : b;
|
|
7520
|
+
};
|
|
7521
|
+
return delivered.reduce((best, row) => better(best, row) === best ? best : row);
|
|
7522
|
+
}
|
|
7523
|
+
/** Load a stored profile revision by digest (for replaying the winning revision). */
|
|
7524
|
+
async function loadProfile(reg, digest) {
|
|
7525
|
+
try {
|
|
7526
|
+
return JSON.parse(await readFile(join(reg.root, PROFILES_DIR, `${digest}.json`), "utf8"));
|
|
7527
|
+
} catch {
|
|
7528
|
+
return;
|
|
7529
|
+
}
|
|
7530
|
+
}
|
|
7531
|
+
/** The winning revision of a name, ready to mount. */
|
|
7532
|
+
async function bestProfileFor(reg, name) {
|
|
7533
|
+
const best = pickBestProfile(await profileRunsForName(reg, name));
|
|
7534
|
+
if (!best) return void 0;
|
|
7535
|
+
const profile = await loadProfile(reg, best.profileDigest);
|
|
7536
|
+
return profile ? {
|
|
7537
|
+
profile,
|
|
7538
|
+
record: best
|
|
7539
|
+
} : void 0;
|
|
7540
|
+
}
|
|
7541
|
+
//#endregion
|
|
7305
7542
|
//#region src/runtime/supervise/sql-run-context.ts
|
|
7306
7543
|
/**
|
|
7307
7544
|
* A cross-machine run context on the existing autocommit SqlAdapter. Reuse the same database,
|
|
@@ -8587,6 +8824,6 @@ function tail(s) {
|
|
|
8587
8824
|
return s.slice(-400);
|
|
8588
8825
|
}
|
|
8589
8826
|
//#endregion
|
|
8590
|
-
export {
|
|
8827
|
+
export { builtinShapes as $, mcpSecretEnvMetadataKey as $t, recordProfileRun as A, declaredCheckDeliverable as At, authorStrategy as B, pairwiseSignificance as Bt, analyzeTrace as C, localSandboxClient as Ct, pickBestProfile as D, superviseDispatch as Dt, loadProfile as E, loopDispatch as Et, chatWorkerSeam as F, completionAuthorizes as Ft, createS3PrivateCasStore as G, SqlRunOwnershipError as Gt, strategyAuthorSystemPrompt as H, renderLeaderboardMarkdown as Ht, createChatSessionStore as I, deterministicCompletion as It, createPrivateCasArtifactPort as J, connectStdioMcp as Jt, printBenchmarkReport as K, openSqlRunStore as Kt, runStrategyEvolution as L, sentinelCompletion as Lt, runCoderChecks as M, declaredCheckJudge as Mt, graphDesignerExtraTools as N, readDeclaredCheck as Nt, profileRegistry as O, assertDeclaredCheck as Ot, chatTransportExecutor as P, runIsolatedCheck as Pt, runPersonified as Q, envKeyProvider as Qt, strategyTournament as R, stopSentinel as Rt, withUntrackedArtifacts as S, resolveSandboxClient as St, bestProfileFor as T, loopCampaignDispatch as Tt, SandboxRunAbortError as U, renderLeaderboardSvg as Ut, strategyAuthorContract as V, renderLeaderboardHtml as Vt, openSandboxRun as W, renderPairwiseMarkdown as Wt, trajectoryReport as X, createMcpEnvironment as Xt, equalKOnCost as Y, materializeLocalMcp as Yt, definePersona as Z, sanitizeMcpToolSchema as Zt, VERIFY_TAIL_CHARS as _, observationFromRegistry as _t, localShell as a, fanout as at, settledWorkerOut as b, harvestCorpus as bt, createVerifierEnvironment as c, panel as ct, harvestSurfaceDiffs as d, verify as dt, resolveMcpServerLaunch as en, createShapeRegistry as et, analystsFromRegistry as f, widen as ft, NOTE_MAX_CHARS as g, registryScopeAnalyst as gt, EVIDENCE_MAX_CHARS as h, createScopeAnalyst as ht, jjWorkspace as i, renderCorpusToInstructions as it, patchDelivered as j, declaredCheckDigest as jt, profileRunsForName as k, checkProgramDigest as kt, boxSurfaceReader as l, pipeline as lt, worktreeFanout as m, buildSteerContext as mt, makeFinding$1 as n, secretEnvOfMcpServer as nn, FileCorpus as nt, runInWorkspace as o, flatWidenGate as ot, failuresAnalyst as p, assertTraceDerivedFindings as pt, runBenchmark as q, McpSpawnFault as qt, gitWorkspace as r, createTangleSandboxExactProcessProvider as rn, InMemoryCorpus as rt, createWaterfallCollector as s, loopUntil as st, computeFindingId$1 as t, resolveSecretEnv as tn, registerShape as tt, fsSurfaceReader as u, selectValidWinner as ut, closingWorkerNote as v, inProcessSandboxClient as vt, createFencedSqlRunContext as w, inlineSandboxClient as wt, copyUntrackedIntoClone as x, defineLeaderboard as xt, composeWorkerEvidence as y, HarvestError as yt, assertStrategyContract as z, leaderboard as zt };
|
|
8591
8828
|
|
|
8592
|
-
//# sourceMappingURL=runtime-
|
|
8829
|
+
//# sourceMappingURL=runtime-6qzuLTJ7.js.map
|