@tangle-network/agent-runtime 0.266.0 → 0.273.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.
Files changed (76) hide show
  1. package/dist/{activation-BERiJjx5.js → activation-Cx2dKA_l.js} +2 -2
  2. package/dist/{activation-BERiJjx5.js.map → activation-Cx2dKA_l.js.map} +1 -1
  3. package/dist/{activation-VpxSbDKJ.d.ts → activation-IfDlhR3J.d.ts} +4 -4
  4. package/dist/agent.d.ts +2 -2
  5. package/dist/agent.js +2 -2
  6. package/dist/candidate-execution/index.js +2 -2
  7. package/dist/{coordination-driver-DdZ-nh_4.js → coordination-driver-CkcW4dxU.js} +173 -92
  8. package/dist/coordination-driver-CkcW4dxU.js.map +1 -0
  9. package/dist/{delegate-Ajx_PVyu.js → delegate-Dvb1-mE-.js} +2 -2
  10. package/dist/{delegate-Ajx_PVyu.js.map → delegate-Dvb1-mE-.js.map} +1 -1
  11. package/dist/durable.d.ts +3 -571
  12. package/dist/durable.js +93 -19
  13. package/dist/durable.js.map +1 -1
  14. package/dist/{graph-CK50N9vG.js → graph-C69Uxtzt.js} +17 -8
  15. package/dist/graph-C69Uxtzt.js.map +1 -0
  16. package/dist/{improvement-cycle-GRPoHLm1.js → improvement-cycle-CO2HRCQq.js} +10 -10
  17. package/dist/improvement-cycle-CO2HRCQq.js.map +1 -0
  18. package/dist/{index-CU2mlMfc.d.ts → index-D2ipSqkP.d.ts} +4335 -3055
  19. package/dist/index.d.ts +7 -451
  20. package/dist/index.js +14 -11
  21. package/dist/index.js.map +1 -1
  22. package/dist/intelligence.d.ts +9 -3
  23. package/dist/intelligence.js +13 -7
  24. package/dist/intelligence.js.map +1 -1
  25. package/dist/kernel.d.ts +4 -4
  26. package/dist/kernel.js +9 -9
  27. package/dist/{loop-runner-bin-cC16EPUq.js → loop-runner-bin-B9MIq9O7.js} +3 -3
  28. package/dist/{loop-runner-bin-cC16EPUq.js.map → loop-runner-bin-B9MIq9O7.js.map} +1 -1
  29. package/dist/{loop-runner-bin-XKZXM08Q.d.ts → loop-runner-bin-ThlwVkvo.d.ts} +3 -3
  30. package/dist/loop-runner-bin.d.ts +1 -1
  31. package/dist/loop-runner-bin.js +1 -1
  32. package/dist/mcp/bin.js +3 -3
  33. package/dist/mcp/index.d.ts +12 -6
  34. package/dist/mcp/index.js +7 -7
  35. package/dist/mcp/memory-bin.js +1 -1
  36. package/dist/{memory-server-Cn8LbAxO.js → memory-server-DXQ8IxGR.js} +2 -2
  37. package/dist/{memory-server-Cn8LbAxO.js.map → memory-server-DXQ8IxGR.js.map} +1 -1
  38. package/dist/{openai-tools-D3ajI_D2.d.ts → openai-tools-Bb0mAr5z.d.ts} +2 -2
  39. package/dist/{prepare-oHUQdC5-.js → prepare-DVlvGP7V.js} +2 -2
  40. package/dist/{prepare-oHUQdC5-.js.map → prepare-DVlvGP7V.js.map} +1 -1
  41. package/dist/profiles.d.ts +2 -2
  42. package/dist/{protected-model-port-DqF0qDU6.js → protected-model-port-BrWgsCnl.js} +2 -2
  43. package/dist/{protected-model-port-DqF0qDU6.js.map → protected-model-port-BrWgsCnl.js.map} +1 -1
  44. package/dist/{protected-redaction--F3v1oo8.js → protected-redaction-DylCC_ot.js} +14 -20
  45. package/dist/protected-redaction-DylCC_ot.js.map +1 -0
  46. package/dist/{provision-supervisor-Bf_bPaCv.js → provision-supervisor-BKAvsDtP.js} +3 -3
  47. package/dist/{provision-supervisor-Bf_bPaCv.js.map → provision-supervisor-BKAvsDtP.js.map} +1 -1
  48. package/dist/{runtime-hOLlAc1i.js → runtime-CHxXrUeZ.js} +1714 -854
  49. package/dist/runtime-CHxXrUeZ.js.map +1 -0
  50. package/dist/{server-DOb67ohd.js → server-2OeFrEVG.js} +4 -4
  51. package/dist/{server-DOb67ohd.js.map → server-2OeFrEVG.js.map} +1 -1
  52. package/dist/{stream-agent-turn-Gw9hLpBn.d.ts → stream-agent-turn-ewm3BZAp.d.ts} +34 -17
  53. package/dist/{structural-rollout-DV9YoQF6.js → structural-rollout-DCUprNpH.js} +2 -2
  54. package/dist/{structural-rollout-DV9YoQF6.js.map → structural-rollout-DCUprNpH.js.map} +1 -1
  55. package/dist/{substrate-CLt9S9ym.d.ts → substrate-VKjmrksz.d.ts} +2 -2
  56. package/dist/{supervise--njTtSL3.js → supervise-Dej5aSDa.js} +220 -52
  57. package/dist/supervise-Dej5aSDa.js.map +1 -0
  58. package/dist/{supervisor-B8UMAXya.js → supervisor-DdKPGluv.js} +1233 -303
  59. package/dist/supervisor-DdKPGluv.js.map +1 -0
  60. package/dist/testing.d.ts +2 -2
  61. package/dist/testing.js +62 -62
  62. package/dist/testing.js.map +1 -1
  63. package/dist/{tool-server-x9NEhvHZ.js → tool-server-Dqer2M4_.js} +30 -12
  64. package/dist/tool-server-Dqer2M4_.js.map +1 -0
  65. package/dist/tui/index.d.ts +1 -1
  66. package/dist/tui/index.js +1 -1
  67. package/dist/{types-CrnwLVYQ.d.ts → types-DMRc3jru.d.ts} +463 -105
  68. package/package.json +6 -5
  69. package/dist/coordination-driver-DdZ-nh_4.js.map +0 -1
  70. package/dist/graph-CK50N9vG.js.map +0 -1
  71. package/dist/improvement-cycle-GRPoHLm1.js.map +0 -1
  72. package/dist/protected-redaction--F3v1oo8.js.map +0 -1
  73. package/dist/runtime-hOLlAc1i.js.map +0 -1
  74. package/dist/supervise--njTtSL3.js.map +0 -1
  75. package/dist/supervisor-B8UMAXya.js.map +0 -1
  76. package/dist/tool-server-x9NEhvHZ.js.map +0 -1
@@ -1,24 +1,24 @@
1
- import { $i as cloneSpend, An as routerBrain, Bn as sandboxClientAsProvider, Dt as insideCursorNamespace, En as probeSandboxCapabilities, Et as InMemorySpawnJournal, Fi as detachedFrozen, Fn as LEAF_CONTINUATION_TASK, Hn as unavailableSignalOfFailure, Hr as harnessInvocation, M as settledToIteration, Mn as canonicalObservedModelParts, Ni as executableAgentProfileSnapshot, On as assertBoxlessPromptOptions, Pi as executableAgentSpecSnapshot, Pt as isTraceAnalysisStore, Qi as chargedTokens, Sn as defaultSelectWinner, Tn as createSandboxLineage, Tt as InMemoryResultBlobStore, Un as createPushTraceSource, Vn as unavailablePauseMs, Zi as addSpend, _t as createExecutorRegistry, aa as sleep, b as withDriverExecutor, da as zeroSpend, dt as rollingDispatch, fi as prepareJsonlAppend, fr as contentAddress, gt as createExecutor, ia as randomSuffix, jn as runBrainLoop, kn as readPromptOptions, mi as writeAllBytes, na as isAbortError, oa as stringifySafe, pi as readCommittedJsonLines, qi as notifySandboxEventObserver, r as createSupervisor, ta as hasCompleteCacheBreakdown, wn as runAgentRounds, ya as armDeadlineTimer, yt as createWorktreeCliExecutor } from "./supervisor-B8UMAXya.js";
1
+ import { $i as detachedSnapshot, Ai as readCommittedJsonLines, Bn as runAgentRounds, Bt as SpawnEventIndex, Ca as stringifySafe, Ct as rollingDispatch, Gn as readPromptOptions, Hn as probeSandboxCapabilities, Ht as encodeResultBlob, Ia as armDeadlineTimer, Jn as canonicalObservedModelParts, Kn as routerBrain, M as withDriverExecutor, O as verdictFromJudgeScore, Oa as zeroSpend, Ot as createExecutor, Qi as detachedFrozen, Rn as defaultSelectWinner, Rt as InMemoryResultBlobStore, Sa as sleep, Ut as insideCursorNamespace, Vn as createSandboxLineage, Vt as assertContentAddress, W as settledToIteration, Wn as assertBoxlessPromptOptions, Xi as executableAgentProfileSnapshot, Xt as isTraceAnalysisStore, Zi as executableAgentSpecSnapshot, Zn as LEAF_CONTINUATION_TASK, _ as CheckUnavailableError, ai as harnessInvocation, ar as createPushTraceSource, ga as cloneSpend, ha as chargedTokens, ir as unavailableSignalOfFailure, ji as writeAllBytes, jt as createWorktreeCliExecutor, ki as prepareJsonlAppend, kr as contentAddress, kt as createExecutorRegistry, ma as addSpend, nr as sandboxClientAsProvider, qn as runBrainLoop, r as createSupervisor, rr as unavailablePauseMs, ua as notifySandboxEventObserver, va as hasCompleteCacheBreakdown, xa as randomSuffix, ya as isAbortError, zt as InMemorySpawnJournal } from "./supervisor-DdKPGluv.js";
2
2
  import { m as ValidationError, n as AnalystError, s as PlannerError } from "./errors-DodWX-cb.js";
3
- import { E as profileChatClient, S as ObservationError, T as renderReport, b as sample, k as strategyAuthorMethod, v as refine, w as observe, x as sampleThenRefine, y as runAgentic } from "./structural-rollout-DV9YoQF6.js";
3
+ import { E as profileChatClient, S as ObservationError, T as renderReport, b as sample, k as strategyAuthorMethod, v as refine, w as observe, x as sampleThenRefine, y as runAgentic } from "./structural-rollout-DCUprNpH.js";
4
4
  import { a as concreteProfileModel, c as profileModelExecutionSettings, i as concreteModelId, l as profileProviderModel, o as enforceTokenLimits, t as assertExecutableAgentProfile } from "./model-policy-BbSCSak0.js";
5
5
  import { C as canonicalCandidateDigest$1, D as immutableCandidateValue, k as sha256Bytes$1, m as captureMaterializedWorkspace } from "./workspace-archive-C9lgf77y.js";
6
6
  import { i as notifyRuntimeHookEvent } from "./runtime-hooks-tXpAarhW.js";
7
- import { i as redactProtectedValue, r as redactProtectedReason } from "./protected-redaction--F3v1oo8.js";
8
- import "./coordination-driver-DdZ-nh_4.js";
9
- import { C as gateOnDeliverable, r as supervise, w as mapExecutorResult } from "./supervise--njTtSL3.js";
7
+ import { i as redactProtectedValue, r as redactProtectedReason } from "./protected-redaction-DylCC_ot.js";
8
+ import { S as foldCoordinationRecords, y as createInMemoryRunContext } from "./coordination-driver-CkcW4dxU.js";
9
+ import { C as gateOnDeliverable, r as supervise, w as mapExecutorResult } from "./supervise-Dej5aSDa.js";
10
10
  import "./run-layout-vwd4SwX_.js";
11
- import "./provision-supervisor-Bf_bPaCv.js";
12
- import "./delegate-Ajx_PVyu.js";
13
- import "./graph-CK50N9vG.js";
14
- import { agentProfileSchema, canonicalAgentProfileDigest, canonicalCandidateDigest, validateAgentProfileSecurity } from "@tangle-network/agent-interface";
11
+ import "./provision-supervisor-BKAvsDtP.js";
12
+ import "./delegate-Dvb1-mE-.js";
13
+ import "./graph-C69Uxtzt.js";
14
+ import { agentProfileSchema, canonicalAgentProfileDigest, canonicalCandidateDigest, sha256Bytes, validateAgentProfileSecurity } from "@tangle-network/agent-interface";
15
15
  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
16
  import { createAgentRunOutcomeTracker } from "@tangle-network/sandbox/runtime";
17
17
  import { createHash, randomUUID } from "node:crypto";
18
18
  import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
19
19
  import { appendFileSync, chmodSync, constants, copyFileSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readlinkSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
20
20
  import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
21
- import { cp, mkdir, mkdtemp, readFile, realpath, stat, writeFile } from "node:fs/promises";
21
+ import { cp, mkdir, mkdtemp, readFile, readdir, realpath, rm, stat, writeFile } from "node:fs/promises";
22
22
  import { materializeProfile } from "@tangle-network/agent-profile-materialize";
23
23
  import { tmpdir } from "node:os";
24
24
  import { isDeepStrictEqual, promisify } from "node:util";
@@ -848,6 +848,433 @@ async function materializeLocalMcp(profile, opts = {}) {
848
848
  };
849
849
  }
850
850
  //#endregion
