@tangle-network/agent-runtime 0.339.0 → 0.342.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{activation-CVSFxis9.js → activation-CWPmt0Do.js} +4 -4
- package/dist/{activation-CVSFxis9.js.map → activation-CWPmt0Do.js.map} +1 -1
- package/dist/{activation-CJIIl_Ey.d.ts → activation-CXqtijue.d.ts} +2 -2
- package/dist/agent.d.ts +4 -18
- package/dist/agent.js +3 -21
- package/dist/agent.js.map +1 -1
- package/dist/analyst-loop.d.ts +2 -2
- package/dist/{bundle-DVOhBTic.js → bundle-Cwpit6Tg.js} +2 -2
- package/dist/{bundle-DVOhBTic.js.map → bundle-Cwpit6Tg.js.map} +1 -1
- package/dist/candidate-execution/index.d.ts +2 -40
- package/dist/candidate-execution/index.js +9 -255
- package/dist/candidate-execution/index.js.map +1 -1
- package/dist/{driver-control-acknowledgers-C53ggdJ6.js → coordination-manager-B5JsolDR.js} +4852 -4539
- package/dist/coordination-manager-B5JsolDR.js.map +1 -0
- package/dist/{delegate-CCWE_AkU.js → delegate-Rl-5paLJ.js} +2 -2
- package/dist/{delegate-CCWE_AkU.js.map → delegate-Rl-5paLJ.js.map} +1 -1
- package/dist/durable.d.ts +1 -1
- package/dist/durable.js +451 -358
- package/dist/durable.js.map +1 -1
- package/dist/{graph-CI9JXKqO.js → graph-Ce-59ZXn.js} +5 -5
- package/dist/{graph-CI9JXKqO.js.map → graph-Ce-59ZXn.js.map} +1 -1
- package/dist/{improve-BOXTLWJ3.js → improve-BZXt2qM0.js} +837 -704
- package/dist/improve-BZXt2qM0.js.map +1 -0
- package/dist/{improvement-adapter-HUt_-cWA.d.ts → improvement-adapter-sIthWkcN.d.ts} +2 -2
- package/dist/index.d.ts +6 -14
- package/dist/index.js +10 -10
- package/dist/intelligence.d.ts +4 -4
- package/dist/intelligence.js +205 -191
- package/dist/intelligence.js.map +1 -1
- package/dist/kernel.d.ts +3 -3
- package/dist/kernel.js +10 -10
- package/dist/{loop-runner-pmPIHFVY.js → loop-runner-B0MV1-CD.js} +2 -2
- package/dist/{loop-runner-pmPIHFVY.js.map → loop-runner-B0MV1-CD.js.map} +1 -1
- package/dist/{loop-runner-CWzG1bH4.d.ts → loop-runner-CuhbgVGo.d.ts} +3 -3
- package/dist/loop-runner-bin.d.ts +1 -1
- package/dist/loop-runner-bin.js +1 -1
- package/dist/mcp/bin.js +3 -3
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +5 -5
- package/dist/placement.d.ts +2 -26
- package/dist/placement.js +1 -35
- package/dist/placement.js.map +1 -1
- package/dist/{prepare-bXkvPMJA.js → prepare-C-cWCyt3.js} +988 -735
- package/dist/prepare-C-cWCyt3.js.map +1 -0
- package/dist/{profile-Dpei_Sq0.js → profile-CbMw5hAn.js} +2 -2
- package/dist/{profile-Dpei_Sq0.js.map → profile-CbMw5hAn.js.map} +1 -1
- package/dist/profile-materialization-bPm0gGLO.d.ts +49 -0
- package/dist/profiles.d.ts +1 -1
- package/dist/{protected-model-port-BGgpy2r9.d.ts → protected-model-port-DVVh-hEk.d.ts} +2 -6
- package/dist/{provision-supervisor-CJ6Zz6dz.js → provision-supervisor-DL6gEMQp.js} +444 -419
- package/dist/provision-supervisor-DL6gEMQp.js.map +1 -0
- package/dist/{runtime-B2fjL9Oi.js → runtime-eghmj6W4.js} +1245 -1028
- package/dist/runtime-eghmj6W4.js.map +1 -0
- package/dist/{sandbox-profile-compat-BzVBFqrz.js → sandbox-profile-compat-FN2kab2-.js} +72 -72
- package/dist/{sandbox-profile-compat-BzVBFqrz.js.map → sandbox-profile-compat-FN2kab2-.js.map} +1 -1
- package/dist/{search-executor-zMumiak_.js → search-executor-rbjdZ3OD.js} +3 -3
- package/dist/{search-executor-zMumiak_.js.map → search-executor-rbjdZ3OD.js.map} +1 -1
- package/dist/{server-_4voDNrl.js → server-BiK1Kcno.js} +4 -4
- package/dist/{server-_4voDNrl.js.map → server-BiK1Kcno.js.map} +1 -1
- package/dist/{structural-rollout-DpLCXzaL.js → structural-rollout-BD9IN7K_.js} +3 -3
- package/dist/{structural-rollout-DpLCXzaL.js.map → structural-rollout-BD9IN7K_.js.map} +1 -1
- package/dist/{supervise-qAwXmPtD.js → supervise-DmOi7gll.js} +6525 -5562
- package/dist/supervise-DmOi7gll.js.map +1 -0
- package/dist/{supervisor-DHrUJhEZ.js → supervisor-DUWcecAd.js} +13717 -12778
- package/dist/supervisor-DUWcecAd.js.map +1 -0
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +13 -13
- package/dist/tui/index.d.ts +1 -1
- package/dist/tui/index.js +1 -1
- package/dist/{types-CaOXqRTq.d.ts → types-Cgs89PQd.d.ts} +315 -409
- package/dist/{types-zWfqDjeL.d.ts → types-Cwrea-bU.d.ts} +2 -17
- package/dist/workspace-store/index.d.ts +1 -82
- package/dist/workspace-store/index.js +274 -680
- package/dist/workspace-store/index.js.map +1 -1
- package/package.json +8 -8
- package/dist/driver-control-acknowledgers-C53ggdJ6.js.map +0 -1
- package/dist/improve-BOXTLWJ3.js.map +0 -1
- package/dist/prepare-bXkvPMJA.js.map +0 -1
- package/dist/profile-materialization-B1wm2SPT.d.ts +0 -94
- package/dist/provision-supervisor-CJ6Zz6dz.js.map +0 -1
- package/dist/runtime-B2fjL9Oi.js.map +0 -1
- package/dist/supervise-qAwXmPtD.js.map +0 -1
- package/dist/supervisor-DHrUJhEZ.js.map +0 -1
package/dist/durable.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { i as publishExclusiveDurableFile, o as writeAtomicDurableFile } from "./durable-file-gNI9ILAn.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Hr as authoredProfileDigest, S as FileSpawnJournal, Si as contentAddress, ar as isFiniteNumber, at as loadSpawnForest, ir as failedItems, xi as detachedSnapshot } from "./supervisor-DUWcecAd.js";
|
|
3
3
|
import { f as RuntimeRunStateError, m as ValidationError } from "./errors-DodWX-cb.js";
|
|
4
4
|
import { t as isRecord } from "./record-value-B6bwJxLa.js";
|
|
5
|
-
import {
|
|
5
|
+
import { W as addSpend, X as errorMessage, ft as zeroSpend, q as cloneSpend } from "./sandbox-profile-compat-FN2kab2-.js";
|
|
6
6
|
import { a as withPursuitContext, t as composeRuntimeHooks } from "./runtime-hooks-tXpAarhW.js";
|
|
7
7
|
import { a as readCommittedJsonLines, n as isNoEntError, t as appendCommittedJsonLine } from "./jsonl-file-C9Kde_0Z.js";
|
|
8
|
-
import { J as readRootStreamReceipt, a as superviseRootProfile, q as readRootStream, t as supervise } from "./supervise-
|
|
9
|
-
import { a as applyExactAgentProfileDiff } from "./profile-
|
|
8
|
+
import { J as readRootStreamReceipt, a as superviseRootProfile, q as readRootStream, t as supervise } from "./supervise-DmOi7gll.js";
|
|
9
|
+
import { a as applyExactAgentProfileDiff } from "./profile-CbMw5hAn.js";
|
|
10
10
|
import { g as supervisorRunDir } from "./run-cancellation-C9oL62sW.js";
|
|
11
|
-
import { i as superviseAgentGraph } from "./graph-
|
|
11
|
+
import { i as superviseAgentGraph } from "./graph-Ce-59ZXn.js";
|
|
12
12
|
import { agentProfileSchema, canonicalAgentProfileDigest, canonicalCandidateDigest, canonicalCandidateJson, sha256Bytes } from "@tangle-network/agent-interface";
|
|
13
13
|
import { createHash } from "node:crypto";
|
|
14
14
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
@@ -1217,6 +1217,269 @@ function reviewPage(version, score, verdict) {
|
|
|
1217
1217
|
].join("\n");
|
|
1218
1218
|
}
|
|
1219
1219
|
//#endregion
|
|
1220
|
+
//#region src/durable/pursuit-version-run.ts
|
|
1221
|
+
/**
|
|
1222
|
+
* One pursuit version chain at run time: running a version in its directory, reading it back
|
|
1223
|
+
* and checking it is this node's run, judging it, turning it into the kernel's cell result, and
|
|
1224
|
+
* reading the chain back from its search ledger.
|
|
1225
|
+
*/
|
|
1226
|
+
/** The execution identity a version's node and cell record. */
|
|
1227
|
+
function versionExecutionIdentity(pursuitId, taskRevision, nodeProfile) {
|
|
1228
|
+
return {
|
|
1229
|
+
model: {
|
|
1230
|
+
provider: "agent-runtime",
|
|
1231
|
+
alias: "supervisePursuit",
|
|
1232
|
+
unknown: "a version runs every model its tree chose; the version's settle record names them"
|
|
1233
|
+
},
|
|
1234
|
+
agent: {
|
|
1235
|
+
uri: `agent-profile:${pursuitId}`,
|
|
1236
|
+
revision: canonicalAgentProfileDigest(nodeProfile)
|
|
1237
|
+
},
|
|
1238
|
+
benchmark: {
|
|
1239
|
+
uri: `pursuit:${pursuitId}`,
|
|
1240
|
+
revision: taskRevision
|
|
1241
|
+
}
|
|
1242
|
+
};
|
|
1243
|
+
}
|
|
1244
|
+
/** A version as the judge and `next` read it. */
|
|
1245
|
+
function versionOf(record, parent, settleDigest, result) {
|
|
1246
|
+
return Object.freeze({
|
|
1247
|
+
version: record.version,
|
|
1248
|
+
nodeId: record.nodeId,
|
|
1249
|
+
runId: record.runId,
|
|
1250
|
+
runDir: record.runDir,
|
|
1251
|
+
settleDigest,
|
|
1252
|
+
result,
|
|
1253
|
+
profile: record.profile,
|
|
1254
|
+
...parent?.seal === void 0 ? {} : { parent: {
|
|
1255
|
+
version: parent.version,
|
|
1256
|
+
runId: parent.runId,
|
|
1257
|
+
settleDigest: parent.seal.sha256
|
|
1258
|
+
} },
|
|
1259
|
+
...record.change === void 0 ? {} : { change: record.change }
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
function outcomeOf(settled, verdict) {
|
|
1263
|
+
if (verdict.score === null) return {
|
|
1264
|
+
status: "errored",
|
|
1265
|
+
metrics: {},
|
|
1266
|
+
error: {
|
|
1267
|
+
code: "unscored",
|
|
1268
|
+
message: `the judge could not score version ${settled.version}`,
|
|
1269
|
+
retryable: false
|
|
1270
|
+
}
|
|
1271
|
+
};
|
|
1272
|
+
if (settled.result.kind === "winner") return {
|
|
1273
|
+
status: "passed",
|
|
1274
|
+
score: verdict.score,
|
|
1275
|
+
metrics: {}
|
|
1276
|
+
};
|
|
1277
|
+
return {
|
|
1278
|
+
status: "failed",
|
|
1279
|
+
score: verdict.score,
|
|
1280
|
+
metrics: {},
|
|
1281
|
+
failure: {
|
|
1282
|
+
code: settled.result.reason,
|
|
1283
|
+
message: `version ${settled.version} settled without a winner: ${settled.result.reason}`
|
|
1284
|
+
}
|
|
1285
|
+
};
|
|
1286
|
+
}
|
|
1287
|
+
var VersionChainRun = class {
|
|
1288
|
+
ctx;
|
|
1289
|
+
sealed = /* @__PURE__ */ new Map();
|
|
1290
|
+
constructor(ctx) {
|
|
1291
|
+
this.ctx = ctx;
|
|
1292
|
+
}
|
|
1293
|
+
/** Run a version if its directory holds no settle record, read it back, and judge it. */
|
|
1294
|
+
async runCell(work) {
|
|
1295
|
+
const chain = await this.versionsOf();
|
|
1296
|
+
const record = chain.get(work.nodeId);
|
|
1297
|
+
if (record?.profile == null) throw new RuntimeRunStateError(`version node ${work.nodeId} has no profile to run`);
|
|
1298
|
+
const parent = record.parentNodeId === null ? void 0 : chain.get(record.parentNodeId);
|
|
1299
|
+
if (parent !== void 0 && (parent.seal === void 0 || parent.profile === null)) throw new RuntimeRunStateError(`version ${record.version}'s parent has no sealed result`);
|
|
1300
|
+
if (await readSettleRecord(record.runDir) === void 0) {
|
|
1301
|
+
const signal = AbortSignal.any([work.signal, this.ctx.expired]);
|
|
1302
|
+
if (signal.aborted) throw new RuntimeRunStateError(`supervisePursuit versions: version ${record.version} was not started: ${errorMessage(signal.reason)}`);
|
|
1303
|
+
await this.runVersion(record, parent, signal);
|
|
1304
|
+
}
|
|
1305
|
+
const { settled, byteLength } = await this.readVersion(record, parent);
|
|
1306
|
+
const verdict = await this.judgeVersion(settled, work.signal);
|
|
1307
|
+
return this.cellResult(settled, byteLength, verdict, work.lane);
|
|
1308
|
+
}
|
|
1309
|
+
/** Run one version: the first as the call's own run, a later one as a fork of its parent. */
|
|
1310
|
+
async runVersion(record, parent, signal) {
|
|
1311
|
+
const { profile, task, base, firstFork, runOne } = this.ctx;
|
|
1312
|
+
if (parent === void 0 || record.change === void 0) {
|
|
1313
|
+
await runOne(profile, task, {
|
|
1314
|
+
...base,
|
|
1315
|
+
runId: record.runId,
|
|
1316
|
+
runDir: record.runDir,
|
|
1317
|
+
...firstFork === void 0 ? {} : { fork: firstFork },
|
|
1318
|
+
signal
|
|
1319
|
+
});
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
const fork = {
|
|
1323
|
+
runDir: parent.runDir,
|
|
1324
|
+
settleDigest: parent.seal.sha256,
|
|
1325
|
+
change: record.change,
|
|
1326
|
+
acceptUncertain: true
|
|
1327
|
+
};
|
|
1328
|
+
const check = parent.verdict?.check;
|
|
1329
|
+
await runOne(parent.profile, task, {
|
|
1330
|
+
...base,
|
|
1331
|
+
...base.continuation !== void 0 && check !== void 0 ? { continuation: {
|
|
1332
|
+
...base.continuation,
|
|
1333
|
+
best: {
|
|
1334
|
+
label: `v${parent.version}`,
|
|
1335
|
+
verdict: check
|
|
1336
|
+
}
|
|
1337
|
+
} } : {},
|
|
1338
|
+
runId: record.runId,
|
|
1339
|
+
runDir: record.runDir,
|
|
1340
|
+
fork,
|
|
1341
|
+
signal
|
|
1342
|
+
});
|
|
1343
|
+
}
|
|
1344
|
+
/**
|
|
1345
|
+
* Read a settled version back and check it is this node's run: its root ran the node's profile
|
|
1346
|
+
* and, for a fork, recorded the parent's seal and the change. A directory that holds another
|
|
1347
|
+
* run is refused, never adopted.
|
|
1348
|
+
*/
|
|
1349
|
+
async readVersion(record, parent) {
|
|
1350
|
+
const { base, firstFork, taskRevision } = this.ctx;
|
|
1351
|
+
const { bytes, result } = await readSealed(record.runDir, record.version);
|
|
1352
|
+
if (result.tree.root !== record.runId) throw new RuntimeRunStateError(`supervisePursuit versions: ${record.runDir} holds run '${result.tree.root}', not version ${record.version}'s '${record.runId}'`);
|
|
1353
|
+
const root = (await new FileSpawnJournal(resolve(record.runDir, "spawn-journal.jsonl")).loadTree(record.runId))?.find((event) => event.kind === "spawned" && event.parent === void 0);
|
|
1354
|
+
const ran = root?.identity?.profileDigest;
|
|
1355
|
+
const expected = authoredProfileDigest(superviseRootProfile(record.profile, base.profileGuidance));
|
|
1356
|
+
const ranTask = root?.identity?.taskDigest;
|
|
1357
|
+
const correlation = root?.identity?.correlation;
|
|
1358
|
+
const fork = parent !== void 0 ? {
|
|
1359
|
+
settleDigest: parent.seal?.sha256,
|
|
1360
|
+
changeId: record.change?.id
|
|
1361
|
+
} : firstFork === void 0 ? void 0 : {
|
|
1362
|
+
settleDigest: firstFork.settleDigest,
|
|
1363
|
+
changeId: firstFork.change.id
|
|
1364
|
+
};
|
|
1365
|
+
const mismatch = [
|
|
1366
|
+
ran !== expected ? `its root ran profile ${ran}, not ${expected}` : void 0,
|
|
1367
|
+
ranTask !== taskRevision ? `its root ran task ${ranTask}, not ${taskRevision}` : void 0,
|
|
1368
|
+
contentAddress(root?.budget) !== contentAddress(base.budget) ? "its root ran under another budget" : void 0,
|
|
1369
|
+
fork !== void 0 && correlation?.forkParentSettleDigest !== fork.settleDigest ? `its root forked from seal ${correlation?.forkParentSettleDigest}, not ${fork.settleDigest}` : void 0,
|
|
1370
|
+
fork !== void 0 && correlation?.forkProfileDiffId !== fork.changeId ? `its root applied change ${correlation?.forkProfileDiffId}, not ${fork.changeId}` : void 0
|
|
1371
|
+
].filter((item) => item !== void 0);
|
|
1372
|
+
if (mismatch.length > 0) throw new RuntimeRunStateError(`supervisePursuit versions: version ${record.version} at ${record.runDir} is not this chain's run: ${mismatch.join("; ")}`);
|
|
1373
|
+
const settled = versionOf(record, parent, sha256Bytes(bytes), result);
|
|
1374
|
+
this.sealed.set(settled.settleDigest, result);
|
|
1375
|
+
return {
|
|
1376
|
+
settled,
|
|
1377
|
+
byteLength: bytes.byteLength
|
|
1378
|
+
};
|
|
1379
|
+
}
|
|
1380
|
+
async judgeVersion(settled, signal) {
|
|
1381
|
+
const { judge } = this.ctx;
|
|
1382
|
+
const verdict = await judge.judge(settled, signal);
|
|
1383
|
+
if (typeof verdict !== "object" || verdict === null) throw new ValidationError("supervisePursuit versions: the judge returned no verdict");
|
|
1384
|
+
if (verdict.judgeDigest !== judge.digest) throw new ValidationError(`supervisePursuit versions: the verdict for version ${settled.version} carries ${String(verdict.judgeDigest)}, not the pinned judge ${judge.digest}`);
|
|
1385
|
+
if (verdict.score !== null && !isFiniteNumber(verdict.score)) throw new ValidationError("supervisePursuit versions: a verdict score must be a finite number or null");
|
|
1386
|
+
return JSON.parse(JSON.stringify(verdict));
|
|
1387
|
+
}
|
|
1388
|
+
cellResult(settled, byteLength, verdict, lane) {
|
|
1389
|
+
const spent = settled.result.spentTotal;
|
|
1390
|
+
const settlePath = resolve(settled.runDir, SETTLE_RECORD_FILE);
|
|
1391
|
+
return {
|
|
1392
|
+
outcome: outcomeOf(settled, verdict),
|
|
1393
|
+
accounting: versionAccounting(spent),
|
|
1394
|
+
identity: versionExecutionIdentity(this.ctx.pursuitId, this.ctx.taskRevision, settled.profile),
|
|
1395
|
+
boxMinutes: isFiniteNumber(spent.boxMinutes) && spent.boxMinutesKnown !== false ? spent.boxMinutes : null,
|
|
1396
|
+
wallMs: isFiniteNumber(spent.ms) ? Math.max(0, Math.round(spent.ms)) : null,
|
|
1397
|
+
placement: {
|
|
1398
|
+
lane,
|
|
1399
|
+
boxId: null
|
|
1400
|
+
},
|
|
1401
|
+
traceRef: { unknown: `version ${settled.version} is run ${settled.runId}; the chain records no trace id` },
|
|
1402
|
+
artifacts: [{
|
|
1403
|
+
role: "settle-record",
|
|
1404
|
+
uri: pathToFileURL(settlePath).href,
|
|
1405
|
+
sha256: settled.settleDigest,
|
|
1406
|
+
byteLength
|
|
1407
|
+
}, this.ctx.recorder.blob("verdict", {
|
|
1408
|
+
kind: "version-verdict",
|
|
1409
|
+
version: settled.version,
|
|
1410
|
+
runId: settled.runId,
|
|
1411
|
+
verdict
|
|
1412
|
+
})]
|
|
1413
|
+
};
|
|
1414
|
+
}
|
|
1415
|
+
/** Every version whose latest settled cell carries a verdict, first first, each read back from
|
|
1416
|
+
* its sealed `result.json`. */
|
|
1417
|
+
async judgedVersions(chain) {
|
|
1418
|
+
const judged = [];
|
|
1419
|
+
for (const record of chain.values()) {
|
|
1420
|
+
if (record.seal === void 0 || record.verdict === void 0) continue;
|
|
1421
|
+
const seal = record.seal.sha256;
|
|
1422
|
+
let result = this.sealed.get(seal);
|
|
1423
|
+
if (result === void 0) {
|
|
1424
|
+
const read = await readSealed(record.runDir, record.version);
|
|
1425
|
+
if (sha256Bytes(read.bytes) !== seal) throw new RuntimeRunStateError(`supervisePursuit versions: version ${record.version}'s result.json changed after it was judged`);
|
|
1426
|
+
result = read.result;
|
|
1427
|
+
this.sealed.set(seal, result);
|
|
1428
|
+
}
|
|
1429
|
+
const parent = record.parentNodeId === null ? void 0 : chain.get(record.parentNodeId);
|
|
1430
|
+
judged.push(Object.freeze({
|
|
1431
|
+
...versionOf(record, parent, seal, result),
|
|
1432
|
+
verdict: record.verdict
|
|
1433
|
+
}));
|
|
1434
|
+
}
|
|
1435
|
+
return judged;
|
|
1436
|
+
}
|
|
1437
|
+
/**
|
|
1438
|
+
* Every node of the chain, in registration order, from the ledger. The state holds cells, not
|
|
1439
|
+
* their events' artifacts, so each cell's seal and verdict are read from the ledger lines the
|
|
1440
|
+
* state verified, through Eval's own line parser.
|
|
1441
|
+
*/
|
|
1442
|
+
async versionsOf() {
|
|
1443
|
+
const { recorder, ledgerPath, searchId, runDir, runId } = this.ctx;
|
|
1444
|
+
const state = await recorder.state();
|
|
1445
|
+
const head = state.head?.sequence ?? -1;
|
|
1446
|
+
const nodes = state.nodes().map((node) => ({
|
|
1447
|
+
node,
|
|
1448
|
+
cellId: state.cells({ nodeId: node.nodeId })[0]?.cellId,
|
|
1449
|
+
diff: node.edgeIds[0] === void 0 ? void 0 : state.edge(node.edgeIds[0])?.diffs[0]
|
|
1450
|
+
}));
|
|
1451
|
+
const settledCells = /* @__PURE__ */ new Map();
|
|
1452
|
+
const text = await readFile(ledgerPath, "utf8");
|
|
1453
|
+
for (const [index, line] of text.split("\n").entries()) {
|
|
1454
|
+
if (line.length === 0) continue;
|
|
1455
|
+
const entry = parseSearchLedgerLine(line, searchId, {
|
|
1456
|
+
path: ledgerPath,
|
|
1457
|
+
line: index + 1
|
|
1458
|
+
});
|
|
1459
|
+
if (entry.sequence > head) break;
|
|
1460
|
+
if (entry.event.kind === "cell-settled") settledCells.set(entry.event.cellId, entry.event);
|
|
1461
|
+
}
|
|
1462
|
+
const chain = /* @__PURE__ */ new Map();
|
|
1463
|
+
for (const { node, cellId, diff } of nodes) {
|
|
1464
|
+
const settled = cellId === void 0 ? void 0 : settledCells.get(cellId);
|
|
1465
|
+
const artifact = (role) => settled?.artifacts.find((candidate) => candidate.role === role);
|
|
1466
|
+
const seal = artifact("settle-record");
|
|
1467
|
+
const verdict = artifact("verdict");
|
|
1468
|
+
chain.set(node.nodeId, {
|
|
1469
|
+
nodeId: node.nodeId,
|
|
1470
|
+
version: node.ordinal + 1,
|
|
1471
|
+
...versionRun(runDir, runId, node.ordinal + 1),
|
|
1472
|
+
profile: loadNode(recorder, node).profile,
|
|
1473
|
+
parentNodeId: node.primaryParentId,
|
|
1474
|
+
...diff === void 0 || "unknown" in diff ? {} : { change: recorder.readBlob(diff).diffs[0] },
|
|
1475
|
+
...seal === void 0 ? {} : { seal },
|
|
1476
|
+
...verdict === void 0 ? {} : { verdict: recorder.readBlob(verdict).verdict }
|
|
1477
|
+
});
|
|
1478
|
+
}
|
|
1479
|
+
return chain;
|
|
1480
|
+
}
|
|
1481
|
+
};
|
|
1482
|
+
//#endregion
|
|
1220
1483
|
//#region src/durable/pursuit-versions.ts
|
|
1221
1484
|
/**
|
|
1222
1485
|
* The pursuit version chain, on Eval's search kernel (`runSearch`).
|
|
@@ -1287,9 +1550,8 @@ const MAX_TIMER_MS = 2147483647;
|
|
|
1287
1550
|
/** 9999-12-31T23:59:59.999Z: the latest instant the ledger's four-digit-year timestamps hold, so
|
|
1288
1551
|
* a deadline such as `Number.MAX_SAFE_INTEGER` means no deadline rather than an invalid date. */
|
|
1289
1552
|
const LATEST_DEADLINE_MS = 0xe677d21fdbff;
|
|
1290
|
-
/**
|
|
1291
|
-
|
|
1292
|
-
const { versions, fork: firstFork, signal: callerSignal, ...base } = opts;
|
|
1553
|
+
/** Refuse a chain call that no version could satisfy, before any compute. */
|
|
1554
|
+
function assertChainCall(versions, base) {
|
|
1293
1555
|
assertPursuitVersions(versions);
|
|
1294
1556
|
for (const key of [
|
|
1295
1557
|
"journal",
|
|
@@ -1298,8 +1560,14 @@ async function runPursuitVersions(profile, task, opts, runOne) {
|
|
|
1298
1560
|
"steerDir"
|
|
1299
1561
|
]) if (base[key] !== void 0) throw new ValidationError(`supervisePursuit versions: ${key} names one run, and a version chain has one per version; omit it`);
|
|
1300
1562
|
if (versions.next === "review-of-best" && base.continuation?.profile.review === void 0) throw new ValidationError("supervisePursuit versions: next 'review-of-best' needs continuation.profile.review, the words the next version reads about its review");
|
|
1301
|
-
const {
|
|
1563
|
+
const { stop } = versions;
|
|
1302
1564
|
if (base.budget.maxUsd !== void 0 && base.budget.maxUsd > stop.maxUsd) throw new ValidationError(`supervisePursuit versions: budget.maxUsd ${base.budget.maxUsd} is above stop.maxUsd ${stop.maxUsd}, so no version could start`);
|
|
1565
|
+
}
|
|
1566
|
+
/** Run a version chain. `supervisePursuit` calls this when `versions` is set. */
|
|
1567
|
+
async function runPursuitVersions(profile, task, opts, runOne) {
|
|
1568
|
+
const { versions, fork: firstFork, signal: callerSignal, ...base } = opts;
|
|
1569
|
+
assertChainCall(versions, base);
|
|
1570
|
+
const { judge, stop } = versions;
|
|
1303
1571
|
const next = versions.next === "review-of-best" ? reviewOfBest(base.runId ?? "supervise", base.continuation?.profile.review ?? "") : versions.next;
|
|
1304
1572
|
const now = base.now ?? Date.now;
|
|
1305
1573
|
const pursuitId = base.pursuitId.trim();
|
|
@@ -1311,33 +1579,98 @@ async function runPursuitVersions(profile, task, opts, runOne) {
|
|
|
1311
1579
|
if (await exists(retired)) throw new ValidationError(`supervisePursuit versions: ${retired} holds a chain in the retired versions.jsonl format; finish it on the agent-runtime release that wrote it, or start a new chain in another runDir`);
|
|
1312
1580
|
const firstProfile = jsonProfile(firstFork === void 0 ? profile : applyExactAgentProfileDiff(profile, firstFork.change, "supervisePursuit versions"));
|
|
1313
1581
|
const taskRevision = pursuitValueDigest(task, "task");
|
|
1314
|
-
const identity = (nodeProfile) => ({
|
|
1315
|
-
model: {
|
|
1316
|
-
provider: "agent-runtime",
|
|
1317
|
-
alias: "supervisePursuit",
|
|
1318
|
-
unknown: "a version runs every model its tree chose; the version's settle record names them"
|
|
1319
|
-
},
|
|
1320
|
-
agent: {
|
|
1321
|
-
uri: `agent-profile:${pursuitId}`,
|
|
1322
|
-
revision: canonicalAgentProfileDigest(nodeProfile)
|
|
1323
|
-
},
|
|
1324
|
-
benchmark: {
|
|
1325
|
-
uri: `pursuit:${pursuitId}`,
|
|
1326
|
-
revision: taskRevision
|
|
1327
|
-
}
|
|
1328
|
-
});
|
|
1329
1582
|
const ledger = openSearchLedger({
|
|
1330
1583
|
path: ledgerPath,
|
|
1331
1584
|
searchId
|
|
1332
1585
|
});
|
|
1333
|
-
const deadline = (await ledger.state()).header
|
|
1334
|
-
const failureLimit = stop.identicalFailures ?? DEFAULT_IDENTICAL_FAILURES;
|
|
1586
|
+
const deadline = await chainDeadline((await ledger.state()).header, now, runDir, stop);
|
|
1335
1587
|
const policy = incumbent({
|
|
1336
1588
|
patience: stop.patience,
|
|
1337
1589
|
...stop.minImprovement === void 0 ? {} : { minImprovement: stop.minImprovement }
|
|
1338
1590
|
});
|
|
1339
1591
|
const allocation = uniform();
|
|
1340
|
-
const recorder = await
|
|
1592
|
+
const recorder = await openVersionRecorder({
|
|
1593
|
+
ledger,
|
|
1594
|
+
now,
|
|
1595
|
+
pursuitId,
|
|
1596
|
+
taskRevision,
|
|
1597
|
+
judge,
|
|
1598
|
+
stop,
|
|
1599
|
+
policy,
|
|
1600
|
+
allocation,
|
|
1601
|
+
deadline,
|
|
1602
|
+
firstProfile
|
|
1603
|
+
});
|
|
1604
|
+
const clock = armChainDeadline(deadline, now);
|
|
1605
|
+
const chain = new VersionChainRun({
|
|
1606
|
+
profile,
|
|
1607
|
+
task,
|
|
1608
|
+
base,
|
|
1609
|
+
firstFork,
|
|
1610
|
+
runOne,
|
|
1611
|
+
judge,
|
|
1612
|
+
recorder,
|
|
1613
|
+
expired: clock.signal,
|
|
1614
|
+
pursuitId,
|
|
1615
|
+
runDir,
|
|
1616
|
+
runId,
|
|
1617
|
+
ledgerPath,
|
|
1618
|
+
searchId,
|
|
1619
|
+
taskRevision
|
|
1620
|
+
});
|
|
1621
|
+
const failureLimit = stop.identicalFailures ?? DEFAULT_IDENTICAL_FAILURES;
|
|
1622
|
+
try {
|
|
1623
|
+
const closed = await runSearch({
|
|
1624
|
+
recorder,
|
|
1625
|
+
root: {
|
|
1626
|
+
profile: firstProfile,
|
|
1627
|
+
refusal: null
|
|
1628
|
+
},
|
|
1629
|
+
codec: versionCodec,
|
|
1630
|
+
policy,
|
|
1631
|
+
allocation,
|
|
1632
|
+
proposer: versionProposer(versions.next, next, chain, failureLimit),
|
|
1633
|
+
executor: versionExecutor(chain, base.budget.maxUsd),
|
|
1634
|
+
admit: (node) => node.refusal,
|
|
1635
|
+
...callerSignal === void 0 ? {} : { signal: callerSignal },
|
|
1636
|
+
now
|
|
1637
|
+
});
|
|
1638
|
+
const judged = await chain.judgedVersions(await chain.versionsOf());
|
|
1639
|
+
const failed = closed.reason === "converged" ? identicalFailureStreak(judged, failureLimit) : null;
|
|
1640
|
+
const stopped = failed === null ? null : {
|
|
1641
|
+
versions: failureLimit,
|
|
1642
|
+
failure: failed
|
|
1643
|
+
};
|
|
1644
|
+
const best = judged.find((version) => version.nodeId === closed.leader);
|
|
1645
|
+
if (best === void 0) throw new RuntimeRunStateError(`supervisePursuit versions: the chain in ${ledgerPath} closed (${closed.reason}) without a judged version to keep`);
|
|
1646
|
+
const observerPath = resolve(best.runDir, "observer.jsonl");
|
|
1647
|
+
return Object.freeze({
|
|
1648
|
+
result: best.result,
|
|
1649
|
+
pursuit: projectPursuit(await new FileObserverJournal(observerPath, pursuitId).read()),
|
|
1650
|
+
observerPath,
|
|
1651
|
+
settlePath: resolve(best.runDir, SETTLE_RECORD_FILE),
|
|
1652
|
+
versions: Object.freeze({
|
|
1653
|
+
ledgerPath,
|
|
1654
|
+
searchId,
|
|
1655
|
+
reason: closed.reason,
|
|
1656
|
+
...stopped === null ? {} : { identicalFailures: stopped },
|
|
1657
|
+
best: best.version,
|
|
1658
|
+
versions: Object.freeze(judged),
|
|
1659
|
+
spend: closed.state.audit.spend,
|
|
1660
|
+
receipt: recorder.receipt({
|
|
1661
|
+
producerId: "pursuit-versions",
|
|
1662
|
+
runId
|
|
1663
|
+
})
|
|
1664
|
+
})
|
|
1665
|
+
});
|
|
1666
|
+
} finally {
|
|
1667
|
+
clock.cancel();
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
/** Open the chain's search recorder: its subject, process revision, splits, policy and budget. */
|
|
1671
|
+
function openVersionRecorder(input) {
|
|
1672
|
+
const { ledger, now, pursuitId, taskRevision, judge, stop, policy, allocation, deadline } = input;
|
|
1673
|
+
return SearchRecorder.open({
|
|
1341
1674
|
ledger,
|
|
1342
1675
|
now
|
|
1343
1676
|
}, {
|
|
@@ -1390,8 +1723,21 @@ async function runPursuitVersions(profile, task, opts, runOne) {
|
|
|
1390
1723
|
},
|
|
1391
1724
|
containment: null,
|
|
1392
1725
|
derivedFrom: null,
|
|
1393
|
-
identity:
|
|
1726
|
+
identity: versionExecutionIdentity(pursuitId, taskRevision, input.firstProfile)
|
|
1394
1727
|
});
|
|
1728
|
+
}
|
|
1729
|
+
/**
|
|
1730
|
+
* The chain's clock starts with its first version, or when the chain opened on a first version
|
|
1731
|
+
* that had already settled. A resumed chain keeps the deadline its ledger recorded.
|
|
1732
|
+
*/
|
|
1733
|
+
async function chainDeadline(opened, now, runDir, stop) {
|
|
1734
|
+
return opened?.budget.deadline ?? new Date(Math.min(now() - settledElapsed(await readSettleRecord(runDir)) + stop.deadlineMs, LATEST_DEADLINE_MS)).toISOString();
|
|
1735
|
+
}
|
|
1736
|
+
/**
|
|
1737
|
+
* The chain's deadline aborts a running version. A timer longer than 2^31 - 1 ms fires at once
|
|
1738
|
+
* in Node, so a long chain re-arms in steps.
|
|
1739
|
+
*/
|
|
1740
|
+
function armChainDeadline(deadline, now) {
|
|
1395
1741
|
const deadlineAt = Date.parse(deadline);
|
|
1396
1742
|
const expired = new AbortController();
|
|
1397
1743
|
let timer;
|
|
@@ -1405,35 +1751,22 @@ async function runPursuitVersions(profile, task, opts, runOne) {
|
|
|
1405
1751
|
timer.unref?.();
|
|
1406
1752
|
};
|
|
1407
1753
|
arm();
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
if (
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
kind: "agent-profile",
|
|
1422
|
-
artifact
|
|
1423
|
-
}]
|
|
1424
|
-
};
|
|
1425
|
-
}
|
|
1426
|
-
const refused = {
|
|
1427
|
-
kind: "unapplied-change",
|
|
1428
|
-
parentDigest: node.parentDigest ?? null,
|
|
1429
|
-
change: node.change ?? null
|
|
1430
|
-
};
|
|
1431
|
-
const artifact = store.blob("change", {
|
|
1432
|
-
...refused,
|
|
1433
|
-
refusal: node.refusal
|
|
1754
|
+
return {
|
|
1755
|
+
signal: expired.signal,
|
|
1756
|
+
cancel() {
|
|
1757
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
1758
|
+
}
|
|
1759
|
+
};
|
|
1760
|
+
}
|
|
1761
|
+
const versionCodec = {
|
|
1762
|
+
node(store, node) {
|
|
1763
|
+
if (node.profile !== null) {
|
|
1764
|
+
const artifact = store.blob("agent-profile", {
|
|
1765
|
+
kind: "agent-profile",
|
|
1766
|
+
profile: node.profile
|
|
1434
1767
|
});
|
|
1435
1768
|
return {
|
|
1436
|
-
artifactDigest:
|
|
1769
|
+
artifactDigest: canonicalAgentProfileDigest(node.profile),
|
|
1437
1770
|
artifact,
|
|
1438
1771
|
surfaces: [{
|
|
1439
1772
|
surfaceId: "profile",
|
|
@@ -1441,24 +1774,44 @@ async function runPursuitVersions(profile, task, opts, runOne) {
|
|
|
1441
1774
|
artifact
|
|
1442
1775
|
}]
|
|
1443
1776
|
};
|
|
1444
|
-
},
|
|
1445
|
-
diff(store, parent, child) {
|
|
1446
|
-
if (parent.profile === null || child.profile === null || child.change === void 0) return { unknown: "a refused change has no profile to diff" };
|
|
1447
|
-
const from = canonicalAgentProfileDigest(parent.profile);
|
|
1448
|
-
if (child.parentDigest !== from) return { unknown: "the change was written against another parent" };
|
|
1449
|
-
return store.blob("diff", {
|
|
1450
|
-
kind: "agent-profile-diff",
|
|
1451
|
-
from,
|
|
1452
|
-
to: canonicalAgentProfileDigest(child.profile),
|
|
1453
|
-
diffs: [child.change]
|
|
1454
|
-
});
|
|
1455
|
-
},
|
|
1456
|
-
load(store, node) {
|
|
1457
|
-
return loadNode(store, node);
|
|
1458
1777
|
}
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1778
|
+
const refused = {
|
|
1779
|
+
kind: "unapplied-change",
|
|
1780
|
+
parentDigest: node.parentDigest ?? null,
|
|
1781
|
+
change: node.change ?? null
|
|
1782
|
+
};
|
|
1783
|
+
const artifact = store.blob("change", {
|
|
1784
|
+
...refused,
|
|
1785
|
+
refusal: node.refusal
|
|
1786
|
+
});
|
|
1787
|
+
return {
|
|
1788
|
+
artifactDigest: canonicalCandidateDigest(refused),
|
|
1789
|
+
artifact,
|
|
1790
|
+
surfaces: [{
|
|
1791
|
+
surfaceId: "profile",
|
|
1792
|
+
kind: "agent-profile",
|
|
1793
|
+
artifact
|
|
1794
|
+
}]
|
|
1795
|
+
};
|
|
1796
|
+
},
|
|
1797
|
+
diff(store, parent, child) {
|
|
1798
|
+
if (parent.profile === null || child.profile === null || child.change === void 0) return { unknown: "a refused change has no profile to diff" };
|
|
1799
|
+
const from = canonicalAgentProfileDigest(parent.profile);
|
|
1800
|
+
if (child.parentDigest !== from) return { unknown: "the change was written against another parent" };
|
|
1801
|
+
return store.blob("diff", {
|
|
1802
|
+
kind: "agent-profile-diff",
|
|
1803
|
+
from,
|
|
1804
|
+
to: canonicalAgentProfileDigest(child.profile),
|
|
1805
|
+
diffs: [child.change]
|
|
1806
|
+
});
|
|
1807
|
+
},
|
|
1808
|
+
load(store, node) {
|
|
1809
|
+
return loadNode(store, node);
|
|
1810
|
+
}
|
|
1811
|
+
};
|
|
1812
|
+
function versionExecutor(chain, maxUsd) {
|
|
1813
|
+
return {
|
|
1814
|
+
lanes: () => [maxUsd === void 0 ? {
|
|
1462
1815
|
name: LANE,
|
|
1463
1816
|
capacity: 1,
|
|
1464
1817
|
costCap: "estimate",
|
|
@@ -1467,31 +1820,22 @@ async function runPursuitVersions(profile, task, opts, runOne) {
|
|
|
1467
1820
|
name: LANE,
|
|
1468
1821
|
capacity: 1,
|
|
1469
1822
|
costCap: "hard",
|
|
1470
|
-
cellUsd:
|
|
1823
|
+
cellUsd: maxUsd
|
|
1471
1824
|
}],
|
|
1472
1825
|
place: () => LANE,
|
|
1473
1826
|
adopt: async () => null,
|
|
1474
|
-
|
|
1475
|
-
const chain = await versionsOf();
|
|
1476
|
-
const record = chain.get(work.nodeId);
|
|
1477
|
-
if (record?.profile == null) throw new RuntimeRunStateError(`version node ${work.nodeId} has no profile to run`);
|
|
1478
|
-
const parent = record.parentNodeId === null ? void 0 : chain.get(record.parentNodeId);
|
|
1479
|
-
if (parent !== void 0 && (parent.seal === void 0 || parent.profile === null)) throw new RuntimeRunStateError(`version ${record.version}'s parent has no sealed result`);
|
|
1480
|
-
if (await readSettleRecord(record.runDir) === void 0) {
|
|
1481
|
-
const signal = AbortSignal.any([work.signal, expired.signal]);
|
|
1482
|
-
if (signal.aborted) throw new RuntimeRunStateError(`supervisePursuit versions: version ${record.version} was not started: ${errorMessage(signal.reason)}`);
|
|
1483
|
-
await runVersion(record, parent, signal);
|
|
1484
|
-
}
|
|
1485
|
-
const { settled, byteLength } = await readVersion(record, parent);
|
|
1486
|
-
return cellResult(settled, byteLength, await judgeVersion(settled, work.signal), work.lane);
|
|
1487
|
-
}
|
|
1827
|
+
run: (work) => chain.runCell(work)
|
|
1488
1828
|
};
|
|
1829
|
+
}
|
|
1830
|
+
/** The proposer: the caller's `next` (or the review of the kept version) as the one edge. */
|
|
1831
|
+
function versionProposer(nextOption, next, chain, failureLimit) {
|
|
1832
|
+
const reviewing = nextOption === "review-of-best";
|
|
1489
1833
|
const proposerSource = {
|
|
1490
|
-
uri:
|
|
1491
|
-
revision: canonicalCandidateDigest({ next:
|
|
1834
|
+
uri: reviewing ? `${VERSION_CHAIN_URI}.review-of-best` : `${VERSION_CHAIN_URI}.next`,
|
|
1835
|
+
revision: canonicalCandidateDigest({ next: reviewing ? "review-of-best" : Function.prototype.toString.call(nextOption) })
|
|
1492
1836
|
};
|
|
1493
|
-
|
|
1494
|
-
name:
|
|
1837
|
+
return {
|
|
1838
|
+
name: reviewing ? "review-of-best" : "next",
|
|
1495
1839
|
kind: "optimizer",
|
|
1496
1840
|
source: proposerSource,
|
|
1497
1841
|
execution: {
|
|
@@ -1501,7 +1845,7 @@ async function runPursuitVersions(profile, task, opts, runOne) {
|
|
|
1501
1845
|
childrenPerProposal: 1,
|
|
1502
1846
|
async propose(request) {
|
|
1503
1847
|
const parent = request.parents[0];
|
|
1504
|
-
const judged = await judgedVersions(await versionsOf());
|
|
1848
|
+
const judged = await chain.judgedVersions(await chain.versionsOf());
|
|
1505
1849
|
const failure = identicalFailureStreak(judged, failureLimit);
|
|
1506
1850
|
if (failure !== null) return {
|
|
1507
1851
|
children: [],
|
|
@@ -1517,30 +1861,13 @@ async function runPursuitVersions(profile, task, opts, runOne) {
|
|
|
1517
1861
|
}, request.signal);
|
|
1518
1862
|
if (typeof returned?.id !== "string" || returned.id.trim().length === 0) throw new ValidationError("supervisePursuit versions: next must return a change with an id");
|
|
1519
1863
|
const change = JSON.parse(JSON.stringify(returned));
|
|
1520
|
-
const parentDigest = canonicalAgentProfileDigest(parent.artifact.profile);
|
|
1521
|
-
let child;
|
|
1522
|
-
try {
|
|
1523
|
-
child = {
|
|
1524
|
-
profile: applyExactAgentProfileDiff(parent.artifact.profile, change, "supervisePursuit versions"),
|
|
1525
|
-
change,
|
|
1526
|
-
parentDigest,
|
|
1527
|
-
refusal: null
|
|
1528
|
-
};
|
|
1529
|
-
} catch (error) {
|
|
1530
|
-
child = {
|
|
1531
|
-
profile: null,
|
|
1532
|
-
change,
|
|
1533
|
-
parentDigest,
|
|
1534
|
-
refusal: errorMessage(error)
|
|
1535
|
-
};
|
|
1536
|
-
}
|
|
1537
1864
|
return {
|
|
1538
1865
|
children: [{
|
|
1539
|
-
artifact:
|
|
1866
|
+
artifact: childNode(parent.artifact.profile, change),
|
|
1540
1867
|
label: change.title ?? returned.id,
|
|
1541
1868
|
rationale: (change.source?.notes ?? []).join("\n")
|
|
1542
1869
|
}],
|
|
1543
|
-
accounting:
|
|
1870
|
+
accounting: reviewing ? FREE : {
|
|
1544
1871
|
tokens: {
|
|
1545
1872
|
status: "unknown",
|
|
1546
1873
|
reason: "the caller's next reports no usage"
|
|
@@ -1554,259 +1881,25 @@ async function runPursuitVersions(profile, task, opts, runOne) {
|
|
|
1554
1881
|
};
|
|
1555
1882
|
}
|
|
1556
1883
|
};
|
|
1884
|
+
}
|
|
1885
|
+
/** The node a change makes, or the refused node when it does not apply to the parent. */
|
|
1886
|
+
function childNode(parentProfile, change) {
|
|
1887
|
+
const parentDigest = canonicalAgentProfileDigest(parentProfile);
|
|
1557
1888
|
try {
|
|
1558
|
-
const closed = await runSearch({
|
|
1559
|
-
recorder,
|
|
1560
|
-
root: {
|
|
1561
|
-
profile: firstProfile,
|
|
1562
|
-
refusal: null
|
|
1563
|
-
},
|
|
1564
|
-
codec,
|
|
1565
|
-
policy,
|
|
1566
|
-
allocation,
|
|
1567
|
-
proposer,
|
|
1568
|
-
executor,
|
|
1569
|
-
admit: (node) => node.refusal,
|
|
1570
|
-
...callerSignal === void 0 ? {} : { signal: callerSignal },
|
|
1571
|
-
now
|
|
1572
|
-
});
|
|
1573
|
-
const judged = await judgedVersions(await versionsOf());
|
|
1574
|
-
const failed = closed.reason === "converged" ? identicalFailureStreak(judged, failureLimit) : null;
|
|
1575
|
-
const stopped = failed === null ? null : {
|
|
1576
|
-
versions: failureLimit,
|
|
1577
|
-
failure: failed
|
|
1578
|
-
};
|
|
1579
|
-
const best = judged.find((version) => version.nodeId === closed.leader);
|
|
1580
|
-
if (best === void 0) throw new RuntimeRunStateError(`supervisePursuit versions: the chain in ${ledgerPath} closed (${closed.reason}) without a judged version to keep`);
|
|
1581
|
-
const observerPath = resolve(best.runDir, "observer.jsonl");
|
|
1582
|
-
return Object.freeze({
|
|
1583
|
-
result: best.result,
|
|
1584
|
-
pursuit: projectPursuit(await new FileObserverJournal(observerPath, pursuitId).read()),
|
|
1585
|
-
observerPath,
|
|
1586
|
-
settlePath: resolve(best.runDir, SETTLE_RECORD_FILE),
|
|
1587
|
-
versions: Object.freeze({
|
|
1588
|
-
ledgerPath,
|
|
1589
|
-
searchId,
|
|
1590
|
-
reason: closed.reason,
|
|
1591
|
-
...stopped === null ? {} : { identicalFailures: stopped },
|
|
1592
|
-
best: best.version,
|
|
1593
|
-
versions: Object.freeze(judged),
|
|
1594
|
-
spend: closed.state.audit.spend,
|
|
1595
|
-
receipt: recorder.receipt({
|
|
1596
|
-
producerId: "pursuit-versions",
|
|
1597
|
-
runId
|
|
1598
|
-
})
|
|
1599
|
-
})
|
|
1600
|
-
});
|
|
1601
|
-
} finally {
|
|
1602
|
-
if (timer !== void 0) clearTimeout(timer);
|
|
1603
|
-
}
|
|
1604
|
-
/** Run one version: the first as the call's own run, a later one as a fork of its parent. */
|
|
1605
|
-
async function runVersion(record, parent, signal) {
|
|
1606
|
-
if (parent === void 0 || record.change === void 0) {
|
|
1607
|
-
await runOne(profile, task, {
|
|
1608
|
-
...base,
|
|
1609
|
-
runId: record.runId,
|
|
1610
|
-
runDir: record.runDir,
|
|
1611
|
-
...firstFork === void 0 ? {} : { fork: firstFork },
|
|
1612
|
-
signal
|
|
1613
|
-
});
|
|
1614
|
-
return;
|
|
1615
|
-
}
|
|
1616
|
-
const fork = {
|
|
1617
|
-
runDir: parent.runDir,
|
|
1618
|
-
settleDigest: parent.seal.sha256,
|
|
1619
|
-
change: record.change,
|
|
1620
|
-
acceptUncertain: true
|
|
1621
|
-
};
|
|
1622
|
-
const check = parent.verdict?.check;
|
|
1623
|
-
await runOne(parent.profile, task, {
|
|
1624
|
-
...base,
|
|
1625
|
-
...base.continuation !== void 0 && check !== void 0 ? { continuation: {
|
|
1626
|
-
...base.continuation,
|
|
1627
|
-
best: {
|
|
1628
|
-
label: `v${parent.version}`,
|
|
1629
|
-
verdict: check
|
|
1630
|
-
}
|
|
1631
|
-
} } : {},
|
|
1632
|
-
runId: record.runId,
|
|
1633
|
-
runDir: record.runDir,
|
|
1634
|
-
fork,
|
|
1635
|
-
signal
|
|
1636
|
-
});
|
|
1637
|
-
}
|
|
1638
|
-
/**
|
|
1639
|
-
* Read a settled version back and check it is this node's run: its root ran the node's profile
|
|
1640
|
-
* and, for a fork, recorded the parent's seal and the change. A directory that holds another
|
|
1641
|
-
* run is refused, never adopted.
|
|
1642
|
-
*/
|
|
1643
|
-
async function readVersion(record, parent) {
|
|
1644
|
-
const { bytes, result } = await readSealed(record.runDir, record.version);
|
|
1645
|
-
if (result.tree.root !== record.runId) throw new RuntimeRunStateError(`supervisePursuit versions: ${record.runDir} holds run '${result.tree.root}', not version ${record.version}'s '${record.runId}'`);
|
|
1646
|
-
const root = (await new FileSpawnJournal(resolve(record.runDir, "spawn-journal.jsonl")).loadTree(record.runId))?.find((event) => event.kind === "spawned" && event.parent === void 0);
|
|
1647
|
-
const ran = root?.identity?.profileDigest;
|
|
1648
|
-
const expected = authoredProfileDigest(superviseRootProfile(record.profile, base.profileGuidance));
|
|
1649
|
-
const ranTask = root?.identity?.taskDigest;
|
|
1650
|
-
const correlation = root?.identity?.correlation;
|
|
1651
|
-
const fork = parent !== void 0 ? {
|
|
1652
|
-
settleDigest: parent.seal?.sha256,
|
|
1653
|
-
changeId: record.change?.id
|
|
1654
|
-
} : firstFork === void 0 ? void 0 : {
|
|
1655
|
-
settleDigest: firstFork.settleDigest,
|
|
1656
|
-
changeId: firstFork.change.id
|
|
1657
|
-
};
|
|
1658
|
-
const mismatch = [
|
|
1659
|
-
ran !== expected ? `its root ran profile ${ran}, not ${expected}` : void 0,
|
|
1660
|
-
ranTask !== taskRevision ? `its root ran task ${ranTask}, not ${taskRevision}` : void 0,
|
|
1661
|
-
contentAddress(root?.budget) !== contentAddress(base.budget) ? "its root ran under another budget" : void 0,
|
|
1662
|
-
fork !== void 0 && correlation?.forkParentSettleDigest !== fork.settleDigest ? `its root forked from seal ${correlation?.forkParentSettleDigest}, not ${fork.settleDigest}` : void 0,
|
|
1663
|
-
fork !== void 0 && correlation?.forkProfileDiffId !== fork.changeId ? `its root applied change ${correlation?.forkProfileDiffId}, not ${fork.changeId}` : void 0
|
|
1664
|
-
].filter((item) => item !== void 0);
|
|
1665
|
-
if (mismatch.length > 0) throw new RuntimeRunStateError(`supervisePursuit versions: version ${record.version} at ${record.runDir} is not this chain's run: ${mismatch.join("; ")}`);
|
|
1666
|
-
const settled = versionOf(record, parent, sha256Bytes(bytes), result);
|
|
1667
|
-
sealed.set(settled.settleDigest, result);
|
|
1668
1889
|
return {
|
|
1669
|
-
|
|
1670
|
-
|
|
1890
|
+
profile: applyExactAgentProfileDiff(parentProfile, change, "supervisePursuit versions"),
|
|
1891
|
+
change,
|
|
1892
|
+
parentDigest,
|
|
1893
|
+
refusal: null
|
|
1671
1894
|
};
|
|
1672
|
-
}
|
|
1673
|
-
async function judgeVersion(settled, signal) {
|
|
1674
|
-
const verdict = await judge.judge(settled, signal);
|
|
1675
|
-
if (typeof verdict !== "object" || verdict === null) throw new ValidationError("supervisePursuit versions: the judge returned no verdict");
|
|
1676
|
-
if (verdict.judgeDigest !== judge.digest) throw new ValidationError(`supervisePursuit versions: the verdict for version ${settled.version} carries ${String(verdict.judgeDigest)}, not the pinned judge ${judge.digest}`);
|
|
1677
|
-
if (verdict.score !== null && !isFiniteNumber(verdict.score)) throw new ValidationError("supervisePursuit versions: a verdict score must be a finite number or null");
|
|
1678
|
-
return JSON.parse(JSON.stringify(verdict));
|
|
1679
|
-
}
|
|
1680
|
-
function cellResult(settled, byteLength, verdict, lane) {
|
|
1681
|
-
const spent = settled.result.spentTotal;
|
|
1682
|
-
const settlePath = resolve(settled.runDir, SETTLE_RECORD_FILE);
|
|
1895
|
+
} catch (error) {
|
|
1683
1896
|
return {
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
code: "unscored",
|
|
1689
|
-
message: `the judge could not score version ${settled.version}`,
|
|
1690
|
-
retryable: false
|
|
1691
|
-
}
|
|
1692
|
-
} : settled.result.kind === "winner" ? {
|
|
1693
|
-
status: "passed",
|
|
1694
|
-
score: verdict.score,
|
|
1695
|
-
metrics: {}
|
|
1696
|
-
} : {
|
|
1697
|
-
status: "failed",
|
|
1698
|
-
score: verdict.score,
|
|
1699
|
-
metrics: {},
|
|
1700
|
-
failure: {
|
|
1701
|
-
code: settled.result.reason,
|
|
1702
|
-
message: `version ${settled.version} settled without a winner: ${settled.result.reason}`
|
|
1703
|
-
}
|
|
1704
|
-
},
|
|
1705
|
-
accounting: versionAccounting(spent),
|
|
1706
|
-
identity: identity(settled.profile),
|
|
1707
|
-
boxMinutes: isFiniteNumber(spent.boxMinutes) && spent.boxMinutesKnown !== false ? spent.boxMinutes : null,
|
|
1708
|
-
wallMs: isFiniteNumber(spent.ms) ? Math.max(0, Math.round(spent.ms)) : null,
|
|
1709
|
-
placement: {
|
|
1710
|
-
lane,
|
|
1711
|
-
boxId: null
|
|
1712
|
-
},
|
|
1713
|
-
traceRef: { unknown: `version ${settled.version} is run ${settled.runId}; the chain records no trace id` },
|
|
1714
|
-
artifacts: [{
|
|
1715
|
-
role: "settle-record",
|
|
1716
|
-
uri: pathToFileURL(settlePath).href,
|
|
1717
|
-
sha256: settled.settleDigest,
|
|
1718
|
-
byteLength
|
|
1719
|
-
}, recorder.blob("verdict", {
|
|
1720
|
-
kind: "version-verdict",
|
|
1721
|
-
version: settled.version,
|
|
1722
|
-
runId: settled.runId,
|
|
1723
|
-
verdict
|
|
1724
|
-
})]
|
|
1897
|
+
profile: null,
|
|
1898
|
+
change,
|
|
1899
|
+
parentDigest,
|
|
1900
|
+
refusal: errorMessage(error)
|
|
1725
1901
|
};
|
|
1726
1902
|
}
|
|
1727
|
-
/** A version as the judge and `next` read it. */
|
|
1728
|
-
function versionOf(record, parent, settleDigest, result) {
|
|
1729
|
-
return Object.freeze({
|
|
1730
|
-
version: record.version,
|
|
1731
|
-
nodeId: record.nodeId,
|
|
1732
|
-
runId: record.runId,
|
|
1733
|
-
runDir: record.runDir,
|
|
1734
|
-
settleDigest,
|
|
1735
|
-
result,
|
|
1736
|
-
profile: record.profile,
|
|
1737
|
-
...parent?.seal === void 0 ? {} : { parent: {
|
|
1738
|
-
version: parent.version,
|
|
1739
|
-
runId: parent.runId,
|
|
1740
|
-
settleDigest: parent.seal.sha256
|
|
1741
|
-
} },
|
|
1742
|
-
...record.change === void 0 ? {} : { change: record.change }
|
|
1743
|
-
});
|
|
1744
|
-
}
|
|
1745
|
-
/** Every version whose latest settled cell carries a verdict, first first, each read back from
|
|
1746
|
-
* its sealed `result.json`. */
|
|
1747
|
-
async function judgedVersions(chain) {
|
|
1748
|
-
const judged = [];
|
|
1749
|
-
for (const record of chain.values()) {
|
|
1750
|
-
if (record.seal === void 0 || record.verdict === void 0) continue;
|
|
1751
|
-
const seal = record.seal.sha256;
|
|
1752
|
-
let result = sealed.get(seal);
|
|
1753
|
-
if (result === void 0) {
|
|
1754
|
-
const read = await readSealed(record.runDir, record.version);
|
|
1755
|
-
if (sha256Bytes(read.bytes) !== seal) throw new RuntimeRunStateError(`supervisePursuit versions: version ${record.version}'s result.json changed after it was judged`);
|
|
1756
|
-
result = read.result;
|
|
1757
|
-
sealed.set(seal, result);
|
|
1758
|
-
}
|
|
1759
|
-
const parent = record.parentNodeId === null ? void 0 : chain.get(record.parentNodeId);
|
|
1760
|
-
judged.push(Object.freeze({
|
|
1761
|
-
...versionOf(record, parent, seal, result),
|
|
1762
|
-
verdict: record.verdict
|
|
1763
|
-
}));
|
|
1764
|
-
}
|
|
1765
|
-
return judged;
|
|
1766
|
-
}
|
|
1767
|
-
/**
|
|
1768
|
-
* Every node of the chain, in registration order, from the ledger. The state holds cells, not
|
|
1769
|
-
* their events' artifacts, so each cell's seal and verdict are read from the ledger lines the
|
|
1770
|
-
* state verified, through Eval's own line parser.
|
|
1771
|
-
*/
|
|
1772
|
-
async function versionsOf() {
|
|
1773
|
-
const state = await recorder.state();
|
|
1774
|
-
const head = state.head?.sequence ?? -1;
|
|
1775
|
-
const nodes = state.nodes().map((node) => ({
|
|
1776
|
-
node,
|
|
1777
|
-
cellId: state.cells({ nodeId: node.nodeId })[0]?.cellId,
|
|
1778
|
-
diff: node.edgeIds[0] === void 0 ? void 0 : state.edge(node.edgeIds[0])?.diffs[0]
|
|
1779
|
-
}));
|
|
1780
|
-
const settledCells = /* @__PURE__ */ new Map();
|
|
1781
|
-
const text = await readFile(ledgerPath, "utf8");
|
|
1782
|
-
for (const [index, line] of text.split("\n").entries()) {
|
|
1783
|
-
if (line.length === 0) continue;
|
|
1784
|
-
const entry = parseSearchLedgerLine(line, searchId, {
|
|
1785
|
-
path: ledgerPath,
|
|
1786
|
-
line: index + 1
|
|
1787
|
-
});
|
|
1788
|
-
if (entry.sequence > head) break;
|
|
1789
|
-
if (entry.event.kind === "cell-settled") settledCells.set(entry.event.cellId, entry.event);
|
|
1790
|
-
}
|
|
1791
|
-
const chain = /* @__PURE__ */ new Map();
|
|
1792
|
-
for (const { node, cellId, diff } of nodes) {
|
|
1793
|
-
const settled = cellId === void 0 ? void 0 : settledCells.get(cellId);
|
|
1794
|
-
const artifact = (role) => settled?.artifacts.find((candidate) => candidate.role === role);
|
|
1795
|
-
const seal = artifact("settle-record");
|
|
1796
|
-
const verdict = artifact("verdict");
|
|
1797
|
-
chain.set(node.nodeId, {
|
|
1798
|
-
nodeId: node.nodeId,
|
|
1799
|
-
version: node.ordinal + 1,
|
|
1800
|
-
...versionRun(runDir, runId, node.ordinal + 1),
|
|
1801
|
-
profile: loadNode(recorder, node).profile,
|
|
1802
|
-
parentNodeId: node.primaryParentId,
|
|
1803
|
-
...diff === void 0 || "unknown" in diff ? {} : { change: recorder.readBlob(diff).diffs[0] },
|
|
1804
|
-
...seal === void 0 ? {} : { seal },
|
|
1805
|
-
...verdict === void 0 ? {} : { verdict: recorder.readBlob(verdict).verdict }
|
|
1806
|
-
});
|
|
1807
|
-
}
|
|
1808
|
-
return chain;
|
|
1809
|
-
}
|
|
1810
1903
|
}
|
|
1811
1904
|
function canonicalStop(stop) {
|
|
1812
1905
|
return {
|