@tangle-network/agent-runtime 0.102.2 → 0.103.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/README.md +73 -10
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +5 -5
- package/dist/analyst-loop.d.ts +1 -1
- package/dist/candidate-execution/index.d.ts +5 -41
- package/dist/candidate-execution/index.js +8 -6
- package/dist/{chunk-QCXD7NHM.js → chunk-3LJF5XSE.js} +79 -334
- package/dist/chunk-3LJF5XSE.js.map +1 -0
- package/dist/{chunk-3DW5DEKQ.js → chunk-5AITUUHO.js} +3 -3
- package/dist/{chunk-SQ3ZJH3Y.js → chunk-6WZZXQV5.js} +467 -23
- package/dist/chunk-6WZZXQV5.js.map +1 -0
- package/dist/{chunk-SCOHHMKU.js → chunk-AAN2MB2X.js} +3 -3
- package/dist/{chunk-KSM6GFHP.js → chunk-B7K7V22Y.js} +2 -2
- package/dist/{chunk-ZUCUAFVF.js → chunk-EAQ5YRRY.js} +1382 -62
- package/dist/chunk-EAQ5YRRY.js.map +1 -0
- package/dist/chunk-ISPWRSEC.js +408 -0
- package/dist/chunk-ISPWRSEC.js.map +1 -0
- package/dist/{chunk-7FJJUC73.js → chunk-LFM4JBRW.js} +29 -6
- package/dist/{chunk-7FJJUC73.js.map → chunk-LFM4JBRW.js.map} +1 -1
- package/dist/{chunk-ROILMKDL.js → chunk-QYCKIV6C.js} +3 -3
- package/dist/{chunk-LJLG734E.js → chunk-SBTWKPVR.js} +10 -11
- package/dist/{chunk-LJLG734E.js.map → chunk-SBTWKPVR.js.map} +1 -1
- package/dist/{chunk-CK76OZPM.js → chunk-SNSMRT6H.js} +56 -386
- package/dist/chunk-SNSMRT6H.js.map +1 -0
- package/dist/{chunk-EKUMRQNR.js → chunk-TUSOOIDV.js} +2 -2
- package/dist/{chunk-J6V6DWWS.js → chunk-ZOYN3JR5.js} +5 -5
- package/dist/{chunk-377GOJHJ.js → chunk-ZXICDSAK.js} +333 -4
- package/dist/chunk-ZXICDSAK.js.map +1 -0
- package/dist/{completion-gate-C6dhVN-N.d.ts → completion-gate-DLINnrkM.d.ts} +1 -1
- package/dist/{coordination-D9l_YmwW.d.ts → coordination-DTehA977.d.ts} +250 -8
- package/dist/environment-provider.d.ts +2 -2
- package/dist/index.d.ts +12 -12
- package/dist/index.js +17 -15
- package/dist/index.js.map +1 -1
- package/dist/intelligence.d.ts +26 -8
- package/dist/intelligence.js +24 -7
- package/dist/intelligence.js.map +1 -1
- package/dist/knowledge.d.ts +6 -6
- package/dist/knowledge.js +9 -9
- package/dist/{loop-runner-bin-PnWslIw4.d.ts → loop-runner-bin-DhIXsLAd.d.ts} +2 -2
- package/dist/loop-runner-bin.d.ts +5 -5
- package/dist/loop-runner-bin.js +6 -6
- package/dist/loops.d.ts +305 -148
- package/dist/loops.js +82 -14
- package/dist/mcp/bin.js +3 -3
- package/dist/mcp/index.d.ts +6 -6
- package/dist/mcp/index.js +6 -6
- package/dist/profiles.d.ts +1 -1
- package/dist/{profile-DbfaMTdk.d.ts → protected-model-port-DzkUY3HQ.d.ts} +41 -3
- package/dist/{structural-rollout-D7xik9XR.d.ts → structural-rollout-BFPIy3iw.d.ts} +3 -3
- package/dist/supervise-Cp8bNcJi.d.ts +379 -0
- package/dist/testing.js +10 -10
- package/dist/testing.js.map +1 -1
- package/dist/{types-CWqfCO8s.d.ts → types-Cbp72qyu.d.ts} +1 -1
- package/dist/{types-CLat4bT9.d.ts → types-DK11_O4L.d.ts} +1 -1
- package/dist/types-lZTE_LBd.d.ts +957 -0
- package/dist/{worktree-fanout-DsIR4d6w.d.ts → worktree-fanout-DiiJWjJO.d.ts} +17 -5
- package/package.json +3 -2
- package/skills/build-with-agent-runtime/SKILL.md +7 -5
- package/skills/generate-eval/SKILL.md +45 -52
- package/skills/loop-writer/SKILL.md +79 -147
- package/skills/supervise/SKILL.md +33 -14
- package/dist/chunk-377GOJHJ.js.map +0 -1
- package/dist/chunk-CK76OZPM.js.map +0 -1
- package/dist/chunk-IMSNJSXH.js +0 -73
- package/dist/chunk-IMSNJSXH.js.map +0 -1
- package/dist/chunk-QCXD7NHM.js.map +0 -1
- package/dist/chunk-SQ3ZJH3Y.js.map +0 -1
- package/dist/chunk-ZUCUAFVF.js.map +0 -1
- package/dist/supervise-BQdNAXtK.d.ts +0 -131
- package/dist/types-D870JlH0.d.ts +0 -500
- /package/dist/{chunk-3DW5DEKQ.js.map → chunk-5AITUUHO.js.map} +0 -0
- /package/dist/{chunk-SCOHHMKU.js.map → chunk-AAN2MB2X.js.map} +0 -0
- /package/dist/{chunk-KSM6GFHP.js.map → chunk-B7K7V22Y.js.map} +0 -0
- /package/dist/{chunk-ROILMKDL.js.map → chunk-QYCKIV6C.js.map} +0 -0
- /package/dist/{chunk-EKUMRQNR.js.map → chunk-TUSOOIDV.js.map} +0 -0
- /package/dist/{chunk-J6V6DWWS.js.map → chunk-ZOYN3JR5.js.map} +0 -0
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
sealAgentCandidateBundle
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-B7K7V22Y.js";
|
|
4
4
|
import {
|
|
5
5
|
RecoveryAgentCandidateTraceStore,
|
|
6
6
|
applyExactAgentProfileDiff,
|
|
7
|
-
assertExactObjectKeys,
|
|
8
7
|
assertPreparedCandidateIntegrity,
|
|
9
8
|
assertRecoveryMatchesStaged,
|
|
10
9
|
assertTerminalAllowedInPhase,
|
|
@@ -15,11 +14,9 @@ import {
|
|
|
15
14
|
candidateCleanupDeadline,
|
|
16
15
|
candidateCleanupTimeout,
|
|
17
16
|
canonicalCandidateBytes,
|
|
18
|
-
canonicalCandidateDigest,
|
|
19
17
|
consumePreparedCandidateExecution,
|
|
20
18
|
embeddedCandidateArtifact,
|
|
21
19
|
freezeGenericAgentCandidateProfile,
|
|
22
|
-
immutableCandidateValue,
|
|
23
20
|
parseExactAgentProfile,
|
|
24
21
|
parseExactAgentProfileDiff,
|
|
25
22
|
parseExactCandidateProfile,
|
|
@@ -34,9 +31,8 @@ import {
|
|
|
34
31
|
sealAgentCandidateModelSettlement,
|
|
35
32
|
sealTerminalDigest,
|
|
36
33
|
terminalRecord,
|
|
37
|
-
usdToNanos,
|
|
38
34
|
withinCandidateCleanupDeadline
|
|
39
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-SBTWKPVR.js";
|
|
40
36
|
|
|
41
37
|
// src/candidate-execution/builder.ts
|
|
42
38
|
import { verifyCodeSurface } from "@tangle-network/agent-eval/campaign";
|
|
@@ -253,19 +249,19 @@ var FileAgentCandidateExecutionClaimStore = class {
|
|
|
253
249
|
}
|
|
254
250
|
async recoverExpired(requestedAttempt, evidence) {
|
|
255
251
|
const attempt = sealAttemptRef(requestedAttempt);
|
|
256
|
-
const
|
|
257
|
-
if (!
|
|
258
|
-
const recovered = recoveredTerminalRecord(
|
|
259
|
-
if (
|
|
260
|
-
const requestedDigest =
|
|
261
|
-
if (
|
|
262
|
-
assertExpiredLease(
|
|
263
|
-
let staged =
|
|
252
|
+
const record = await this.storedAttempt(attempt);
|
|
253
|
+
if (!record) throw new Error("candidate execution recovery does not name an acquired attempt");
|
|
254
|
+
const recovered = recoveredTerminalRecord(record.claim, record.phase, evidence);
|
|
255
|
+
if (record.staged) assertRecoveryMatchesStaged(record.staged, recovered);
|
|
256
|
+
const requestedDigest = record.staged?.terminalDigest ?? recovered.terminalDigest;
|
|
257
|
+
if (record.terminal) return rejectedFinish(record.terminal, requestedDigest);
|
|
258
|
+
assertExpiredLease(record.claim.leaseExpiresAtMs, this.now());
|
|
259
|
+
let staged = record.staged;
|
|
264
260
|
if (!staged) {
|
|
265
|
-
const transition =
|
|
261
|
+
const transition = record.phase === "claimed" ? 1 : 2;
|
|
266
262
|
const didStage = await writeRecordIfAbsent(
|
|
267
263
|
this.directory,
|
|
268
|
-
this.transitionPath(
|
|
264
|
+
this.transitionPath(record.claim, transition),
|
|
269
265
|
{
|
|
270
266
|
kind: "candidate-execution-pending-terminal",
|
|
271
267
|
terminal: recovered
|
|
@@ -274,7 +270,7 @@ var FileAgentCandidateExecutionClaimStore = class {
|
|
|
274
270
|
if (didStage) {
|
|
275
271
|
staged = recovered;
|
|
276
272
|
} else {
|
|
277
|
-
const winner2 = await this.transitionState(
|
|
273
|
+
const winner2 = await this.transitionState(record.claim);
|
|
278
274
|
if (!winner2.staged) {
|
|
279
275
|
throw new Error(
|
|
280
276
|
"candidate execution recovery lost terminal staging to a phase transition"
|
|
@@ -291,7 +287,7 @@ var FileAgentCandidateExecutionClaimStore = class {
|
|
|
291
287
|
if (didFinish) return Object.freeze({ finished: true, terminal: staged });
|
|
292
288
|
const winner = await readTerminal(terminalPath);
|
|
293
289
|
assertSameSlot(winner, attempt, terminalPath);
|
|
294
|
-
assertTerminalMatchesClaim(winner,
|
|
290
|
+
assertTerminalMatchesClaim(winner, record.claim, terminalPath);
|
|
295
291
|
assertTerminalMatchesStaged(winner, staged, terminalPath);
|
|
296
292
|
return rejectedFinish(winner, staged.terminalDigest);
|
|
297
293
|
}
|
|
@@ -355,12 +351,12 @@ var FileAgentCandidateExecutionClaimStore = class {
|
|
|
355
351
|
return join(this.directory, `${claimSlot(claim)}.transition-${ordinal}.json`);
|
|
356
352
|
}
|
|
357
353
|
};
|
|
358
|
-
async function writeRecordIfAbsent(directory, destination,
|
|
354
|
+
async function writeRecordIfAbsent(directory, destination, record, options = {}) {
|
|
359
355
|
const temporaryPath = join(directory, `.candidate-execution-${process.pid}-${randomUUID()}.tmp`);
|
|
360
356
|
const handle = await open(temporaryPath, "wx", 384);
|
|
361
357
|
try {
|
|
362
358
|
await handle.writeFile(
|
|
363
|
-
Buffer.concat([Buffer.from(canonicalCandidateBytes(
|
|
359
|
+
Buffer.concat([Buffer.from(canonicalCandidateBytes(record)), Buffer.from("\n")])
|
|
364
360
|
);
|
|
365
361
|
await handle.sync();
|
|
366
362
|
} finally {
|
|
@@ -462,356 +458,31 @@ async function disposePreparedAgentCandidateExecution(prepared, options = {}) {
|
|
|
462
458
|
return Object.freeze({ disposed: true });
|
|
463
459
|
}
|
|
464
460
|
|
|
465
|
-
// src/candidate-execution/protected-model-port.ts
|
|
466
|
-
var MAX_RECENT_SETTLEMENTS = 4096;
|
|
467
|
-
var RECOVERED_SETTLEMENT_RETENTION_MS = 15 * 60 * 1e3;
|
|
468
|
-
function createProtectedAgentCandidateModelPort(options) {
|
|
469
|
-
const gatewayDomain = assertGatewayDomain(options.gatewayDomain);
|
|
470
|
-
const activationEnvNames = exactEnvironmentNames(options.activationEnvNames);
|
|
471
|
-
const reservations = /* @__PURE__ */ new Map();
|
|
472
|
-
const recentSettlements = /* @__PURE__ */ new Map();
|
|
473
|
-
return {
|
|
474
|
-
resolve: async (input) => {
|
|
475
|
-
const request = immutableCandidateValue(input);
|
|
476
|
-
const resolved = validateResolvedModel(await options.resolveModel(request), request);
|
|
477
|
-
return immutableCandidateValue(resolved);
|
|
478
|
-
},
|
|
479
|
-
reserveGrant: async (input) => {
|
|
480
|
-
pruneExpiredState(reservations, recentSettlements, Date.now());
|
|
481
|
-
const request = immutableCandidateValue(input);
|
|
482
|
-
validateReserveInput(request);
|
|
483
|
-
const requestDigest = canonicalCandidateDigest(request);
|
|
484
|
-
const key = reservationKey(request.executionId, request.preparationId);
|
|
485
|
-
if (recentSettlements.has(key)) {
|
|
486
|
-
throw new Error("protected model reservation is already settled");
|
|
487
|
-
}
|
|
488
|
-
const previous = reservations.get(key);
|
|
489
|
-
if (previous && previous.requestDigest !== requestDigest) {
|
|
490
|
-
throw new Error("protected model reservation retry changed immutable input");
|
|
491
|
-
}
|
|
492
|
-
const reservation = validateReservation(
|
|
493
|
-
await options.client.reserve(request),
|
|
494
|
-
request,
|
|
495
|
-
gatewayDomain
|
|
496
|
-
);
|
|
497
|
-
const responseDigest = canonicalCandidateDigest(reservation);
|
|
498
|
-
if (recentSettlements.has(key)) {
|
|
499
|
-
throw new Error("protected model reservation completed after the grant was settled");
|
|
500
|
-
}
|
|
501
|
-
const recorded = previous ?? reservations.get(key);
|
|
502
|
-
if (recorded && recorded.requestDigest !== requestDigest) {
|
|
503
|
-
throw new Error("protected model reservation retry changed immutable input");
|
|
504
|
-
}
|
|
505
|
-
if (recorded && recorded.responseDigest !== responseDigest) {
|
|
506
|
-
throw new Error("protected model reservation retry returned different evidence");
|
|
507
|
-
}
|
|
508
|
-
if (!recorded) {
|
|
509
|
-
reservations.set(key, {
|
|
510
|
-
requestDigest,
|
|
511
|
-
responseDigest,
|
|
512
|
-
executionId: request.executionId,
|
|
513
|
-
preparationId: request.preparationId,
|
|
514
|
-
grantDigest: reservation.digest,
|
|
515
|
-
expiresAtMs: request.expiresAtMs,
|
|
516
|
-
resolved: immutableCandidateValue(request.resolved),
|
|
517
|
-
limits: immutableCandidateValue(request.limits),
|
|
518
|
-
maxCostUsdNanos: usdToNanos(request.limits.maxCostUsd, "reserved maxCostUsd"),
|
|
519
|
-
activation: "reserved"
|
|
520
|
-
});
|
|
521
|
-
}
|
|
522
|
-
return reservation;
|
|
523
|
-
},
|
|
524
|
-
activateGrant: async (input) => {
|
|
525
|
-
pruneExpiredState(reservations, recentSettlements, Date.now());
|
|
526
|
-
const request = immutableCandidateValue(input);
|
|
527
|
-
const key = reservationKey(request.executionId, request.preparationId);
|
|
528
|
-
if (recentSettlements.has(key)) throw new Error("protected model grant is already settled");
|
|
529
|
-
const state = reservations.get(key);
|
|
530
|
-
if (!state) throw new Error("protected model grant was not reserved by this port");
|
|
531
|
-
assertGrantIdentity(state, request);
|
|
532
|
-
if (state.settlementDigest) throw new Error("protected model grant is already settled");
|
|
533
|
-
if (state.activation !== "reserved") {
|
|
534
|
-
throw new Error("protected model grant activation is single-use");
|
|
535
|
-
}
|
|
536
|
-
if (!Number.isSafeInteger(request.deadlineAtMs) || request.deadlineAtMs <= 0) {
|
|
537
|
-
throw new Error("protected model activation deadline must be a positive safe integer");
|
|
538
|
-
}
|
|
539
|
-
if (request.deadlineAtMs <= Date.now()) {
|
|
540
|
-
throw new Error("protected model activation deadline must be in the future");
|
|
541
|
-
}
|
|
542
|
-
if (request.deadlineAtMs > state.expiresAtMs) {
|
|
543
|
-
throw new Error("protected model activation deadline exceeds the reserved expiry");
|
|
544
|
-
}
|
|
545
|
-
state.activation = "activating";
|
|
546
|
-
try {
|
|
547
|
-
const activation = validateActivation(
|
|
548
|
-
await options.client.activate(request),
|
|
549
|
-
state.limits.maxModelCalls === 0 ? [] : activationEnvNames
|
|
550
|
-
);
|
|
551
|
-
if (recentSettlements.has(key) || reservations.get(key) !== state) {
|
|
552
|
-
throw new Error("protected model grant settled while activation was in flight");
|
|
553
|
-
}
|
|
554
|
-
state.activation = "activated";
|
|
555
|
-
return activation;
|
|
556
|
-
} catch (error) {
|
|
557
|
-
state.activation = "reserved";
|
|
558
|
-
throw error;
|
|
559
|
-
}
|
|
560
|
-
},
|
|
561
|
-
settleGrant: async (input) => {
|
|
562
|
-
const now = Date.now();
|
|
563
|
-
pruneExpiredState(reservations, recentSettlements, now);
|
|
564
|
-
const request = immutableCandidateValue(input);
|
|
565
|
-
const key = reservationKey(request.executionId, request.preparationId);
|
|
566
|
-
const state = reservations.get(key);
|
|
567
|
-
if (state) assertGrantIdentity(state, request);
|
|
568
|
-
const remembered = state ?? recentSettlements.get(key);
|
|
569
|
-
if (remembered?.settlementReason && remembered.settlementReason !== request.reason) {
|
|
570
|
-
throw new Error("protected model settlement retry changed the termination reason");
|
|
571
|
-
}
|
|
572
|
-
const sealed = sealAgentCandidateModelSettlement(await options.client.settle(request), {
|
|
573
|
-
preparationId: request.preparationId,
|
|
574
|
-
grantDigest: request.grantDigest,
|
|
575
|
-
model: request.resolved.model
|
|
576
|
-
});
|
|
577
|
-
if (state) assertWithinReservedLimits(sealed.usage, state);
|
|
578
|
-
const settlementDigest = canonicalCandidateDigest(sealed.value);
|
|
579
|
-
if (remembered?.settlementDigest && remembered.settlementDigest !== settlementDigest) {
|
|
580
|
-
throw new Error("protected model settlement retry returned a different final ledger");
|
|
581
|
-
}
|
|
582
|
-
if (remembered?.settlementReason && remembered.settlementReason !== request.reason) {
|
|
583
|
-
throw new Error("protected model settlement retry changed the termination reason");
|
|
584
|
-
}
|
|
585
|
-
const expiresAtMs = state?.expiresAtMs ?? now + RECOVERED_SETTLEMENT_RETENTION_MS;
|
|
586
|
-
if (state) {
|
|
587
|
-
state.settlementDigest = settlementDigest;
|
|
588
|
-
state.settlementReason = request.reason;
|
|
589
|
-
}
|
|
590
|
-
reservations.delete(key);
|
|
591
|
-
rememberSettlement(recentSettlements, key, {
|
|
592
|
-
settlementDigest,
|
|
593
|
-
settlementReason: request.reason,
|
|
594
|
-
expiresAtMs
|
|
595
|
-
});
|
|
596
|
-
return sealed.value;
|
|
597
|
-
}
|
|
598
|
-
};
|
|
599
|
-
}
|
|
600
|
-
function validateReserveInput(input) {
|
|
601
|
-
if (!Number.isSafeInteger(input.expiresAtMs) || input.expiresAtMs <= 0) {
|
|
602
|
-
throw new Error("protected model reservation expiry must be a positive safe integer");
|
|
603
|
-
}
|
|
604
|
-
if (input.expiresAtMs <= Date.now()) {
|
|
605
|
-
throw new Error("protected model reservation expiry must be in the future");
|
|
606
|
-
}
|
|
607
|
-
for (const [name, value] of [
|
|
608
|
-
["maxModelCalls", input.limits.maxModelCalls],
|
|
609
|
-
["maxInputTokens", input.limits.maxInputTokens],
|
|
610
|
-
["maxOutputTokens", input.limits.maxOutputTokens]
|
|
611
|
-
]) {
|
|
612
|
-
if (!Number.isSafeInteger(value) || value < 0) {
|
|
613
|
-
throw new Error(`protected model reservation ${name} must be a nonnegative safe integer`);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
usdToNanos(input.limits.maxCostUsd, "reserved maxCostUsd");
|
|
617
|
-
}
|
|
618
|
-
function validateReservation(value, expected, gatewayDomain) {
|
|
619
|
-
const source = exactRecord(
|
|
620
|
-
value,
|
|
621
|
-
["preparationId", "digest", "expiresAtMs", "enforcedLimits", "network"],
|
|
622
|
-
"protected model reservation response"
|
|
623
|
-
);
|
|
624
|
-
if (source.preparationId !== expected.preparationId) {
|
|
625
|
-
throw new Error("protected model reservation response changed preparation identity");
|
|
626
|
-
}
|
|
627
|
-
if (!isSha256Digest(source.digest)) {
|
|
628
|
-
throw new Error("protected model reservation response has an invalid digest");
|
|
629
|
-
}
|
|
630
|
-
if (source.expiresAtMs !== expected.expiresAtMs) {
|
|
631
|
-
throw new Error("protected model reservation response changed expiry");
|
|
632
|
-
}
|
|
633
|
-
exactRecord(
|
|
634
|
-
source.enforcedLimits,
|
|
635
|
-
["maxModelCalls", "maxInputTokens", "maxOutputTokens", "maxCostUsd"],
|
|
636
|
-
"protected model reservation enforced limits"
|
|
637
|
-
);
|
|
638
|
-
if (canonicalCandidateDigest(source.enforcedLimits) !== canonicalCandidateDigest(expected.limits)) {
|
|
639
|
-
throw new Error("protected model reservation response changed enforced limits");
|
|
640
|
-
}
|
|
641
|
-
const network = validateReservationNetwork(
|
|
642
|
-
source.network,
|
|
643
|
-
expected.limits.maxModelCalls,
|
|
644
|
-
gatewayDomain
|
|
645
|
-
);
|
|
646
|
-
return immutableCandidateValue({
|
|
647
|
-
preparationId: source.preparationId,
|
|
648
|
-
digest: source.digest,
|
|
649
|
-
expiresAtMs: source.expiresAtMs,
|
|
650
|
-
enforcedLimits: source.enforcedLimits,
|
|
651
|
-
network
|
|
652
|
-
});
|
|
653
|
-
}
|
|
654
|
-
function validateReservationNetwork(value, maxModelCalls, gatewayDomain) {
|
|
655
|
-
if (maxModelCalls === 0) {
|
|
656
|
-
const source2 = exactRecord(value, ["mode"], "protected model reservation network");
|
|
657
|
-
if (source2.mode !== "disabled") {
|
|
658
|
-
throw new Error("zero-call protected model reservation must disable gateway access");
|
|
659
|
-
}
|
|
660
|
-
return { mode: "disabled" };
|
|
661
|
-
}
|
|
662
|
-
const source = exactRecord(value, ["mode", "domains"], "protected model reservation network");
|
|
663
|
-
if (source.mode !== "gateway-only") {
|
|
664
|
-
throw new Error("protected model reservation must allow only its model gateway");
|
|
665
|
-
}
|
|
666
|
-
if (!Array.isArray(source.domains) || source.domains.length !== 1 || source.domains[0] !== gatewayDomain) {
|
|
667
|
-
throw new Error("protected model reservation returned an unexpected gateway domain");
|
|
668
|
-
}
|
|
669
|
-
return { mode: "gateway-only", domains: [gatewayDomain] };
|
|
670
|
-
}
|
|
671
|
-
function validateActivation(value, expectedNames) {
|
|
672
|
-
const source = exactRecord(value, ["env"], "protected model activation response");
|
|
673
|
-
const env = record(source.env, "protected model activation environment");
|
|
674
|
-
const actualNames = Object.keys(env).sort();
|
|
675
|
-
if (actualNames.length !== expectedNames.length || actualNames.some((name, index) => name !== expectedNames[index])) {
|
|
676
|
-
throw new Error("protected model activation returned unexpected environment names");
|
|
677
|
-
}
|
|
678
|
-
const detached = /* @__PURE__ */ Object.create(null);
|
|
679
|
-
for (const name of expectedNames) {
|
|
680
|
-
const value2 = env[name];
|
|
681
|
-
if (typeof value2 !== "string" || value2.length < 8 || value2.length > 65536) {
|
|
682
|
-
throw new Error(`protected model activation ${name} must be a non-empty protected value`);
|
|
683
|
-
}
|
|
684
|
-
detached[name] = value2;
|
|
685
|
-
}
|
|
686
|
-
return Object.freeze({ env: Object.freeze(detached) });
|
|
687
|
-
}
|
|
688
|
-
function validateResolvedModel(value, expected) {
|
|
689
|
-
const source = exactRecord(
|
|
690
|
-
value,
|
|
691
|
-
["requested", "provider", "model", "snapshot", "reasoningEffort"],
|
|
692
|
-
"resolved candidate model"
|
|
693
|
-
);
|
|
694
|
-
if (source.requested !== expected.requested) {
|
|
695
|
-
throw new Error("model resolver changed the evaluator-owned request");
|
|
696
|
-
}
|
|
697
|
-
if (source.reasoningEffort !== expected.reasoningEffort) {
|
|
698
|
-
throw new Error("model resolver changed the evaluator-owned reasoning effort");
|
|
699
|
-
}
|
|
700
|
-
for (const name of ["requested", "provider", "model", "snapshot"]) {
|
|
701
|
-
if (typeof source[name] !== "string" || source[name].length === 0) {
|
|
702
|
-
throw new Error(`resolved candidate model ${name} must be non-empty`);
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
return source;
|
|
706
|
-
}
|
|
707
|
-
function assertGrantIdentity(expected, actual) {
|
|
708
|
-
if (actual.executionId !== expected.executionId || actual.preparationId !== expected.preparationId || actual.grantDigest !== expected.grantDigest || canonicalCandidateDigest(actual.resolved) !== canonicalCandidateDigest(expected.resolved)) {
|
|
709
|
-
throw new Error("protected model grant input does not match its immutable reservation");
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
function assertWithinReservedLimits(usage, reservation) {
|
|
713
|
-
for (const [name, actual, limit] of [
|
|
714
|
-
["model calls", usage.modelCalls, reservation.limits.maxModelCalls],
|
|
715
|
-
["input tokens", usage.inputTokens, reservation.limits.maxInputTokens],
|
|
716
|
-
["output tokens", usage.outputTokens, reservation.limits.maxOutputTokens],
|
|
717
|
-
["cost USD nanos", usage.costUsdNanos, reservation.maxCostUsdNanos]
|
|
718
|
-
]) {
|
|
719
|
-
if (actual > limit) {
|
|
720
|
-
throw new Error(`protected model settlement ${name} ${actual} exceeds reserved ${limit}`);
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
function exactEnvironmentNames(values) {
|
|
725
|
-
if (values.length === 0) {
|
|
726
|
-
throw new Error("protected model activation environment names must not be empty");
|
|
727
|
-
}
|
|
728
|
-
const names = [...values].sort();
|
|
729
|
-
if (new Set(names).size !== names.length) {
|
|
730
|
-
throw new Error("protected model activation environment names must be unique");
|
|
731
|
-
}
|
|
732
|
-
for (const name of names) {
|
|
733
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name) || ["__proto__", "constructor", "prototype"].includes(name)) {
|
|
734
|
-
throw new Error(`protected model activation environment name is invalid: ${name}`);
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
return Object.freeze(names);
|
|
738
|
-
}
|
|
739
|
-
function assertGatewayDomain(value) {
|
|
740
|
-
if (value.length > 253 || value !== value.toLowerCase() || value.endsWith(".") || value.includes(":") || value === "localhost" || value.endsWith(".localhost") || value === "metadata.google" || value === "metadata.google.internal") {
|
|
741
|
-
throw new Error("protected model gateway must be an exact lowercase public DNS name");
|
|
742
|
-
}
|
|
743
|
-
const labels = value.split(".");
|
|
744
|
-
if (labels.length < 2 || !labels.every(
|
|
745
|
-
(label) => label.length >= 1 && label.length <= 63 && /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(label)
|
|
746
|
-
) || !/[a-z]/.test(labels.at(-1) ?? "")) {
|
|
747
|
-
throw new Error("protected model gateway must be an exact lowercase public DNS name");
|
|
748
|
-
}
|
|
749
|
-
return value;
|
|
750
|
-
}
|
|
751
|
-
function reservationKey(executionId, preparationId) {
|
|
752
|
-
return canonicalCandidateDigest({ executionId, preparationId });
|
|
753
|
-
}
|
|
754
|
-
function pruneExpiredState(reservations, settlements, now) {
|
|
755
|
-
for (const [key, value] of reservations) {
|
|
756
|
-
if (value.expiresAtMs <= now) reservations.delete(key);
|
|
757
|
-
}
|
|
758
|
-
for (const [key, value] of settlements) {
|
|
759
|
-
if (value.expiresAtMs <= now) settlements.delete(key);
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
function rememberSettlement(settlements, key, value) {
|
|
763
|
-
settlements.delete(key);
|
|
764
|
-
settlements.set(key, value);
|
|
765
|
-
while (settlements.size > MAX_RECENT_SETTLEMENTS) {
|
|
766
|
-
const oldest = settlements.keys().next().value;
|
|
767
|
-
if (oldest === void 0) return;
|
|
768
|
-
settlements.delete(oldest);
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
function isSha256Digest(value) {
|
|
772
|
-
return typeof value === "string" && /^sha256:[a-f0-9]{64}$/.test(value);
|
|
773
|
-
}
|
|
774
|
-
function exactRecord(value, keys, label) {
|
|
775
|
-
const source = record(value, label);
|
|
776
|
-
assertExactObjectKeys(source, keys, label);
|
|
777
|
-
return source;
|
|
778
|
-
}
|
|
779
|
-
function record(value, label) {
|
|
780
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
781
|
-
throw new Error(`${label} must be an object`);
|
|
782
|
-
}
|
|
783
|
-
const prototype = Object.getPrototypeOf(value);
|
|
784
|
-
if (prototype !== Object.prototype && prototype !== null) {
|
|
785
|
-
throw new Error(`${label} must be a plain object`);
|
|
786
|
-
}
|
|
787
|
-
return value;
|
|
788
|
-
}
|
|
789
|
-
|
|
790
461
|
// src/candidate-execution/recover.ts
|
|
791
462
|
import {
|
|
792
463
|
agentCandidateExecutionPlanMaterialSchema,
|
|
793
464
|
agentCandidateMaterializationReceiptSchema
|
|
794
465
|
} from "@tangle-network/agent-interface";
|
|
795
466
|
async function recoverExpiredAgentCandidateExecution(options) {
|
|
796
|
-
const
|
|
797
|
-
if (!
|
|
798
|
-
if (
|
|
799
|
-
return Object.freeze({ finished: false, terminal:
|
|
467
|
+
const record = await options.claimStore.getAttempt(options.attempt);
|
|
468
|
+
if (!record) throw new Error("candidate execution recovery attempt is missing");
|
|
469
|
+
if (record.terminal) {
|
|
470
|
+
return Object.freeze({ finished: false, terminal: record.terminal, exactReplay: true });
|
|
800
471
|
}
|
|
801
472
|
const cleanupTimeoutMs = candidateCleanupTimeout(
|
|
802
|
-
options.cleanupTimeoutMs ??
|
|
473
|
+
options.cleanupTimeoutMs ?? record.claim.cleanup.cleanupTimeoutMs
|
|
803
474
|
);
|
|
804
|
-
if (cleanupTimeoutMs >
|
|
475
|
+
if (cleanupTimeoutMs > record.claim.cleanup.cleanupTimeoutMs) {
|
|
805
476
|
throw new Error("recovery cleanup timeout exceeds the frozen preparation bound");
|
|
806
477
|
}
|
|
807
478
|
const now = options.now ?? Date.now;
|
|
808
|
-
if (now() <
|
|
479
|
+
if (now() < record.claim.leaseExpiresAtMs) {
|
|
809
480
|
throw new Error("candidate execution lease has not expired");
|
|
810
481
|
}
|
|
811
482
|
const cleanupDeadlineAtMs = candidateCleanupDeadline(cleanupTimeoutMs);
|
|
812
483
|
const recoveryTraceStore = new RecoveryAgentCandidateTraceStore(options.traceStore);
|
|
813
484
|
const preparation = withinCandidateCleanupDeadline(
|
|
814
|
-
() => readRecoveryPreparation(
|
|
485
|
+
() => readRecoveryPreparation(record.claim, options.outputArtifacts),
|
|
815
486
|
cleanupDeadlineAtMs,
|
|
816
487
|
"expired candidate preparation evidence read"
|
|
817
488
|
);
|
|
@@ -819,8 +490,8 @@ async function recoverExpiredAgentCandidateExecution(options) {
|
|
|
819
490
|
async (cleanupSignal) => {
|
|
820
491
|
const stopped = await options.executor.stop(
|
|
821
492
|
{
|
|
822
|
-
executionId:
|
|
823
|
-
executionPlanDigest:
|
|
493
|
+
executionId: record.claim.executionId,
|
|
494
|
+
executionPlanDigest: record.claim.executionPlanDigest
|
|
824
495
|
},
|
|
825
496
|
{
|
|
826
497
|
traceStore: recoveryTraceStore,
|
|
@@ -833,8 +504,8 @@ async function recoverExpiredAgentCandidateExecution(options) {
|
|
|
833
504
|
if (options.executor.dispose) {
|
|
834
505
|
const disposed = await options.executor.dispose(
|
|
835
506
|
{
|
|
836
|
-
executionId:
|
|
837
|
-
executionPlanDigest:
|
|
507
|
+
executionId: record.claim.executionId,
|
|
508
|
+
executionPlanDigest: record.claim.executionPlanDigest
|
|
838
509
|
},
|
|
839
510
|
{ signal: cleanupSignal }
|
|
840
511
|
);
|
|
@@ -850,28 +521,28 @@ async function recoverExpiredAgentCandidateExecution(options) {
|
|
|
850
521
|
const modelClosure = withinCandidateCleanupDeadline(
|
|
851
522
|
async () => sealAgentCandidateModelSettlement(
|
|
852
523
|
await options.ports.models.settleGrant({
|
|
853
|
-
executionId:
|
|
854
|
-
preparationId:
|
|
855
|
-
grantDigest:
|
|
856
|
-
resolved:
|
|
524
|
+
executionId: record.claim.executionId,
|
|
525
|
+
preparationId: record.claim.cleanup.preparationId,
|
|
526
|
+
grantDigest: record.claim.cleanup.modelGrantDigest,
|
|
527
|
+
resolved: record.claim.cleanup.resolvedModel,
|
|
857
528
|
reason: "failed"
|
|
858
529
|
}),
|
|
859
530
|
{
|
|
860
|
-
preparationId:
|
|
861
|
-
grantDigest:
|
|
862
|
-
model:
|
|
531
|
+
preparationId: record.claim.cleanup.preparationId,
|
|
532
|
+
grantDigest: record.claim.cleanup.modelGrantDigest,
|
|
533
|
+
model: record.claim.cleanup.resolvedModel.model
|
|
863
534
|
}
|
|
864
535
|
),
|
|
865
536
|
cleanupDeadlineAtMs,
|
|
866
537
|
"expired candidate model settlement"
|
|
867
538
|
);
|
|
868
|
-
const memoryClosure =
|
|
539
|
+
const memoryClosure = record.claim.cleanup.memory ? withinCandidateCleanupDeadline(
|
|
869
540
|
async () => {
|
|
870
|
-
const memory2 =
|
|
541
|
+
const memory2 = record.claim.cleanup.memory;
|
|
871
542
|
if (!memory2) throw new Error("expired candidate memory handle is missing");
|
|
872
543
|
const closed = await options.ports.memory.close({
|
|
873
|
-
executionId:
|
|
874
|
-
preparationId:
|
|
544
|
+
executionId: record.claim.executionId,
|
|
545
|
+
preparationId: record.claim.cleanup.preparationId,
|
|
875
546
|
accessDigest: memory2.accessDigest,
|
|
876
547
|
effectiveNamespace: memory2.effectiveNamespace,
|
|
877
548
|
reason: "failed"
|
|
@@ -907,9 +578,9 @@ async function recoverExpiredAgentCandidateExecution(options) {
|
|
|
907
578
|
const modelSettlement = await withinCandidateCleanupDeadline(
|
|
908
579
|
() => persistCandidateModelSettlementEvidence(
|
|
909
580
|
{
|
|
910
|
-
executionId:
|
|
911
|
-
executionPlanDigest:
|
|
912
|
-
resolvedModel:
|
|
581
|
+
executionId: record.claim.executionId,
|
|
582
|
+
executionPlanDigest: record.claim.executionPlanDigest,
|
|
583
|
+
resolvedModel: record.claim.cleanup.resolvedModel
|
|
913
584
|
},
|
|
914
585
|
model,
|
|
915
586
|
options.outputArtifacts
|
|
@@ -917,28 +588,28 @@ async function recoverExpiredAgentCandidateExecution(options) {
|
|
|
917
588
|
cleanupDeadlineAtMs,
|
|
918
589
|
"expired candidate model-settlement persistence"
|
|
919
590
|
);
|
|
920
|
-
const failureClass =
|
|
591
|
+
const failureClass = record.phase === "claimed" && model.usage.modelCalls === 0 ? "pre-model-infrastructure" : "unknown";
|
|
921
592
|
const failureEvidence = await withinCandidateCleanupDeadline(
|
|
922
593
|
() => persistCandidateOutputArtifact(options.outputArtifacts, {
|
|
923
|
-
executionId:
|
|
594
|
+
executionId: record.claim.executionId,
|
|
924
595
|
purpose: "failure-evidence",
|
|
925
596
|
bytes: canonicalCandidateBytes({
|
|
926
597
|
kind: "agent-candidate-recovery-failure",
|
|
927
|
-
executionId:
|
|
928
|
-
attempt:
|
|
929
|
-
bundleDigest:
|
|
930
|
-
executionPlanDigest:
|
|
931
|
-
materializationReceiptDigest:
|
|
598
|
+
executionId: record.claim.executionId,
|
|
599
|
+
attempt: record.claim.attempt,
|
|
600
|
+
bundleDigest: record.claim.bundleDigest,
|
|
601
|
+
executionPlanDigest: record.claim.executionPlanDigest,
|
|
602
|
+
materializationReceiptDigest: record.claim.preparationEvidence.materializationReceipt.sha256,
|
|
932
603
|
failureClass,
|
|
933
604
|
processStopped: true,
|
|
934
605
|
modelSettlementDigest: modelSettlement.digest,
|
|
935
|
-
memoryClosed:
|
|
606
|
+
memoryClosed: record.claim.cleanup.memory !== void 0
|
|
936
607
|
})
|
|
937
608
|
}),
|
|
938
609
|
cleanupDeadlineAtMs,
|
|
939
610
|
"expired candidate failure-evidence persistence"
|
|
940
611
|
);
|
|
941
|
-
const memory =
|
|
612
|
+
const memory = record.claim.cleanup.memory;
|
|
942
613
|
return await options.claimStore.recoverExpired(options.attempt, {
|
|
943
614
|
failureClass,
|
|
944
615
|
usage: model.usage,
|
|
@@ -946,17 +617,17 @@ async function recoverExpiredAgentCandidateExecution(options) {
|
|
|
946
617
|
failureEvidence,
|
|
947
618
|
process: {
|
|
948
619
|
stopped: true,
|
|
949
|
-
executionPlanDigest:
|
|
620
|
+
executionPlanDigest: record.claim.executionPlanDigest
|
|
950
621
|
},
|
|
951
622
|
model: {
|
|
952
623
|
closed: true,
|
|
953
|
-
preparationId:
|
|
954
|
-
grantDigest:
|
|
624
|
+
preparationId: record.claim.cleanup.preparationId,
|
|
625
|
+
grantDigest: record.claim.cleanup.modelGrantDigest
|
|
955
626
|
},
|
|
956
627
|
...memory ? {
|
|
957
628
|
memory: {
|
|
958
629
|
closed: true,
|
|
959
|
-
preparationId:
|
|
630
|
+
preparationId: record.claim.cleanup.preparationId,
|
|
960
631
|
accessDigest: memory.accessDigest,
|
|
961
632
|
effectiveNamespace: memory.effectiveNamespace
|
|
962
633
|
}
|
|
@@ -1004,7 +675,6 @@ export {
|
|
|
1004
675
|
buildAgentCandidateBundle,
|
|
1005
676
|
FileAgentCandidateExecutionClaimStore,
|
|
1006
677
|
disposePreparedAgentCandidateExecution,
|
|
1007
|
-
createProtectedAgentCandidateModelPort,
|
|
1008
678
|
recoverExpiredAgentCandidateExecution
|
|
1009
679
|
};
|
|
1010
|
-
//# sourceMappingURL=chunk-
|
|
680
|
+
//# sourceMappingURL=chunk-SNSMRT6H.js.map
|