851
+ //#region src/durable/spawn-journal-sql.ts
852
+ /**
853
+ * SQL-backed durable stores for supervised runs — `SqlSpawnJournal` and `SqlResultBlobStore`
854
+ * over the same minimal statement seam `SqlConversationJournal` uses (D1, postgres, sqlite,
855
+ * libSQL; positional `?` placeholders). This closes the orchestration-durability gap recorded in
856
+ * `conformance/durability/STATUS.md`: until now the spawn layer was file-only.
857
+ *
858
+ * Parity with the JSONL file stores, by construction:
859
+ * • same corruption guards — `beginTree` precedes events (enforced by the schema: an event row
860
+ * names a tree row), duplicate cursor seqs and duplicate materialization receipts are refused
861
+ * by the same `SpawnEventIndex` the file journal replays through, on both append and load;
862
+ * • same content-address law for blobs — a `put` whose ref does not hash to the artifact is
863
+ * refused, a re-put of the same ref asserts the identical bytes;
864
+ * • load order is insertion order (`INTEGER PRIMARY KEY AUTOINCREMENT`), the SQL analogue of
865
+ * the JSONL append-only spine.
866
+ *
867
+ * Durability note: this suite and its process-kill test run against `node:sqlite`, whose
868
+ * autocommit commits survive SIGKILL (process death, not OS crash). A deployment that must
869
+ * survive power loss sets its driver's synchronous mode (`PRAGMA synchronous=FULL` + WAL) at the
870
+ * adapter; agent-runtime takes no opinion.
871
+ *
872
+ * @experimental — draft: cross-process ownership is single-writer by convention (the same
873
+ * limitation `createFileRunContext` documents); a machine-visible ownership lease is follow-up.
874
+ */
875
+ const TREES_DDL = (table) => `
876
+ CREATE TABLE IF NOT EXISTS ${table}_trees (
877
+ root TEXT PRIMARY KEY,
878
+ begun_at TEXT NOT NULL
879
+ )
880
+ `;
881
+ const EVENTS_DDL = (table) => `
882
+ CREATE TABLE IF NOT EXISTS ${table}_events (
883
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
884
+ root TEXT NOT NULL REFERENCES ${table}_trees (root),
885
+ body TEXT NOT NULL
886
+ )
887
+ `;
888
+ const BLOBS_DDL = (table) => `
889
+ CREATE TABLE IF NOT EXISTS ${table}_blobs (
890
+ ref TEXT PRIMARY KEY,
891
+ body TEXT NOT NULL
892
+ )
893
+ `;
894
+ /** SQL-backed `SpawnJournal`. One row per event; insertion order is replay order. */
895
+ var SqlSpawnJournal = class {
896
+ db;
897
+ table;
898
+ cache = /* @__PURE__ */ new Map();
899
+ appendTail = Promise.resolve();
900
+ constructor(db, table = "runtime_spawn_journal") {
901
+ this.db = db;
902
+ this.table = table;
903
+ }
904
+ /** Create the journal's tables if absent. Idempotent. */
905
+ async migrate() {
906
+ await this.db.exec(TREES_DDL(this.table));
907
+ await this.db.exec(EVENTS_DDL(this.table));
908
+ }
909
+ async loadTree(root) {
910
+ if ((await this.db.query(`SELECT begun_at FROM ${this.table}_trees WHERE root = ?`, [root])).length === 0) return void 0;
911
+ const rows = await this.db.query(`SELECT id, body FROM ${this.table}_events WHERE root = ? ORDER BY id`, [root]);
912
+ const index = new SpawnEventIndex(root);
913
+ const events = [];
914
+ for (const row of rows) {
915
+ const event = JSON.parse(row.body);
916
+ index.assert(event);
917
+ index.add(event);
918
+ events.push(event);
919
+ }
920
+ return events;
921
+ }
922
+ async beginTree(root, at) {
923
+ return this.serializeAppend(async () => {
924
+ await this.ensureMigrated();
925
+ const existing = await this.db.query(`SELECT begun_at FROM ${this.table}_trees WHERE root = ?`, [root]);
926
+ if (existing.length > 0) {
927
+ const begunAt = existing[0]?.begun_at;
928
+ if (begunAt !== at) throw new Error(`spawn tree '${root}' already begun in SQL at ${begunAt}; refusing to overwrite with ${at}`);
929
+ return;
930
+ }
931
+ await this.db.exec(`INSERT INTO ${this.table}_trees (root, begun_at) VALUES (?, ?)`, [root, at]);
932
+ this.cache.set(root, {
933
+ maxId: 0,
934
+ index: new SpawnEventIndex(root)
935
+ });
936
+ });
937
+ }
938
+ async appendEvent(root, ev) {
939
+ const event = detachedSnapshot(ev, "spawn event");
940
+ return this.serializeAppend(async () => {
941
+ await this.ensureMigrated();
942
+ const state = await this.validationIndex(root);
943
+ state.index.assert(event);
944
+ if ((await this.db.exec(`INSERT INTO ${this.table}_events (root, body) VALUES (?, ?)`, [root, JSON.stringify(event)])).rowsAffected !== 1) throw new Error(`spawn journal SQL: append of an event for tree '${root}' affected no rows`);
945
+ state.index.add(event);
946
+ state.maxId = await this.maxEventId(root);
947
+ });
948
+ }
949
+ async validationIndex(root) {
950
+ if ((await this.db.query(`SELECT begun_at FROM ${this.table}_trees WHERE root = ?`, [root])).length === 0) throw new Error(`appendEvent called for unknown spawn tree '${root}'; call beginTree first`);
951
+ const max = await this.maxEventId(root);
952
+ const cached = this.cache.get(root);
953
+ if (cached && cached.maxId === max) return cached;
954
+ const index = new SpawnEventIndex(root);
955
+ if (max > 0) {
956
+ const rows = await this.db.query(`SELECT body FROM ${this.table}_events WHERE root = ? ORDER BY id`, [root]);
957
+ for (const row of rows) {
958
+ const event = JSON.parse(row.body);
959
+ index.assert(event);
960
+ index.add(event);
961
+ }
962
+ }
963
+ const state = {
964
+ maxId: max,
965
+ index
966
+ };
967
+ this.cache.set(root, state);
968
+ return state;
969
+ }
970
+ async maxEventId(root) {
971
+ return (await this.db.query(`SELECT MAX(id) AS max FROM ${this.table}_events WHERE root = ?`, [root]))[0]?.max ?? 0;
972
+ }
973
+ migrated = false;
974
+ async ensureMigrated() {
975
+ if (this.migrated) return;
976
+ await this.migrate();
977
+ this.migrated = true;
978
+ }
979
+ serializeAppend(operation) {
980
+ const append = this.appendTail.then(operation);
981
+ this.appendTail = append.catch(() => void 0);
982
+ return append;
983
+ }
984
+ };
985
+ /** SQL-backed `ResultBlobStore`. One content-addressed row per settled result. */
986
+ var SqlResultBlobStore = class {
987
+ db;
988
+ table;
989
+ migrated = false;
990
+ constructor(db, table = "runtime_result_blobs") {
991
+ this.db = db;
992
+ this.table = table;
993
+ }
994
+ async migrate() {
995
+ await this.db.exec(BLOBS_DDL(this.table));
996
+ }
997
+ async put(outRef, artifact) {
998
+ await this.ensureMigrated();
999
+ const { text } = encodeResultBlob(outRef, artifact);
1000
+ if ((await this.db.exec(`INSERT OR IGNORE INTO ${this.table}_blobs (ref, body) VALUES (?, ?)`, [outRef, text])).rowsAffected === 1) return;
1001
+ assertContentAddress(outRef, await this.get(outRef));
1002
+ }
1003
+ async get(outRef) {
1004
+ await this.ensureMigrated();
1005
+ const rows = await this.db.query(`SELECT body FROM ${this.table}_blobs WHERE ref = ?`, [outRef]);
1006
+ if (rows.length === 0) return void 0;
1007
+ const artifact = JSON.parse(rows[0]?.body ?? "null");
1008
+ assertContentAddress(outRef, artifact);
1009
+ return artifact;
1010
+ }
1011
+ async ensureMigrated() {
1012
+ if (this.migrated) return;
1013
+ await this.migrate();
1014
+ this.migrated = true;
1015
+ }
1016
+ };
1017
+ //#endregion
1018
+ //#region src/durable/sql-run-store.ts
1019
+ /** Refuses a competing or stale SQL run owner before it can publish new work. */
1020
+ var SqlRunOwnershipError = class extends Error {
1021
+ constructor(message) {
1022
+ super(message);
1023
+ this.name = "SqlRunOwnershipError";
1024
+ }
1025
+ };
1026
+ /**
1027
+ * Append-only immutable records, published by ONE compare-and-set of the run's head.
1028
+ *
1029
+ * SqlAdapter has no pinned-connection transaction API. INSERT ... SELECT owner is NOT a
1030
+ * fence on MVCC databases: its snapshot can outlive a takeover. Here both publication and
1031
+ * takeover UPDATE the SAME row. Unpublished records are harmless, unreachable staging.
1032
+ * Healthy appends write only their new payload and one fixed-size head, never the history.
1033
+ *
1034
+ * Liveness uses a persisted progress counter, not incomparable host clocks. A contender must
1035
+ * observe the SAME generation/counter for leaseMs before replacing it with a CAS. Every
1036
+ * heartbeat and publication advances that counter. The interval is stored per run so a
1037
+ * differently configured contender cannot shorten an existing owner's lease.
1038
+ * @internal
1039
+ */
1040
+ async function openSqlRunStore(db, runId, options = {}) {
1041
+ const prefix = options.tablePrefix ?? "agent_run";
1042
+ const leaseMs = options.leaseMs ?? 3e4;
1043
+ const heartbeatMs = options.heartbeatMs ?? Math.floor(leaseMs / 3);
1044
+ if (!/^[A-Za-z_][A-Za-z0-9_]{0,39}$/.test(prefix)) throw new Error("SQL run context tablePrefix must be a SQL identifier of at most 40 characters");
1045
+ if (typeof runId !== "string" || runId.length === 0) throw new Error("SQL runId must be nonempty");
1046
+ if (!Number.isSafeInteger(leaseMs) || leaseMs < 100 || leaseMs > 2147483647) throw new Error("SQL leaseMs must be an integer between 100 and 2147483647");
1047
+ if (!Number.isSafeInteger(heartbeatMs) || heartbeatMs < 1 || heartbeatMs > leaseMs / 3) throw new Error("SQL heartbeatMs must be a positive integer no greater than leaseMs / 3");
1048
+ const heads = `${prefix}_heads`;
1049
+ const records = `${prefix}_records`;
1050
+ await db.exec(`CREATE TABLE IF NOT EXISTS ${heads} (
1051
+ run_id TEXT PRIMARY KEY,
1052
+ owner TEXT NOT NULL,
1053
+ generation INTEGER NOT NULL,
1054
+ pulse INTEGER NOT NULL,
1055
+ head TEXT NOT NULL,
1056
+ revision INTEGER NOT NULL,
1057
+ lease_ms INTEGER NOT NULL,
1058
+ namespace TEXT NOT NULL
1059
+ )`);
1060
+ await db.exec(`CREATE TABLE IF NOT EXISTS ${records} (
1061
+ run_id TEXT NOT NULL,
1062
+ id TEXT NOT NULL,
1063
+ parent TEXT NOT NULL,
1064
+ revision INTEGER NOT NULL,
1065
+ payload TEXT NOT NULL,
1066
+ PRIMARY KEY (run_id, id)
1067
+ )`);
1068
+ await db.exec(`INSERT INTO ${heads} (run_id, owner, generation, pulse, head, revision, lease_ms, namespace)
1069
+ VALUES (?, '', 0, 0, '', 0, ?, ?) ON CONFLICT (run_id) DO NOTHING`, [
1070
+ runId,
1071
+ leaseMs,
1072
+ randomUUID()
1073
+ ]);
1074
+ async function readHead() {
1075
+ const [row] = await db.query(`SELECT * FROM ${heads} WHERE run_id = ?`, [runId]);
1076
+ if (!row) throw new Error(`SQL run '${runId}' has no head`);
1077
+ for (const key of [
1078
+ "generation",
1079
+ "pulse",
1080
+ "revision",
1081
+ "lease_ms"
1082
+ ]) {
1083
+ row[key] = Number(row[key]);
1084
+ if (!Number.isSafeInteger(row[key]) || row[key] < 0) throw new Error(`SQL run '${runId}' has an invalid ${key}`);
1085
+ }
1086
+ if (typeof row.namespace !== "string" || row.namespace.length === 0 || typeof row.head !== "string" || typeof row.owner !== "string" || row.head === "" !== (row.revision === 0)) throw new Error(`SQL run '${runId}' has an invalid head`);
1087
+ if (row.lease_ms !== leaseMs) throw new Error(`SQL run '${runId}' lease configuration differs: recorded ${row.lease_ms}ms, requested ${leaseMs}ms`);
1088
+ return row;
1089
+ }
1090
+ async function load(head) {
1091
+ if (head.revision === 0) return [];
1092
+ const rows = await db.query(`SELECT id, parent, revision, payload FROM ${records} WHERE run_id = ? AND revision <= ?`, [runId, head.revision]);
1093
+ const byId = new Map(rows.map((row) => [row.id, row]));
1094
+ const history = [];
1095
+ let id = head.head;
1096
+ for (let revision = head.revision; revision > 0; revision -= 1) {
1097
+ const row = byId.get(id);
1098
+ if (!row || Number(row.revision) !== revision || recordId(row.parent, revision, row.payload) !== id) throw new Error(`SQL run '${runId}' has a missing or corrupt committed record at revision ${revision}`);
1099
+ history.push(JSON.parse(row.payload));
1100
+ id = row.parent;
1101
+ }
1102
+ if (id !== "") throw new Error(`SQL run '${runId}' has an invalid history origin`);
1103
+ return history.reverse();
1104
+ }
1105
+ return {
1106
+ namespace: (await readHead()).namespace,
1107
+ async read() {
1108
+ return load(await readHead());
1109
+ },
1110
+ async acquire(signal) {
1111
+ signal?.throwIfAborted();
1112
+ const observed = await readHead();
1113
+ if (observed.owner !== "") await wait(leaseMs, signal);
1114
+ signal?.throwIfAborted();
1115
+ const owner = randomUUID();
1116
+ let claimed = false;
1117
+ try {
1118
+ claimed = (await db.exec(`UPDATE ${heads} SET owner = ?, generation = generation + 1, pulse = pulse + 1
1119
+ WHERE run_id = ? AND owner = ? AND generation = ? AND pulse = ?`, [
1120
+ owner,
1121
+ runId,
1122
+ observed.owner,
1123
+ observed.generation,
1124
+ observed.pulse
1125
+ ])).rowsAffected === 1;
1126
+ } catch (error) {
1127
+ if ((await readHead().catch(() => void 0))?.owner !== owner) throw error;
1128
+ claimed = true;
1129
+ }
1130
+ if (!claimed) throw new SqlRunOwnershipError(`SQL run '${runId}' is owned by another live process`);
1131
+ const generation = observed.generation + 1;
1132
+ const controller = new AbortController();
1133
+ let accepting = true;
1134
+ let released;
1135
+ let tail = Promise.resolve();
1136
+ let heartbeat;
1137
+ let progressAt = performance.now();
1138
+ let head = observed.head;
1139
+ let revision = observed.revision;
1140
+ let history = [];
1141
+ const lose = (error) => {
1142
+ accepting = false;
1143
+ clearInterval(timer);
1144
+ controller.abort(error);
1145
+ };
1146
+ const timer = setInterval(() => {
1147
+ if (controller.signal.aborted) return;
1148
+ if (performance.now() - progressAt >= leaseMs) {
1149
+ lose(new SqlRunOwnershipError(`SQL run '${runId}' lease heartbeat expired`));
1150
+ return;
1151
+ }
1152
+ if (heartbeat) return;
1153
+ heartbeat = db.exec(`UPDATE ${heads} SET pulse = pulse + 1 WHERE run_id = ? AND owner = ? AND generation = ?`, [
1154
+ runId,
1155
+ owner,
1156
+ generation
1157
+ ]).then((result) => {
1158
+ if (result.rowsAffected !== 1) throw new SqlRunOwnershipError(`SQL run '${runId}' lease was replaced`);
1159
+ progressAt = performance.now();
1160
+ }).catch(lose).finally(() => {
1161
+ heartbeat = void 0;
1162
+ });
1163
+ }, heartbeatMs);
1164
+ timer.unref();
1165
+ const lease = {
1166
+ signal: controller.signal,
1167
+ get records() {
1168
+ return JSON.parse(JSON.stringify(history));
1169
+ },
1170
+ append(payload) {
1171
+ if (!accepting) return Promise.reject(controller.signal.reason ?? new SqlRunOwnershipError(`SQL run '${runId}' lease is released`));
1172
+ let encoded;
1173
+ try {
1174
+ encoded = JSON.stringify(payload);
1175
+ if (encoded === void 0) throw new Error("SQL run records must be JSON serializable");
1176
+ } catch (error) {
1177
+ return Promise.reject(error);
1178
+ }
1179
+ const write = tail.then(async () => {
1180
+ controller.signal.throwIfAborted();
1181
+ const nextRevision = revision + 1;
1182
+ const id = recordId(head, nextRevision, encoded);
1183
+ try {
1184
+ await db.exec(`INSERT INTO ${records} (run_id, id, parent, revision, payload) VALUES (?, ?, ?, ?, ?)
1185
+ ON CONFLICT (run_id, id) DO NOTHING`, [
1186
+ runId,
1187
+ id,
1188
+ head,
1189
+ nextRevision,
1190
+ encoded
1191
+ ]);
1192
+ } catch (error) {
1193
+ const [staged] = await db.query(`SELECT id, parent, revision, payload FROM ${records} WHERE run_id = ? AND id = ?`, [runId, id]).catch(() => []);
1194
+ if (!staged || staged.payload !== encoded || staged.parent !== head || Number(staged.revision) !== nextRevision) throw error;
1195
+ }
1196
+ controller.signal.throwIfAborted();
1197
+ let published = false;
1198
+ let failure;
1199
+ try {
1200
+ published = (await db.exec(`UPDATE ${heads} SET head = ?, revision = ?, pulse = pulse + 1
1201
+ WHERE run_id = ? AND owner = ? AND generation = ? AND head = ? AND revision = ?`, [
1202
+ id,
1203
+ nextRevision,
1204
+ runId,
1205
+ owner,
1206
+ generation,
1207
+ head,
1208
+ revision
1209
+ ])).rowsAffected === 1;
1210
+ } catch (error) {
1211
+ failure = error;
1212
+ }
1213
+ if (!published) {
1214
+ const current = await readHead();
1215
+ if (current.owner !== owner || current.generation !== generation) throw new SqlRunOwnershipError(`SQL run '${runId}' lease was replaced before publication`);
1216
+ if (current.head !== id || current.revision !== nextRevision) throw failure ?? new SqlRunOwnershipError(`SQL run '${runId}' publication conflicted`);
1217
+ }
1218
+ controller.signal.throwIfAborted();
1219
+ head = id;
1220
+ revision = nextRevision;
1221
+ history.push(JSON.parse(encoded));
1222
+ progressAt = performance.now();
1223
+ });
1224
+ tail = write.catch(lose);
1225
+ return write;
1226
+ },
1227
+ release() {
1228
+ if (released) return released;
1229
+ accepting = false;
1230
+ released = (async () => {
1231
+ await tail;
1232
+ clearInterval(timer);
1233
+ try {
1234
+ await db.exec(`UPDATE ${heads} SET owner = '', pulse = pulse + 1 WHERE run_id = ? AND owner = ? AND generation = ?`, [
1235
+ runId,
1236
+ owner,
1237
+ generation
1238
+ ]);
1239
+ } finally {
1240
+ controller.abort(new SqlRunOwnershipError(`SQL run '${runId}' lease is released`));
1241
+ }
1242
+ })();
1243
+ return released;
1244
+ }
1245
+ };
1246
+ try {
1247
+ history = await load(observed);
1248
+ signal?.throwIfAborted();
1249
+ controller.signal.throwIfAborted();
1250
+ return lease;
1251
+ } catch (error) {
1252
+ await lease.release().catch(() => void 0);
1253
+ throw error;
1254
+ }
1255
+ }
1256
+ };
1257
+ }
1258
+ function recordId(parent, revision, payload) {
1259
+ return createHash("sha256").update(`${revision}\0${parent}\0${payload}`).digest("hex");
1260
+ }
1261
+ function wait(ms, signal) {
1262
+ return new Promise((resolve, reject) => {
1263
+ const cleanup = () => signal?.removeEventListener("abort", abort);
1264
+ const timer = setTimeout(() => {
1265
+ cleanup();
1266
+ resolve();
1267
+ }, ms);
1268
+ const abort = () => {
1269
+ clearTimeout(timer);
1270
+ cleanup();
1271
+ reject(signal?.reason);
1272
+ };
1273
+ if (signal?.aborted) abort();
1274
+ else signal?.addEventListener("abort", abort, { once: true });
1275
+ });
1276
+ }
1277
+ //#endregion
851
1278
  //#region src/runtime/audit-intent.ts
852
1279
  /** Default system instruction for intent-auditor agents: diagnose diverged/drifting trajectories. */
853
1280
  const defaultAuditorInstruction = "You audit whether an AI agent is on the RIGHT ROUTE — not whether it works hard, but whether its actions serve the stated intents. Infer the REVEALED intent from the action pattern (what the trajectory is actually optimizing). Compare against the declared task intent, the user intent when given, and the meta-intent when given. Flawless execution down the wrong route is DIVERGED. Busy-work that neither advances nor harms is DRIFTING. Judge only from the trajectory — be specific about which actions ground your verdict. Recommend abort only when continuing cannot serve the intent.";
@@ -1361,256 +1788,909 @@ function deterministicCompletion(check) {
1361
1788
  } };
1362
1789
  }
1363
1790
  //#endregion
1364
- //#region src/runtime/loop-dispatch.ts
1365
- /** Bridge a campaign `DispatchContext.trace` to a `LoopTraceEmitter` so every
1366
- * `loop.*` event lands as a span under the cell's scoped trace. */
1367
- function campaignTraceToLoopEmitter(trace) {
1368
- return { emit(event) {
1369
- trace.span(event.kind, {
1370
- runId: event.runId,
1371
- timestamp: event.timestamp,
1372
- ...event.payload
1373
- }).end();
1374
- } };
1375
- }
1376
- async function runLoopForCell(opts, scenario, profile, ctx) {
1377
- const loopOptions = opts.toLoopOptions(scenario, profile);
1378
- return runLoopWithCampaignContext(opts, loopOptions, ctx, {
1379
- model: profile.model?.default ?? modelFromLoopOptions(loopOptions),
1380
- maximumCharge: typeof opts.maximumCharge === "function" ? opts.maximumCharge(scenario, profile) : opts.maximumCharge,
1381
- resolveModel: opts.resolveCostModel ? (result) => opts.resolveCostModel?.(result, scenario, profile) : void 0
1382
- });
1383
- }
1384
- async function runLoopWithCampaignContext(opts, loopOptions, ctx, cost) {
1385
- const paid = await ctx.cost.runPaidCall({
1386
- channel: "agent",
1387
- actor: opts.costSource ?? "loop",
1388
- model: cost.model,
1389
- signal: ctx.signal,
1390
- ...cost.maximumCharge ? { maximumCharge: cost.maximumCharge } : {},
1391
- execute: (executionSignal) => runAgentRounds({
1392
- ...loopOptions,
1393
- ctx: {
1394
- sandboxClient: opts.sandboxClient,
1395
- ...opts.promptOptions === void 0 ? {} : { promptOptions: opts.promptOptions },
1396
- signal: executionSignal,
1397
- traceEmitter: opts.forwardTrace === false ? void 0 : campaignTraceToLoopEmitter(ctx.trace)
1791
+ //#region src/runtime/isolated-checker.ts
1792
+ const toolchains = [
1793
+ "/usr",
1794
+ "/bin",
1795
+ "/lib",
1796
+ "/lib64"
1797
+ ];
1798
+ const contains = (parent, child) => {
1799
+ const path = relative(parent, child);
1800
+ return path === "" || path !== ".." && !path.startsWith(`..${sep}`) && !path.startsWith(sep);
1801
+ };
1802
+ /**
1803
+ * Run an untrusted check in Linux Bubblewrap, or in its own Sandbox box when `box` is set.
1804
+ * Never falls back to host execution.
1805
+ *
1806
+ * Bubblewrap requires /usr/bin/bwrap and permission to create Linux namespaces.
1807
+ * Only trusted system toolchains, private proc/dev/tmp, and the writable copy are mounted.
1808
+ * The canonical input path remains the working directory; copy writes are discarded.
1809
+ * Limits bound command time and captured output, not copy size or memory consumption.
1810
+ * Callers must keep the input and trusted toolchains stable while preparing the check.
1811
+ *
1812
+ * A box check creates one fresh box with no owner secrets and blocked egress (or strict egress to
1813
+ * the placement's named domains), delivers the tree's regular files verified by sha256, runs the
1814
+ * command there with only the environment `env` names, and deletes the box.
1815
+ */
1816
+ async function runIsolatedCheck(options) {
1817
+ if (options.box) return runInBox(options, options.box);
1818
+ let scratch;
1819
+ let result;
1820
+ try {
1821
+ if (process.platform !== "linux") throw new Error("Linux Bubblewrap namespaces are required");
1822
+ const { timeoutMs, maxOutputBytes } = checkLimits(options);
1823
+ if (options.signal?.aborted) return {
1824
+ succeeded: false,
1825
+ reason: "cancelled",
1826
+ diagnostic: "Check cancelled"
1827
+ };
1828
+ const { workspace, tree } = await protectedTree(options);
1829
+ const binds = [];
1830
+ for (const path of toolchains) {
1831
+ let actual;
1832
+ try {
1833
+ actual = await realpath(path);
1834
+ } catch (error) {
1835
+ if (error.code === "ENOENT") continue;
1836
+ throw error;
1398
1837
  }
1399
- }),
1400
- receipt: (result) => loopCostReceipt(result, cost.resolveModel?.(result) ?? cost.model)
1401
- });
1402
- if (!paid.succeeded) throw paid.error;
1403
- const result = paid.value;
1404
- return (opts.toArtifact ?? ((r) => r.winner?.output))(result);
1838
+ for (const mount of [path, actual]) if (contains(mount, workspace) || contains(workspace, mount) || contains(mount, tree) || contains(tree, mount)) throw new Error(`Toolchain overlaps protected workspace: ${path}`);
1839
+ binds.push("--ro-bind", actual, path);
1840
+ }
1841
+ if (["/proc", "/dev"].some((path) => contains(path, tree) || contains(tree, path))) throw new Error("Tree overlaps a reserved namespace mount");
1842
+ scratch = await mkdtemp(join(tmpdir(), "runtime-check-"));
1843
+ if (contains(tree, scratch)) throw new Error("Temporary storage must be outside the input tree");
1844
+ const copy = join(scratch, "tree");
1845
+ await cp(tree, copy, {
1846
+ recursive: true,
1847
+ dereference: false,
1848
+ verbatimSymlinks: true
1849
+ });
1850
+ result = await execute([
1851
+ "--unshare-all",
1852
+ "--die-with-parent",
1853
+ "--new-session",
1854
+ "--cap-drop",
1855
+ "ALL",
1856
+ "--clearenv",
1857
+ "--setenv",
1858
+ "PATH",
1859
+ "/usr/bin:/bin",
1860
+ "--setenv",
1861
+ "HOME",
1862
+ "/tmp",
1863
+ "--setenv",
1864
+ "LANG",
1865
+ "C",
1866
+ ...Object.entries(options.env ?? {}).flatMap(([name, value]) => [
1867
+ "--setenv",
1868
+ name,
1869
+ value
1870
+ ]),
1871
+ ...binds,
1872
+ "--proc",
1873
+ "/proc",
1874
+ "--dev",
1875
+ "/dev",
1876
+ "--tmpfs",
1877
+ "/tmp",
1878
+ "--bind",
1879
+ copy,
1880
+ tree,
1881
+ "--chdir",
1882
+ tree,
1883
+ "--",
1884
+ ...options.command
1885
+ ], timeoutMs, maxOutputBytes, options.signal);
1886
+ } catch (error) {
1887
+ result = {
1888
+ succeeded: false,
1889
+ reason: "refused",
1890
+ diagnostic: String(error)
1891
+ };
1892
+ }
1893
+ if (scratch) try {
1894
+ await removeScratch(scratch);
1895
+ } catch (error) {
1896
+ const cleanupDiagnostic = String(error);
1897
+ result = result.succeeded ? {
1898
+ succeeded: false,
1899
+ reason: "cleanup-failed",
1900
+ diagnostic: cleanupDiagnostic,
1901
+ stdout: result.value.stdout,
1902
+ stderr: result.value.stderr,
1903
+ exitCode: 0
1904
+ } : {
1905
+ ...result,
1906
+ cleanupDiagnostic
1907
+ };
1908
+ }
1909
+ return result;
1405
1910
  }
1406
- function loopCostReceipt(result, model) {
1407
- return costReceiptFromUsage(result.tokenUsage, model, {
1408
- usageUnknown: result.tokenUsage.tokensKnown === false,
1409
- actualCostUsd: result.costUsdKnown !== false ? result.costUsd : void 0,
1410
- costUnknown: result.costUsdKnown === false,
1411
- estimatedCostUsd: result.estimatedCostUsd
1412
- });
1911
+ function checkLimits(options) {
1912
+ const timeoutMs = options.timeoutMs ?? 3e4;
1913
+ const maxOutputBytes = options.maxOutputBytes ?? 1048576;
1914
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 2147483647 || !Number.isSafeInteger(maxOutputBytes) || maxOutputBytes < 1) throw new Error("Invalid execution limits");
1915
+ if (!options.command.length || !options.command[0]) throw new Error("A command is required");
1916
+ return {
1917
+ timeoutMs,
1918
+ maxOutputBytes
1919
+ };
1413
1920
  }
1414
- /** Map Runtime usage into Eval's canonical paid-call receipt without inventing cache classes. */
1415
- function costReceiptFromUsage(usage, model, cost) {
1416
- const cacheComplete = hasCompleteCacheBreakdown(usage) && (usage.freshInput !== void 0 || usage.cacheRead !== void 0 || usage.cacheWrite !== void 0);
1417
- const cacheRead = cacheComplete ? usage.cacheRead ?? 0 : void 0;
1418
- const cacheWrite = cacheComplete ? usage.cacheWrite ?? 0 : void 0;
1419
- const classified = (cacheRead ?? 0) + (cacheWrite ?? 0);
1921
+ async function protectedTree(options) {
1922
+ const workspace = await realpath(options.workspaceRoot);
1923
+ const tree = await realpath(options.tree);
1924
+ if (!contains(workspace, tree) || !(await stat(tree)).isDirectory()) throw new Error("Tree must be a directory inside the workspace");
1420
1925
  return {
1421
- model,
1422
- inputTokens: cacheComplete ? usage.input - classified : usage.input,
1423
- outputTokens: usage.output,
1424
- ...cacheComplete ? {
1425
- cachedTokens: cacheRead,
1426
- cacheWriteTokens: cacheWrite
1427
- } : {},
1428
- ...usage.tokensKnown === false || cost.usageUnknown ? { usageUnknown: true } : {},
1429
- ...cost.actualCostUsd !== void 0 ? { actualCostUsd: cost.actualCostUsd } : {},
1430
- ...cost.costUnknown ? { costUnknown: true } : {},
1431
- ...cost.estimatedCostUsd !== void 0 ? { estimatedCostUsd: cost.estimatedCostUsd } : {}
1432
- };
1433
- }
1434
- /** Eval has one pre-admitted paid call for this dispatch. A tree can settle that call only when
1435
- * Runtime has provider-served identity for every inference attempt that actually started. Plan
1436
- * materialization is deliberately ignored: it describes what Runtime requested, not what the
1437
- * provider served. Every visible terminal child must carry provider attempt evidence; a missing
1438
- * evidence record stays unknown, including zero-valued or incomplete spend.
1439
- * @internal Testable identity projection used by superviseDispatch. */
1440
- function supervisedTreeModelForDispatch(result, rootProfile) {
1441
- const canonicalModels = /* @__PURE__ */ new Set();
1442
- const observedModels = [];
1443
- const wholeTreeEvidence = result.providerModel;
1444
- if (wholeTreeEvidence === void 0 || wholeTreeEvidence.status !== "known" && wholeTreeEvidence.reason !== "provider-model-conflict" || wholeTreeEvidence.attempts.length === 0) return { kind: "unknown" };
1445
- const wholeTreeIdentity = collectProviderModels(wholeTreeEvidence, () => true);
1446
- if (wholeTreeIdentity.kind !== "known") return wholeTreeIdentity;
1447
- for (const model of wholeTreeIdentity.observed) {
1448
- observedModels.push(model.raw);
1449
- canonicalModels.add(model.canonical);
1450
- }
1451
- if (canonicalModels.size === 0) return { kind: "unknown" };
1452
- if (canonicalModels.size !== 1) return {
1453
- kind: "mixed",
1454
- models: [...canonicalModels].sort()
1455
- };
1456
- return {
1457
- kind: "known",
1458
- model: observedModels[0]
1926
+ workspace,
1927
+ tree
1459
1928
  };
1460
1929
  }
1461
- function collectProviderModels(evidence, validate) {
1462
- if (evidence.status !== "known" && evidence.reason !== "provider-model-conflict" || !Array.isArray(evidence.attempts) || evidence.attempts.length === 0 || !Array.isArray(evidence.models)) return { kind: "unknown" };
1463
- const observed = [];
1464
- const canonical = /* @__PURE__ */ new Set();
1465
- const observedRaw = /* @__PURE__ */ new Set();
1466
- for (const attempt of evidence.attempts) {
1467
- if (attempt.providerDispatch === "not_started") {
1468
- if (attempt.observations.length > 0 || attempt.identityConflict === true) return { kind: "unknown" };
1469
- continue;
1470
- }
1471
- if (attempt === null || typeof attempt !== "object" || !Array.isArray(attempt.observations) || attempt.observations.length === 0 || attempt.identityConflict === true) return { kind: "unknown" };
1472
- let attemptBase;
1473
- let attemptSnapshot;
1474
- let attemptSnapshotKind;
1475
- let representative;
1476
- for (const model of attempt.observations) {
1477
- if (typeof model !== "string" || !validate(model)) return { kind: "unknown" };
1478
- const identity = canonicalObservedModelParts(model);
1479
- if (identity === void 0) return { kind: "unknown" };
1480
- const base = identity.base;
1481
- const snapshot = identity.snapshot;
1482
- if (attemptBase !== void 0 && attemptBase !== base) return {
1483
- kind: "mixed",
1484
- models: [.../* @__PURE__ */ new Set([...attemptBase ? [attemptBase] : [], identity.canonical])]
1485
- };
1486
- if (attemptSnapshot !== void 0 && snapshot !== void 0 && (attemptSnapshot !== snapshot || attemptSnapshotKind !== identity.snapshotKind)) {
1487
- if (attemptBase === void 0 || attemptSnapshotKind === void 0) return { kind: "unknown" };
1488
- return {
1489
- kind: "mixed",
1490
- models: [attemptIdentityText(attemptBase, attemptSnapshot, attemptSnapshotKind), identity.canonical]
1491
- };
1930
+ /** Box-workspace-relative directory that receives the tree and is the command's cwd. */
1931
+ const BOX_TREE = "tree";
1932
+ /** Bound on provisioning, delivery, and deletion; the box expires even if this process dies. */
1933
+ const BOX_SETUP_SECONDS = 900;
1934
+ /** The box's own process timeout is a backstop behind this module's deadline. */
1935
+ const BOX_PROCESS_BACKSTOP_MS = 3e4;
1936
+ /** Concurrent file deliveries into one check box. */
1937
+ const BOX_UPLOADS = 4;
1938
+ /** The box's process supervisor prefixes this to stderr when it cannot start the executable. */
1939
+ const BOX_EXEC_FAILURE = "process-supervisor: exec failed";
1940
+ async function runInBox(options, placement) {
1941
+ let box;
1942
+ let evidence;
1943
+ let result;
1944
+ try {
1945
+ const { timeoutMs, maxOutputBytes } = checkLimits(options);
1946
+ if (options.signal?.aborted) return {
1947
+ succeeded: false,
1948
+ reason: "cancelled",
1949
+ diagnostic: "Check cancelled"
1950
+ };
1951
+ const { tree } = await protectedTree(options);
1952
+ const captured = await captureMaterializedWorkspace(tree);
1953
+ if (placement.builderAccounts.length === 0 || placement.builderAccounts.some((id) => !id)) throw new Error("builderAccounts must name the account of every key the judged run holds");
1954
+ const account = (await placement.client.getIdentity()).customerId;
1955
+ if (!account) throw new Error("Sandbox returned no account for the check key");
1956
+ if (placement.builderAccounts.includes(account)) throw new Error(`Check account ${account} is an account the judged run holds a key to, so the run can reach the check box`);
1957
+ options.signal?.throwIfAborted();
1958
+ box = await placement.client.createIsolated({
1959
+ environment: placement.environment,
1960
+ agent: false,
1961
+ bare: false,
1962
+ ephemeral: true,
1963
+ egressPolicy: egressFor(placement),
1964
+ ...placement.resources ? { resources: placement.resources } : {},
1965
+ maxLifetimeSeconds: Math.ceil(timeoutMs / 1e3) + BOX_SETUP_SECONDS,
1966
+ idempotencyKey: `agent-runtime-check-${randomUUID()}`
1967
+ }, options.signal ? { signal: options.signal } : void 0);
1968
+ const receipt = box.createReceipt();
1969
+ if (receipt?.outcome !== "created" || receipt.ownerContext !== "isolated" || !Array.isArray(receipt.injectedSecrets) || receipt.injectedSecrets.length !== 0) throw new Error("Sandbox did not confirm a fresh box with no owner secrets");
1970
+ const egress = (await box.egress.get()).policy;
1971
+ const wanted = egressFor(placement);
1972
+ if (egress.mode !== wanted.mode || wanted.mode === "strict" && (egress.includeImplicitDomains === true || [...egress.allowDomains ?? []].sort().join(",") !== [...wanted.allowDomains ?? []].sort().join(","))) throw new Error(`Check box egress is ${egress.mode} ${JSON.stringify(egress.allowDomains ?? [])}, not ${wanted.mode} ${JSON.stringify(wanted.allowDomains ?? [])}`);
1973
+ await box.fs.mkdir(BOX_TREE, { recursive: true });
1974
+ const digests = new Map(captured.manifest.files.map((entry) => [entry.path, entry.sha256]));
1975
+ const target = box;
1976
+ const pending = [...captured.files];
1977
+ const deliver = async () => {
1978
+ try {
1979
+ for (let file = pending.shift(); file; file = pending.shift()) {
1980
+ options.signal?.throwIfAborted();
1981
+ const received = await target.fs.uploadData(`${BOX_TREE}/${file.path}`, file.bytes, { mode: file.mode });
1982
+ if (`sha256:${received.hash.replace(/^sha256:/, "").toLowerCase()}` !== digests.get(file.path) || received.size !== file.bytes.byteLength) throw new Error(`Check box received different bytes for ${file.path}`);
1983
+ }
1984
+ } catch (error) {
1985
+ pending.length = 0;
1986
+ throw error;
1492
1987
  }
1493
- attemptBase = base;
1494
- attemptSnapshot ??= snapshot;
1495
- attemptSnapshotKind ??= identity.snapshotKind;
1496
- if (snapshot !== void 0) representative = model;
1497
- observedRaw.add(model);
1498
- }
1499
- if (attemptBase === void 0 || attemptSnapshot === void 0 || attemptSnapshotKind === void 0 || representative === void 0) return { kind: "unknown" };
1500
- const attemptIdentity = attemptIdentityText(attemptBase, attemptSnapshot, attemptSnapshotKind);
1501
- observed.push({
1502
- raw: representative,
1503
- canonical: attemptIdentity
1504
- });
1505
- canonical.add(attemptIdentity);
1988
+ };
1989
+ await Promise.all(Array.from({ length: BOX_UPLOADS }, deliver));
1990
+ evidence = {
1991
+ sandboxId: box.id,
1992
+ account,
1993
+ input: captured.manifest,
1994
+ inputDigest: canonicalCandidateDigest(captured.manifest)
1995
+ };
1996
+ result = await executeInBox(box, options.command, timeoutMs, maxOutputBytes, options.env ?? {}, options.signal);
1997
+ } catch (error) {
1998
+ result = {
1999
+ succeeded: false,
2000
+ reason: options.signal?.aborted ? "cancelled" : "refused",
2001
+ diagnostic: String(error)
2002
+ };
1506
2003
  }
1507
- if (observed.length === 0) return { kind: "unknown" };
1508
- const declaredRaw = /* @__PURE__ */ new Set();
1509
- for (const model of evidence.models) {
1510
- if (typeof model !== "string") return { kind: "unknown" };
1511
- declaredRaw.add(model);
2004
+ if (box) try {
2005
+ await box.delete();
2006
+ } catch (error) {
2007
+ const cleanupDiagnostic = `Check box ${box.id} was not deleted: ${String(error)}`;
2008
+ result = result.succeeded ? {
2009
+ succeeded: false,
2010
+ reason: "cleanup-failed",
2011
+ diagnostic: cleanupDiagnostic,
2012
+ stdout: result.value.stdout,
2013
+ stderr: result.value.stderr,
2014
+ exitCode: 0
2015
+ } : {
2016
+ ...result,
2017
+ cleanupDiagnostic
2018
+ };
1512
2019
  }
1513
- if (declaredRaw.size !== observedRaw.size || [...declaredRaw].some((model) => !observedRaw.has(model))) return { kind: "unknown" };
1514
- return canonical.size > 1 ? {
1515
- kind: "mixed",
1516
- models: [...canonical].sort()
1517
- } : {
1518
- kind: "known",
1519
- observed
1520
- };
2020
+ return evidence ? {
2021
+ ...result,
2022
+ box: evidence
2023
+ } : result;
1521
2024
  }
1522
- function attemptIdentityText(base, snapshot, kind) {
1523
- return kind === "date" ? `${base}-${snapshot}` : `${base}@${snapshot}`;
2025
+ /** Blocked unless the placement names domains; then strict, with no implicit domain list. */
2026
+ function egressFor(placement) {
2027
+ const domains = [...new Set(placement.egress ?? [])].filter((domain) => domain.trim() !== "");
2028
+ return domains.length === 0 ? { mode: "blocked" } : {
2029
+ mode: "strict",
2030
+ allowDomains: domains,
2031
+ includeImplicitDomains: false
2032
+ };
1524
2033
  }
1525
- /** The Eval receipt surface has no pre-admitted per-model recursive-tree receipt bundle yet. */
1526
- var SupervisedTreeModelIdentityError = class extends Error {
1527
- constructor(identity) {
1528
- const detail = identity.kind === "mixed" ? `multiple models (${identity.models.join(", ")})` : "an unknown materialized model";
1529
- super(`superviseDispatch: cannot settle one Eval paid-call receipt for a tree with ${detail}`);
1530
- this.name = "SupervisedTreeModelIdentityError";
2034
+ async function executeInBox(box, command, timeoutMs, limit, env, signal) {
2035
+ const [executable, ...args] = command;
2036
+ const child = await box.process.spawnExact(executable, args, {
2037
+ cwd: BOX_TREE,
2038
+ env: {
2039
+ PATH: "/usr/bin:/bin",
2040
+ HOME: "/tmp",
2041
+ LANG: "C",
2042
+ ...env
2043
+ },
2044
+ inheritEnv: false,
2045
+ timeoutMs: timeoutMs + BOX_PROCESS_BACKSTOP_MS
2046
+ });
2047
+ const stdout = [];
2048
+ const stderr = [];
2049
+ let bytes = 0;
2050
+ let failure;
2051
+ let stopping;
2052
+ const stop = (reason) => {
2053
+ failure ??= reason;
2054
+ stopping ??= child.kill("SIGKILL", { tree: true }).catch(() => void 0);
2055
+ };
2056
+ const clearTimer = armDeadlineTimer(timeoutMs, () => stop("timeout"), true);
2057
+ const cancel = () => stop("cancelled");
2058
+ signal?.addEventListener("abort", cancel, { once: true });
2059
+ if (signal?.aborted) cancel();
2060
+ const capture = async (stream, target) => {
2061
+ for await (const text of stream) {
2062
+ const chunk = Buffer.from(text);
2063
+ const remaining = Math.max(0, limit - bytes);
2064
+ bytes += chunk.length;
2065
+ if (remaining) target.push(chunk.subarray(0, remaining));
2066
+ if (bytes > limit) stop("output-limit");
2067
+ }
2068
+ };
2069
+ let exitCode;
2070
+ let exitSignal;
2071
+ try {
2072
+ await Promise.all([capture(child.stdout(), stdout), capture(child.stderr(), stderr)]);
2073
+ exitCode = await child.wait();
2074
+ exitSignal = (await child.status()).exitSignal;
2075
+ } finally {
2076
+ clearTimer();
2077
+ signal?.removeEventListener("abort", cancel);
2078
+ await stopping;
1531
2079
  }
1532
- };
1533
- function unknownSupervisedTreeReceipt() {
1534
- return {
1535
- model: "unknown",
1536
- inputTokens: 0,
1537
- outputTokens: 0,
1538
- usageUnknown: true,
1539
- costUnknown: true
2080
+ const out = Buffer.concat(stdout).toString();
2081
+ const err = Buffer.concat(stderr).toString();
2082
+ const evidence = {
2083
+ stdout: out,
2084
+ stderr: err,
2085
+ exitCode: exitSignal ? null : exitCode
1540
2086
  };
1541
- }
1542
- /** Run one recursive supervised tree inside Eval's pre-execution paid-call lifecycle. */
1543
- function superviseDispatch(opts) {
1544
- return async (profile, scenario, ctx) => {
1545
- const superviseOptions = opts.toSuperviseOptions(scenario, profile);
1546
- const task = opts.toTask(scenario, profile);
1547
- const maximumCharge = typeof opts.maximumCharge === "function" ? opts.maximumCharge(scenario, profile) : opts.maximumCharge;
1548
- const paid = await ctx.cost.runPaidCall({
1549
- channel: "agent",
1550
- actor: opts.costSource ?? "supervise",
1551
- model: "unknown",
1552
- signal: ctx.signal,
1553
- ...maximumCharge ? { maximumCharge } : {},
1554
- execute: async (executionSignal) => {
1555
- const result = await supervise(profile, task, {
1556
- ...superviseOptions,
1557
- signal: executionSignal
1558
- });
1559
- const identity = supervisedTreeModelForDispatch(result, profile);
1560
- if (identity.kind !== "known") throw new SupervisedTreeModelIdentityError(identity);
1561
- return result;
1562
- },
1563
- receipt: (result) => {
1564
- const identity = supervisedTreeModelForDispatch(result, profile);
1565
- if (identity.kind !== "known") throw new SupervisedTreeModelIdentityError(identity);
1566
- return costReceiptFromUsage(result.spentTotal.tokens, identity.model, {
1567
- usageUnknown: result.spentTotal.tokensKnown === false,
1568
- actualCostUsd: result.spentTotal.usdKnown !== false ? result.spentTotal.usd : void 0,
1569
- costUnknown: result.spentTotal.usdKnown === false
1570
- });
1571
- },
1572
- receiptFromError: (error) => error instanceof SupervisedTreeModelIdentityError ? unknownSupervisedTreeReceipt() : void 0
2087
+ if (failure) return {
2088
+ succeeded: false,
2089
+ reason: failure,
2090
+ diagnostic: err || failure,
2091
+ ...evidence
2092
+ };
2093
+ if (exitCode === 127 && err.startsWith(BOX_EXEC_FAILURE)) return {
2094
+ succeeded: false,
2095
+ reason: "refused",
2096
+ diagnostic: err,
2097
+ ...evidence
2098
+ };
2099
+ if (exitSignal) return {
2100
+ succeeded: false,
2101
+ reason: "failed",
2102
+ diagnostic: err || `Check killed by ${exitSignal}`,
2103
+ ...evidence
2104
+ };
2105
+ if (exitCode !== 0) return {
2106
+ succeeded: false,
2107
+ reason: "failed",
2108
+ diagnostic: err || out || `Check exited ${exitCode}`,
2109
+ ...evidence
2110
+ };
2111
+ return {
2112
+ succeeded: true,
2113
+ value: {
2114
+ stdout: out,
2115
+ stderr: err
2116
+ }
2117
+ };
2118
+ }
2119
+ function execute(args, timeoutMs, limit, signal) {
2120
+ return new Promise((done) => {
2121
+ const child = spawn("/usr/bin/bwrap", [
2122
+ "--json-status-fd",
2123
+ "3",
2124
+ ...args
2125
+ ], {
2126
+ env: {},
2127
+ stdio: [
2128
+ "ignore",
2129
+ "pipe",
2130
+ "pipe",
2131
+ "pipe"
2132
+ ],
2133
+ detached: true
1573
2134
  });
1574
- if (!paid.succeeded) throw paid.error;
1575
- return (opts.toArtifact ?? ((result) => {
1576
- if (result.kind !== "winner") throw new Error(`superviseDispatch: supervised tree ended without a winner (${result.reason})`);
1577
- return result.out;
1578
- }))(paid.value);
2135
+ const stdout = [];
2136
+ const stderr = [];
2137
+ let bytes = 0;
2138
+ let status = "";
2139
+ let failure;
2140
+ const stop = (reason) => {
2141
+ failure ??= reason;
2142
+ if (child.pid) try {
2143
+ process.kill(-child.pid, "SIGKILL");
2144
+ } catch (error) {
2145
+ if (error.code !== "ESRCH") child.kill("SIGKILL");
2146
+ }
2147
+ };
2148
+ const clearTimer = armDeadlineTimer(timeoutMs, () => stop("timeout"), true);
2149
+ const cancel = () => stop("cancelled");
2150
+ signal?.addEventListener("abort", cancel, { once: true });
2151
+ if (signal?.aborted) cancel();
2152
+ const capture = (target) => (chunk) => {
2153
+ const remaining = Math.max(0, limit - bytes);
2154
+ bytes += chunk.length;
2155
+ if (remaining) target.push(chunk.subarray(0, remaining));
2156
+ if (bytes > limit) stop("output-limit");
2157
+ };
2158
+ child.stdio[3]?.on("data", (chunk) => {
2159
+ if (status.length + chunk.length > 16384) {
2160
+ stop("output-limit");
2161
+ return;
2162
+ }
2163
+ status += chunk.toString();
2164
+ });
2165
+ child.stdout.on("data", capture(stdout));
2166
+ child.stderr.on("data", capture(stderr));
2167
+ let spawnError;
2168
+ child.on("error", (error) => {
2169
+ spawnError = error;
2170
+ });
2171
+ child.on("close", (code) => {
2172
+ clearTimer();
2173
+ signal?.removeEventListener("abort", cancel);
2174
+ const out = Buffer.concat(stdout).toString();
2175
+ const err = Buffer.concat(stderr).toString();
2176
+ const evidence = {
2177
+ stdout: out,
2178
+ stderr: err,
2179
+ exitCode: code
2180
+ };
2181
+ const executed = status.split("\n").some((line) => {
2182
+ try {
2183
+ const record = JSON.parse(line);
2184
+ return record !== null && typeof record === "object" && "exit-code" in record && typeof record["exit-code"] === "number" && record["exit-code"] === code;
2185
+ } catch {
2186
+ return false;
2187
+ }
2188
+ });
2189
+ if (failure) done({
2190
+ succeeded: false,
2191
+ reason: failure,
2192
+ diagnostic: err || failure,
2193
+ ...evidence
2194
+ });
2195
+ else if (spawnError) done({
2196
+ succeeded: false,
2197
+ reason: "refused",
2198
+ diagnostic: String(spawnError),
2199
+ ...evidence
2200
+ });
2201
+ else if (!executed) done({
2202
+ succeeded: false,
2203
+ reason: "refused",
2204
+ diagnostic: err || "Bubblewrap did not confirm command execution",
2205
+ ...evidence
2206
+ });
2207
+ else if (code !== 0) done({
2208
+ succeeded: false,
2209
+ reason: "failed",
2210
+ diagnostic: err || out || `Check exited ${code}`,
2211
+ ...evidence
2212
+ });
2213
+ else done({
2214
+ succeeded: true,
2215
+ value: {
2216
+ stdout: out,
2217
+ stderr: err
2218
+ }
2219
+ });
2220
+ });
2221
+ });
2222
+ }
2223
+ const executeFile = promisify(execFile);
2224
+ /** GNU tools traverse relative to open directories, including trees deeper than PATH_MAX.
2225
+ * Recursive chmod ignores encountered symlinks; rm never follows their targets. */
2226
+ async function removeScratch(path) {
2227
+ const options = {
2228
+ env: {},
2229
+ timeout: 1e4,
2230
+ maxBuffer: 16384
1579
2231
  };
2232
+ let permissionError;
2233
+ try {
2234
+ await executeFile("/bin/chmod", [
2235
+ "--recursive",
2236
+ "--preserve-root",
2237
+ "u+rwX",
2238
+ "--",
2239
+ path
2240
+ ], options);
2241
+ } catch (error) {
2242
+ permissionError = error;
2243
+ }
2244
+ try {
2245
+ await executeFile("/bin/rm", [
2246
+ "--recursive",
2247
+ "--force",
2248
+ "--one-file-system",
2249
+ "--",
2250
+ path
2251
+ ], options);
2252
+ } catch (error) {
2253
+ throw new Error([permissionError, error].filter((value) => value !== void 0).map(String).join("; "));
2254
+ }
1580
2255
  }
1581
- function modelFromLoopOptions(options) {
1582
- const profiles = options.agentRun ? [options.agentRun.profile] : options.agentRuns?.map((run) => run.profile) ?? [];
1583
- const models = new Set(profiles.map((profile) => profile.model?.default).filter((model) => !!model));
1584
- if (models.size === 1) return [...models][0];
1585
- return models.size > 1 ? "mixed" : "unknown";
2256
+ //#endregion
2257
+ //#region src/runtime/declared-check.ts
2258
+ /**
2259
+ * A declared check: the one frozen evaluator program that decides "done" for a run, named by
2260
+ * digest, run by Runtime in a fresh box on the check account.
2261
+ *
2262
+ * The same program is read three times (discovery `docs/38-one-loop-and-continuation.md`, section
2263
+ * 1): inside the run on every `submit_result` and at a turn end with no accepted result, after the
2264
+ * run to score it, and after each version to rank versions. Before this, each play wrote its own
2265
+ * check as Lab code in a method bundle — an exact-check judge, a sealed-cases judge, a product
2266
+ * judge — and the in-run check was a separate, weaker "shape and persistence" test, so 22 directors
2267
+ * passed their own check and then failed the outside one.
2268
+ *
2269
+ * The program prints one agent-eval `JudgeScore` as JSON on its last line of stdout: each checked
2270
+ * item is a dimension, `composite` is the score, and `notes` holds one `FAIL <item> <where>:
2271
+ * <reason>` line per failed item. The record states the pass threshold. A program that does not
2272
+ * run, or prints no score, gives no verdict: it is {@link CheckUnavailableError}, and the loop
2273
+ * pauses instead of blaming the director.
2274
+ *
2275
+ * The box receives the program's files at its working directory, the submitted result at
2276
+ * `_input/result.json` when there is one, and the sealed cases at `_sealed/` only when the read
2277
+ * scores a run or a version. `CHECK_SET` is `development` or `sealed`; `CHECK_RESULT` names the
2278
+ * result file when present. Sealed cases never reach an in-run read, so their lines never reach
2279
+ * the director.
2280
+ */
2281
+ const INPUT_DIR = "_input";
2282
+ const SEALED_DIR = "_sealed";
2283
+ const DEFAULT_TIMEOUT_MS = 15 * 6e4;
2284
+ /** Refuse a malformed declaration before any compute. */
2285
+ function assertDeclaredCheck(check, context) {
2286
+ const fail = (message) => {
2287
+ throw new ValidationError(`${context}: check ${message}`);
2288
+ };
2289
+ if (typeof check !== "object" || check === null) fail("must be an object");
2290
+ if (typeof check.program?.dir !== "string" || check.program.dir.trim() === "") fail("program.dir must name the evaluator directory");
2291
+ if (!/^sha256:[0-9a-f]{64}$/u.test(check.program?.digest ?? "")) fail("program.digest must be a sha256 digest");
2292
+ if (!Array.isArray(check.command) || check.command.length === 0 || !check.command[0]) fail("command must name an executable");
2293
+ if (typeof check.environment !== "string" || check.environment.trim() === "") fail("environment must name the box image");
2294
+ if (typeof check.pass !== "number" || !Number.isFinite(check.pass)) fail("pass must be a finite threshold on the composite");
2295
+ if (check.feedback !== "verbatim" && check.feedback !== "pass-only") fail("feedback must be 'verbatim' or 'pass-only'");
2296
+ if (check.sealed !== void 0 && !/^sha256:[0-9a-f]{64}$/u.test(check.sealed.digest ?? "")) fail("sealed.digest must be a sha256 digest");
2297
+ for (const name of check.secrets ?? []) if (!/^[A-Z_][A-Z0-9_]*$/u.test(name)) fail(`secret name ${JSON.stringify(name)} is not an env name`);
2298
+ }
2299
+ /** The canonical digest of a directory's files: the digest a record names a program by. */
2300
+ async function checkProgramDigest(dir) {
2301
+ return canonicalCandidateDigest((await captureMaterializedWorkspace(dir)).manifest);
2302
+ }
2303
+ /** The digest a version judge records: the program, the sealed cases, and how they are run. */
2304
+ function declaredCheckDigest(check) {
2305
+ return sha256Bytes(Buffer.from(JSON.stringify({
2306
+ program: check.program.digest,
2307
+ sealed: check.sealed?.digest ?? null,
2308
+ command: check.command,
2309
+ environment: check.environment,
2310
+ pass: check.pass
2311
+ })));
1586
2312
  }
1587
2313
  /**
1588
- * Adapter for plain `runCampaign` scenarios. This is the Runtime-side pair for
1589
- * agent-eval fixture scenarios: load fixtures in `agent-eval/campaign`, build
1590
- * the Runtime cell here, and keep paid-call admission, receipts, and traces
1591
- * automatic.
2314
+ * Read the check once. `result` is the submitted result, absent for a read of the run's state.
2315
+ * `set: 'sealed'` adds the sealed cases. Throws {@link CheckUnavailableError} when the program
2316
+ * could not run or printed no score.
1592
2317
  */
1593
- function loopCampaignDispatch(opts) {
1594
- return (scenario, ctx) => {
1595
- const loopOptions = opts.toLoopOptions(scenario);
1596
- return runLoopWithCampaignContext(opts, loopOptions, ctx, {
1597
- model: modelFromLoopOptions(loopOptions),
1598
- maximumCharge: typeof opts.maximumCharge === "function" ? opts.maximumCharge(scenario) : opts.maximumCharge,
1599
- resolveModel: opts.resolveCostModel ? (result) => opts.resolveCostModel?.(result, scenario) : void 0
2318
+ async function readDeclaredCheck(check, placement, read) {
2319
+ if (read.set === "sealed" && check.sealed === void 0) throw new ValidationError("readDeclaredCheck: a sealed read needs check.sealed");
2320
+ const environment = placement.env ?? process.env;
2321
+ const secrets = {};
2322
+ for (const name of check.secrets ?? []) {
2323
+ const value = environment[name];
2324
+ if (value === void 0 || value === "") throw new CheckUnavailableError(`the check's secret ${name} is not set on this host`);
2325
+ secrets[name] = value;
2326
+ }
2327
+ const workspace = await mkdtemp(join(tmpdir(), "declared-check-"));
2328
+ try {
2329
+ const tree = join(workspace, "tree");
2330
+ await copyVerified(check.program.dir, check.program.digest, tree, "program");
2331
+ const entries = await readdir(tree);
2332
+ if (entries.includes(INPUT_DIR) || entries.includes(SEALED_DIR)) throw new ValidationError(`readDeclaredCheck: the program may not hold ${INPUT_DIR}/ or ${SEALED_DIR}/; Runtime mounts them`);
2333
+ const env = {
2334
+ ...secrets,
2335
+ CHECK_SET: read.set
2336
+ };
2337
+ if (read.result !== void 0) {
2338
+ await mkdir(join(tree, INPUT_DIR));
2339
+ await writeFile(join(tree, INPUT_DIR, "result.json"), `${JSON.stringify(read.result)}\n`);
2340
+ env.CHECK_RESULT = `${INPUT_DIR}/result.json`;
2341
+ }
2342
+ if (read.set === "sealed" && check.sealed !== void 0) await copyVerified(check.sealed.dir, check.sealed.digest, join(tree, SEALED_DIR), "sealed cases");
2343
+ return verdictOf(await runIsolatedCheck({
2344
+ workspaceRoot: workspace,
2345
+ tree,
2346
+ command: check.command,
2347
+ timeoutMs: check.timeoutMs ?? DEFAULT_TIMEOUT_MS,
2348
+ env,
2349
+ ...read.signal === void 0 ? {} : { signal: read.signal },
2350
+ box: {
2351
+ client: placement.client,
2352
+ builderAccounts: placement.builderAccounts,
2353
+ environment: check.environment,
2354
+ ...check.egress === void 0 ? {} : { egress: check.egress },
2355
+ ...check.resources === void 0 ? {} : { resources: check.resources }
2356
+ }
2357
+ }), check.pass);
2358
+ } finally {
2359
+ await rm(workspace, {
2360
+ recursive: true,
2361
+ force: true
1600
2362
  });
2363
+ }
2364
+ }
2365
+ /** The declared check as a manager's completion check: every in-run read uses development cases. */
2366
+ function declaredCheckDeliverable(check, placement) {
2367
+ assertDeclaredCheck(check, "declaredCheckDeliverable");
2368
+ return {
2369
+ check: (result) => readDeclaredCheck(check, placement, {
2370
+ result,
2371
+ set: "development"
2372
+ }),
2373
+ checkState: () => readDeclaredCheck(check, placement, { set: "development" }),
2374
+ feedback: check.feedback,
2375
+ ...check.sealed === void 0 ? {} : { sealed: true },
2376
+ ...check.describe === void 0 ? {} : { describe: check.describe }
1601
2377
  };
1602
2378
  }
1603
2379
  /**
1604
- * Adapter for `runProfileMatrix` (profile is an axis). Returns a
1605
- * `ProfileDispatchFn` that runs `runAgentRounds` per (profile, scenario) cell
1606
- * inside Eval's paid-call lifecycle.
2380
+ * The declared check as a version chain's judge: it scores a settled version on its sealed cases
2381
+ * when the record has them, and on its development cases otherwise. The per-item verdict rides in
2382
+ * the ledger, so the next version's review names each item. A read that could not run scores
2383
+ * `null`, which never counts as an improvement.
1607
2384
  */
1608
- function loopDispatch(opts) {
1609
- return (profile, scenario, ctx) => runLoopForCell(opts, scenario, profile, ctx);
2385
+ function declaredCheckJudge(check, placement) {
2386
+ assertDeclaredCheck(check, "declaredCheckJudge");
2387
+ const digest = declaredCheckDigest(check);
2388
+ return {
2389
+ digest,
2390
+ async judge(version, signal) {
2391
+ try {
2392
+ const verdict = await readDeclaredCheck(check, placement, {
2393
+ ...version.result.kind === "winner" ? { result: version.result.out } : {},
2394
+ set: check.sealed === void 0 ? "development" : "sealed",
2395
+ signal
2396
+ });
2397
+ return {
2398
+ score: verdict.composite ?? (verdict.pass ? 1 : 0),
2399
+ judgeDigest: digest,
2400
+ check: verdict
2401
+ };
2402
+ } catch (error) {
2403
+ if (!(error instanceof CheckUnavailableError)) throw error;
2404
+ return {
2405
+ score: null,
2406
+ judgeDigest: digest,
2407
+ detail: { unavailable: error.message }
2408
+ };
2409
+ }
2410
+ }
2411
+ };
2412
+ }
2413
+ function verdictOf(outcome, pass) {
2414
+ if (!outcome.succeeded) throw new CheckUnavailableError(`the check program ${outcome.reason}: ${outcome.diagnostic.slice(0, 2e3)}`);
2415
+ const last = outcome.value.stdout.trimEnd().split("\n").at(-1) ?? "";
2416
+ let score;
2417
+ try {
2418
+ score = JSON.parse(last);
2419
+ } catch {
2420
+ throw new CheckUnavailableError("the check program printed no JudgeScore on its last line");
2421
+ }
2422
+ const raw = score;
2423
+ if (typeof raw !== "object" || raw === null || typeof raw.dimensions !== "object" || raw.dimensions === null || typeof raw.composite !== "number" || typeof raw.notes !== "string") throw new CheckUnavailableError("the check program printed a line that is not a JudgeScore");
2424
+ return verdictFromJudgeScore({
2425
+ dimensions: raw.dimensions,
2426
+ composite: raw.composite,
2427
+ notes: raw.notes,
2428
+ ...raw.failed === true ? { failed: true } : {}
2429
+ }, pass);
2430
+ }
2431
+ /** Copy exactly the bytes whose digest was checked: the files are read once, verified, and those
2432
+ * bytes are written, so a file changed after the check cannot reach the box. */
2433
+ async function copyVerified(from, digest, to, label) {
2434
+ const captured = await captureMaterializedWorkspace(from);
2435
+ const actual = canonicalCandidateDigest(captured.manifest);
2436
+ if (actual !== digest) throw new ValidationError(`readDeclaredCheck: the ${label} at ${from} is ${actual}; the record names ${digest}`);
2437
+ for (const file of captured.files) {
2438
+ const path = join(to, file.path);
2439
+ await mkdir(dirname(path), { recursive: true });
2440
+ await writeFile(path, file.bytes, { mode: file.mode });
2441
+ }
1610
2442
  }
1611
2443
  //#endregion
1612
- //#region src/runtime/inline-sandbox-client.ts
1613
- /**
2444
+ //#region src/runtime/loop-dispatch.ts
2445
+ /** Bridge a campaign `DispatchContext.trace` to a `LoopTraceEmitter` so every
2446
+ * `loop.*` event lands as a span under the cell's scoped trace. */
2447
+ function campaignTraceToLoopEmitter(trace) {
2448
+ return { emit(event) {
2449
+ trace.span(event.kind, {
2450
+ runId: event.runId,
2451
+ timestamp: event.timestamp,
2452
+ ...event.payload
2453
+ }).end();
2454
+ } };
2455
+ }
2456
+ async function runLoopForCell(opts, scenario, profile, ctx) {
2457
+ const loopOptions = opts.toLoopOptions(scenario, profile);
2458
+ return runLoopWithCampaignContext(opts, loopOptions, ctx, {
2459
+ model: profile.model?.default ?? modelFromLoopOptions(loopOptions),
2460
+ maximumCharge: typeof opts.maximumCharge === "function" ? opts.maximumCharge(scenario, profile) : opts.maximumCharge,
2461
+ resolveModel: opts.resolveCostModel ? (result) => opts.resolveCostModel?.(result, scenario, profile) : void 0
2462
+ });
2463
+ }
2464
+ async function runLoopWithCampaignContext(opts, loopOptions, ctx, cost) {
2465
+ const paid = await ctx.cost.runPaidCall({
2466
+ channel: "agent",
2467
+ actor: opts.costSource ?? "loop",
2468
+ model: cost.model,
2469
+ signal: ctx.signal,
2470
+ ...cost.maximumCharge ? { maximumCharge: cost.maximumCharge } : {},
2471
+ execute: (executionSignal) => runAgentRounds({
2472
+ ...loopOptions,
2473
+ ctx: {
2474
+ sandboxClient: opts.sandboxClient,
2475
+ ...opts.promptOptions === void 0 ? {} : { promptOptions: opts.promptOptions },
2476
+ signal: executionSignal,
2477
+ traceEmitter: opts.forwardTrace === false ? void 0 : campaignTraceToLoopEmitter(ctx.trace)
2478
+ }
2479
+ }),
2480
+ receipt: (result) => loopCostReceipt(result, cost.resolveModel?.(result) ?? cost.model)
2481
+ });
2482
+ if (!paid.succeeded) throw paid.error;
2483
+ const result = paid.value;
2484
+ return (opts.toArtifact ?? ((r) => r.winner?.output))(result);
2485
+ }
2486
+ function loopCostReceipt(result, model) {
2487
+ return costReceiptFromUsage(result.tokenUsage, model, {
2488
+ usageUnknown: result.tokenUsage.tokensKnown === false,
2489
+ actualCostUsd: result.costUsdKnown !== false ? result.costUsd : void 0,
2490
+ costUnknown: result.costUsdKnown === false,
2491
+ estimatedCostUsd: result.estimatedCostUsd
2492
+ });
2493
+ }
2494
+ /** Map Runtime usage into Eval's canonical paid-call receipt without inventing cache classes. */
2495
+ function costReceiptFromUsage(usage, model, cost) {
2496
+ const cacheComplete = hasCompleteCacheBreakdown(usage) && (usage.freshInput !== void 0 || usage.cacheRead !== void 0 || usage.cacheWrite !== void 0);
2497
+ const cacheRead = cacheComplete ? usage.cacheRead ?? 0 : void 0;
2498
+ const cacheWrite = cacheComplete ? usage.cacheWrite ?? 0 : void 0;
2499
+ const classified = (cacheRead ?? 0) + (cacheWrite ?? 0);
2500
+ return {
2501
+ model,
2502
+ inputTokens: cacheComplete ? usage.input - classified : usage.input,
2503
+ outputTokens: usage.output,
2504
+ ...cacheComplete ? {
2505
+ cachedTokens: cacheRead,
2506
+ cacheWriteTokens: cacheWrite
2507
+ } : {},
2508
+ ...usage.tokensKnown === false || cost.usageUnknown ? { usageUnknown: true } : {},
2509
+ ...cost.actualCostUsd !== void 0 ? { actualCostUsd: cost.actualCostUsd } : {},
2510
+ ...cost.costUnknown ? { costUnknown: true } : {},
2511
+ ...cost.estimatedCostUsd !== void 0 ? { estimatedCostUsd: cost.estimatedCostUsd } : {}
2512
+ };
2513
+ }
2514
+ /** Eval has one pre-admitted paid call for this dispatch. A tree can settle that call only when
2515
+ * Runtime has provider-served identity for every inference attempt that actually started. Plan
2516
+ * materialization is deliberately ignored: it describes what Runtime requested, not what the
2517
+ * provider served. Every visible terminal child must carry provider attempt evidence; a missing
2518
+ * evidence record stays unknown, including zero-valued or incomplete spend.
2519
+ * @internal Testable identity projection used by superviseDispatch. */
2520
+ function supervisedTreeModelForDispatch(result, rootProfile) {
2521
+ const canonicalModels = /* @__PURE__ */ new Set();
2522
+ const observedModels = [];
2523
+ const wholeTreeEvidence = result.providerModel;
2524
+ if (wholeTreeEvidence === void 0 || wholeTreeEvidence.status !== "known" && wholeTreeEvidence.reason !== "provider-model-conflict" || wholeTreeEvidence.attempts.length === 0) return { kind: "unknown" };
2525
+ const wholeTreeIdentity = collectProviderModels(wholeTreeEvidence, () => true);
2526
+ if (wholeTreeIdentity.kind !== "known") return wholeTreeIdentity;
2527
+ for (const model of wholeTreeIdentity.observed) {
2528
+ observedModels.push(model.raw);
2529
+ canonicalModels.add(model.canonical);
2530
+ }
2531
+ if (canonicalModels.size === 0) return { kind: "unknown" };
2532
+ if (canonicalModels.size !== 1) return {
2533
+ kind: "mixed",
2534
+ models: [...canonicalModels].sort()
2535
+ };
2536
+ return {
2537
+ kind: "known",
2538
+ model: observedModels[0]
2539
+ };
2540
+ }
2541
+ function collectProviderModels(evidence, validate) {
2542
+ if (evidence.status !== "known" && evidence.reason !== "provider-model-conflict" || !Array.isArray(evidence.attempts) || evidence.attempts.length === 0 || !Array.isArray(evidence.models)) return { kind: "unknown" };
2543
+ const observed = [];
2544
+ const canonical = /* @__PURE__ */ new Set();
2545
+ const observedRaw = /* @__PURE__ */ new Set();
2546
+ for (const attempt of evidence.attempts) {
2547
+ if (attempt.providerDispatch === "not_started") {
2548
+ if (attempt.observations.length > 0 || attempt.identityConflict === true) return { kind: "unknown" };
2549
+ continue;
2550
+ }
2551
+ if (attempt === null || typeof attempt !== "object" || !Array.isArray(attempt.observations) || attempt.observations.length === 0 || attempt.identityConflict === true) return { kind: "unknown" };
2552
+ let attemptBase;
2553
+ let attemptSnapshot;
2554
+ let attemptSnapshotKind;
2555
+ let representative;
2556
+ for (const model of attempt.observations) {
2557
+ if (typeof model !== "string" || !validate(model)) return { kind: "unknown" };
2558
+ const identity = canonicalObservedModelParts(model);
2559
+ if (identity === void 0) return { kind: "unknown" };
2560
+ const base = identity.base;
2561
+ const snapshot = identity.snapshot;
2562
+ if (attemptBase !== void 0 && attemptBase !== base) return {
2563
+ kind: "mixed",
2564
+ models: [.../* @__PURE__ */ new Set([...attemptBase ? [attemptBase] : [], identity.canonical])]
2565
+ };
2566
+ if (attemptSnapshot !== void 0 && snapshot !== void 0 && (attemptSnapshot !== snapshot || attemptSnapshotKind !== identity.snapshotKind)) {
2567
+ if (attemptBase === void 0 || attemptSnapshotKind === void 0) return { kind: "unknown" };
2568
+ return {
2569
+ kind: "mixed",
2570
+ models: [attemptIdentityText(attemptBase, attemptSnapshot, attemptSnapshotKind), identity.canonical]
2571
+ };
2572
+ }
2573
+ attemptBase = base;
2574
+ attemptSnapshot ??= snapshot;
2575
+ attemptSnapshotKind ??= identity.snapshotKind;
2576
+ if (snapshot !== void 0) representative = model;
2577
+ observedRaw.add(model);
2578
+ }
2579
+ if (attemptBase === void 0 || attemptSnapshot === void 0 || attemptSnapshotKind === void 0 || representative === void 0) return { kind: "unknown" };
2580
+ const attemptIdentity = attemptIdentityText(attemptBase, attemptSnapshot, attemptSnapshotKind);
2581
+ observed.push({
2582
+ raw: representative,
2583
+ canonical: attemptIdentity
2584
+ });
2585
+ canonical.add(attemptIdentity);
2586
+ }
2587
+ if (observed.length === 0) return { kind: "unknown" };
2588
+ const declaredRaw = /* @__PURE__ */ new Set();
2589
+ for (const model of evidence.models) {
2590
+ if (typeof model !== "string") return { kind: "unknown" };
2591
+ declaredRaw.add(model);
2592
+ }
2593
+ if (declaredRaw.size !== observedRaw.size || [...declaredRaw].some((model) => !observedRaw.has(model))) return { kind: "unknown" };
2594
+ return canonical.size > 1 ? {
2595
+ kind: "mixed",
2596
+ models: [...canonical].sort()
2597
+ } : {
2598
+ kind: "known",
2599
+ observed
2600
+ };
2601
+ }
2602
+ function attemptIdentityText(base, snapshot, kind) {
2603
+ return kind === "date" ? `${base}-${snapshot}` : `${base}@${snapshot}`;
2604
+ }
2605
+ /** The Eval receipt surface has no pre-admitted per-model recursive-tree receipt bundle yet. */
2606
+ var SupervisedTreeModelIdentityError = class extends Error {
2607
+ constructor(identity) {
2608
+ const detail = identity.kind === "mixed" ? `multiple models (${identity.models.join(", ")})` : "an unknown materialized model";
2609
+ super(`superviseDispatch: cannot settle one Eval paid-call receipt for a tree with ${detail}`);
2610
+ this.name = "SupervisedTreeModelIdentityError";
2611
+ }
2612
+ };
2613
+ function unknownSupervisedTreeReceipt() {
2614
+ return {
2615
+ model: "unknown",
2616
+ inputTokens: 0,
2617
+ outputTokens: 0,
2618
+ usageUnknown: true,
2619
+ costUnknown: true
2620
+ };
2621
+ }
2622
+ /** Run one recursive supervised tree inside Eval's pre-execution paid-call lifecycle. */
2623
+ function superviseDispatch(opts) {
2624
+ return async (profile, scenario, ctx) => {
2625
+ const superviseOptions = opts.toSuperviseOptions(scenario, profile);
2626
+ const task = opts.toTask(scenario, profile);
2627
+ const maximumCharge = typeof opts.maximumCharge === "function" ? opts.maximumCharge(scenario, profile) : opts.maximumCharge;
2628
+ const paid = await ctx.cost.runPaidCall({
2629
+ channel: "agent",
2630
+ actor: opts.costSource ?? "supervise",
2631
+ model: "unknown",
2632
+ signal: ctx.signal,
2633
+ ...maximumCharge ? { maximumCharge } : {},
2634
+ execute: async (executionSignal) => {
2635
+ const result = await supervise(profile, task, {
2636
+ ...superviseOptions,
2637
+ signal: executionSignal
2638
+ });
2639
+ const identity = supervisedTreeModelForDispatch(result, profile);
2640
+ if (identity.kind !== "known") throw new SupervisedTreeModelIdentityError(identity);
2641
+ return result;
2642
+ },
2643
+ receipt: (result) => {
2644
+ const identity = supervisedTreeModelForDispatch(result, profile);
2645
+ if (identity.kind !== "known") throw new SupervisedTreeModelIdentityError(identity);
2646
+ return costReceiptFromUsage(result.spentTotal.tokens, identity.model, {
2647
+ usageUnknown: result.spentTotal.tokensKnown === false,
2648
+ actualCostUsd: result.spentTotal.usdKnown !== false ? result.spentTotal.usd : void 0,
2649
+ costUnknown: result.spentTotal.usdKnown === false
2650
+ });
2651
+ },
2652
+ receiptFromError: (error) => error instanceof SupervisedTreeModelIdentityError ? unknownSupervisedTreeReceipt() : void 0
2653
+ });
2654
+ if (!paid.succeeded) throw paid.error;
2655
+ return (opts.toArtifact ?? ((result) => {
2656
+ if (result.kind !== "winner") throw new Error(`superviseDispatch: supervised tree ended without a winner (${result.reason})`);
2657
+ return result.out;
2658
+ }))(paid.value);
2659
+ };
2660
+ }
2661
+ function modelFromLoopOptions(options) {
2662
+ const profiles = options.agentRun ? [options.agentRun.profile] : options.agentRuns?.map((run) => run.profile) ?? [];
2663
+ const models = new Set(profiles.map((profile) => profile.model?.default).filter((model) => !!model));
2664
+ if (models.size === 1) return [...models][0];
2665
+ return models.size > 1 ? "mixed" : "unknown";
2666
+ }
2667
+ /**
2668
+ * Adapter for plain `runCampaign` scenarios. This is the Runtime-side pair for
2669
+ * agent-eval fixture scenarios: load fixtures in `agent-eval/campaign`, build
2670
+ * the Runtime cell here, and keep paid-call admission, receipts, and traces
2671
+ * automatic.
2672
+ */
2673
+ function loopCampaignDispatch(opts) {
2674
+ return (scenario, ctx) => {
2675
+ const loopOptions = opts.toLoopOptions(scenario);
2676
+ return runLoopWithCampaignContext(opts, loopOptions, ctx, {
2677
+ model: modelFromLoopOptions(loopOptions),
2678
+ maximumCharge: typeof opts.maximumCharge === "function" ? opts.maximumCharge(scenario) : opts.maximumCharge,
2679
+ resolveModel: opts.resolveCostModel ? (result) => opts.resolveCostModel?.(result, scenario) : void 0
2680
+ });
2681
+ };
2682
+ }
2683
+ /**
2684
+ * Adapter for `runProfileMatrix` (profile is an axis). Returns a
2685
+ * `ProfileDispatchFn` that runs `runAgentRounds` per (profile, scenario) cell
2686
+ * inside Eval's paid-call lifecycle.
2687
+ */
2688
+ function loopDispatch(opts) {
2689
+ return (profile, scenario, ctx) => runLoopForCell(opts, scenario, profile, ctx);
2690
+ }
2691
+ //#endregion
2692
+ //#region src/runtime/inline-sandbox-client.ts
2693
+ /**
1614
2694
  * The ONE pseudo-box adapter: present any one-shot `Executor` (router / bridge /
1615
2695
  * BYO) as a `SandboxClient` so the round-synchronous `runAgentRounds` can drive it
1616
2696
  * without each call site re-faking a box. This is the single shell that
@@ -2264,626 +3344,177 @@ async function harvestCorpus(opts) {
2264
3344
  if (done || opts.signal?.aborted || opts.maxRuns !== void 0 && consumed >= opts.maxRuns) return null;
2265
3345
  const sequence = ++consumed;
2266
3346
  let r;
2267
- try {
2268
- r = await iterator.next();
2269
- } catch (error) {
2270
- done = true;
2271
- report.failures.push({
2272
- runId: `source-${sequence}`,
2273
- error: `trace source: ${error instanceof Error ? error.message.slice(0, 300) : String(error)}`
2274
- });
2275
- return null;
2276
- }
2277
- if (r.done) {
2278
- done = true;
2279
- return null;
2280
- }
2281
- return {
2282
- input: r.value,
2283
- sequence
2284
- };
2285
- };
2286
- const workers = Array.from({ length: concurrency }, async () => {
2287
- for (let run = await next(); run !== null; run = await next()) {
2288
- const { input, sequence } = run;
2289
- if (opts.signal?.aborted) return;
2290
- try {
2291
- const obs = await observe(input, opts);
2292
- report.runsObserved += 1;
2293
- report.findings += obs.findings.length;
2294
- report.learned += obs.learned.length;
2295
- report.usage.input += obs.usage.input;
2296
- report.usage.output += obs.usage.output;
2297
- report.usage.known &&= obs.usage.known;
2298
- } catch (e) {
2299
- report.usage.known &&= e instanceof ObservationError && e.usage.known;
2300
- if (e instanceof ObservationError) {
2301
- report.usage.input += e.usage.input;
2302
- report.usage.output += e.usage.output;
2303
- }
2304
- report.failures.push({
2305
- runId: input.runId ?? `run-${sequence}`,
2306
- error: e instanceof Error ? e.message.slice(0, 300) : String(e)
2307
- });
2308
- }
2309
- }
2310
- });
2311
- await Promise.all(workers);
2312
- if (report.runsObserved === 0 && report.failures.length > 0) throw new HarvestError(report);
2313
- return report;
2314
- }
2315
- //#endregion
2316
- //#region src/runtime/in-process-sandbox-client.ts
2317
- /**
2318
- * The ONE in-process pseudo-box: present a plain user callback as a
2319
- * `SandboxClient` so an example or test can drive `runAgentRounds` / `openSandboxRun`
2320
- * with zero credentials and zero network — without re-faking a box at each call
2321
- * site via `as unknown as SandboxInstance`.
2322
- *
2323
- * It is the structural sibling of {@link inlineSandboxClient}: that one adapts an
2324
- * `Executor` (router / bridge / BYO) into a box; this one adapts a single
2325
- * `onPrompt(prompt, round)` callback into a box. Both exist because
2326
- * `SandboxInstance` is a `declare class` with private fields — a plain object
2327
- * literal can NEVER structurally satisfy it, so every offline seam was forced to
2328
- * write `as unknown as SandboxInstance`. The one unavoidable cast now lives HERE,
2329
- * documented and tested, instead of in every example.
2330
- *
2331
- * What the box implements is exactly the subset `runAgentRounds` + `openSandboxRun`
2332
- * actually call on a box:
2333
- * - `id` — stable per box, used for trace correlation.
2334
- * - `streamPrompt(prompt, opts?)` — runs `onPrompt` and streams its events.
2335
- * - `fs.read` / `fs.write` — over the optional real `workdir` (the deliverable
2336
- * artifact + any seeded fixtures live there). Present only when a `workdir`
2337
- * is given.
2338
- * - `exec(command)` — runs the command in `workdir`. Present only when a
2339
- * `workdir` is given.
2340
- * - `delete()` — removes the per-box temp dir (when one was minted) and is a
2341
- * no-op otherwise; `deleteBoxSafe` calls it at teardown.
2342
- *
2343
- * The `SandboxEvent` shape the callback returns — `{ type, data }` — is the
2344
- * runtime metering protocol the kernel reads: emit a flat `llm_call`
2345
- * (`{ tokensIn, tokensOut, costUsd }`) or a terminal `done`
2346
- * (`{ tokenUsage, totalCostUsd }`) / `result` event and the kernel's cost ledger
2347
- * picks it up. No cast is needed on the events (the union is structural); only
2348
- * the box object is cast, once, inside this file.
2349
- */
2350
- function isAsyncIterable(v) {
2351
- return typeof v === "object" && v !== null && Symbol.asyncIterator in v;
2352
- }
2353
- /**
2354
- * Adapt a single `onPrompt(prompt, ctx)` callback into a `SandboxClient` for
2355
- * `runAgentRounds` / `openSandboxRun`. Returns a PROPERLY-TYPED `SandboxClient`: the
2356
- * lone `SandboxInstance` cast (object literal → `declare class`) lives inside
2357
- * this function, so call sites stay cast-free.
2358
- *
2359
- * There is no box, so a per-prompt `backend` override is refused rather than dropped. A per-turn
2360
- * `model` IS delivered, because `onPrompt` receives the verbatim options and is free to honor it.
2361
- * Other per-prompt options (`timeoutMs`, `context`) are accepted and ignored.
2362
- *
2363
- * @experimental
2364
- */
2365
- function inProcessSandboxClient(options) {
2366
- const { onPrompt, workdir: workdirPrefix, id: idOption } = options;
2367
- let seq = 0;
2368
- return { async create(_options) {
2369
- const current = seq++;
2370
- const id = typeof idOption === "function" ? idOption(current) : idOption ?? `in-process-${current}`;
2371
- const boxWorkdir = workdirPrefix !== void 0 ? mkdtempSync(join(tmpdir(), `${workdirPrefix}-`)) : void 0;
2372
- let round = 0;
2373
- const fsMembers = boxWorkdir !== void 0 ? {
2374
- fs: {
2375
- async read(path) {
2376
- return readFile(join(boxWorkdir, path), "utf8");
2377
- },
2378
- async write(path, content) {
2379
- const abs = join(boxWorkdir, path);
2380
- await mkdir(dirname(abs), { recursive: true });
2381
- await writeFile(abs, content, "utf8");
2382
- }
2383
- },
2384
- async exec(command) {
2385
- const { exec: execCb } = await import("node:child_process");
2386
- const { promisify } = await import("node:util");
2387
- const execAsync = promisify(execCb);
2388
- try {
2389
- const { stdout, stderr } = await execAsync(command, {
2390
- cwd: boxWorkdir,
2391
- timeout: 3e4
2392
- });
2393
- return {
2394
- exitCode: 0,
2395
- stdout,
2396
- stderr
2397
- };
2398
- } catch (err) {
2399
- const e = err;
2400
- return {
2401
- exitCode: e.code ?? 1,
2402
- stdout: e.stdout ?? "",
2403
- stderr: e.stderr ?? e.message ?? ""
2404
- };
2405
- }
2406
- }
2407
- } : {};
2408
- async function* drive(behavior, message, opts) {
2409
- const prompt = typeof message === "string" ? message : JSON.stringify(message);
2410
- const { signal: optSignal, ...rest } = opts ?? {};
2411
- const signal = optSignal ?? new AbortController().signal;
2412
- const ctx = {
2413
- round,
2414
- workdir: boxWorkdir,
2415
- signal,
2416
- ...Object.keys(rest).length > 0 ? { options: rest } : {}
2417
- };
2418
- round += 1;
2419
- const produced = await behavior(prompt, ctx);
2420
- if (isAsyncIterable(produced)) for await (const ev of produced) yield ev;
2421
- else for (const ev of produced) yield ev;
2422
- }
2423
- return {
2424
- id,
2425
- streamPrompt(message, opts) {
2426
- assertBoxlessPromptOptions(opts, "inProcessSandboxClient", ["backend"]);
2427
- return drive(onPrompt, message, opts);
2428
- },
2429
- ...fsMembers,
2430
- async delete() {
2431
- if (boxWorkdir !== void 0) rmSync(boxWorkdir, {
2432
- recursive: true,
2433
- force: true
2434
- });
2435
- }
2436
- };
2437
- } };
2438
- }
2439
- //#endregion
2440
- //#region src/runtime/isolated-checker.ts
2441
- const toolchains = [
2442
- "/usr",
2443
- "/bin",
2444
- "/lib",
2445
- "/lib64"
2446
- ];
2447
- const contains = (parent, child) => {
2448
- const path = relative(parent, child);
2449
- return path === "" || path !== ".." && !path.startsWith(`..${sep}`) && !path.startsWith(sep);
2450
- };
2451
- /**
2452
- * Run an untrusted check in Linux Bubblewrap, or in its own Sandbox box when `box` is set.
2453
- * Never falls back to host execution.
2454
- *
2455
- * Bubblewrap requires /usr/bin/bwrap and permission to create Linux namespaces.
2456
- * Only trusted system toolchains, private proc/dev/tmp, and the writable copy are mounted.
2457
- * The canonical input path remains the working directory; copy writes are discarded.
2458
- * Limits bound command time and captured output, not copy size or memory consumption.
2459
- * Callers must keep the input and trusted toolchains stable while preparing the check.
2460
- *
2461
- * A box check creates one fresh box with no owner secrets and blocked egress, delivers the
2462
- * tree's regular files verified by sha256, runs the command there, and deletes the box.
2463
- */
2464
- async function runIsolatedCheck(options) {
2465
- if (options.box) return runInBox(options, options.box);
2466
- let scratch;
2467
- let result;
2468
- try {
2469
- if (process.platform !== "linux") throw new Error("Linux Bubblewrap namespaces are required");
2470
- const { timeoutMs, maxOutputBytes } = checkLimits(options);
2471
- if (options.signal?.aborted) return {
2472
- succeeded: false,
2473
- reason: "cancelled",
2474
- diagnostic: "Check cancelled"
2475
- };
2476
- const { workspace, tree } = await protectedTree(options);
2477
- const binds = [];
2478
- for (const path of toolchains) {
2479
- let actual;
2480
- try {
2481
- actual = await realpath(path);
2482
- } catch (error) {
2483
- if (error.code === "ENOENT") continue;
2484
- throw error;
2485
- }
2486
- for (const mount of [path, actual]) if (contains(mount, workspace) || contains(workspace, mount) || contains(mount, tree) || contains(tree, mount)) throw new Error(`Toolchain overlaps protected workspace: ${path}`);
2487
- binds.push("--ro-bind", actual, path);
2488
- }
2489
- if (["/proc", "/dev"].some((path) => contains(path, tree) || contains(tree, path))) throw new Error("Tree overlaps a reserved namespace mount");
2490
- scratch = await mkdtemp(join(tmpdir(), "runtime-check-"));
2491
- if (contains(tree, scratch)) throw new Error("Temporary storage must be outside the input tree");
2492
- const copy = join(scratch, "tree");
2493
- await cp(tree, copy, {
2494
- recursive: true,
2495
- dereference: false,
2496
- verbatimSymlinks: true
2497
- });
2498
- result = await execute([
2499
- "--unshare-all",
2500
- "--die-with-parent",
2501
- "--new-session",
2502
- "--cap-drop",
2503
- "ALL",
2504
- "--clearenv",
2505
- "--setenv",
2506
- "PATH",
2507
- "/usr/bin:/bin",
2508
- "--setenv",
2509
- "HOME",
2510
- "/tmp",
2511
- "--setenv",
2512
- "LANG",
2513
- "C",
2514
- ...binds,
2515
- "--proc",
2516
- "/proc",
2517
- "--dev",
2518
- "/dev",
2519
- "--tmpfs",
2520
- "/tmp",
2521
- "--bind",
2522
- copy,
2523
- tree,
2524
- "--chdir",
2525
- tree,
2526
- "--",
2527
- ...options.command
2528
- ], timeoutMs, maxOutputBytes, options.signal);
2529
- } catch (error) {
2530
- result = {
2531
- succeeded: false,
2532
- reason: "refused",
2533
- diagnostic: String(error)
2534
- };
2535
- }
2536
- if (scratch) try {
2537
- await removeScratch(scratch);
2538
- } catch (error) {
2539
- const cleanupDiagnostic = String(error);
2540
- result = result.succeeded ? {
2541
- succeeded: false,
2542
- reason: "cleanup-failed",
2543
- diagnostic: cleanupDiagnostic,
2544
- stdout: result.value.stdout,
2545
- stderr: result.value.stderr,
2546
- exitCode: 0
2547
- } : {
2548
- ...result,
2549
- cleanupDiagnostic
2550
- };
2551
- }
2552
- return result;
2553
- }
2554
- function checkLimits(options) {
2555
- const timeoutMs = options.timeoutMs ?? 3e4;
2556
- const maxOutputBytes = options.maxOutputBytes ?? 1048576;
2557
- if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 2147483647 || !Number.isSafeInteger(maxOutputBytes) || maxOutputBytes < 1) throw new Error("Invalid execution limits");
2558
- if (!options.command.length || !options.command[0]) throw new Error("A command is required");
2559
- return {
2560
- timeoutMs,
2561
- maxOutputBytes
2562
- };
2563
- }
2564
- async function protectedTree(options) {
2565
- const workspace = await realpath(options.workspaceRoot);
2566
- const tree = await realpath(options.tree);
2567
- if (!contains(workspace, tree) || !(await stat(tree)).isDirectory()) throw new Error("Tree must be a directory inside the workspace");
2568
- return {
2569
- workspace,
2570
- tree
2571
- };
2572
- }
2573
- /** Box-workspace-relative directory that receives the tree and is the command's cwd. */
2574
- const BOX_TREE = "tree";
2575
- /** Bound on provisioning, delivery, and deletion; the box expires even if this process dies. */
2576
- const BOX_SETUP_SECONDS = 900;
2577
- /** The box's own process timeout is a backstop behind this module's deadline. */
2578
- const BOX_PROCESS_BACKSTOP_MS = 3e4;
2579
- /** Concurrent file deliveries into one check box. */
2580
- const BOX_UPLOADS = 4;
2581
- /** The box's process supervisor prefixes this to stderr when it cannot start the executable. */
2582
- const BOX_EXEC_FAILURE = "process-supervisor: exec failed";
2583
- async function runInBox(options, placement) {
2584
- let box;
2585
- let evidence;
2586
- let result;
2587
- try {
2588
- const { timeoutMs, maxOutputBytes } = checkLimits(options);
2589
- if (options.signal?.aborted) return {
2590
- succeeded: false,
2591
- reason: "cancelled",
2592
- diagnostic: "Check cancelled"
2593
- };
2594
- const { tree } = await protectedTree(options);
2595
- const captured = await captureMaterializedWorkspace(tree);
2596
- if (placement.builderAccounts.length === 0 || placement.builderAccounts.some((id) => !id)) throw new Error("builderAccounts must name the account of every key the judged run holds");
2597
- const account = (await placement.client.getIdentity()).customerId;
2598
- if (!account) throw new Error("Sandbox returned no account for the check key");
2599
- if (placement.builderAccounts.includes(account)) throw new Error(`Check account ${account} is an account the judged run holds a key to, so the run can reach the check box`);
2600
- options.signal?.throwIfAborted();
2601
- box = await placement.client.createIsolated({
2602
- environment: placement.environment,
2603
- agent: false,
2604
- bare: false,
2605
- ephemeral: true,
2606
- egressPolicy: { mode: "blocked" },
2607
- ...placement.resources ? { resources: placement.resources } : {},
2608
- maxLifetimeSeconds: Math.ceil(timeoutMs / 1e3) + BOX_SETUP_SECONDS,
2609
- idempotencyKey: `agent-runtime-check-${randomUUID()}`
2610
- }, options.signal ? { signal: options.signal } : void 0);
2611
- const receipt = box.createReceipt();
2612
- if (receipt?.outcome !== "created" || receipt.ownerContext !== "isolated" || !Array.isArray(receipt.injectedSecrets) || receipt.injectedSecrets.length !== 0) throw new Error("Sandbox did not confirm a fresh box with no owner secrets");
2613
- const egress = (await box.egress.get()).policy;
2614
- if (egress.mode !== "blocked") throw new Error(`Check box egress is ${egress.mode}, not blocked`);
2615
- await box.fs.mkdir(BOX_TREE, { recursive: true });
2616
- const digests = new Map(captured.manifest.files.map((entry) => [entry.path, entry.sha256]));
2617
- const target = box;
2618
- const pending = [...captured.files];
2619
- const deliver = async () => {
2620
- try {
2621
- for (let file = pending.shift(); file; file = pending.shift()) {
2622
- options.signal?.throwIfAborted();
2623
- const received = await target.fs.uploadData(`${BOX_TREE}/${file.path}`, file.bytes, { mode: file.mode });
2624
- if (`sha256:${received.hash.replace(/^sha256:/, "").toLowerCase()}` !== digests.get(file.path) || received.size !== file.bytes.byteLength) throw new Error(`Check box received different bytes for ${file.path}`);
2625
- }
2626
- } catch (error) {
2627
- pending.length = 0;
2628
- throw error;
2629
- }
2630
- };
2631
- await Promise.all(Array.from({ length: BOX_UPLOADS }, deliver));
2632
- evidence = {
2633
- sandboxId: box.id,
2634
- account,
2635
- input: captured.manifest,
2636
- inputDigest: canonicalCandidateDigest(captured.manifest)
2637
- };
2638
- result = await executeInBox(box, options.command, timeoutMs, maxOutputBytes, options.signal);
2639
- } catch (error) {
2640
- result = {
2641
- succeeded: false,
2642
- reason: options.signal?.aborted ? "cancelled" : "refused",
2643
- diagnostic: String(error)
2644
- };
2645
- }
2646
- if (box) try {
2647
- await box.delete();
2648
- } catch (error) {
2649
- const cleanupDiagnostic = `Check box ${box.id} was not deleted: ${String(error)}`;
2650
- result = result.succeeded ? {
2651
- succeeded: false,
2652
- reason: "cleanup-failed",
2653
- diagnostic: cleanupDiagnostic,
2654
- stdout: result.value.stdout,
2655
- stderr: result.value.stderr,
2656
- exitCode: 0
2657
- } : {
2658
- ...result,
2659
- cleanupDiagnostic
2660
- };
2661
- }
2662
- return evidence ? {
2663
- ...result,
2664
- box: evidence
2665
- } : result;
2666
- }
2667
- async function executeInBox(box, command, timeoutMs, limit, signal) {
2668
- const [executable, ...args] = command;
2669
- const child = await box.process.spawnExact(executable, args, {
2670
- cwd: BOX_TREE,
2671
- env: {
2672
- PATH: "/usr/bin:/bin",
2673
- HOME: "/tmp",
2674
- LANG: "C"
2675
- },
2676
- inheritEnv: false,
2677
- timeoutMs: timeoutMs + BOX_PROCESS_BACKSTOP_MS
2678
- });
2679
- const stdout = [];
2680
- const stderr = [];
2681
- let bytes = 0;
2682
- let failure;
2683
- let stopping;
2684
- const stop = (reason) => {
2685
- failure ??= reason;
2686
- stopping ??= child.kill("SIGKILL", { tree: true }).catch(() => void 0);
2687
- };
2688
- const clearTimer = armDeadlineTimer(timeoutMs, () => stop("timeout"), true);
2689
- const cancel = () => stop("cancelled");
2690
- signal?.addEventListener("abort", cancel, { once: true });
2691
- if (signal?.aborted) cancel();
2692
- const capture = async (stream, target) => {
2693
- for await (const text of stream) {
2694
- const chunk = Buffer.from(text);
2695
- const remaining = Math.max(0, limit - bytes);
2696
- bytes += chunk.length;
2697
- if (remaining) target.push(chunk.subarray(0, remaining));
2698
- if (bytes > limit) stop("output-limit");
2699
- }
2700
- };
2701
- let exitCode;
2702
- let exitSignal;
2703
- try {
2704
- await Promise.all([capture(child.stdout(), stdout), capture(child.stderr(), stderr)]);
2705
- exitCode = await child.wait();
2706
- exitSignal = (await child.status()).exitSignal;
2707
- } finally {
2708
- clearTimer();
2709
- signal?.removeEventListener("abort", cancel);
2710
- await stopping;
2711
- }
2712
- const out = Buffer.concat(stdout).toString();
2713
- const err = Buffer.concat(stderr).toString();
2714
- const evidence = {
2715
- stdout: out,
2716
- stderr: err,
2717
- exitCode: exitSignal ? null : exitCode
2718
- };
2719
- if (failure) return {
2720
- succeeded: false,
2721
- reason: failure,
2722
- diagnostic: err || failure,
2723
- ...evidence
2724
- };
2725
- if (exitCode === 127 && err.startsWith(BOX_EXEC_FAILURE)) return {
2726
- succeeded: false,
2727
- reason: "refused",
2728
- diagnostic: err,
2729
- ...evidence
2730
- };
2731
- if (exitSignal) return {
2732
- succeeded: false,
2733
- reason: "failed",
2734
- diagnostic: err || `Check killed by ${exitSignal}`,
2735
- ...evidence
2736
- };
2737
- if (exitCode !== 0) return {
2738
- succeeded: false,
2739
- reason: "failed",
2740
- diagnostic: err || out || `Check exited ${exitCode}`,
2741
- ...evidence
2742
- };
2743
- return {
2744
- succeeded: true,
2745
- value: {
2746
- stdout: out,
2747
- stderr: err
2748
- }
2749
- };
2750
- }
2751
- function execute(args, timeoutMs, limit, signal) {
2752
- return new Promise((done) => {
2753
- const child = spawn("/usr/bin/bwrap", [
2754
- "--json-status-fd",
2755
- "3",
2756
- ...args
2757
- ], {
2758
- env: {},
2759
- stdio: [
2760
- "ignore",
2761
- "pipe",
2762
- "pipe",
2763
- "pipe"
2764
- ],
2765
- detached: true
2766
- });
2767
- const stdout = [];
2768
- const stderr = [];
2769
- let bytes = 0;
2770
- let status = "";
2771
- let failure;
2772
- const stop = (reason) => {
2773
- failure ??= reason;
2774
- if (child.pid) try {
2775
- process.kill(-child.pid, "SIGKILL");
2776
- } catch (error) {
2777
- if (error.code !== "ESRCH") child.kill("SIGKILL");
2778
- }
2779
- };
2780
- const clearTimer = armDeadlineTimer(timeoutMs, () => stop("timeout"), true);
2781
- const cancel = () => stop("cancelled");
2782
- signal?.addEventListener("abort", cancel, { once: true });
2783
- if (signal?.aborted) cancel();
2784
- const capture = (target) => (chunk) => {
2785
- const remaining = Math.max(0, limit - bytes);
2786
- bytes += chunk.length;
2787
- if (remaining) target.push(chunk.subarray(0, remaining));
2788
- if (bytes > limit) stop("output-limit");
2789
- };
2790
- child.stdio[3]?.on("data", (chunk) => {
2791
- if (status.length + chunk.length > 16384) {
2792
- stop("output-limit");
2793
- return;
2794
- }
2795
- status += chunk.toString();
2796
- });
2797
- child.stdout.on("data", capture(stdout));
2798
- child.stderr.on("data", capture(stderr));
2799
- let spawnError;
2800
- child.on("error", (error) => {
2801
- spawnError = error;
2802
- });
2803
- child.on("close", (code) => {
2804
- clearTimer();
2805
- signal?.removeEventListener("abort", cancel);
2806
- const out = Buffer.concat(stdout).toString();
2807
- const err = Buffer.concat(stderr).toString();
2808
- const evidence = {
2809
- stdout: out,
2810
- stderr: err,
2811
- exitCode: code
2812
- };
2813
- const executed = status.split("\n").some((line) => {
2814
- try {
2815
- const record = JSON.parse(line);
2816
- return record !== null && typeof record === "object" && "exit-code" in record && typeof record["exit-code"] === "number" && record["exit-code"] === code;
2817
- } catch {
2818
- return false;
2819
- }
2820
- });
2821
- if (failure) done({
2822
- succeeded: false,
2823
- reason: failure,
2824
- diagnostic: err || failure,
2825
- ...evidence
2826
- });
2827
- else if (spawnError) done({
2828
- succeeded: false,
2829
- reason: "refused",
2830
- diagnostic: String(spawnError),
2831
- ...evidence
2832
- });
2833
- else if (!executed) done({
2834
- succeeded: false,
2835
- reason: "refused",
2836
- diagnostic: err || "Bubblewrap did not confirm command execution",
2837
- ...evidence
2838
- });
2839
- else if (code !== 0) done({
2840
- succeeded: false,
2841
- reason: "failed",
2842
- diagnostic: err || out || `Check exited ${code}`,
2843
- ...evidence
3347
+ try {
3348
+ r = await iterator.next();
3349
+ } catch (error) {
3350
+ done = true;
3351
+ report.failures.push({
3352
+ runId: `source-${sequence}`,
3353
+ error: `trace source: ${error instanceof Error ? error.message.slice(0, 300) : String(error)}`
2844
3354
  });
2845
- else done({
2846
- succeeded: true,
2847
- value: {
2848
- stdout: out,
2849
- stderr: err
3355
+ return null;
3356
+ }
3357
+ if (r.done) {
3358
+ done = true;
3359
+ return null;
3360
+ }
3361
+ return {
3362
+ input: r.value,
3363
+ sequence
3364
+ };
3365
+ };
3366
+ const workers = Array.from({ length: concurrency }, async () => {
3367
+ for (let run = await next(); run !== null; run = await next()) {
3368
+ const { input, sequence } = run;
3369
+ if (opts.signal?.aborted) return;
3370
+ try {
3371
+ const obs = await observe(input, opts);
3372
+ report.runsObserved += 1;
3373
+ report.findings += obs.findings.length;
3374
+ report.learned += obs.learned.length;
3375
+ report.usage.input += obs.usage.input;
3376
+ report.usage.output += obs.usage.output;
3377
+ report.usage.known &&= obs.usage.known;
3378
+ } catch (e) {
3379
+ report.usage.known &&= e instanceof ObservationError && e.usage.known;
3380
+ if (e instanceof ObservationError) {
3381
+ report.usage.input += e.usage.input;
3382
+ report.usage.output += e.usage.output;
2850
3383
  }
2851
- });
2852
- });
3384
+ report.failures.push({
3385
+ runId: input.runId ?? `run-${sequence}`,
3386
+ error: e instanceof Error ? e.message.slice(0, 300) : String(e)
3387
+ });
3388
+ }
3389
+ }
2853
3390
  });
3391
+ await Promise.all(workers);
3392
+ if (report.runsObserved === 0 && report.failures.length > 0) throw new HarvestError(report);
3393
+ return report;
2854
3394
  }
2855
- const executeFile = promisify(execFile);
2856
- /** GNU tools traverse relative to open directories, including trees deeper than PATH_MAX.
2857
- * Recursive chmod ignores encountered symlinks; rm never follows their targets. */
2858
- async function removeScratch(path) {
2859
- const options = {
2860
- env: {},
2861
- timeout: 1e4,
2862
- maxBuffer: 16384
2863
- };
2864
- let permissionError;
2865
- try {
2866
- await executeFile("/bin/chmod", [
2867
- "--recursive",
2868
- "--preserve-root",
2869
- "u+rwX",
2870
- "--",
2871
- path
2872
- ], options);
2873
- } catch (error) {
2874
- permissionError = error;
2875
- }
2876
- try {
2877
- await executeFile("/bin/rm", [
2878
- "--recursive",
2879
- "--force",
2880
- "--one-file-system",
2881
- "--",
2882
- path
2883
- ], options);
2884
- } catch (error) {
2885
- throw new Error([permissionError, error].filter((value) => value !== void 0).map(String).join("; "));
2886
- }
3395
+ //#endregion
3396
+ //#region src/runtime/in-process-sandbox-client.ts
3397
+ /**
3398
+ * The ONE in-process pseudo-box: present a plain user callback as a
3399
+ * `SandboxClient` so an example or test can drive `runAgentRounds` / `openSandboxRun`
3400
+ * with zero credentials and zero network — without re-faking a box at each call
3401
+ * site via `as unknown as SandboxInstance`.
3402
+ *
3403
+ * It is the structural sibling of {@link inlineSandboxClient}: that one adapts an
3404
+ * `Executor` (router / bridge / BYO) into a box; this one adapts a single
3405
+ * `onPrompt(prompt, round)` callback into a box. Both exist because
3406
+ * `SandboxInstance` is a `declare class` with private fields — a plain object
3407
+ * literal can NEVER structurally satisfy it, so every offline seam was forced to
3408
+ * write `as unknown as SandboxInstance`. The one unavoidable cast now lives HERE,
3409
+ * documented and tested, instead of in every example.
3410
+ *
3411
+ * What the box implements is exactly the subset `runAgentRounds` + `openSandboxRun`
3412
+ * actually call on a box:
3413
+ * - `id` — stable per box, used for trace correlation.
3414
+ * - `streamPrompt(prompt, opts?)` — runs `onPrompt` and streams its events.
3415
+ * - `fs.read` / `fs.write` — over the optional real `workdir` (the deliverable
3416
+ * artifact + any seeded fixtures live there). Present only when a `workdir`
3417
+ * is given.
3418
+ * - `exec(command)` — runs the command in `workdir`. Present only when a
3419
+ * `workdir` is given.
3420
+ * - `delete()` — removes the per-box temp dir (when one was minted) and is a
3421
+ * no-op otherwise; `deleteBoxSafe` calls it at teardown.
3422
+ *
3423
+ * The `SandboxEvent` shape the callback returns — `{ type, data }` — is the
3424
+ * runtime metering protocol the kernel reads: emit a flat `llm_call`
3425
+ * (`{ tokensIn, tokensOut, costUsd }`) or a terminal `done`
3426
+ * (`{ tokenUsage, totalCostUsd }`) / `result` event and the kernel's cost ledger
3427
+ * picks it up. No cast is needed on the events (the union is structural); only
3428
+ * the box object is cast, once, inside this file.
3429
+ */
3430
+ function isAsyncIterable(v) {
3431
+ return typeof v === "object" && v !== null && Symbol.asyncIterator in v;
3432
+ }
3433
+ /**
3434
+ * Adapt a single `onPrompt(prompt, ctx)` callback into a `SandboxClient` for
3435
+ * `runAgentRounds` / `openSandboxRun`. Returns a PROPERLY-TYPED `SandboxClient`: the
3436
+ * lone `SandboxInstance` cast (object literal → `declare class`) lives inside
3437
+ * this function, so call sites stay cast-free.
3438
+ *
3439
+ * There is no box, so a per-prompt `backend` override is refused rather than dropped. A per-turn
3440
+ * `model` IS delivered, because `onPrompt` receives the verbatim options and is free to honor it.
3441
+ * Other per-prompt options (`timeoutMs`, `context`) are accepted and ignored.
3442
+ *
3443
+ * @experimental
3444
+ */
3445
+ function inProcessSandboxClient(options) {
3446
+ const { onPrompt, workdir: workdirPrefix, id: idOption } = options;
3447
+ let seq = 0;
3448
+ return { async create(_options) {
3449
+ const current = seq++;
3450
+ const id = typeof idOption === "function" ? idOption(current) : idOption ?? `in-process-${current}`;
3451
+ const boxWorkdir = workdirPrefix !== void 0 ? mkdtempSync(join(tmpdir(), `${workdirPrefix}-`)) : void 0;
3452
+ let round = 0;
3453
+ const fsMembers = boxWorkdir !== void 0 ? {
3454
+ fs: {
3455
+ async read(path) {
3456
+ return readFile(join(boxWorkdir, path), "utf8");
3457
+ },
3458
+ async write(path, content) {
3459
+ const abs = join(boxWorkdir, path);
3460
+ await mkdir(dirname(abs), { recursive: true });
3461
+ await writeFile(abs, content, "utf8");
3462
+ }
3463
+ },
3464
+ async exec(command) {
3465
+ const { exec: execCb } = await import("node:child_process");
3466
+ const { promisify } = await import("node:util");
3467
+ const execAsync = promisify(execCb);
3468
+ try {
3469
+ const { stdout, stderr } = await execAsync(command, {
3470
+ cwd: boxWorkdir,
3471
+ timeout: 3e4
3472
+ });
3473
+ return {
3474
+ exitCode: 0,
3475
+ stdout,
3476
+ stderr
3477
+ };
3478
+ } catch (err) {
3479
+ const e = err;
3480
+ return {
3481
+ exitCode: e.code ?? 1,
3482
+ stdout: e.stdout ?? "",
3483
+ stderr: e.stderr ?? e.message ?? ""
3484
+ };
3485
+ }
3486
+ }
3487
+ } : {};
3488
+ async function* drive(behavior, message, opts) {
3489
+ const prompt = typeof message === "string" ? message : JSON.stringify(message);
3490
+ const { signal: optSignal, ...rest } = opts ?? {};
3491
+ const signal = optSignal ?? new AbortController().signal;
3492
+ const ctx = {
3493
+ round,
3494
+ workdir: boxWorkdir,
3495
+ signal,
3496
+ ...Object.keys(rest).length > 0 ? { options: rest } : {}
3497
+ };
3498
+ round += 1;
3499
+ const produced = await behavior(prompt, ctx);
3500
+ if (isAsyncIterable(produced)) for await (const ev of produced) yield ev;
3501
+ else for (const ev of produced) yield ev;
3502
+ }
3503
+ return {
3504
+ id,
3505
+ streamPrompt(message, opts) {
3506
+ assertBoxlessPromptOptions(opts, "inProcessSandboxClient", ["backend"]);
3507
+ return drive(onPrompt, message, opts);
3508
+ },
3509
+ ...fsMembers,
3510
+ async delete() {
3511
+ if (boxWorkdir !== void 0) rmSync(boxWorkdir, {
3512
+ recursive: true,
3513
+ force: true
3514
+ });
3515
+ }
3516
+ };
3517
+ } };
2887
3518
  }
2888
3519
  //#endregion
2889
3520
  //#region src/runtime/observation-registry.ts
@@ -5438,6 +6069,7 @@ async function createWorker(lease, root, createProfile, placement) {
5438
6069
  const timeoutMs = options?.timeoutMs ?? 0;
5439
6070
  const turnDeadline = timeoutMs > 0 ? Date.now() + timeoutMs : void 0;
5440
6071
  let sessionId;
6072
+ const subagents = /* @__PURE__ */ new Set();
5441
6073
  let refusalsInARow = 0;
5442
6074
  let prompt = message;
5443
6075
  for (let invocation = 1;; invocation += 1) {
@@ -5465,12 +6097,14 @@ async function createWorker(lease, root, createProfile, placement) {
5465
6097
  running = void 0;
5466
6098
  }
5467
6099
  sessionId = parsed.sessionId() ?? sessionId;
6100
+ for (const child of parsed.subagentSessionIds()) subagents.add(child);
5468
6101
  const failure = parsed.failure(exitCode, errorText);
5469
6102
  const refusal = failure === void 0 || unavailablePause === false || signal?.aborted ? void 0 : unavailableSignalOfFailure({ error: failure });
5470
6103
  refusalsInARow = parsed.madeProgress() ? 1 : refusalsInARow + 1;
5471
6104
  const pauseMs = refusal === void 0 || unavailablePause === false ? 0 : unavailablePauseMs(refusalsInARow, unavailablePause);
5472
6105
  if (refusal === void 0 || turnDeadline !== void 0 && Date.now() + pauseMs >= turnDeadline) {
5473
6106
  if (sessionId !== void 0) await exportSession(run, collect, paths, sessionId);
6107
+ for (const child of subagents) if (child !== sessionId) await exportSession(run, collect, paths, child);
5474
6108
  signal?.throwIfAborted();
5475
6109
  yield* parsed.finish(exitCode, errorText, invocation);
5476
6110
  return;
@@ -5494,7 +6128,7 @@ async function createWorker(lease, root, createProfile, placement) {
5494
6128
  if (released) throw new ValidationError("sharedBoxPlacement: this worker was released");
5495
6129
  if (turnActive) throw new ValidationError("sharedBoxPlacement: a worker runs one turn at a time");
5496
6130
  const turnProfile = options?.backend?.profile === void 0 ? createProfile : agentProfileSchema.parse(options.backend.profile);
5497
- if (canonicalCandidateDigest(turnProfile) !== canonicalCandidateDigest(createProfile) && sharedBoxRefusal(turnProfile) !== void 0) throw new ValidationError(`sharedBoxPlacement: ${sharedBoxRefusal(turnProfile)}`);
6131
+ if (canonicalAgentProfileDigest(turnProfile) !== canonicalAgentProfileDigest(createProfile) && sharedBoxRefusal(turnProfile) !== void 0) throw new ValidationError(`sharedBoxPlacement: ${sharedBoxRefusal(turnProfile)}`);
5498
6132
  if (options?.backend?.type !== void 0 && options.backend.type !== HARNESS) throw new ValidationError(`sharedBoxPlacement: backend ${options.backend.type} is not ${HARNESS}`);
5499
6133
  turnActive = true;
5500
6134
  try {
@@ -5688,7 +6322,7 @@ async function materializeWorker(box, paths, profile, task, turnModel, clientNam
5688
6322
  * `opencode export` writes the same session as JSON.
5689
6323
  */
5690
6324
  async function exportSession(run, collect, paths, sessionId) {
5691
- if (!/^[A-Za-z0-9_-]+$/u.test(sessionId)) return;
6325
+ if (!SESSION_ID.test(sessionId)) return;
5692
6326
  await collect(await run([
5693
6327
  "/bin/sh",
5694
6328
  "-c",
@@ -5698,6 +6332,29 @@ async function exportSession(run, collect, paths, sessionId) {
5698
6332
  `${paths.home}/.local/share/opencode/export/${sessionId}.json`
5699
6333
  ], DEFAULT_EXEC_TIMEOUT_MS));
5700
6334
  }
6335
+ const SESSION_ID = /^[A-Za-z0-9_-]+$/u;
6336
+ /** A subagent's session id in a `task` result (`<task id="ses_…">`) or failure (`task_id: ses_…`). */
6337
+ const TASK_SESSION = /(?:<task id="|task_id: )(ses_[A-Za-z0-9]+)/u;
6338
+ /**
6339
+ * The session a harness subagent ran in, named by its parent's `task` tool part.
6340
+ *
6341
+ * opencode starts each subagent in a child session and refuses a nested one unless the
6342
+ * configuration raises `subagent_depth` above 1, so under the default the parent's parts name
6343
+ * every subagent session. A running part carries the id in `state.metadata.sessionId`; a finished
6344
+ * one also carries it in its output, and a failed one in its error.
6345
+ */
6346
+ function subagentSessionOf(part) {
6347
+ if (part.type !== "tool" || part.tool !== "task") return void 0;
6348
+ const state = part.state;
6349
+ if (state === void 0 || state === null || typeof state !== "object") return void 0;
6350
+ const { metadata, output, error } = state;
6351
+ const named = metadata !== null && typeof metadata === "object" ? metadata.sessionId : void 0;
6352
+ if (typeof named === "string" && SESSION_ID.test(named)) return named;
6353
+ for (const text of [output, error]) {
6354
+ const match = typeof text === "string" ? TASK_SESSION.exec(text) : null;
6355
+ if (match !== null) return match[1];
6356
+ }
6357
+ }
5701
6358
  /**
5702
6359
  * Translate opencode's JSON event lines into the Sandbox event wire the provider executor reads.
5703
6360
  *
@@ -5711,6 +6368,7 @@ function createOpencodeEventParser(model) {
5711
6368
  let sessionId;
5712
6369
  let finalMessageId;
5713
6370
  const textByMessage = /* @__PURE__ */ new Map();
6371
+ const subagentSessions = /* @__PURE__ */ new Set();
5714
6372
  const errors = [];
5715
6373
  let malformed = 0;
5716
6374
  let spentTokens = false;
@@ -5723,6 +6381,7 @@ function createOpencodeEventParser(model) {
5723
6381
  };
5724
6382
  return {
5725
6383
  sessionId: () => sessionId,
6384
+ subagentSessionIds: () => [...subagentSessions],
5726
6385
  /** Why this run failed, or `undefined` when it answered. */
5727
6386
  failure: failureOf,
5728
6387
  /** Whether this run spent any model tokens before it ended. */
@@ -5747,6 +6406,8 @@ function createOpencodeEventParser(model) {
5747
6406
  }
5748
6407
  const part = event.part;
5749
6408
  if (part === void 0 || part === null || typeof part !== "object") return;
6409
+ const subagent = subagentSessionOf(part);
6410
+ if (subagent !== void 0) subagentSessions.add(subagent);
5750
6411
  yield {
5751
6412
  type: "message.part.updated",
5752
6413
  data: { part }
@@ -7001,6 +7662,205 @@ function signalPass(value, required) {
7001
7662
  return !required;
7002
7663
  }
7003
7664
  //#endregion
7665
+ //#region src/runtime/supervise/run-context-sql.ts
7666
+ /**
7667
+ *
7668
+ * `createSqlRunContext` — the SQL-backed durable bundle a `createSupervisor().run` (or a
7669
+ * `runGraph`/`supervise` call that accepts injected stores) needs: a `SqlSpawnJournal`, a
7670
+ * `SqlResultBlobStore` (both over one `SqlStatements` seam — the same adapter shape
7671
+ * `SqlConversationJournal` takes), and a fresh `createExecutorRegistry()`, with `resume: true`
7672
+ * so spreading the context makes the run loadTree-first.
7673
+ *
7674
+ * The SQL analogue of `createFileRunContext`: where that bundle owns a directory, this one owns
7675
+ * tables in a database the caller already operates. The durable coordination side-log and
7676
+ * cancellation observers remain file-based behind `runDir`; a SQL coordination log is follow-up.
7677
+ *
7678
+ * @experimental
7679
+ */
7680
+ /** Build a durable run context over one SQL statement seam. Tables are created on first use. */
7681
+ function createSqlRunContext(db) {
7682
+ return {
7683
+ journal: new SqlSpawnJournal(db),
7684
+ blobs: new SqlResultBlobStore(db),
7685
+ executors: createExecutorRegistry(),
7686
+ resume: true
7687
+ };
7688
+ }
7689
+ //#endregion
7690
+ //#region src/runtime/supervise/sql-run-context.ts
7691
+ /**
7692
+ * A cross-machine run context on the existing autocommit SqlAdapter. Reuse the same database,
7693
+ * tablePrefix and runId on every host; no runDir or shared filesystem is required.
7694
+ *
7695
+ * Each ownership generation gets fresh store capabilities. The public context can inspect SQL
7696
+ * at any time, but cannot write without acquire(). runGraph/supervise acquire and release it.
7697
+ * Retained provider execution supplies external admission/result idempotency; SQL does not turn
7698
+ * an arbitrary unkeyed network effect into an exactly-once operation.
7699
+ * @experimental
7700
+ */
7701
+ async function createFencedSqlRunContext(db, runId, options = {}) {
7702
+ const store = await openSqlRunStore(db, runId, options);
7703
+ const { executors } = createInMemoryRunContext({ withDriver: options.withDriver ?? true });
7704
+ const cold = async () => projection(await store.read());
7705
+ const unowned = async () => {
7706
+ throw new SqlRunOwnershipError(`SQL run '${runId}' requires an acquired lease before writing`);
7707
+ };
7708
+ const context = {
7709
+ durability: "sql",
7710
+ runId,
7711
+ namespace: store.namespace,
7712
+ resume: true,
7713
+ executors,
7714
+ journal: {
7715
+ loadTree: async (root) => (await cold()).journal.loadTree(root),
7716
+ beginTree: unowned,
7717
+ appendEvent: unowned,
7718
+ appendEvents: unowned
7719
+ },
7720
+ blobs: {
7721
+ get: async (ref) => (await cold()).blobs.get(ref),
7722
+ put: unowned
7723
+ },
7724
+ coordinationLog: {
7725
+ load: async (id, owner) => (await cold()).loadCoordination(id, owner),
7726
+ append: unowned
7727
+ },
7728
+ async acquire(signal) {
7729
+ const lease = await store.acquire(signal);
7730
+ try {
7731
+ const failureController = new AbortController();
7732
+ const leaseSignal = AbortSignal.any([lease.signal, failureController.signal]);
7733
+ const view = await projection(lease.records);
7734
+ let tail = Promise.resolve();
7735
+ let accepting = true;
7736
+ let failed;
7737
+ let hasFailed = false;
7738
+ const check = () => {
7739
+ leaseSignal.throwIfAborted();
7740
+ if (hasFailed) throw failed;
7741
+ };
7742
+ const read = async (operation) => {
7743
+ await tail;
7744
+ check();
7745
+ return operation();
7746
+ };
7747
+ const commit = (entry) => {
7748
+ if (!accepting) return unowned();
7749
+ const captured = detachedSnapshot(entry, "SQL run record");
7750
+ const write = tail.then(async () => {
7751
+ check();
7752
+ if (await view.apply(captured)) await lease.append(captured);
7753
+ });
7754
+ tail = write.catch((error) => {
7755
+ hasFailed = true;
7756
+ failed = error;
7757
+ failureController.abort(error);
7758
+ });
7759
+ return write;
7760
+ };
7761
+ const bound = {
7762
+ durability: "sql",
7763
+ runId,
7764
+ namespace: store.namespace,
7765
+ resume: true,
7766
+ executors,
7767
+ journal: {
7768
+ loadTree: (root) => read(() => view.journal.loadTree(root)),
7769
+ beginTree: (root, at) => commit({
7770
+ kind: "begin",
7771
+ root,
7772
+ at
7773
+ }),
7774
+ appendEvent: (root, event) => commit({
7775
+ kind: "events",
7776
+ root,
7777
+ events: [event]
7778
+ }),
7779
+ appendEvents: (root, events) => commit({
7780
+ kind: "events",
7781
+ root,
7782
+ events: [...events]
7783
+ })
7784
+ },
7785
+ blobs: {
7786
+ get: (ref) => read(() => view.blobs.get(ref)),
7787
+ put: (ref, value) => commit({
7788
+ kind: "blobs",
7789
+ ref,
7790
+ value
7791
+ })
7792
+ },
7793
+ coordinationLog: {
7794
+ load: (id, owner) => read(() => view.loadCoordination(id, owner)),
7795
+ append: (id, record, ownerId) => commit({
7796
+ kind: "coordination",
7797
+ runId: id,
7798
+ record,
7799
+ ...ownerId === void 0 ? {} : { ownerId }
7800
+ })
7801
+ }
7802
+ };
7803
+ return {
7804
+ context: Object.freeze(bound),
7805
+ signal: leaseSignal,
7806
+ async release() {
7807
+ accepting = false;
7808
+ await tail;
7809
+ await lease.release();
7810
+ }
7811
+ };
7812
+ } catch (error) {
7813
+ await lease.release().catch(() => void 0);
7814
+ throw error;
7815
+ }
7816
+ }
7817
+ };
7818
+ return Object.freeze(context);
7819
+ }
7820
+ /** Reuse the existing journal's uniqueness/sequence rules and blob hash validation verbatim. */
7821
+ async function projection(entries) {
7822
+ const journal = new InMemorySpawnJournal();
7823
+ const blobs = new InMemoryResultBlobStore();
7824
+ const beginnings = /* @__PURE__ */ new Map();
7825
+ const coordination = [];
7826
+ const apply = async (entry) => {
7827
+ switch (entry.kind) {
7828
+ case "begin": {
7829
+ const prior = beginnings.get(entry.root);
7830
+ await journal.beginTree(entry.root, entry.at);
7831
+ beginnings.set(entry.root, entry.at);
7832
+ return prior === void 0;
7833
+ }
7834
+ case "events":
7835
+ for (const event of entry.events) await journal.appendEvent(entry.root, event);
7836
+ return entry.events.length > 0;
7837
+ case "blobs": {
7838
+ const existing = await blobs.get(entry.ref);
7839
+ await blobs.put(entry.ref, entry.value);
7840
+ return existing === void 0;
7841
+ }
7842
+ case "coordination":
7843
+ if (entry.record.event.type === "settled") return false;
7844
+ coordination.push(entry);
7845
+ return true;
7846
+ default: throw new Error("Unknown SQL run record kind");
7847
+ }
7848
+ };
7849
+ for (const entry of entries) await apply(entry);
7850
+ return {
7851
+ journal,
7852
+ blobs,
7853
+ apply,
7854
+ loadCoordination(id, ownerId) {
7855
+ return foldCoordinationRecords(coordination.map(({ runId, ownerId, record }) => ({
7856
+ runId,
7857
+ ...record,
7858
+ ...ownerId === void 0 ? {} : { ownerId }
7859
+ })), id, ownerId);
7860
+ }
7861
+ };
7862
+ }
7863
+ //#endregion
7004
7864
  //#region src/runtime/supervise/trajectory-recorder.ts
7005
7865
  /**
7006
7866
  *
@@ -8284,6 +9144,6 @@ function tail(s) {
8284
9144
  return s.slice(-400);
8285
9145
  }
8286
9146
  //#endregion
8287
- export { definePersona as $, createTangleSandboxExactProcessProvider as $t, chatWorkerSeam as A, superviseDispatch as At, DEFAULT_SHARED_BOX_RESOURCES as B, renderPairwiseMarkdown as Bt, withUntrackedArtifacts as C, harvestCorpus as Ct, codeModeSupervisorTools as D, inlineSandboxClient as Dt, runCoderChecks as E, localSandboxClient as Et, selectChampion as F, leaderboard as Ft, sharedWorkerClientName as G, materializeLocalMcp as Gt, ROUTER_CLIENT_HEADER as H, defaultAuditorInstruction as Ht, assertStrategyContract as I, pairwiseSignificance as It, printBenchmarkReport as J, envKeyProvider as Jt, SandboxRunAbortError as K, createMcpEnvironment as Kt, authorStrategy as L, renderLeaderboardHtml as Lt, discriminatingMeans as M, deterministicCompletion as Mt, pickChampion as N, sentinelCompletion as Nt, unsafeInProcessRunner as O, loopCampaignDispatch as Ot, runStrategyEvolution as P, stopSentinel as Pt, trajectoryReport as Q, secretEnvOfMcpServer as Qt, strategyAuthorContract as R, renderLeaderboardMarkdown as Rt, copyUntrackedIntoClone as S, HarvestError as St, patchDelivered as T, resolveSandboxClient as Tt, sharedBoxPlacement as U, McpSpawnFault as Ut, DEFAULT_SHARED_BOX_WORKERS as V, auditIntent as Vt, sharedBoxRefusal as W, connectStdioMcp as Wt, promotionGate as X, resolveMcpServerLaunch as Xt, runBenchmark as Y, mcpSecretEnvMetadataKey as Yt, equalKOnCost as Z, resolveSecretEnv as Zt, NOTE_MAX_CHARS as _, createScopeAnalyst as _t, localShell as a, InMemoryCorpus as at, composeWorkerEvidence as b, runIsolatedCheck as bt, createVerifierEnvironment as c, flatWidenGate as ct, harvestSurfaceDiffs as d, pipeline as dt, runPersonified as et, analystsFromRegistry as f, selectValidWinner as ft, EVIDENCE_MAX_CHARS as g, buildSteerContext as gt, worktreeFanout as h, assertTraceDerivedFindings as ht, jjWorkspace as i, FileCorpus as it, createChatSessionStore as j, completionAuthorizes as jt, chatTransportExecutor as k, loopDispatch as kt, boxSurfaceReader as l, loopUntil as lt, superviseSurface as m, widen as mt, makeFinding$1 as n, createShapeRegistry as nt, runInWorkspace as o, renderCorpusToInstructions as ot, failuresAnalyst as p, verify as pt, openSandboxRun as q, sanitizeMcpToolSchema as qt, gitWorkspace as r, registerShape as rt, createWaterfallCollector as s, fanout as st, computeFindingId$1 as t, builtinShapes as tt, fsSurfaceReader as u, panel as ut, VERIFY_TAIL_CHARS as v, registryScopeAnalyst as vt, analyzeTrace as w, defineLeaderboard as wt, settledWorkerOut as x, inProcessSandboxClient as xt, closingWorkerNote as y, observationFromRegistry as yt, strategyAuthorSystemPrompt as z, renderLeaderboardSvg as zt };
9147
+ export { equalKOnCost as $, SqlResultBlobStore as $t, unsafeInProcessRunner as A, loopDispatch as At, strategyAuthorContract as B, deterministicCompletion as Bt, withUntrackedArtifacts as C, HarvestError as Ct, patchDelivered as D, localSandboxClient as Dt, createSqlRunContext as E, resolveSandboxClient as Et, pickChampion as F, declaredCheckDigest as Ft, sharedBoxPlacement as G, renderLeaderboardHtml as Gt, DEFAULT_SHARED_BOX_RESOURCES as H, stopSentinel as Ht, runStrategyEvolution as I, declaredCheckJudge as It, SandboxRunAbortError as J, renderPairwiseMarkdown as Jt, sharedBoxRefusal as K, renderLeaderboardMarkdown as Kt, selectChampion as L, readDeclaredCheck as Lt, chatWorkerSeam as M, assertDeclaredCheck as Mt, createChatSessionStore as N, checkProgramDigest as Nt, runCoderChecks as O, inlineSandboxClient as Ot, discriminatingMeans as P, declaredCheckDeliverable as Pt, promotionGate as Q, openSqlRunStore as Qt, assertStrategyContract as R, runIsolatedCheck as Rt, copyUntrackedIntoClone as S, inProcessSandboxClient as St, createFencedSqlRunContext as T, defineLeaderboard as Tt, DEFAULT_SHARED_BOX_WORKERS as U, leaderboard as Ut, strategyAuthorSystemPrompt as V, sentinelCompletion as Vt, ROUTER_CLIENT_HEADER as W, pairwiseSignificance as Wt, printBenchmarkReport as X, defaultAuditorInstruction as Xt, openSandboxRun as Y, auditIntent as Yt, runBenchmark as Z, SqlRunOwnershipError as Zt, NOTE_MAX_CHARS as _, assertTraceDerivedFindings as _t, localShell as a, sanitizeMcpToolSchema as an, registerShape as at, composeWorkerEvidence as b, registryScopeAnalyst as bt, createVerifierEnvironment as c, resolveMcpServerLaunch as cn, renderCorpusToInstructions as ct, harvestSurfaceDiffs as d, createTangleSandboxExactProcessProvider as dn, loopUntil as dt, SqlSpawnJournal as en, trajectoryReport as et, analystsFromRegistry as f, panel as ft, EVIDENCE_MAX_CHARS as g, widen as gt, worktreeFanout as h, verify as ht, jjWorkspace as i, createMcpEnvironment as in, createShapeRegistry as it, chatTransportExecutor as j, superviseDispatch as jt, codeModeSupervisorTools as k, loopCampaignDispatch as kt, boxSurfaceReader as l, resolveSecretEnv as ln, fanout as lt, superviseSurface as m, selectValidWinner as mt, makeFinding$1 as n, connectStdioMcp as nn, runPersonified as nt, runInWorkspace as o, envKeyProvider as on, FileCorpus as ot, failuresAnalyst as p, pipeline as pt, sharedWorkerClientName as q, renderLeaderboardSvg as qt, gitWorkspace as r, materializeLocalMcp as rn, builtinShapes as rt, createWaterfallCollector as s, mcpSecretEnvMetadataKey as sn, InMemoryCorpus as st, computeFindingId$1 as t, McpSpawnFault as tn, definePersona as tt, fsSurfaceReader as u, secretEnvOfMcpServer as un, flatWidenGate as ut, VERIFY_TAIL_CHARS as v, buildSteerContext as vt, analyzeTrace as w, harvestCorpus as wt, settledWorkerOut as x, observationFromRegistry as xt, closingWorkerNote as y, createScopeAnalyst as yt, authorStrategy as z, completionAuthorizes as zt };
8288
9148
 
8289
- //# sourceMappingURL=runtime-hOLlAc1i.js.map
9149
+ //# sourceMappingURL=runtime-CHxXrUeZ.js.map