@tangle-network/agent-runtime 0.94.12 → 0.95.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/agent.d.ts +2 -25
- package/dist/agent.js +9 -12
- package/dist/agent.js.map +1 -1
- package/dist/{agentic-generator-DDMM45kZ.d.ts → agentic-generator-hCaQRAes.d.ts} +0 -1
- package/dist/analyst-loop.d.ts +1 -1
- package/dist/candidate-execution/index.d.ts +43 -16
- package/dist/candidate-execution/index.js +18 -8
- package/dist/{chunk-VYA2YEKA.js → chunk-2KGAN2HM.js} +83 -14
- package/dist/chunk-2KGAN2HM.js.map +1 -0
- package/dist/{chunk-FTXM7Q7P.js → chunk-6YBA64Z2.js} +120 -724
- package/dist/chunk-6YBA64Z2.js.map +1 -0
- package/dist/{chunk-HGRW27YY.js → chunk-AP7CPGMZ.js} +139 -19
- package/dist/chunk-AP7CPGMZ.js.map +1 -0
- package/dist/{chunk-XP5KDM3R.js → chunk-BPGXIKK7.js} +3 -3
- package/dist/{chunk-D3H7F6L2.js → chunk-DHCHL6OG.js} +2 -3
- package/dist/chunk-DHCHL6OG.js.map +1 -0
- package/dist/{chunk-PCURO3DL.js → chunk-G55QE4IQ.js} +512 -36
- package/dist/chunk-G55QE4IQ.js.map +1 -0
- package/dist/{chunk-C3UKLQ54.js → chunk-IADLKE7I.js} +14 -4
- package/dist/chunk-IADLKE7I.js.map +1 -0
- package/dist/{chunk-WIPGQ4GT.js → chunk-IMSNJSXH.js} +1 -1
- package/dist/{chunk-WIPGQ4GT.js.map → chunk-IMSNJSXH.js.map} +1 -1
- package/dist/{chunk-VSWBYWFK.js → chunk-M6MD6JBS.js} +20 -27
- package/dist/chunk-M6MD6JBS.js.map +1 -0
- package/dist/chunk-MKGRLDWB.js +684 -0
- package/dist/chunk-MKGRLDWB.js.map +1 -0
- package/dist/{chunk-AEG3NGJ2.js → chunk-Q2JSAVQ3.js} +34 -2
- package/dist/chunk-Q2JSAVQ3.js.map +1 -0
- package/dist/{chunk-37V4KQDC.js → chunk-WTZ37EQY.js} +1021 -514
- package/dist/chunk-WTZ37EQY.js.map +1 -0
- package/dist/{chunk-U33YZ7B2.js → chunk-YLUOTX6U.js} +4 -4
- package/dist/{chunk-33OG2NN3.js → chunk-Z5I642SY.js} +2 -2
- package/dist/{completion-gate-D1gX1-hg.d.ts → completion-gate-C80jiRfN.d.ts} +1 -1
- package/dist/conversation.d.ts +12 -1
- package/dist/conversation.js +2 -2
- package/dist/{coordination-Dr_axlAf.d.ts → coordination-BFE3Den7.d.ts} +10 -11
- package/dist/environment-provider.d.ts +2 -2
- package/dist/environment-provider.js +1 -1
- package/dist/{improve-BN3HyXIO.d.ts → improve-B-UYaEH5.d.ts} +3 -3
- package/dist/index.d.ts +22 -25
- package/dist/index.js +45 -50
- package/dist/index.js.map +1 -1
- package/dist/intelligence.d.ts +177 -119
- package/dist/intelligence.js +501 -342
- package/dist/intelligence.js.map +1 -1
- package/dist/knowledge.d.ts +22 -11
- package/dist/knowledge.js +9 -4
- package/dist/lifecycle.d.ts +2 -2
- package/dist/lifecycle.js +1 -1
- package/dist/{loop-runner-bin-BRQSQdHa.d.ts → loop-runner-bin-BIQldFS8.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 +12 -12
- package/dist/loops.js +5 -5
- package/dist/mcp/bin.js +3 -3
- package/dist/mcp/index.d.ts +6 -6
- package/dist/mcp/index.js +6 -6
- package/dist/{mcp-serve-verifier-DQQDbuyz.d.ts → mcp-serve-verifier-Bs_n0xPc.d.ts} +1 -1
- package/dist/primeintellect/index.js +1 -1
- package/dist/profile-DbfaMTdk.d.ts +233 -0
- package/dist/profiles.d.ts +1 -1
- package/dist/{supervise-DmYOug5f.d.ts → supervise-BLPI50-w.d.ts} +3 -3
- package/dist/{types-ByAYqlVb.d.ts → types-B3vAW0Oq.d.ts} +1 -1
- package/dist/types-CWqfCO8s.d.ts +491 -0
- package/dist/{types-1d5QGK3t.d.ts → types-CmnA2iL3.d.ts} +3 -3
- package/dist/{worktree-fanout-CPprU-qI.d.ts → worktree-fanout-DCA3G4bO.d.ts} +3 -3
- package/package.json +13 -10
- package/dist/chunk-37V4KQDC.js.map +0 -1
- package/dist/chunk-AEG3NGJ2.js.map +0 -1
- package/dist/chunk-C3UKLQ54.js.map +0 -1
- package/dist/chunk-D3H7F6L2.js.map +0 -1
- package/dist/chunk-FTXM7Q7P.js.map +0 -1
- package/dist/chunk-HGRW27YY.js.map +0 -1
- package/dist/chunk-PCURO3DL.js.map +0 -1
- package/dist/chunk-VSWBYWFK.js.map +0 -1
- package/dist/chunk-VYA2YEKA.js.map +0 -1
- package/dist/prepare-DIeVgQG3.d.ts +0 -718
- /package/dist/{chunk-XP5KDM3R.js.map → chunk-BPGXIKK7.js.map} +0 -0
- /package/dist/{chunk-U33YZ7B2.js.map → chunk-YLUOTX6U.js.map} +0 -0
- /package/dist/{chunk-33OG2NN3.js.map → chunk-Z5I642SY.js.map} +0 -0
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
contentAddress
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-IMSNJSXH.js";
|
|
4
4
|
|
|
5
|
-
// src/candidate-execution/
|
|
6
|
-
import {
|
|
5
|
+
// src/candidate-execution/profile.ts
|
|
6
|
+
import {
|
|
7
|
+
agentCandidateProfileActivationSchema,
|
|
8
|
+
agentCandidateProfileSchema,
|
|
9
|
+
agentProfileDiffSchema,
|
|
10
|
+
agentProfileSchema,
|
|
11
|
+
applyAgentProfileDiff
|
|
12
|
+
} from "@tangle-network/agent-interface";
|
|
7
13
|
|
|
8
14
|
// src/candidate-execution/digest.ts
|
|
9
15
|
import { createHash } from "crypto";
|
|
@@ -38,6 +44,12 @@ function canonicalCandidateDocument(valueWithoutDigest) {
|
|
|
38
44
|
digest
|
|
39
45
|
});
|
|
40
46
|
}
|
|
47
|
+
function verifyCanonicalCandidateDocument(value, label) {
|
|
48
|
+
if (canonicalCandidateDigest(omitTopLevelDigest(value)) !== value.digest) {
|
|
49
|
+
throw new Error(`${label} digest does not match`);
|
|
50
|
+
}
|
|
51
|
+
return immutableCandidateValue(value);
|
|
52
|
+
}
|
|
41
53
|
function embeddedCandidateArtifact(bytes) {
|
|
42
54
|
return {
|
|
43
55
|
encoding: "base64",
|
|
@@ -61,24 +73,69 @@ function deepFreezeCandidate(value, seen = /* @__PURE__ */ new Set()) {
|
|
|
61
73
|
return Object.freeze(value);
|
|
62
74
|
}
|
|
63
75
|
|
|
64
|
-
// src/candidate-execution/
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
76
|
+
// src/candidate-execution/profile.ts
|
|
77
|
+
var MATERIALIZER_HARNESSES = /* @__PURE__ */ new Set([
|
|
78
|
+
"claude-code",
|
|
79
|
+
"claude",
|
|
80
|
+
"claudish",
|
|
81
|
+
"nanoclaw",
|
|
82
|
+
"codex",
|
|
83
|
+
"opencode",
|
|
84
|
+
"kimi-code",
|
|
85
|
+
"kimi",
|
|
86
|
+
"pi",
|
|
87
|
+
"gemini",
|
|
88
|
+
"hermes",
|
|
89
|
+
"openclaw"
|
|
90
|
+
]);
|
|
91
|
+
function candidateMaterializerHarness(harness) {
|
|
92
|
+
if (!MATERIALIZER_HARNESSES.has(harness)) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`sealed candidate profile materialization is unsupported for harness ${harness}`
|
|
95
|
+
);
|
|
71
96
|
}
|
|
72
|
-
return
|
|
97
|
+
return harness;
|
|
98
|
+
}
|
|
99
|
+
function createAgentCandidateProfileActivation(plan, profilePlan) {
|
|
100
|
+
const sourceByPath = new Map(plan.files.map((file) => [file.relPath, file]));
|
|
101
|
+
if (sourceByPath.size !== plan.files.length) {
|
|
102
|
+
throw new Error("candidate profile activation contains duplicate native file paths");
|
|
103
|
+
}
|
|
104
|
+
const files = profilePlan.material.files.map((expected) => {
|
|
105
|
+
const source = sourceByPath.get(expected.relPath);
|
|
106
|
+
if (!source) {
|
|
107
|
+
throw new Error(`candidate profile activation is missing ${expected.relPath}`);
|
|
108
|
+
}
|
|
109
|
+
const mode = source.mode ?? 420;
|
|
110
|
+
if (!Number.isSafeInteger(mode) || mode < 0 || mode > 511) {
|
|
111
|
+
throw new Error(`candidate profile activation has invalid mode for ${expected.relPath}`);
|
|
112
|
+
}
|
|
113
|
+
return { path: expected.relPath, mode, content: source.content };
|
|
114
|
+
});
|
|
115
|
+
if (files.length !== plan.files.length) {
|
|
116
|
+
throw new Error("candidate profile activation contains unplanned native files");
|
|
117
|
+
}
|
|
118
|
+
return parseAgentCandidateProfileActivation(
|
|
119
|
+
canonicalCandidateDocument({
|
|
120
|
+
kind: "agent-candidate-profile-activation",
|
|
121
|
+
profilePlan,
|
|
122
|
+
files
|
|
123
|
+
}).value,
|
|
124
|
+
profilePlan.digest
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
function parseAgentCandidateProfileActivation(input, expectedProfilePlanDigest) {
|
|
128
|
+
const activation = agentCandidateProfileActivationSchema.parse(input);
|
|
129
|
+
const planBytes = canonicalCandidateBytes(activation.profilePlan.material);
|
|
130
|
+
const profilePlanArtifact = activation.profilePlan.artifact;
|
|
131
|
+
if (sha256Bytes(planBytes) !== activation.profilePlan.digest || profilePlanArtifact.sha256 !== activation.profilePlan.digest || profilePlanArtifact.byteLength !== planBytes.byteLength || "content" in profilePlanArtifact && !Buffer.from(profilePlanArtifact.content, "base64").equals(Buffer.from(planBytes)) || expectedProfilePlanDigest !== void 0 && activation.profilePlan.digest !== expectedProfilePlanDigest) {
|
|
132
|
+
throw new Error("candidate profile activation has an invalid canonical profile plan");
|
|
133
|
+
}
|
|
134
|
+
if (canonicalCandidateDigest(omitTopLevelDigest(activation)) !== activation.digest) {
|
|
135
|
+
throw new Error("candidate profile activation digest does not match");
|
|
136
|
+
}
|
|
137
|
+
return immutableCandidateValue(activation);
|
|
73
138
|
}
|
|
74
|
-
|
|
75
|
-
// src/candidate-execution/profile.ts
|
|
76
|
-
import {
|
|
77
|
-
agentCandidateProfileSchema,
|
|
78
|
-
agentProfileDiffSchema,
|
|
79
|
-
agentProfileSchema,
|
|
80
|
-
applyAgentProfileDiff
|
|
81
|
-
} from "@tangle-network/agent-interface";
|
|
82
139
|
var CANDIDATE_PROFILE_DIRECT_FIELDS = [
|
|
83
140
|
"name",
|
|
84
141
|
"description",
|
|
@@ -137,18 +194,28 @@ function assertCandidateProfileBinding(measuredInput, bundled) {
|
|
|
137
194
|
if (measured.connections || measured.metadata || measured.extensions) {
|
|
138
195
|
throw new Error("proposal candidate profile contains fields unsupported by sealed candidates");
|
|
139
196
|
}
|
|
140
|
-
const normalized =
|
|
197
|
+
const normalized = agentCandidateProfileAsAgentProfile(bundled);
|
|
141
198
|
if (canonicalCandidateDigest(measured) !== canonicalCandidateDigest(normalized)) {
|
|
142
199
|
throw new Error("proposal candidateProfile does not match candidateBundle.profile");
|
|
143
200
|
}
|
|
144
201
|
}
|
|
145
202
|
function parseExactAgentProfile(input, label) {
|
|
146
|
-
|
|
203
|
+
let parsed;
|
|
204
|
+
try {
|
|
205
|
+
parsed = agentProfileSchema.parse(input);
|
|
206
|
+
} catch (cause) {
|
|
207
|
+
throw new Error(`${label} contains unsupported or non-canonical fields`, { cause });
|
|
208
|
+
}
|
|
147
209
|
assertCanonicalParse(input, parsed, label);
|
|
148
210
|
return parsed;
|
|
149
211
|
}
|
|
150
212
|
function parseExactAgentProfileDiff(input, label) {
|
|
151
|
-
|
|
213
|
+
let parsed;
|
|
214
|
+
try {
|
|
215
|
+
parsed = agentProfileDiffSchema.parse(input);
|
|
216
|
+
} catch (cause) {
|
|
217
|
+
throw new Error(`${label} contains unsupported or non-canonical fields`, { cause });
|
|
218
|
+
}
|
|
152
219
|
assertCanonicalParse(input, parsed, label);
|
|
153
220
|
return parsed;
|
|
154
221
|
}
|
|
@@ -172,7 +239,7 @@ function assertCandidateProfileExecutionSupport(profile) {
|
|
|
172
239
|
);
|
|
173
240
|
}
|
|
174
241
|
}
|
|
175
|
-
function
|
|
242
|
+
function agentCandidateProfileAsAgentProfile(candidate) {
|
|
176
243
|
const output = {};
|
|
177
244
|
copyDirectProfileFields(output, candidate);
|
|
178
245
|
if (candidate.model) output.model = { ...candidate.model };
|
|
@@ -375,13 +442,9 @@ import {
|
|
|
375
442
|
} from "@tangle-network/agent-interface";
|
|
376
443
|
|
|
377
444
|
// src/candidate-execution/claim-file-formats.ts
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
var PHASE_FORMAT_VERSION = 1;
|
|
382
|
-
|
|
383
|
-
// src/candidate-execution/claim-terminal.ts
|
|
384
|
-
import { agentCandidateArtifactRefSchema } from "@tangle-network/agent-interface";
|
|
445
|
+
import {
|
|
446
|
+
agentCandidateArtifactRefSchema
|
|
447
|
+
} from "@tangle-network/agent-interface";
|
|
385
448
|
|
|
386
449
|
// src/candidate-execution/exact-object.ts
|
|
387
450
|
function assertExactObjectKeys(value, required, label, optional = []) {
|
|
@@ -400,7 +463,31 @@ function assertExactObjectKeys(value, required, label, optional = []) {
|
|
|
400
463
|
}
|
|
401
464
|
}
|
|
402
465
|
|
|
466
|
+
// src/candidate-execution/claim-file-formats.ts
|
|
467
|
+
function sealCandidatePreparationEvidence(value, executionPlanDigest) {
|
|
468
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
469
|
+
throw new Error("candidate execution preparation evidence must be an object");
|
|
470
|
+
}
|
|
471
|
+
const record = value;
|
|
472
|
+
assertExactObjectKeys(
|
|
473
|
+
record,
|
|
474
|
+
["executionPlan", "materializationReceipt"],
|
|
475
|
+
"candidate execution preparation evidence"
|
|
476
|
+
);
|
|
477
|
+
const executionPlan = immutableCandidateValue(
|
|
478
|
+
agentCandidateArtifactRefSchema.parse(record.executionPlan)
|
|
479
|
+
);
|
|
480
|
+
const materializationReceipt = immutableCandidateValue(
|
|
481
|
+
agentCandidateArtifactRefSchema.parse(record.materializationReceipt)
|
|
482
|
+
);
|
|
483
|
+
if (executionPlan.sha256 !== executionPlanDigest) {
|
|
484
|
+
throw new Error("candidate execution plan artifact digest does not match its claim");
|
|
485
|
+
}
|
|
486
|
+
return Object.freeze({ executionPlan, materializationReceipt });
|
|
487
|
+
}
|
|
488
|
+
|
|
403
489
|
// src/candidate-execution/claim-terminal.ts
|
|
490
|
+
import { agentCandidateArtifactRefSchema as agentCandidateArtifactRefSchema2 } from "@tangle-network/agent-interface";
|
|
404
491
|
var SHA256_PATTERN = /^sha256:[a-f0-9]{64}$/;
|
|
405
492
|
function terminalRecord(claim, result) {
|
|
406
493
|
const terminal = sealTerminalResult(result);
|
|
@@ -409,6 +496,7 @@ function terminalRecord(claim, result) {
|
|
|
409
496
|
attempt: claim.attempt,
|
|
410
497
|
bundleDigest: claim.bundleDigest,
|
|
411
498
|
executionPlanDigest: claim.executionPlanDigest,
|
|
499
|
+
preparationEvidence: claim.preparationEvidence,
|
|
412
500
|
...terminal
|
|
413
501
|
};
|
|
414
502
|
return immutableCandidateValue({
|
|
@@ -419,7 +507,6 @@ function terminalRecord(claim, result) {
|
|
|
419
507
|
function recoveredTerminalRecord(claim, phase, evidence) {
|
|
420
508
|
const recovered = sealRecoveryEvidence(evidence, claim);
|
|
421
509
|
return terminalRecord(claim, {
|
|
422
|
-
schemaVersion: 1,
|
|
423
510
|
status: "failed",
|
|
424
511
|
failureClass: recovered.failureClass === "pre-model-infrastructure" && phase !== "claimed" ? "unknown" : recovered.failureClass,
|
|
425
512
|
usage: recovered.usage,
|
|
@@ -474,8 +561,8 @@ function sealTerminalRecordValue(value, label) {
|
|
|
474
561
|
"attempt",
|
|
475
562
|
"bundleDigest",
|
|
476
563
|
"executionPlanDigest",
|
|
564
|
+
"preparationEvidence",
|
|
477
565
|
"terminalDigest",
|
|
478
|
-
"schemaVersion",
|
|
479
566
|
"status",
|
|
480
567
|
"usage",
|
|
481
568
|
"modelSettlement",
|
|
@@ -487,8 +574,8 @@ function sealTerminalRecordValue(value, label) {
|
|
|
487
574
|
"attempt",
|
|
488
575
|
"bundleDigest",
|
|
489
576
|
"executionPlanDigest",
|
|
577
|
+
"preparationEvidence",
|
|
490
578
|
"terminalDigest",
|
|
491
|
-
"schemaVersion",
|
|
492
579
|
"status",
|
|
493
580
|
"failureClass",
|
|
494
581
|
"usage",
|
|
@@ -497,14 +584,19 @@ function sealTerminalRecordValue(value, label) {
|
|
|
497
584
|
],
|
|
498
585
|
label
|
|
499
586
|
);
|
|
587
|
+
const executionPlanDigest = requireString(
|
|
588
|
+
value.executionPlanDigest,
|
|
589
|
+
label,
|
|
590
|
+
"executionPlanDigest"
|
|
591
|
+
);
|
|
500
592
|
const identity = {
|
|
501
593
|
executionId: requireString(value.executionId, label, "executionId"),
|
|
502
594
|
attempt: requireNumber(value.attempt, label, "attempt"),
|
|
503
595
|
bundleDigest: requireString(value.bundleDigest, label, "bundleDigest"),
|
|
504
|
-
executionPlanDigest
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
596
|
+
executionPlanDigest,
|
|
597
|
+
preparationEvidence: sealCandidatePreparationEvidence(
|
|
598
|
+
value.preparationEvidence,
|
|
599
|
+
executionPlanDigest
|
|
508
600
|
)
|
|
509
601
|
};
|
|
510
602
|
assertExecutionId(identity.executionId);
|
|
@@ -513,28 +605,21 @@ function sealTerminalRecordValue(value, label) {
|
|
|
513
605
|
}
|
|
514
606
|
assertSha256Digest(identity.bundleDigest, "bundleDigest");
|
|
515
607
|
assertSha256Digest(identity.executionPlanDigest, "executionPlanDigest");
|
|
608
|
+
if (identity.preparationEvidence.executionPlan.sha256 !== identity.executionPlanDigest) {
|
|
609
|
+
throw new Error(`${label} execution plan artifact does not match executionPlanDigest`);
|
|
610
|
+
}
|
|
516
611
|
const result = sealTerminalResult(
|
|
517
612
|
status === "succeeded" ? {
|
|
518
|
-
schemaVersion: requireNumber(value.schemaVersion, label, "schemaVersion"),
|
|
519
613
|
status,
|
|
520
|
-
usage: requireObject(
|
|
521
|
-
value.usage,
|
|
522
|
-
label,
|
|
523
|
-
"usage"
|
|
524
|
-
),
|
|
614
|
+
usage: requireObject(value.usage, label, "usage"),
|
|
525
615
|
modelSettlement: requireArtifactRef(value.modelSettlement, label, "modelSettlement"),
|
|
526
616
|
taskOutcome: requireArtifactRef(value.taskOutcome, label, "taskOutcome"),
|
|
527
617
|
benchmarkResult: requireArtifactRef(value.benchmarkResult, label, "benchmarkResult"),
|
|
528
618
|
runReceipt: requireArtifactRef(value.runReceipt, label, "runReceipt")
|
|
529
619
|
} : {
|
|
530
|
-
schemaVersion: requireNumber(value.schemaVersion, label, "schemaVersion"),
|
|
531
620
|
status,
|
|
532
621
|
failureClass: requireFailureClass(value.failureClass, label),
|
|
533
|
-
usage: requireObject(
|
|
534
|
-
value.usage,
|
|
535
|
-
label,
|
|
536
|
-
"usage"
|
|
537
|
-
),
|
|
622
|
+
usage: requireObject(value.usage, label, "usage"),
|
|
538
623
|
modelSettlement: requireArtifactRef(value.modelSettlement, label, "modelSettlement"),
|
|
539
624
|
...value.failureEvidence ? {
|
|
540
625
|
failureEvidence: requireArtifactRef(
|
|
@@ -561,7 +646,7 @@ function sealTerminalRecordValue(value, label) {
|
|
|
561
646
|
});
|
|
562
647
|
}
|
|
563
648
|
function assertTerminalMatchesClaim(terminal, claim, path) {
|
|
564
|
-
if (terminal.executionId !== claim.executionId || terminal.attempt !== claim.attempt || terminal.bundleDigest !== claim.bundleDigest || terminal.executionPlanDigest !== claim.executionPlanDigest) {
|
|
649
|
+
if (terminal.executionId !== claim.executionId || terminal.attempt !== claim.attempt || terminal.bundleDigest !== claim.bundleDigest || terminal.executionPlanDigest !== claim.executionPlanDigest || canonicalCandidateDigest(terminal.preparationEvidence) !== canonicalCandidateDigest(claim.preparationEvidence)) {
|
|
565
650
|
throw new Error(`candidate execution terminal record at ${path} does not match its claim`);
|
|
566
651
|
}
|
|
567
652
|
}
|
|
@@ -640,16 +725,7 @@ function sealTerminalResult(result) {
|
|
|
640
725
|
}
|
|
641
726
|
assertExactObjectKeys(
|
|
642
727
|
result,
|
|
643
|
-
result.status === "succeeded" ? [
|
|
644
|
-
"schemaVersion",
|
|
645
|
-
"status",
|
|
646
|
-
"usage",
|
|
647
|
-
"modelSettlement",
|
|
648
|
-
"taskOutcome",
|
|
649
|
-
"benchmarkResult",
|
|
650
|
-
"runReceipt"
|
|
651
|
-
] : [
|
|
652
|
-
"schemaVersion",
|
|
728
|
+
result.status === "succeeded" ? ["status", "usage", "modelSettlement", "taskOutcome", "benchmarkResult", "runReceipt"] : [
|
|
653
729
|
"status",
|
|
654
730
|
"failureClass",
|
|
655
731
|
"usage",
|
|
@@ -658,14 +734,10 @@ function sealTerminalResult(result) {
|
|
|
658
734
|
],
|
|
659
735
|
"candidate execution terminal result"
|
|
660
736
|
);
|
|
661
|
-
if (result.schemaVersion !== 1) {
|
|
662
|
-
throw new Error("candidate execution terminal schemaVersion must be 1");
|
|
663
|
-
}
|
|
664
737
|
const usage = sealUsage(result.usage);
|
|
665
738
|
const modelSettlement = sealArtifactRef(result.modelSettlement, "modelSettlement");
|
|
666
739
|
if (result.status === "succeeded") {
|
|
667
740
|
return Object.freeze({
|
|
668
|
-
schemaVersion: 1,
|
|
669
741
|
status: "succeeded",
|
|
670
742
|
usage,
|
|
671
743
|
modelSettlement,
|
|
@@ -679,7 +751,6 @@ function sealTerminalResult(result) {
|
|
|
679
751
|
throw new Error("pre-model infrastructure failure cannot contain model calls");
|
|
680
752
|
}
|
|
681
753
|
return Object.freeze({
|
|
682
|
-
schemaVersion: 1,
|
|
683
754
|
status: "failed",
|
|
684
755
|
failureClass: result.failureClass,
|
|
685
756
|
usage,
|
|
@@ -713,7 +784,7 @@ function sealUsage(usage) {
|
|
|
713
784
|
});
|
|
714
785
|
}
|
|
715
786
|
function sealArtifactRef(ref, label) {
|
|
716
|
-
const parsed =
|
|
787
|
+
const parsed = agentCandidateArtifactRefSchema2.parse(ref);
|
|
717
788
|
if (!Number.isSafeInteger(parsed.byteLength)) {
|
|
718
789
|
throw new Error(`candidate execution terminal ${label} byteLength exceeds safe integer range`);
|
|
719
790
|
}
|
|
@@ -798,29 +869,15 @@ function candidateResultTimeout(timeoutMs, taskTimeoutMs) {
|
|
|
798
869
|
return effective;
|
|
799
870
|
}
|
|
800
871
|
async function withinCandidateCleanupDeadline(operation, deadlineAtMs, label) {
|
|
801
|
-
|
|
802
|
-
if (remainingMs <= 0) throw new CandidateCleanupTimeoutError(label);
|
|
803
|
-
const pending = Promise.resolve().then(operation);
|
|
804
|
-
void pending.catch(() => void 0);
|
|
805
|
-
let timer;
|
|
806
|
-
try {
|
|
807
|
-
const result = await Promise.race([
|
|
808
|
-
pending,
|
|
809
|
-
new Promise((_resolve, reject) => {
|
|
810
|
-
timer = setTimeout(() => reject(new CandidateCleanupTimeoutError(label)), remainingMs);
|
|
811
|
-
})
|
|
812
|
-
]);
|
|
813
|
-
if (Date.now() >= deadlineAtMs) throw new CandidateCleanupTimeoutError(label);
|
|
814
|
-
return result;
|
|
815
|
-
} finally {
|
|
816
|
-
if (timer) clearTimeout(timer);
|
|
817
|
-
}
|
|
872
|
+
return withinCandidateDeadline(operation, deadlineAtMs, new CandidateCleanupTimeoutError(label));
|
|
818
873
|
}
|
|
819
874
|
async function withinCandidateResultDeadline(operation, deadlineAtMs, label) {
|
|
875
|
+
return withinCandidateDeadline(operation, deadlineAtMs, new CandidateResultTimeoutError(label));
|
|
876
|
+
}
|
|
877
|
+
async function withinCandidateDeadline(operation, deadlineAtMs, timeoutError) {
|
|
820
878
|
const remainingMs = deadlineAtMs - Date.now();
|
|
821
|
-
if (remainingMs <= 0) throw
|
|
879
|
+
if (remainingMs <= 0) throw timeoutError;
|
|
822
880
|
const controller = new AbortController();
|
|
823
|
-
const timeoutError = new CandidateResultTimeoutError(label);
|
|
824
881
|
const pending = Promise.resolve().then(() => operation(controller.signal));
|
|
825
882
|
void pending.catch(() => void 0);
|
|
826
883
|
let timer;
|
|
@@ -949,8 +1006,8 @@ var InMemoryAgentCandidateExecutionClaimStore = class {
|
|
|
949
1006
|
}
|
|
950
1007
|
};
|
|
951
1008
|
var SHA256_PATTERN2 = /^sha256:[a-f0-9]{64}$/;
|
|
952
|
-
var LEASE_TOKEN_PATTERN = /^candidate-execution-lease
|
|
953
|
-
var PREPARATION_ID_PATTERN = /^candidate-preparation
|
|
1009
|
+
var LEASE_TOKEN_PATTERN = /^candidate-execution-lease\.[A-Za-z0-9_-]{43}$/;
|
|
1010
|
+
var PREPARATION_ID_PATTERN = /^candidate-preparation\.[A-Za-z0-9_-]{43}$/;
|
|
954
1011
|
function sealClaim(claim) {
|
|
955
1012
|
assertExactObjectKeys(
|
|
956
1013
|
claim,
|
|
@@ -961,6 +1018,7 @@ function sealClaim(claim) {
|
|
|
961
1018
|
"retryPolicy",
|
|
962
1019
|
"bundleDigest",
|
|
963
1020
|
"executionPlanDigest",
|
|
1021
|
+
"preparationEvidence",
|
|
964
1022
|
"retryLineageDigest",
|
|
965
1023
|
"leaseExpiresAtMs",
|
|
966
1024
|
"resultTimeoutMs",
|
|
@@ -986,6 +1044,10 @@ function sealClaim(claim) {
|
|
|
986
1044
|
}
|
|
987
1045
|
assertSha256Digest2(claim.bundleDigest, "bundleDigest");
|
|
988
1046
|
assertSha256Digest2(claim.executionPlanDigest, "executionPlanDigest");
|
|
1047
|
+
const preparationEvidence = sealCandidatePreparationEvidence(
|
|
1048
|
+
claim.preparationEvidence,
|
|
1049
|
+
claim.executionPlanDigest
|
|
1050
|
+
);
|
|
989
1051
|
assertSha256Digest2(claim.retryLineageDigest, "retryLineageDigest");
|
|
990
1052
|
assertPositiveTimestamp(claim.leaseExpiresAtMs, "leaseExpiresAtMs");
|
|
991
1053
|
candidateResultTimeout(claim.resultTimeoutMs, claim.resultTimeoutMs);
|
|
@@ -997,6 +1059,7 @@ function sealClaim(claim) {
|
|
|
997
1059
|
retryPolicy: claim.retryPolicy,
|
|
998
1060
|
bundleDigest: claim.bundleDigest,
|
|
999
1061
|
executionPlanDigest: claim.executionPlanDigest,
|
|
1062
|
+
preparationEvidence,
|
|
1000
1063
|
retryLineageDigest: claim.retryLineageDigest,
|
|
1001
1064
|
leaseExpiresAtMs: claim.leaseExpiresAtMs,
|
|
1002
1065
|
resultTimeoutMs: claim.resultTimeoutMs,
|
|
@@ -1080,7 +1143,7 @@ function newLease(claim) {
|
|
|
1080
1143
|
return Object.freeze({
|
|
1081
1144
|
executionId: claim.executionId,
|
|
1082
1145
|
attempt: claim.attempt,
|
|
1083
|
-
token: `candidate-execution-lease
|
|
1146
|
+
token: `candidate-execution-lease.${randomBytes(32).toString("base64url")}`,
|
|
1084
1147
|
expiresAtMs: claim.leaseExpiresAtMs
|
|
1085
1148
|
});
|
|
1086
1149
|
}
|
|
@@ -1131,19 +1194,16 @@ function rejectedRetry(claim, detail) {
|
|
|
1131
1194
|
async function readClaim(path) {
|
|
1132
1195
|
const parsed = await readJsonObject(path, "claim");
|
|
1133
1196
|
const record = parsed;
|
|
1134
|
-
if (record.version !== CLAIM_FORMAT_VERSION) {
|
|
1135
|
-
throw new Error(`candidate execution claim at ${path} has unsupported version`);
|
|
1136
|
-
}
|
|
1137
1197
|
assertExactObjectKeys(
|
|
1138
1198
|
parsed,
|
|
1139
1199
|
[
|
|
1140
|
-
"version",
|
|
1141
1200
|
"executionId",
|
|
1142
1201
|
"attempt",
|
|
1143
1202
|
"maxAttempts",
|
|
1144
1203
|
"retryPolicy",
|
|
1145
1204
|
"bundleDigest",
|
|
1146
1205
|
"executionPlanDigest",
|
|
1206
|
+
"preparationEvidence",
|
|
1147
1207
|
"retryLineageDigest",
|
|
1148
1208
|
"leaseExpiresAtMs",
|
|
1149
1209
|
"resultTimeoutMs",
|
|
@@ -1164,6 +1224,11 @@ async function readClaim(path) {
|
|
|
1164
1224
|
path,
|
|
1165
1225
|
"executionPlanDigest"
|
|
1166
1226
|
),
|
|
1227
|
+
preparationEvidence: requireObject2(
|
|
1228
|
+
record.preparationEvidence,
|
|
1229
|
+
path,
|
|
1230
|
+
"preparationEvidence"
|
|
1231
|
+
),
|
|
1167
1232
|
retryLineageDigest: requireString2(
|
|
1168
1233
|
record.retryLineageDigest,
|
|
1169
1234
|
path,
|
|
@@ -1199,10 +1264,7 @@ async function readClaimIfPresent(path) {
|
|
|
1199
1264
|
async function readTerminal(path) {
|
|
1200
1265
|
const parsed = await readJsonObject(path, "terminal record");
|
|
1201
1266
|
const record = parsed;
|
|
1202
|
-
|
|
1203
|
-
throw new Error(`candidate execution terminal record at ${path} has unsupported version`);
|
|
1204
|
-
}
|
|
1205
|
-
assertExactObjectKeys(parsed, ["version", "terminal"], `candidate execution terminal record at ${path}`);
|
|
1267
|
+
assertExactObjectKeys(parsed, ["terminal"], `candidate execution terminal record at ${path}`);
|
|
1206
1268
|
return sealTerminalRecordValue(
|
|
1207
1269
|
requireObject2(record.terminal, path, "terminal"),
|
|
1208
1270
|
`candidate execution terminal record at ${path}`
|
|
@@ -1226,12 +1288,9 @@ async function readTransitionIfPresent(path, claim) {
|
|
|
1226
1288
|
}
|
|
1227
1289
|
if (parsed.kind === "candidate-execution-phase") {
|
|
1228
1290
|
const record = parsed;
|
|
1229
|
-
if (record.version !== PHASE_FORMAT_VERSION) {
|
|
1230
|
-
throw new Error(`candidate execution phase record at ${path} has unsupported version`);
|
|
1231
|
-
}
|
|
1232
1291
|
assertExactObjectKeys(
|
|
1233
1292
|
parsed,
|
|
1234
|
-
["
|
|
1293
|
+
["kind", "executionId", "attempt", "executionPlanDigest", "phase"],
|
|
1235
1294
|
`candidate execution phase record at ${path}`
|
|
1236
1295
|
);
|
|
1237
1296
|
if (record.executionId !== claim.executionId || record.attempt !== claim.attempt || record.executionPlanDigest !== claim.executionPlanDigest || record.phase !== "candidate-may-run") {
|
|
@@ -1241,14 +1300,7 @@ async function readTransitionIfPresent(path, claim) {
|
|
|
1241
1300
|
}
|
|
1242
1301
|
if (parsed.kind === "candidate-execution-pending-terminal") {
|
|
1243
1302
|
const record = parsed;
|
|
1244
|
-
|
|
1245
|
-
throw new Error(`candidate execution pending record at ${path} has unsupported version`);
|
|
1246
|
-
}
|
|
1247
|
-
assertExactObjectKeys(
|
|
1248
|
-
parsed,
|
|
1249
|
-
["version", "kind", "terminal"],
|
|
1250
|
-
`candidate execution pending record at ${path}`
|
|
1251
|
-
);
|
|
1303
|
+
assertExactObjectKeys(parsed, ["kind", "terminal"], `candidate execution pending record at ${path}`);
|
|
1252
1304
|
const terminal = sealTerminalRecordValue(
|
|
1253
1305
|
requireObject2(record.terminal, path, "terminal"),
|
|
1254
1306
|
`candidate execution pending record at ${path}`
|
|
@@ -1398,6 +1450,8 @@ function candidateTerminalWindowMs(cleanupTimeoutMs) {
|
|
|
1398
1450
|
|
|
1399
1451
|
// src/candidate-execution/prepared-state.ts
|
|
1400
1452
|
import {
|
|
1453
|
+
agentCandidateBenchmarkSuiteSchema,
|
|
1454
|
+
agentCandidateBenchmarkTaskSchema,
|
|
1401
1455
|
agentCandidateExecutionPlanEvidenceSchema,
|
|
1402
1456
|
agentCandidateMaterializationReceiptSchema,
|
|
1403
1457
|
agentCandidateProfilePlanEvidenceSchema
|
|
@@ -1464,6 +1518,17 @@ async function readMaterializedWorkspaceFiles(root, expected, options = {}) {
|
|
|
1464
1518
|
(file) => Object.freeze({ path: file.path, mode: file.mode, bytes: Uint8Array.from(file.bytes) })
|
|
1465
1519
|
);
|
|
1466
1520
|
}
|
|
1521
|
+
function candidateWorkspaceManifest(files) {
|
|
1522
|
+
return {
|
|
1523
|
+
kind: "agent-candidate-workspace-manifest",
|
|
1524
|
+
files: files.map((file) => ({
|
|
1525
|
+
path: file.path,
|
|
1526
|
+
mode: file.mode,
|
|
1527
|
+
sha256: sha256Bytes(file.bytes),
|
|
1528
|
+
byteLength: file.bytes.byteLength
|
|
1529
|
+
})).sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0)
|
|
1530
|
+
};
|
|
1531
|
+
}
|
|
1467
1532
|
function assertWorkspaceManifest(observed, expected) {
|
|
1468
1533
|
if (!Buffer.from(canonicalCandidateBytes(observed)).equals(canonicalCandidateBytes(expected))) {
|
|
1469
1534
|
throw new Error(
|
|
@@ -1493,7 +1558,6 @@ async function scanWorkspace(root, ignoredProtectedRootEntries, limits) {
|
|
|
1493
1558
|
if (await realpath(absoluteRoot) !== absoluteRoot) {
|
|
1494
1559
|
throw new Error("workspace root has a symlinked path component");
|
|
1495
1560
|
}
|
|
1496
|
-
const files = [];
|
|
1497
1561
|
const capturedFiles = [];
|
|
1498
1562
|
let totalBytes = 0;
|
|
1499
1563
|
async function visit(directory) {
|
|
@@ -1519,7 +1583,7 @@ async function scanWorkspace(root, ignoredProtectedRootEntries, limits) {
|
|
|
1519
1583
|
if (!stats.isFile()) {
|
|
1520
1584
|
throw new Error(`workspace contains a non-regular entry: ${relPath}`);
|
|
1521
1585
|
}
|
|
1522
|
-
if (limits &&
|
|
1586
|
+
if (limits && capturedFiles.length >= limits.maxFiles) {
|
|
1523
1587
|
throw new Error("workspace exceeds maxFiles");
|
|
1524
1588
|
}
|
|
1525
1589
|
const descriptor = await open(
|
|
@@ -1535,9 +1599,6 @@ async function scanWorkspace(root, ignoredProtectedRootEntries, limits) {
|
|
|
1535
1599
|
throw new Error(`workspace contains a hard-linked file: ${relPath}`);
|
|
1536
1600
|
}
|
|
1537
1601
|
const mode = openedStats.mode & 511;
|
|
1538
|
-
if (mode !== 420 && mode !== 493) {
|
|
1539
|
-
throw new Error(`workspace file has unsupported mode ${mode.toString(8)}: ${relPath}`);
|
|
1540
|
-
}
|
|
1541
1602
|
if (limits && openedStats.size > limits.maxFileBytes) {
|
|
1542
1603
|
throw new Error(`workspace file exceeds maxFileBytes: ${relPath}`);
|
|
1543
1604
|
}
|
|
@@ -1551,28 +1612,15 @@ async function scanWorkspace(root, ignoredProtectedRootEntries, limits) {
|
|
|
1551
1612
|
relPath
|
|
1552
1613
|
);
|
|
1553
1614
|
totalBytes += bytes.byteLength;
|
|
1554
|
-
|
|
1555
|
-
files.push({
|
|
1556
|
-
path: relPath,
|
|
1557
|
-
mode: supportedMode,
|
|
1558
|
-
sha256: sha256Bytes(bytes),
|
|
1559
|
-
byteLength: bytes.byteLength
|
|
1560
|
-
});
|
|
1561
|
-
capturedFiles.push({ path: relPath, mode: supportedMode, bytes: Uint8Array.from(bytes) });
|
|
1615
|
+
capturedFiles.push({ path: relPath, mode, bytes: Uint8Array.from(bytes) });
|
|
1562
1616
|
} finally {
|
|
1563
1617
|
await descriptor.close();
|
|
1564
1618
|
}
|
|
1565
1619
|
}
|
|
1566
1620
|
}
|
|
1567
1621
|
await visit(absoluteRoot);
|
|
1568
|
-
files.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
1569
|
-
capturedFiles.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
1570
1622
|
return {
|
|
1571
|
-
manifest:
|
|
1572
|
-
schemaVersion: 1,
|
|
1573
|
-
kind: "agent-candidate-workspace-manifest",
|
|
1574
|
-
files
|
|
1575
|
-
},
|
|
1623
|
+
manifest: candidateWorkspaceManifest(capturedFiles),
|
|
1576
1624
|
files: capturedFiles
|
|
1577
1625
|
};
|
|
1578
1626
|
}
|
|
@@ -1797,19 +1845,9 @@ async function assertSafeTree(repositoryRoot, tree, environment = {}) {
|
|
|
1797
1845
|
}
|
|
1798
1846
|
}
|
|
1799
1847
|
async function workspaceManifestFromGitTree(repositoryRoot, tree, environment) {
|
|
1800
|
-
|
|
1801
|
-
(
|
|
1802
|
-
path,
|
|
1803
|
-
mode,
|
|
1804
|
-
sha256: sha256Bytes(bytes),
|
|
1805
|
-
byteLength: bytes.byteLength
|
|
1806
|
-
})
|
|
1848
|
+
return candidateWorkspaceManifest(
|
|
1849
|
+
await readCandidateGitTreeFiles(repositoryRoot, tree, environment)
|
|
1807
1850
|
);
|
|
1808
|
-
return {
|
|
1809
|
-
schemaVersion: 1,
|
|
1810
|
-
kind: "agent-candidate-workspace-manifest",
|
|
1811
|
-
files
|
|
1812
|
-
};
|
|
1813
1851
|
}
|
|
1814
1852
|
async function readCandidateGitTreeFiles(repositoryRoot, tree, environment = {}, limits) {
|
|
1815
1853
|
const listing = (await runCandidateGit(
|
|
@@ -1959,9 +1997,11 @@ function createPreparedCandidateExecution(input) {
|
|
|
1959
1997
|
assertPrivateCandidateIntegrity(state);
|
|
1960
1998
|
const prepared = Object.freeze({
|
|
1961
1999
|
bundle: state.bundle,
|
|
2000
|
+
benchmark: Object.freeze({ suite: state.benchmarkSuite, task: state.benchmarkTask }),
|
|
1962
2001
|
executionId: state.executionId,
|
|
1963
2002
|
roots: state.roots,
|
|
1964
2003
|
profilePlan: evidenceView(state.profilePlan),
|
|
2004
|
+
profileActivation: state.profileActivation,
|
|
1965
2005
|
executionPlan: evidenceView(state.executionPlan),
|
|
1966
2006
|
materializationReceipt: state.materializationReceipt,
|
|
1967
2007
|
launch: state.launch,
|
|
@@ -2014,8 +2054,9 @@ function beginPreparedCandidateRun(prepared, modelAccess, memoryAccess) {
|
|
|
2014
2054
|
const material = state.executionPlan.value.material;
|
|
2015
2055
|
const request = Object.freeze({
|
|
2016
2056
|
executionId: state.executionId,
|
|
2057
|
+
benchmark: preparedBenchmark(state),
|
|
2017
2058
|
inputs: Object.freeze({
|
|
2018
|
-
task: workspaceInputView(
|
|
2059
|
+
task: workspaceInputView(state.benchmarkTask.workspace, state.executorInputs.taskFiles),
|
|
2019
2060
|
...material.candidateWorkspace && state.executorInputs.candidateFiles ? {
|
|
2020
2061
|
candidate: workspaceInputView(
|
|
2021
2062
|
material.candidateWorkspace,
|
|
@@ -2030,6 +2071,7 @@ function beginPreparedCandidateRun(prepared, modelAccess, memoryAccess) {
|
|
|
2030
2071
|
}),
|
|
2031
2072
|
roots: state.roots.execution,
|
|
2032
2073
|
profilePlan: evidenceView(state.profilePlan),
|
|
2074
|
+
profileActivation: state.profileActivation,
|
|
2033
2075
|
executionPlan: evidenceView(state.executionPlan),
|
|
2034
2076
|
materializationReceipt: state.materializationReceipt,
|
|
2035
2077
|
launch: immutableCandidateValue({ ...state.launch, env: completeEnvironment }),
|
|
@@ -2043,6 +2085,9 @@ function beginPreparedCandidateRun(prepared, modelAccess, memoryAccess) {
|
|
|
2043
2085
|
});
|
|
2044
2086
|
return { state, request };
|
|
2045
2087
|
}
|
|
2088
|
+
function preparedBenchmark(state) {
|
|
2089
|
+
return Object.freeze({ suite: state.benchmarkSuite, task: state.benchmarkTask });
|
|
2090
|
+
}
|
|
2046
2091
|
function consumePreparedCandidateExecution(prepared, outcome) {
|
|
2047
2092
|
transitionLifecycle(
|
|
2048
2093
|
prepared,
|
|
@@ -2055,10 +2100,16 @@ function beginPreparedCandidateSettlement(prepared) {
|
|
|
2055
2100
|
}
|
|
2056
2101
|
async function assertPreparedCandidateWorkspaces(state) {
|
|
2057
2102
|
const plan = state.executionPlan.value.material;
|
|
2058
|
-
await verifyMaterializedWorkspace(
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2103
|
+
await verifyMaterializedWorkspace(
|
|
2104
|
+
state.roots.staging.taskRoot,
|
|
2105
|
+
state.benchmarkTask.workspace.material,
|
|
2106
|
+
{
|
|
2107
|
+
ignoredProtectedRootEntries: [".git", ".sidecar"]
|
|
2108
|
+
}
|
|
2109
|
+
);
|
|
2110
|
+
if (state.benchmarkTask.repository) {
|
|
2111
|
+
await verifyTaskCheckout(state.roots.staging.taskRoot, state.benchmarkTask.repository);
|
|
2112
|
+
}
|
|
2062
2113
|
await verifyMaterializedProfileWorkspace(
|
|
2063
2114
|
state.roots.staging.profileRoot,
|
|
2064
2115
|
state.profilePlan.value.material
|
|
@@ -2072,9 +2123,19 @@ async function assertPreparedCandidateWorkspaces(state) {
|
|
|
2072
2123
|
}
|
|
2073
2124
|
}
|
|
2074
2125
|
function detachPreparedCandidateState(input) {
|
|
2126
|
+
const benchmarkSuite = immutableCandidateValue(
|
|
2127
|
+
agentCandidateBenchmarkSuiteSchema.parse(input.benchmarkSuite)
|
|
2128
|
+
);
|
|
2129
|
+
const benchmarkTask = immutableCandidateValue(
|
|
2130
|
+
agentCandidateBenchmarkTaskSchema.parse(input.benchmarkTask)
|
|
2131
|
+
);
|
|
2075
2132
|
const profilePlan = immutableCandidateValue(
|
|
2076
2133
|
agentCandidateProfilePlanEvidenceSchema.parse(input.profilePlan.value)
|
|
2077
2134
|
);
|
|
2135
|
+
const profileActivation = parseAgentCandidateProfileActivation(
|
|
2136
|
+
input.profileActivation,
|
|
2137
|
+
profilePlan.digest
|
|
2138
|
+
);
|
|
2078
2139
|
const executionPlan = immutableCandidateValue(
|
|
2079
2140
|
agentCandidateExecutionPlanEvidenceSchema.parse(input.executionPlan.value)
|
|
2080
2141
|
);
|
|
@@ -2090,6 +2151,8 @@ function detachPreparedCandidateState(input) {
|
|
|
2090
2151
|
return Object.freeze({
|
|
2091
2152
|
ports: input.ports,
|
|
2092
2153
|
bundle: input.bundle,
|
|
2154
|
+
benchmarkSuite,
|
|
2155
|
+
benchmarkTask,
|
|
2093
2156
|
executionId: input.executionId,
|
|
2094
2157
|
roots: immutableCandidateValue(input.roots),
|
|
2095
2158
|
profilePlan: Object.freeze({
|
|
@@ -2097,6 +2160,7 @@ function detachPreparedCandidateState(input) {
|
|
|
2097
2160
|
bytes: Uint8Array.from(input.profilePlan.bytes),
|
|
2098
2161
|
written: Object.freeze([...input.profilePlan.written])
|
|
2099
2162
|
}),
|
|
2163
|
+
profileActivation,
|
|
2100
2164
|
executionPlan: Object.freeze({
|
|
2101
2165
|
value: executionPlan,
|
|
2102
2166
|
bytes: Uint8Array.from(input.executionPlan.bytes)
|
|
@@ -2116,18 +2180,15 @@ function detachPreparedCandidateState(input) {
|
|
|
2116
2180
|
executorInputs: Object.freeze({
|
|
2117
2181
|
taskFiles: immutableExecutorFiles(input.executorInputs.taskFiles),
|
|
2118
2182
|
...input.executorInputs.candidateFiles ? { candidateFiles: immutableExecutorFiles(input.executorInputs.candidateFiles) } : {},
|
|
2119
|
-
profileFiles:
|
|
2120
|
-
input.executorInputs.profileFiles.map(
|
|
2121
|
-
(file) => Object.freeze({ ...file, bytes: Uint8Array.from(file.bytes) })
|
|
2122
|
-
)
|
|
2123
|
-
)
|
|
2183
|
+
profileFiles: immutableExecutorFiles(input.executorInputs.profileFiles)
|
|
2124
2184
|
}),
|
|
2125
2185
|
...input.memoryReservation ? { memoryReservation: immutableCandidateValue(input.memoryReservation) } : {},
|
|
2126
2186
|
...input.knowledge ? {
|
|
2127
2187
|
knowledge: Object.freeze({
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2188
|
+
candidate: immutableCandidateValue(input.knowledge.candidate),
|
|
2189
|
+
snapshot: immutableCandidateValue(input.knowledge.snapshot),
|
|
2190
|
+
files: immutableExecutorFiles(input.knowledge.files),
|
|
2191
|
+
...input.knowledge.retrievalConfig ? { retrievalConfig: Uint8Array.from(input.knowledge.retrievalConfig) } : {}
|
|
2131
2192
|
})
|
|
2132
2193
|
} : {},
|
|
2133
2194
|
trace: immutableCandidateValue(input.trace),
|
|
@@ -2140,6 +2201,7 @@ function assertPrivateCandidateIntegrity(state) {
|
|
|
2140
2201
|
throw new Error("prepared candidate bundle no longer matches its digest");
|
|
2141
2202
|
}
|
|
2142
2203
|
assertPlanEvidence(state.profilePlan.value, state.profilePlan.bytes, "profile plan");
|
|
2204
|
+
parseAgentCandidateProfileActivation(state.profileActivation, state.profilePlan.value.digest);
|
|
2143
2205
|
assertPlanEvidence(state.executionPlan.value, state.executionPlan.bytes, "execution plan");
|
|
2144
2206
|
agentCandidateExecutionPlanEvidenceSchema.parse(state.executionPlan.value);
|
|
2145
2207
|
const receipt = agentCandidateMaterializationReceiptSchema.parse(
|
|
@@ -2149,14 +2211,16 @@ function assertPrivateCandidateIntegrity(state) {
|
|
|
2149
2211
|
if (canonicalCandidateDigest(omitTopLevelDigest(receipt)) !== state.materializationReceipt.digest || !Buffer.from(receiptBytes).equals(Buffer.from(state.materializationReceipt.bytes))) {
|
|
2150
2212
|
throw new Error("prepared materialization receipt no longer matches its canonical bytes");
|
|
2151
2213
|
}
|
|
2152
|
-
|
|
2153
|
-
|
|
2214
|
+
assertSignedBenchmarkInput(state);
|
|
2215
|
+
const instruction = Buffer.from(state.benchmarkTask.instruction, "utf8");
|
|
2216
|
+
if (!Buffer.from(state.instruction.bytes).equals(instruction) || JSON.stringify(state.instruction.delivery) !== JSON.stringify(state.executionPlan.value.material.instructionDelivery)) {
|
|
2154
2217
|
throw new Error("prepared instruction no longer matches the signed execution plan");
|
|
2155
2218
|
}
|
|
2156
|
-
if (!/^candidate-preparation
|
|
2219
|
+
if (!/^candidate-preparation\.[A-Za-z0-9_-]{43}$/.test(state.preparationId) || !Number.isSafeInteger(state.reservationExpiresAtMs) || state.reservationExpiresAtMs <= 0 || !Number.isSafeInteger(state.cleanupTimeoutMs) || state.cleanupTimeoutMs <= 0 || !Number.isSafeInteger(state.resultTimeoutMs) || state.resultTimeoutMs <= 0 || JSON.stringify(state.resolvedModel) !== JSON.stringify(state.executionPlan.value.material.model.resolved) || state.modelReservation.digest !== state.executionPlan.value.material.model.access.grantDigest || state.modelReservation.preparationId !== state.preparationId || state.modelReservation.expiresAtMs !== state.reservationExpiresAtMs || canonicalCandidateDigest(state.modelReservation.network) !== canonicalCandidateDigest(state.executionPlan.value.material.model.access.network) || canonicalCandidateDigest(state.modelReservation.enforcedLimits) !== canonicalCandidateDigest(modelLimits(state.executionPlan.value.material.limits))) {
|
|
2157
2220
|
throw new Error("prepared model access no longer matches the signed execution plan");
|
|
2158
2221
|
}
|
|
2159
2222
|
assertExecutorInputs(state);
|
|
2223
|
+
assertPreparedKnowledge(state);
|
|
2160
2224
|
if (state.memory.mode === "isolated" && !state.memoryReservation || state.memory.mode === "disabled" && state.memoryReservation) {
|
|
2161
2225
|
throw new Error("prepared memory reservation does not match the signed execution plan");
|
|
2162
2226
|
}
|
|
@@ -2180,7 +2244,7 @@ function assertPrivateCandidateIntegrity(state) {
|
|
|
2180
2244
|
[CANDIDATE_TRACE_ENV.traceRunId]: state.trace.runId
|
|
2181
2245
|
};
|
|
2182
2246
|
if (!state.trace.runId.startsWith(
|
|
2183
|
-
`${state.executionId}:attempt-${state.executionPlan.value.material.attempt
|
|
2247
|
+
`${state.executionId}:attempt-${state.executionPlan.value.material.runCell.attempt}:`
|
|
2184
2248
|
) || canonicalCandidateDigest(state.trace.tags) !== canonicalCandidateDigest(expectedTags) || canonicalCandidateDigest(state.trace.env) !== canonicalCandidateDigest(expectedTraceEnvironment)) {
|
|
2185
2249
|
throw new Error("prepared trace identity no longer matches the signed execution");
|
|
2186
2250
|
}
|
|
@@ -2210,19 +2274,22 @@ function bytesView(value, key) {
|
|
|
2210
2274
|
});
|
|
2211
2275
|
}
|
|
2212
2276
|
function knowledgeView(knowledge) {
|
|
2213
|
-
const
|
|
2277
|
+
const retrievalConfig = knowledge.retrievalConfig ? Uint8Array.from(knowledge.retrievalConfig) : void 0;
|
|
2214
2278
|
return Object.freeze({
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2279
|
+
candidate: knowledge.candidate,
|
|
2280
|
+
snapshot: knowledge.snapshot,
|
|
2281
|
+
files: Object.freeze(knowledge.files.map((file) => profileFileView(file))),
|
|
2282
|
+
...retrievalConfig ? {
|
|
2283
|
+
get retrievalConfig() {
|
|
2284
|
+
return Uint8Array.from(retrievalConfig);
|
|
2285
|
+
}
|
|
2286
|
+
} : {}
|
|
2220
2287
|
});
|
|
2221
2288
|
}
|
|
2222
2289
|
function workspaceInputView(snapshot, sourceFiles) {
|
|
2223
2290
|
return Object.freeze({
|
|
2224
2291
|
snapshot,
|
|
2225
|
-
files: Object.freeze(sourceFiles.map((file) =>
|
|
2292
|
+
files: Object.freeze(sourceFiles.map((file) => executorFileView(file)))
|
|
2226
2293
|
});
|
|
2227
2294
|
}
|
|
2228
2295
|
function profileFileView(source) {
|
|
@@ -2235,9 +2302,22 @@ function profileFileView(source) {
|
|
|
2235
2302
|
}
|
|
2236
2303
|
});
|
|
2237
2304
|
}
|
|
2305
|
+
function executorFileView(source) {
|
|
2306
|
+
const bytes = Uint8Array.from(source.bytes);
|
|
2307
|
+
return Object.freeze({
|
|
2308
|
+
path: source.path,
|
|
2309
|
+
mode: source.mode,
|
|
2310
|
+
get bytes() {
|
|
2311
|
+
return Uint8Array.from(bytes);
|
|
2312
|
+
}
|
|
2313
|
+
});
|
|
2314
|
+
}
|
|
2238
2315
|
function assertExecutorInputs(state) {
|
|
2239
2316
|
const material = state.executionPlan.value.material;
|
|
2240
|
-
assertWorkspaceExecutorFiles(
|
|
2317
|
+
assertWorkspaceExecutorFiles(
|
|
2318
|
+
state.executorInputs.taskFiles,
|
|
2319
|
+
state.benchmarkTask.workspace.material
|
|
2320
|
+
);
|
|
2241
2321
|
if (material.candidateWorkspace) {
|
|
2242
2322
|
if (!state.executorInputs.candidateFiles) {
|
|
2243
2323
|
throw new Error("prepared candidate executor files are missing");
|
|
@@ -2261,6 +2341,28 @@ function assertExecutorInputs(state) {
|
|
|
2261
2341
|
}
|
|
2262
2342
|
}
|
|
2263
2343
|
}
|
|
2344
|
+
function assertPreparedKnowledge(state) {
|
|
2345
|
+
const expected = state.bundle.knowledge;
|
|
2346
|
+
const actual = state.knowledge;
|
|
2347
|
+
if (!expected || !actual) {
|
|
2348
|
+
if (expected || actual)
|
|
2349
|
+
throw new Error("prepared knowledge does not match the candidate bundle");
|
|
2350
|
+
return;
|
|
2351
|
+
}
|
|
2352
|
+
if (canonicalCandidateDigest(actual.candidate) !== canonicalCandidateDigest(expected.candidate) || canonicalCandidateDigest(actual.snapshot) !== canonicalCandidateDigest(expected.snapshot) || state.executionPlan.value.material.knowledgeManifestDigest !== expected.snapshot.digest) {
|
|
2353
|
+
throw new Error("prepared knowledge identity does not match the candidate bundle");
|
|
2354
|
+
}
|
|
2355
|
+
assertWorkspaceExecutorFiles(actual.files, expected.snapshot.material);
|
|
2356
|
+
if (!expected.retrievalConfig || !actual.retrievalConfig) {
|
|
2357
|
+
if (expected.retrievalConfig || actual.retrievalConfig) {
|
|
2358
|
+
throw new Error("prepared knowledge retrieval config does not match the candidate bundle");
|
|
2359
|
+
}
|
|
2360
|
+
return;
|
|
2361
|
+
}
|
|
2362
|
+
if (actual.retrievalConfig.byteLength !== expected.retrievalConfig.byteLength || sha256Bytes(actual.retrievalConfig) !== expected.retrievalConfig.sha256) {
|
|
2363
|
+
throw new Error("prepared knowledge retrieval config does not match the candidate bundle");
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2264
2366
|
function assertWorkspaceExecutorFiles(actualFiles, expected) {
|
|
2265
2367
|
if (actualFiles.length !== expected.files.length) {
|
|
2266
2368
|
throw new Error("prepared workspace executor files do not match the signed manifest");
|
|
@@ -2273,6 +2375,22 @@ function assertWorkspaceExecutorFiles(actualFiles, expected) {
|
|
|
2273
2375
|
}
|
|
2274
2376
|
}
|
|
2275
2377
|
}
|
|
2378
|
+
function assertSignedBenchmarkInput(state) {
|
|
2379
|
+
const plan = state.executionPlan.value.material;
|
|
2380
|
+
const cell = plan.runCell;
|
|
2381
|
+
const suite = state.benchmarkSuite;
|
|
2382
|
+
const task = state.benchmarkTask;
|
|
2383
|
+
const receipt = state.materializationReceipt.value;
|
|
2384
|
+
const cellIndex = cell.taskIndex * suite.reps + cell.repetition;
|
|
2385
|
+
if (canonicalCandidateDigest(omitTopLevelDigest(suite)) !== suite.digest || canonicalCandidateDigest(omitTopLevelDigest(task)) !== task.digest || canonicalCandidateDigest(omitTopLevelDigest(cell)) !== cell.digest || cell.bundleDigest !== state.bundle.digest || cell.suiteDigest !== suite.digest || cell.taskDigest !== task.digest || suite.taskDigests[cell.taskIndex] !== task.digest || suite.seeds[cellIndex] !== cell.seed || cell.repetition >= suite.reps || cell.attempt < 1 || cell.attempt > task.attempt.maxAttempts) {
|
|
2386
|
+
throw new Error("prepared candidate no longer matches its signed experiment cell");
|
|
2387
|
+
}
|
|
2388
|
+
const suiteBytes = canonicalCandidateBytes(omitTopLevelDigest(suite));
|
|
2389
|
+
const taskBytes = canonicalCandidateBytes(omitTopLevelDigest(task));
|
|
2390
|
+
if (receipt.benchmark.suite.digest !== suite.digest || receipt.benchmark.suite.material.sha256 !== sha256Bytes(suiteBytes) || receipt.benchmark.suite.material.byteLength !== suiteBytes.byteLength || receipt.benchmark.task.digest !== task.digest || receipt.benchmark.task.material.sha256 !== sha256Bytes(taskBytes) || receipt.benchmark.task.material.byteLength !== taskBytes.byteLength) {
|
|
2391
|
+
throw new Error("materialization receipt no longer matches its signed benchmark input");
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2276
2394
|
function immutableExecutorFiles(files) {
|
|
2277
2395
|
return Object.freeze(
|
|
2278
2396
|
files.map((file) => Object.freeze({ ...file, bytes: Uint8Array.from(file.bytes) }))
|
|
@@ -2310,10 +2428,14 @@ function assertProtectedEnvironment(state, modelEnvironment, memoryEnvironment)
|
|
|
2310
2428
|
}
|
|
2311
2429
|
|
|
2312
2430
|
// src/candidate-execution/claim-plan.ts
|
|
2313
|
-
function candidateExecutionClaim(prepared) {
|
|
2431
|
+
function candidateExecutionClaim(prepared, preparationEvidence) {
|
|
2314
2432
|
const state = assertPreparedCandidateIntegrity(prepared);
|
|
2315
2433
|
const material = prepared.executionPlan.value.material;
|
|
2316
|
-
const attempt =
|
|
2434
|
+
const attempt = {
|
|
2435
|
+
number: material.runCell.attempt,
|
|
2436
|
+
maxAttempts: state.benchmarkTask.attempt.maxAttempts,
|
|
2437
|
+
retryPolicy: state.benchmarkTask.attempt.retryPolicy
|
|
2438
|
+
};
|
|
2317
2439
|
const nowMs = Date.now();
|
|
2318
2440
|
if (!Number.isSafeInteger(nowMs) || nowMs < 0) {
|
|
2319
2441
|
throw new Error("candidate execution claim-store clock returned an invalid timestamp");
|
|
@@ -2331,6 +2453,14 @@ function candidateExecutionClaim(prepared) {
|
|
|
2331
2453
|
"candidate preparation expires before its full execution and cleanup owner window"
|
|
2332
2454
|
);
|
|
2333
2455
|
}
|
|
2456
|
+
if (preparationEvidence.executionPlan.sha256 !== prepared.executionPlan.value.digest || preparationEvidence.executionPlan.byteLength !== state.executionPlan.bytes.byteLength) {
|
|
2457
|
+
throw new Error("persisted execution plan does not match its canonical preparation bytes");
|
|
2458
|
+
}
|
|
2459
|
+
if (preparationEvidence.materializationReceipt.sha256 !== state.materializationReceipt.digest || preparationEvidence.materializationReceipt.byteLength !== state.materializationReceipt.bytes.byteLength) {
|
|
2460
|
+
throw new Error(
|
|
2461
|
+
"persisted materialization receipt does not match its canonical preparation bytes"
|
|
2462
|
+
);
|
|
2463
|
+
}
|
|
2334
2464
|
return candidateClaimFileInternals.sealClaim({
|
|
2335
2465
|
executionId: prepared.executionId,
|
|
2336
2466
|
attempt: attempt.number,
|
|
@@ -2338,6 +2468,7 @@ function candidateExecutionClaim(prepared) {
|
|
|
2338
2468
|
retryPolicy: attempt.retryPolicy,
|
|
2339
2469
|
bundleDigest: prepared.bundle.digest,
|
|
2340
2470
|
executionPlanDigest: prepared.executionPlan.value.digest,
|
|
2471
|
+
preparationEvidence,
|
|
2341
2472
|
retryLineageDigest: retryLineageDigest(prepared, state.resultTimeoutMs),
|
|
2342
2473
|
leaseExpiresAtMs,
|
|
2343
2474
|
resultTimeoutMs: state.resultTimeoutMs,
|
|
@@ -2362,7 +2493,11 @@ function retryLineageDigest(prepared, resultTimeoutMs) {
|
|
|
2362
2493
|
resultTimeoutMs,
|
|
2363
2494
|
executionPlan: {
|
|
2364
2495
|
...material,
|
|
2365
|
-
|
|
2496
|
+
runCell: {
|
|
2497
|
+
...material.runCell,
|
|
2498
|
+
attempt: 0,
|
|
2499
|
+
digest: `sha256:${"0".repeat(64)}`
|
|
2500
|
+
},
|
|
2366
2501
|
model: {
|
|
2367
2502
|
...material.model,
|
|
2368
2503
|
access: {
|
|
@@ -2398,13 +2533,13 @@ function retryLineageDigest(prepared, resultTimeoutMs) {
|
|
|
2398
2533
|
|
|
2399
2534
|
// src/candidate-execution/output-artifacts.ts
|
|
2400
2535
|
import {
|
|
2401
|
-
agentCandidateArtifactRefSchema as
|
|
2536
|
+
agentCandidateArtifactRefSchema as agentCandidateArtifactRefSchema3
|
|
2402
2537
|
} from "@tangle-network/agent-interface";
|
|
2403
2538
|
async function persistCandidateOutputArtifact(port, input) {
|
|
2404
2539
|
input.signal?.throwIfAborted();
|
|
2405
2540
|
const bytes = Uint8Array.from(input.bytes);
|
|
2406
2541
|
const expectedDigest = sha256Bytes(bytes);
|
|
2407
|
-
const ref =
|
|
2542
|
+
const ref = agentCandidateArtifactRefSchema3.parse(
|
|
2408
2543
|
await port.put({
|
|
2409
2544
|
executionId: input.executionId,
|
|
2410
2545
|
purpose: input.purpose,
|
|
@@ -2427,6 +2562,7 @@ import {
|
|
|
2427
2562
|
agentCandidateTerminationSchema,
|
|
2428
2563
|
agentCandidateWorkspaceManifestMaterialSchema
|
|
2429
2564
|
} from "@tangle-network/agent-interface";
|
|
2565
|
+
var sealedFinalCaptureBrand = /* @__PURE__ */ Symbol("sealedAgentCandidateExecutorFinalCapture");
|
|
2430
2566
|
function sealAgentCandidateProtectedRunCapture(value) {
|
|
2431
2567
|
const capture = requireRecord(value, "candidate execution capture");
|
|
2432
2568
|
assertExactObjectKeys(capture, ["executionId", "termination"], "candidate execution capture");
|
|
@@ -2438,20 +2574,33 @@ function sealAgentCandidateProtectedRunCapture(value) {
|
|
|
2438
2574
|
termination: Object.freeze(agentCandidateTerminationSchema.parse(capture.termination))
|
|
2439
2575
|
});
|
|
2440
2576
|
}
|
|
2441
|
-
function sealAgentCandidateExecutorFinalCapture(value) {
|
|
2577
|
+
function sealAgentCandidateExecutorFinalCapture(value, expectedOutcome) {
|
|
2442
2578
|
const capture = requireRecord(value, "candidate final capture");
|
|
2443
|
-
assertExactObjectKeys(capture, [
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2579
|
+
assertExactObjectKeys(capture, [], "candidate final capture", [
|
|
2580
|
+
"taskOutcome",
|
|
2581
|
+
"memoryAfter",
|
|
2582
|
+
"evidence"
|
|
2583
|
+
]);
|
|
2584
|
+
const taskOutcome = capture.taskOutcome ? sealTaskOutcomeCapture(capture.taskOutcome, expectedOutcome) : void 0;
|
|
2448
2585
|
const memoryAfter = capture.memoryAfter ? sealMemoryCapture(capture.memoryAfter) : void 0;
|
|
2586
|
+
if (capture.evidence !== void 0 && !(capture.evidence instanceof Uint8Array)) {
|
|
2587
|
+
throw new Error("candidate executor evidence must be a byte array");
|
|
2588
|
+
}
|
|
2589
|
+
const evidence = capture.evidence ? Uint8Array.from(capture.evidence) : void 0;
|
|
2449
2590
|
return Object.freeze({
|
|
2450
|
-
stopped: true,
|
|
2451
2591
|
...taskOutcome ? { taskOutcome } : {},
|
|
2452
|
-
...memoryAfter ? { memoryAfter: Object.freeze(memoryAfter) } : {}
|
|
2592
|
+
...memoryAfter ? { memoryAfter: Object.freeze(memoryAfter) } : {},
|
|
2593
|
+
...evidence ? { evidence } : {},
|
|
2594
|
+
[sealedFinalCaptureBrand]: true
|
|
2453
2595
|
});
|
|
2454
2596
|
}
|
|
2597
|
+
function sealAgentCandidateExecutorStopAcknowledgement(value) {
|
|
2598
|
+
const capture = requireRecord(value, "candidate stop acknowledgement");
|
|
2599
|
+
assertExactObjectKeys(capture, ["stopped"], "candidate stop acknowledgement");
|
|
2600
|
+
if (capture.stopped !== true) {
|
|
2601
|
+
throw new Error("candidate stop acknowledgement does not prove process death");
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2455
2604
|
function sealMemoryCapture(value) {
|
|
2456
2605
|
const capture = requireRecord(value, "candidate memory capture");
|
|
2457
2606
|
assertExactObjectKeys(capture, ["afterState", "archive"], "candidate memory capture");
|
|
@@ -2465,13 +2614,32 @@ function sealMemoryCapture(value) {
|
|
|
2465
2614
|
archive: Uint8Array.from(capture.archive)
|
|
2466
2615
|
});
|
|
2467
2616
|
}
|
|
2468
|
-
function sealTaskOutcomeCapture(value) {
|
|
2617
|
+
function sealTaskOutcomeCapture(value, expected) {
|
|
2469
2618
|
const capture = requireRecord(value, "candidate task capture");
|
|
2619
|
+
if (capture.kind === "output") {
|
|
2620
|
+
assertExactObjectKeys(capture, ["kind", "bytes"], "candidate task output capture");
|
|
2621
|
+
if (expected.kind !== "output") {
|
|
2622
|
+
throw new Error("candidate task output capture does not match the signed outcome kind");
|
|
2623
|
+
}
|
|
2624
|
+
if (!(capture.bytes instanceof Uint8Array)) {
|
|
2625
|
+
throw new Error("candidate task output capture must contain a byte array");
|
|
2626
|
+
}
|
|
2627
|
+
if (capture.bytes.byteLength > expected.maxBytes) {
|
|
2628
|
+
throw new Error(`candidate task output exceeds the frozen ${expected.maxBytes}-byte maximum`);
|
|
2629
|
+
}
|
|
2630
|
+
return Object.freeze({ kind: "output", bytes: Uint8Array.from(capture.bytes) });
|
|
2631
|
+
}
|
|
2470
2632
|
assertExactObjectKeys(
|
|
2471
2633
|
capture,
|
|
2472
|
-
["resultTree", "afterState", "archive", "gitDiff"],
|
|
2634
|
+
["kind", "resultTree", "afterState", "archive", "gitDiff"],
|
|
2473
2635
|
"candidate task capture"
|
|
2474
2636
|
);
|
|
2637
|
+
if (capture.kind !== "workspace") {
|
|
2638
|
+
throw new Error("candidate task capture has an invalid outcome kind");
|
|
2639
|
+
}
|
|
2640
|
+
if (expected.kind !== "workspace") {
|
|
2641
|
+
throw new Error("candidate workspace capture does not match the signed outcome kind");
|
|
2642
|
+
}
|
|
2475
2643
|
if (typeof capture.resultTree !== "string" || !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(capture.resultTree)) {
|
|
2476
2644
|
throw new Error("candidate task capture resultTree is not a Git object id");
|
|
2477
2645
|
}
|
|
@@ -2480,6 +2648,7 @@ function sealTaskOutcomeCapture(value) {
|
|
|
2480
2648
|
}
|
|
2481
2649
|
const afterState = agentCandidateWorkspaceManifestMaterialSchema.parse(capture.afterState);
|
|
2482
2650
|
return Object.freeze({
|
|
2651
|
+
kind: "workspace",
|
|
2483
2652
|
resultTree: capture.resultTree,
|
|
2484
2653
|
afterState: Object.freeze(afterState),
|
|
2485
2654
|
archive: Uint8Array.from(capture.archive),
|
|
@@ -2494,11 +2663,11 @@ function requireRecord(value, label) {
|
|
|
2494
2663
|
}
|
|
2495
2664
|
|
|
2496
2665
|
// src/candidate-execution/finalize.ts
|
|
2497
|
-
import { mkdtemp as mkdtemp2, rm as rm2 } from "fs/promises";
|
|
2498
|
-
import { tmpdir as tmpdir2 } from "os";
|
|
2499
|
-
import { join as join2 } from "path";
|
|
2500
2666
|
import { isLlmSpan as isLlmSpan2, REDACTION_VERSION as REDACTION_VERSION2 } from "@tangle-network/agent-eval";
|
|
2501
|
-
import {
|
|
2667
|
+
import {
|
|
2668
|
+
agentCandidateRunReceiptSchema,
|
|
2669
|
+
agentCandidateWorkspaceSnapshotEvidenceSchema
|
|
2670
|
+
} from "@tangle-network/agent-interface";
|
|
2502
2671
|
|
|
2503
2672
|
// src/candidate-execution/model-settlement.ts
|
|
2504
2673
|
import { isLlmSpan } from "@tangle-network/agent-eval";
|
|
@@ -2525,7 +2694,6 @@ function sealAgentCandidateModelSettlement(settlement, expected) {
|
|
|
2525
2694
|
let outputTokens = 0;
|
|
2526
2695
|
let cachedInputTokens = 0;
|
|
2527
2696
|
let reasoningTokens = 0;
|
|
2528
|
-
let hasCachedInput = false;
|
|
2529
2697
|
let costUsdNanos = 0;
|
|
2530
2698
|
const calls = settlement.calls.map((source, index) => {
|
|
2531
2699
|
assertExactObjectKeys(
|
|
@@ -2578,7 +2746,6 @@ function sealAgentCandidateModelSettlement(settlement, expected) {
|
|
|
2578
2746
|
source.cachedInputTokens,
|
|
2579
2747
|
"cached input token total"
|
|
2580
2748
|
);
|
|
2581
|
-
hasCachedInput = true;
|
|
2582
2749
|
assertCount2(source.reasoningTokens, `model settlement call ${index} reasoningTokens`);
|
|
2583
2750
|
reasoningTokens = safeAdd(reasoningTokens, source.reasoningTokens, "reasoning token total");
|
|
2584
2751
|
assertCount2(source.costUsdNanos, `model settlement call ${index} costUsdNanos`);
|
|
@@ -2588,13 +2755,6 @@ function sealAgentCandidateModelSettlement(settlement, expected) {
|
|
|
2588
2755
|
return Object.freeze({ ...source });
|
|
2589
2756
|
});
|
|
2590
2757
|
const usage = Object.freeze({
|
|
2591
|
-
costUsd: costUsdNanos / USD_NANOS,
|
|
2592
|
-
inputTokens,
|
|
2593
|
-
outputTokens,
|
|
2594
|
-
...hasCachedInput ? { cachedInputTokens } : {},
|
|
2595
|
-
modelCalls: calls.length
|
|
2596
|
-
});
|
|
2597
|
-
const fixedUsage = Object.freeze({
|
|
2598
2758
|
costUsdNanos,
|
|
2599
2759
|
inputTokens,
|
|
2600
2760
|
outputTokens,
|
|
@@ -2609,9 +2769,7 @@ function sealAgentCandidateModelSettlement(settlement, expected) {
|
|
|
2609
2769
|
closed: true,
|
|
2610
2770
|
calls: Object.freeze(calls)
|
|
2611
2771
|
}),
|
|
2612
|
-
usage
|
|
2613
|
-
fixedUsage,
|
|
2614
|
-
costUsdNanos
|
|
2772
|
+
usage
|
|
2615
2773
|
});
|
|
2616
2774
|
}
|
|
2617
2775
|
async function appendAuthoritativeModelSettlementSpans(traceStore, runId, settlement) {
|
|
@@ -2872,66 +3030,15 @@ function escapeRegularExpression(value) {
|
|
|
2872
3030
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2873
3031
|
}
|
|
2874
3032
|
|
|
2875
|
-
// src/candidate-execution/workspace-snapshot.ts
|
|
2876
|
-
import {
|
|
2877
|
-
agentCandidateWorkspaceManifestMaterialSchema as agentCandidateWorkspaceManifestMaterialSchema2,
|
|
2878
|
-
agentCandidateWorkspaceSnapshotEvidenceSchema
|
|
2879
|
-
} from "@tangle-network/agent-interface";
|
|
2880
|
-
function provisionalCandidateWorkspaceSnapshot(materialInput, archive) {
|
|
2881
|
-
const material = immutableCandidateValue(
|
|
2882
|
-
agentCandidateWorkspaceManifestMaterialSchema2.parse(materialInput)
|
|
2883
|
-
);
|
|
2884
|
-
const manifestBytes = canonicalCandidateBytes(material);
|
|
2885
|
-
const snapshot = Object.freeze({
|
|
2886
|
-
schemaVersion: 1,
|
|
2887
|
-
kind: "agent-candidate-workspace-snapshot",
|
|
2888
|
-
digest: sha256Bytes(manifestBytes),
|
|
2889
|
-
material,
|
|
2890
|
-
manifest: Object.freeze(embeddedCandidateArtifact(manifestBytes)),
|
|
2891
|
-
archive: Object.freeze(embeddedCandidateArtifact(archive))
|
|
2892
|
-
});
|
|
2893
|
-
return Object.freeze({ material, manifestBytes, snapshot });
|
|
2894
|
-
}
|
|
2895
|
-
async function persistCandidateWorkspaceSnapshot(port, input) {
|
|
2896
|
-
input.signal?.throwIfAborted();
|
|
2897
|
-
const material = immutableCandidateValue(input.material);
|
|
2898
|
-
const manifestBytes = canonicalCandidateBytes(material);
|
|
2899
|
-
const [manifest, archive] = await Promise.all([
|
|
2900
|
-
persistCandidateOutputArtifact(port, {
|
|
2901
|
-
executionId: input.executionId,
|
|
2902
|
-
purpose: input.purpose === "task" ? "task-manifest" : "memory-after-manifest",
|
|
2903
|
-
bytes: manifestBytes,
|
|
2904
|
-
...input.signal ? { signal: input.signal } : {}
|
|
2905
|
-
}),
|
|
2906
|
-
persistCandidateOutputArtifact(port, {
|
|
2907
|
-
executionId: input.executionId,
|
|
2908
|
-
purpose: input.purpose === "task" ? "task-archive" : "memory-after-archive",
|
|
2909
|
-
bytes: input.archive,
|
|
2910
|
-
...input.signal ? { signal: input.signal } : {}
|
|
2911
|
-
})
|
|
2912
|
-
]);
|
|
2913
|
-
return immutableCandidateValue(
|
|
2914
|
-
agentCandidateWorkspaceSnapshotEvidenceSchema.parse({
|
|
2915
|
-
schemaVersion: 1,
|
|
2916
|
-
kind: "agent-candidate-workspace-snapshot",
|
|
2917
|
-
digest: sha256Bytes(manifestBytes),
|
|
2918
|
-
material,
|
|
2919
|
-
manifest,
|
|
2920
|
-
archive
|
|
2921
|
-
})
|
|
2922
|
-
);
|
|
2923
|
-
}
|
|
2924
|
-
|
|
2925
3033
|
// src/candidate-execution/finalize.ts
|
|
2926
3034
|
async function finalizeAgentCandidateRun(state, capture, traceStore, settlement, evidence, protectedValues, writeRedactionReport, signal) {
|
|
2927
3035
|
let termination;
|
|
2928
3036
|
try {
|
|
2929
3037
|
signal?.throwIfAborted();
|
|
2930
|
-
|
|
2931
|
-
if (protectedCapture.executionId !== state.executionId) {
|
|
3038
|
+
if (capture.executionId !== state.executionId) {
|
|
2932
3039
|
throw new Error("protected capture execution id does not match the prepared execution");
|
|
2933
3040
|
}
|
|
2934
|
-
termination =
|
|
3041
|
+
termination = capture.termination;
|
|
2935
3042
|
if (termination.kind === "timeout" && termination.timeoutMs !== state.executionPlan.value.material.limits.timeoutMs) {
|
|
2936
3043
|
throw new Error("timeout termination does not match the frozen execution limit");
|
|
2937
3044
|
}
|
|
@@ -2961,19 +3068,15 @@ async function finalizeAgentCandidateRun(state, capture, traceStore, settlement,
|
|
|
2961
3068
|
);
|
|
2962
3069
|
const modelSpans = orderedSpans.filter(isLlmSpan2);
|
|
2963
3070
|
assertTraceMatchesModelSettlement(modelSpans, settlement);
|
|
2964
|
-
const usage = settlement.usage;
|
|
2965
3071
|
enforceLimits(state, run.startedAt, run.endedAt, orderedSpans, settlement);
|
|
2966
|
-
const finalCapture = sealAgentCandidateExecutorFinalCapture(evidence.finalCapture);
|
|
2967
3072
|
const memory = await memoryReceipt(
|
|
2968
3073
|
state,
|
|
2969
|
-
finalCapture,
|
|
2970
|
-
evidence.
|
|
2971
|
-
protectedValues,
|
|
3074
|
+
evidence.finalCapture,
|
|
3075
|
+
evidence.persistedCapture.memoryAfter,
|
|
2972
3076
|
signal
|
|
2973
3077
|
);
|
|
2974
3078
|
const redacted = redactProtectedValue(
|
|
2975
3079
|
{
|
|
2976
|
-
schemaVersion: 1,
|
|
2977
3080
|
run: { ...run, redactionVersion: REDACTION_VERSION2 },
|
|
2978
3081
|
spans: orderedSpans,
|
|
2979
3082
|
events: orderedEvents,
|
|
@@ -3004,29 +3107,31 @@ async function finalizeAgentCandidateRun(state, capture, traceStore, settlement,
|
|
|
3004
3107
|
signal
|
|
3005
3108
|
});
|
|
3006
3109
|
const trace = {
|
|
3007
|
-
schemaVersion: 1,
|
|
3008
3110
|
artifact: traceArtifact,
|
|
3009
3111
|
eventCount: 1 + orderedSpans.length + orderedEvents.length + orderedBudget.length + orderedArtifacts.length,
|
|
3010
3112
|
modelCallCount: modelSpans.length
|
|
3011
3113
|
};
|
|
3012
3114
|
const document = canonicalCandidateDocument({
|
|
3013
|
-
schemaVersion: 2,
|
|
3014
3115
|
kind: "agent-candidate-run",
|
|
3015
3116
|
digestAlgorithm: "rfc8785-sha256",
|
|
3016
3117
|
bundleDigest: state.bundle.digest,
|
|
3118
|
+
runCellDigest: state.executionPlan.value.material.runCell.digest,
|
|
3017
3119
|
materializationReceiptDigest: state.materializationReceipt.digest,
|
|
3018
3120
|
executionPlanDigest: state.executionPlan.value.digest,
|
|
3121
|
+
timing: {
|
|
3122
|
+
startedAtMs: run.startedAt,
|
|
3123
|
+
endedAtMs: run.endedAt,
|
|
3124
|
+
durationMs: run.endedAt - run.startedAt
|
|
3125
|
+
},
|
|
3019
3126
|
memory,
|
|
3020
|
-
usage,
|
|
3021
|
-
modelUsage: { resolved: state.resolvedModel, usage },
|
|
3022
3127
|
trace,
|
|
3023
3128
|
termination,
|
|
3024
|
-
|
|
3129
|
+
executorCapture: evidence.persistedCapture.evidence,
|
|
3025
3130
|
modelSettlement: evidence.modelSettlement,
|
|
3026
3131
|
taskOutcome: evidence.taskOutcome.evidence,
|
|
3027
3132
|
benchmarkResult: evidence.benchmarkResult
|
|
3028
3133
|
});
|
|
3029
|
-
|
|
3134
|
+
agentCandidateRunReceiptSchema.parse(document.value);
|
|
3030
3135
|
const runReceipt = await persistCandidateOutputArtifact(evidence.outputArtifacts, {
|
|
3031
3136
|
executionId: state.executionId,
|
|
3032
3137
|
purpose: "run-receipt",
|
|
@@ -3038,6 +3143,7 @@ async function finalizeAgentCandidateRun(state, capture, traceStore, settlement,
|
|
|
3038
3143
|
receipt: document,
|
|
3039
3144
|
artifacts: {
|
|
3040
3145
|
modelSettlement: evidence.modelSettlement.artifact,
|
|
3146
|
+
executorCapture: evidence.persistedCapture.evidence,
|
|
3041
3147
|
taskOutcome: evidence.taskOutcome.evidence.artifact,
|
|
3042
3148
|
benchmarkResult: evidence.benchmarkResult.artifact,
|
|
3043
3149
|
runReceipt
|
|
@@ -3082,45 +3188,30 @@ function enforceLimits(state, startedAt, endedAt, spans, settlement) {
|
|
|
3082
3188
|
for (const [actual, limit, label] of checks) {
|
|
3083
3189
|
if (actual > limit) throw new Error(`protected ${label} ${actual} exceeds ${limit}`);
|
|
3084
3190
|
}
|
|
3085
|
-
if (
|
|
3086
|
-
throw new Error(
|
|
3191
|
+
if (usage.costUsdNanos > usdToNanos(limits.maxCostUsd, "frozen maxCostUsd")) {
|
|
3192
|
+
throw new Error(
|
|
3193
|
+
`protected cost USD ${usage.costUsdNanos / 1e9} exceeds ${limits.maxCostUsd}`
|
|
3194
|
+
);
|
|
3087
3195
|
}
|
|
3088
3196
|
}
|
|
3089
|
-
async function memoryReceipt(state, capture,
|
|
3197
|
+
async function memoryReceipt(state, capture, persisted, signal) {
|
|
3090
3198
|
signal?.throwIfAborted();
|
|
3091
3199
|
if (state.memory.mode === "disabled") {
|
|
3092
|
-
if (capture.memoryAfter !== void 0) {
|
|
3200
|
+
if (capture.memoryAfter !== void 0 || persisted !== void 0) {
|
|
3093
3201
|
throw new Error("disabled memory cannot return an after-state");
|
|
3094
3202
|
}
|
|
3095
3203
|
return { mode: "disabled" };
|
|
3096
3204
|
}
|
|
3097
3205
|
if (!capture.memoryAfter) throw new Error("isolated memory is missing its protected after-state");
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
const
|
|
3101
|
-
const
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
const root = await mkdtemp2(join2(tmpdir2(), "agent-candidate-memory-after-"));
|
|
3105
|
-
try {
|
|
3106
|
-
await state.ports.workspaces.materialize({
|
|
3107
|
-
role: "memory",
|
|
3108
|
-
snapshot: provisional.snapshot,
|
|
3109
|
-
archive: Uint8Array.from(archive),
|
|
3110
|
-
destination: root
|
|
3111
|
-
});
|
|
3112
|
-
const files = await readMaterializedWorkspaceFiles(root, afterState);
|
|
3113
|
-
for (const file of files) assertNoProtectedBytes(file.bytes, protectedValues);
|
|
3114
|
-
signal?.throwIfAborted();
|
|
3115
|
-
} finally {
|
|
3116
|
-
await rm2(root, { recursive: true, force: true });
|
|
3117
|
-
}
|
|
3118
|
-
const snapshot = await persistCandidateWorkspaceSnapshot(outputArtifacts, {
|
|
3119
|
-
executionId: state.executionId,
|
|
3206
|
+
if (!persisted) throw new Error("isolated memory is missing persisted capture evidence");
|
|
3207
|
+
const afterState = capture.memoryAfter.afterState;
|
|
3208
|
+
const manifestBytes = canonicalCandidateBytes(afterState);
|
|
3209
|
+
const snapshot = agentCandidateWorkspaceSnapshotEvidenceSchema.parse({
|
|
3210
|
+
kind: "agent-candidate-workspace-snapshot",
|
|
3211
|
+
digest: sha256Bytes(manifestBytes),
|
|
3120
3212
|
material: afterState,
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
signal
|
|
3213
|
+
manifest: persisted.manifest,
|
|
3214
|
+
archive: persisted.archive
|
|
3124
3215
|
});
|
|
3125
3216
|
return {
|
|
3126
3217
|
mode: "isolated",
|
|
@@ -3150,19 +3241,20 @@ function compareStrings(a, b) {
|
|
|
3150
3241
|
}
|
|
3151
3242
|
|
|
3152
3243
|
// src/candidate-execution/outcome-evidence.ts
|
|
3153
|
-
import { mkdtemp as
|
|
3154
|
-
import { tmpdir as
|
|
3155
|
-
import { join as
|
|
3244
|
+
import { mkdtemp as mkdtemp2, rm as rm2 } from "fs/promises";
|
|
3245
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
3246
|
+
import { join as join2 } from "path";
|
|
3156
3247
|
import {
|
|
3157
3248
|
agentCandidateBenchmarkResultEvidenceSchema,
|
|
3158
3249
|
agentCandidateModelSettlementEvidenceSchema,
|
|
3159
|
-
agentCandidateTaskOutcomeEvidenceSchema
|
|
3250
|
+
agentCandidateTaskOutcomeEvidenceSchema,
|
|
3251
|
+
agentCandidateWorkspaceSnapshotEvidenceSchema as agentCandidateWorkspaceSnapshotEvidenceSchema2
|
|
3160
3252
|
} from "@tangle-network/agent-interface";
|
|
3161
3253
|
|
|
3162
3254
|
// src/candidate-execution/benchmark-grader.ts
|
|
3163
3255
|
async function runBoundCandidateBenchmarkGrader(input) {
|
|
3164
3256
|
input.signal?.throwIfAborted();
|
|
3165
|
-
const descriptor = snapshotGraderDescriptor(input.grader);
|
|
3257
|
+
const descriptor = snapshotGraderDescriptor(input.grader, input.expectedGrader);
|
|
3166
3258
|
const implementationBytes = await readVerifiedArtifact(descriptor.artifact, input.artifacts);
|
|
3167
3259
|
if (implementationBytes.byteLength === 0) {
|
|
3168
3260
|
throw new Error("candidate benchmark grader implementation cannot be empty");
|
|
@@ -3170,6 +3262,7 @@ async function runBoundCandidateBenchmarkGrader(input) {
|
|
|
3170
3262
|
const expectedImplementationDigest = sha256Bytes(implementationBytes);
|
|
3171
3263
|
const termination = immutableCandidateValue(input.termination);
|
|
3172
3264
|
const run = input.grader.run;
|
|
3265
|
+
const startedAtMs = Date.now();
|
|
3173
3266
|
const result = await run(
|
|
3174
3267
|
Object.freeze({
|
|
3175
3268
|
executionId: input.executionId,
|
|
@@ -3179,6 +3272,7 @@ async function runBoundCandidateBenchmarkGrader(input) {
|
|
|
3179
3272
|
signal: input.signal ?? new AbortController().signal
|
|
3180
3273
|
})
|
|
3181
3274
|
);
|
|
3275
|
+
const endedAtMs = Math.max(startedAtMs, Date.now());
|
|
3182
3276
|
input.signal?.throwIfAborted();
|
|
3183
3277
|
assertExactRunnerResult(result);
|
|
3184
3278
|
const evidence = Uint8Array.from(result.evidence);
|
|
@@ -3198,19 +3292,42 @@ async function runBoundCandidateBenchmarkGrader(input) {
|
|
|
3198
3292
|
}
|
|
3199
3293
|
return Object.freeze({
|
|
3200
3294
|
grader: descriptor,
|
|
3295
|
+
grading: immutableCandidateValue({
|
|
3296
|
+
usage: emptyFixedSpend(),
|
|
3297
|
+
timing: {
|
|
3298
|
+
startedAtMs,
|
|
3299
|
+
endedAtMs,
|
|
3300
|
+
durationMs: endedAtMs - startedAtMs
|
|
3301
|
+
}
|
|
3302
|
+
}),
|
|
3201
3303
|
evaluation: result.evaluation,
|
|
3202
3304
|
evidence
|
|
3203
3305
|
});
|
|
3204
3306
|
}
|
|
3205
|
-
function snapshotGraderDescriptor(grader) {
|
|
3307
|
+
function snapshotGraderDescriptor(grader, expected) {
|
|
3206
3308
|
if (!grader.name || !grader.version) {
|
|
3207
3309
|
throw new Error("candidate benchmark grader name and version must be non-empty");
|
|
3208
3310
|
}
|
|
3209
|
-
|
|
3311
|
+
const actual = {
|
|
3210
3312
|
name: grader.name,
|
|
3211
3313
|
version: grader.version,
|
|
3314
|
+
format: "tangle-grader",
|
|
3212
3315
|
artifact: grader.artifact
|
|
3213
|
-
}
|
|
3316
|
+
};
|
|
3317
|
+
if (canonicalCandidateDigest(actual) !== canonicalCandidateDigest(expected)) {
|
|
3318
|
+
throw new Error("candidate benchmark grader does not match the signed task grader");
|
|
3319
|
+
}
|
|
3320
|
+
return immutableCandidateValue(expected);
|
|
3321
|
+
}
|
|
3322
|
+
function emptyFixedSpend() {
|
|
3323
|
+
return {
|
|
3324
|
+
inputTokens: 0,
|
|
3325
|
+
outputTokens: 0,
|
|
3326
|
+
cachedInputTokens: 0,
|
|
3327
|
+
reasoningTokens: 0,
|
|
3328
|
+
modelCalls: 0,
|
|
3329
|
+
costUsdNanos: 0
|
|
3330
|
+
};
|
|
3214
3331
|
}
|
|
3215
3332
|
function detachedImplementation(bytes) {
|
|
3216
3333
|
const stored = Uint8Array.from(bytes);
|
|
@@ -3242,6 +3359,104 @@ function assertExactRunnerResult(value) {
|
|
|
3242
3359
|
}
|
|
3243
3360
|
}
|
|
3244
3361
|
|
|
3362
|
+
// src/candidate-execution/executor-capture-evidence.ts
|
|
3363
|
+
async function persistAgentCandidateExecutorCapture(identity, expected, capture, outputArtifacts, signal) {
|
|
3364
|
+
const executorEvidence = capture.evidence ? await persistCandidateOutputArtifact(outputArtifacts, {
|
|
3365
|
+
executionId: identity.executionId,
|
|
3366
|
+
purpose: "executor-native-evidence",
|
|
3367
|
+
bytes: capture.evidence,
|
|
3368
|
+
signal
|
|
3369
|
+
}) : void 0;
|
|
3370
|
+
const taskOutcome = capture.taskOutcome ? await persistTaskCapture(
|
|
3371
|
+
identity.executionId,
|
|
3372
|
+
expected,
|
|
3373
|
+
capture.taskOutcome,
|
|
3374
|
+
outputArtifacts,
|
|
3375
|
+
signal
|
|
3376
|
+
) : void 0;
|
|
3377
|
+
const memoryAfter = capture.memoryAfter ? await persistWorkspaceCapture(
|
|
3378
|
+
identity.executionId,
|
|
3379
|
+
"memory-after-manifest",
|
|
3380
|
+
"memory-after-archive",
|
|
3381
|
+
capture.memoryAfter.afterState,
|
|
3382
|
+
capture.memoryAfter.archive,
|
|
3383
|
+
outputArtifacts,
|
|
3384
|
+
signal
|
|
3385
|
+
) : void 0;
|
|
3386
|
+
const bytes = canonicalCandidateBytes({
|
|
3387
|
+
kind: "agent-candidate-executor-capture",
|
|
3388
|
+
executionPlanDigest: identity.executionPlanDigest,
|
|
3389
|
+
...executorEvidence ? { executorEvidence } : {},
|
|
3390
|
+
...taskOutcome ? { taskOutcome } : {},
|
|
3391
|
+
...memoryAfter ? { memoryAfter } : {}
|
|
3392
|
+
});
|
|
3393
|
+
const evidence = await persistCandidateOutputArtifact(outputArtifacts, {
|
|
3394
|
+
executionId: identity.executionId,
|
|
3395
|
+
purpose: "executor-capture",
|
|
3396
|
+
bytes,
|
|
3397
|
+
signal
|
|
3398
|
+
});
|
|
3399
|
+
return Object.freeze({
|
|
3400
|
+
evidence,
|
|
3401
|
+
...taskOutcome ? { taskOutcome: Object.freeze(taskOutcome) } : {},
|
|
3402
|
+
...memoryAfter ? { memoryAfter: Object.freeze(memoryAfter) } : {}
|
|
3403
|
+
});
|
|
3404
|
+
}
|
|
3405
|
+
async function persistTaskCapture(executionId, expected, capture, outputArtifacts, signal) {
|
|
3406
|
+
if (capture.kind === "output") {
|
|
3407
|
+
if (expected.kind !== "output")
|
|
3408
|
+
throw new Error("captured output does not match the signed task");
|
|
3409
|
+
const artifact = await persistCandidateOutputArtifact(outputArtifacts, {
|
|
3410
|
+
executionId,
|
|
3411
|
+
purpose: "task-output",
|
|
3412
|
+
bytes: capture.bytes,
|
|
3413
|
+
signal
|
|
3414
|
+
});
|
|
3415
|
+
return {
|
|
3416
|
+
kind: "output",
|
|
3417
|
+
spec: { mediaType: expected.mediaType, maxBytes: expected.maxBytes },
|
|
3418
|
+
artifact
|
|
3419
|
+
};
|
|
3420
|
+
}
|
|
3421
|
+
if (expected.kind !== "workspace") {
|
|
3422
|
+
throw new Error("captured workspace does not match the signed task");
|
|
3423
|
+
}
|
|
3424
|
+
const workspace = await persistWorkspaceCapture(
|
|
3425
|
+
executionId,
|
|
3426
|
+
"task-manifest",
|
|
3427
|
+
"task-archive",
|
|
3428
|
+
capture.afterState,
|
|
3429
|
+
capture.archive,
|
|
3430
|
+
outputArtifacts,
|
|
3431
|
+
signal
|
|
3432
|
+
);
|
|
3433
|
+
const gitDiff = await persistCandidateOutputArtifact(outputArtifacts, {
|
|
3434
|
+
executionId,
|
|
3435
|
+
purpose: "task-patch",
|
|
3436
|
+
bytes: capture.gitDiff,
|
|
3437
|
+
signal
|
|
3438
|
+
});
|
|
3439
|
+
return { kind: "workspace", resultTree: capture.resultTree, ...workspace, gitDiff };
|
|
3440
|
+
}
|
|
3441
|
+
async function persistWorkspaceCapture(executionId, manifestPurpose, archivePurpose, afterState, archiveBytes, outputArtifacts, signal) {
|
|
3442
|
+
const manifestBytes = canonicalCandidateBytes(afterState);
|
|
3443
|
+
const [manifest, archive] = await Promise.all([
|
|
3444
|
+
persistCandidateOutputArtifact(outputArtifacts, {
|
|
3445
|
+
executionId,
|
|
3446
|
+
purpose: manifestPurpose,
|
|
3447
|
+
bytes: manifestBytes,
|
|
3448
|
+
signal
|
|
3449
|
+
}),
|
|
3450
|
+
persistCandidateOutputArtifact(outputArtifacts, {
|
|
3451
|
+
executionId,
|
|
3452
|
+
purpose: archivePurpose,
|
|
3453
|
+
bytes: archiveBytes,
|
|
3454
|
+
signal
|
|
3455
|
+
})
|
|
3456
|
+
]);
|
|
3457
|
+
return { afterState, manifest, archive };
|
|
3458
|
+
}
|
|
3459
|
+
|
|
3245
3460
|
// src/candidate-execution/outcome-evidence.ts
|
|
3246
3461
|
async function persistCandidateModelSettlement(state, settlement, outputArtifacts) {
|
|
3247
3462
|
return await persistCandidateModelSettlementEvidence(
|
|
@@ -3256,7 +3471,6 @@ async function persistCandidateModelSettlement(state, settlement, outputArtifact
|
|
|
3256
3471
|
}
|
|
3257
3472
|
async function persistCandidateModelSettlementEvidence(identity, settlement, outputArtifacts) {
|
|
3258
3473
|
const material = {
|
|
3259
|
-
schemaVersion: 2,
|
|
3260
3474
|
kind: "agent-candidate-model-settlement-material",
|
|
3261
3475
|
executionPlanDigest: identity.executionPlanDigest,
|
|
3262
3476
|
preparationId: settlement.value.preparationId,
|
|
@@ -3277,7 +3491,7 @@ async function persistCandidateModelSettlementEvidence(identity, settlement, out
|
|
|
3277
3491
|
reasoningTokens: call.reasoningTokens ?? 0,
|
|
3278
3492
|
costUsdNanos: call.costUsdNanos
|
|
3279
3493
|
})),
|
|
3280
|
-
usage: settlement.
|
|
3494
|
+
usage: settlement.usage
|
|
3281
3495
|
};
|
|
3282
3496
|
const bytes = canonicalCandidateBytes(material);
|
|
3283
3497
|
const digest = sha256Bytes(bytes);
|
|
@@ -3288,7 +3502,6 @@ async function persistCandidateModelSettlementEvidence(identity, settlement, out
|
|
|
3288
3502
|
});
|
|
3289
3503
|
return immutableCandidateValue(
|
|
3290
3504
|
agentCandidateModelSettlementEvidenceSchema.parse({
|
|
3291
|
-
schemaVersion: 1,
|
|
3292
3505
|
kind: "agent-candidate-model-settlement",
|
|
3293
3506
|
digest,
|
|
3294
3507
|
material,
|
|
@@ -3296,16 +3509,53 @@ async function persistCandidateModelSettlementEvidence(identity, settlement, out
|
|
|
3296
3509
|
})
|
|
3297
3510
|
);
|
|
3298
3511
|
}
|
|
3299
|
-
async function
|
|
3512
|
+
async function persistVerifiedAgentCandidateExecutorCapture(state, capture, outputArtifacts, protectedValues, signal) {
|
|
3300
3513
|
signal?.throwIfAborted();
|
|
3514
|
+
const taskCapture = capture.taskOutcome;
|
|
3515
|
+
if (!taskCapture) throw new Error("candidate final capture is missing the task outcome");
|
|
3516
|
+
if (capture.evidence) assertNoProtectedBytes(capture.evidence, protectedValues);
|
|
3517
|
+
const expected = state.benchmarkTask.outcome;
|
|
3518
|
+
if (taskCapture.kind !== expected.kind) {
|
|
3519
|
+
throw new Error(
|
|
3520
|
+
`candidate captured ${taskCapture.kind} outcome does not match expected ${expected.kind} outcome`
|
|
3521
|
+
);
|
|
3522
|
+
}
|
|
3523
|
+
const verified = taskCapture.kind === "output" && expected.kind === "output" ? verifyOutputTaskCapture(taskCapture.bytes, expected, protectedValues) : taskCapture.kind === "workspace" && expected.kind === "workspace" ? await verifyWorkspaceTaskCapture(state, taskCapture, protectedValues, signal) : void 0;
|
|
3524
|
+
if (!verified) throw new Error("candidate task outcome kind could not be narrowed");
|
|
3525
|
+
await verifyMemoryCapture(state, capture, protectedValues, signal);
|
|
3526
|
+
const persistedCapture = await persistAgentCandidateExecutorCapture(
|
|
3527
|
+
{
|
|
3528
|
+
executionId: state.executionId,
|
|
3529
|
+
executionPlanDigest: state.executionPlan.value.digest
|
|
3530
|
+
},
|
|
3531
|
+
expected,
|
|
3532
|
+
capture,
|
|
3533
|
+
outputArtifacts,
|
|
3534
|
+
signal
|
|
3535
|
+
);
|
|
3536
|
+
const persisted = persistedCapture.taskOutcome;
|
|
3537
|
+
if (!persisted || persisted.kind !== verified.kind) {
|
|
3538
|
+
throw new Error("persisted task capture kind changed");
|
|
3539
|
+
}
|
|
3540
|
+
const taskOutcome = verified.kind === "output" && persisted.kind === "output" ? await persistVerifiedOutputTaskOutcome(state, verified, persisted, outputArtifacts, signal) : verified.kind === "workspace" && persisted.kind === "workspace" ? await persistVerifiedWorkspaceTaskOutcome(
|
|
3541
|
+
state,
|
|
3542
|
+
verified,
|
|
3543
|
+
persisted,
|
|
3544
|
+
outputArtifacts,
|
|
3545
|
+
signal
|
|
3546
|
+
) : void 0;
|
|
3547
|
+
if (!taskOutcome) throw new Error("persisted task outcome kind could not be narrowed");
|
|
3548
|
+
return Object.freeze({ persistedCapture, taskOutcome });
|
|
3549
|
+
}
|
|
3550
|
+
async function verifyWorkspaceTaskCapture(state, capture, protectedValues, signal) {
|
|
3551
|
+
const repository = state.benchmarkTask.repository;
|
|
3552
|
+
if (!repository) throw new Error("workspace task outcome is missing repository identity");
|
|
3301
3553
|
const patch = Uint8Array.from(capture.gitDiff);
|
|
3302
3554
|
const archive = Uint8Array.from(capture.archive);
|
|
3303
3555
|
if (archive.byteLength === 0) throw new Error("candidate task archive cannot be empty");
|
|
3304
3556
|
assertNoProtectedBytes(patch, protectedValues);
|
|
3305
3557
|
assertNoProtectedBytes(archive, protectedValues);
|
|
3306
|
-
const
|
|
3307
|
-
const afterState = provisional.material;
|
|
3308
|
-
const repository = state.executionPlan.value.material.task.repository;
|
|
3558
|
+
const afterState = immutableCandidateValue(capture.afterState);
|
|
3309
3559
|
const verified = await verifyTaskOutcomePatch({
|
|
3310
3560
|
repositoryRoot: state.roots.staging.taskRoot,
|
|
3311
3561
|
baseCommit: repository.baseCommit,
|
|
@@ -3315,44 +3565,111 @@ async function persistVerifiedCandidateTaskOutcome(state, capture, outputArtifac
|
|
|
3315
3565
|
afterState
|
|
3316
3566
|
});
|
|
3317
3567
|
signal?.throwIfAborted();
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3568
|
+
const manifestBytes = canonicalCandidateBytes(afterState);
|
|
3569
|
+
assertNoProtectedBytes(manifestBytes, protectedValues);
|
|
3570
|
+
const provisionalSnapshot = agentCandidateWorkspaceSnapshotEvidenceSchema2.parse({
|
|
3571
|
+
kind: "agent-candidate-workspace-snapshot",
|
|
3572
|
+
digest: sha256Bytes(manifestBytes),
|
|
3323
3573
|
material: afterState,
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
signal
|
|
3574
|
+
manifest: embeddedCandidateArtifact(manifestBytes),
|
|
3575
|
+
archive: embeddedCandidateArtifact(archive)
|
|
3327
3576
|
});
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3577
|
+
await verifyTaskOutcomeArchive(state, provisionalSnapshot, archive, protectedValues);
|
|
3578
|
+
signal?.throwIfAborted();
|
|
3579
|
+
return {
|
|
3580
|
+
kind: "workspace",
|
|
3581
|
+
patch,
|
|
3582
|
+
archive,
|
|
3583
|
+
afterState,
|
|
3584
|
+
manifestBytes,
|
|
3585
|
+
resultCommit: verified.resultCommit,
|
|
3586
|
+
resultTree: verified.resultTree,
|
|
3587
|
+
repository
|
|
3588
|
+
};
|
|
3589
|
+
}
|
|
3590
|
+
async function persistVerifiedWorkspaceTaskOutcome(state, verified, persisted, outputArtifacts, signal) {
|
|
3591
|
+
const { afterState, manifestBytes, patch, repository } = verified;
|
|
3592
|
+
const snapshot = agentCandidateWorkspaceSnapshotEvidenceSchema2.parse({
|
|
3593
|
+
kind: "agent-candidate-workspace-snapshot",
|
|
3594
|
+
digest: sha256Bytes(manifestBytes),
|
|
3595
|
+
material: afterState,
|
|
3596
|
+
manifest: persisted.manifest,
|
|
3597
|
+
archive: persisted.archive
|
|
3333
3598
|
});
|
|
3334
3599
|
const material = {
|
|
3335
|
-
schemaVersion: 1,
|
|
3336
3600
|
kind: "agent-candidate-task-outcome-material",
|
|
3337
3601
|
executionPlanDigest: state.executionPlan.value.digest,
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3602
|
+
outcome: {
|
|
3603
|
+
kind: "workspace",
|
|
3604
|
+
baseRepository: {
|
|
3605
|
+
identity: repository.identity,
|
|
3606
|
+
rootIdentity: repository.rootIdentity,
|
|
3607
|
+
commit: repository.baseCommit,
|
|
3608
|
+
tree: repository.baseTree
|
|
3609
|
+
},
|
|
3610
|
+
resultRepository: {
|
|
3611
|
+
identity: repository.identity,
|
|
3612
|
+
rootIdentity: repository.rootIdentity,
|
|
3613
|
+
commit: verified.resultCommit,
|
|
3614
|
+
tree: verified.resultTree
|
|
3615
|
+
},
|
|
3616
|
+
afterState: snapshot,
|
|
3617
|
+
gitDiff: {
|
|
3618
|
+
format: "git-diff-binary",
|
|
3619
|
+
artifact: persisted.gitDiff
|
|
3620
|
+
}
|
|
3621
|
+
}
|
|
3622
|
+
};
|
|
3623
|
+
const evidence = await persistTaskOutcomeEvidence(state, material, outputArtifacts, signal);
|
|
3624
|
+
const storedPatch = Uint8Array.from(patch);
|
|
3625
|
+
return Object.freeze({
|
|
3626
|
+
kind: "workspace",
|
|
3627
|
+
evidence,
|
|
3628
|
+
get patch() {
|
|
3629
|
+
return Uint8Array.from(storedPatch);
|
|
3349
3630
|
},
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3631
|
+
[verifiedTaskOutcomeBrand]: true
|
|
3632
|
+
});
|
|
3633
|
+
}
|
|
3634
|
+
function verifyOutputTaskCapture(capturedBytes, expected, protectedValues) {
|
|
3635
|
+
if (capturedBytes.byteLength === 0) throw new Error("candidate task output cannot be empty");
|
|
3636
|
+
if (capturedBytes.byteLength > expected.maxBytes) {
|
|
3637
|
+
throw new Error(`candidate task output exceeds the frozen ${expected.maxBytes}-byte maximum`);
|
|
3638
|
+
}
|
|
3639
|
+
const output = Uint8Array.from(capturedBytes);
|
|
3640
|
+
assertNoProtectedBytes(output, protectedValues);
|
|
3641
|
+
return {
|
|
3642
|
+
kind: "output",
|
|
3643
|
+
bytes: output,
|
|
3644
|
+
spec: { mediaType: expected.mediaType, maxBytes: expected.maxBytes }
|
|
3645
|
+
};
|
|
3646
|
+
}
|
|
3647
|
+
async function persistVerifiedOutputTaskOutcome(state, verified, persisted, outputArtifacts, signal) {
|
|
3648
|
+
if (persisted.spec.mediaType !== verified.spec.mediaType || persisted.spec.maxBytes !== verified.spec.maxBytes) {
|
|
3649
|
+
throw new Error("persisted task output changed the signed media constraints");
|
|
3650
|
+
}
|
|
3651
|
+
const material = {
|
|
3652
|
+
kind: "agent-candidate-task-outcome-material",
|
|
3653
|
+
executionPlanDigest: state.executionPlan.value.digest,
|
|
3654
|
+
outcome: {
|
|
3655
|
+
kind: "output",
|
|
3656
|
+
spec: verified.spec,
|
|
3657
|
+
artifact: persisted.artifact
|
|
3354
3658
|
}
|
|
3355
3659
|
};
|
|
3660
|
+
const evidence = await persistTaskOutcomeEvidence(state, material, outputArtifacts, signal);
|
|
3661
|
+
const storedOutput = Uint8Array.from(verified.bytes);
|
|
3662
|
+
return Object.freeze({
|
|
3663
|
+
kind: "output",
|
|
3664
|
+
evidence,
|
|
3665
|
+
spec: immutableCandidateValue(verified.spec),
|
|
3666
|
+
get bytes() {
|
|
3667
|
+
return Uint8Array.from(storedOutput);
|
|
3668
|
+
},
|
|
3669
|
+
[verifiedTaskOutcomeBrand]: true
|
|
3670
|
+
});
|
|
3671
|
+
}
|
|
3672
|
+
async function persistTaskOutcomeEvidence(state, material, outputArtifacts, signal) {
|
|
3356
3673
|
const bytes = canonicalCandidateBytes(material);
|
|
3357
3674
|
const digest = sha256Bytes(bytes);
|
|
3358
3675
|
const artifact = await persistCandidateOutputArtifact(outputArtifacts, {
|
|
@@ -3361,23 +3678,14 @@ async function persistVerifiedCandidateTaskOutcome(state, capture, outputArtifac
|
|
|
3361
3678
|
bytes,
|
|
3362
3679
|
signal
|
|
3363
3680
|
});
|
|
3364
|
-
|
|
3681
|
+
return immutableCandidateValue(
|
|
3365
3682
|
agentCandidateTaskOutcomeEvidenceSchema.parse({
|
|
3366
|
-
schemaVersion: 1,
|
|
3367
3683
|
kind: "agent-candidate-task-outcome",
|
|
3368
3684
|
digest,
|
|
3369
3685
|
material,
|
|
3370
3686
|
artifact
|
|
3371
3687
|
})
|
|
3372
3688
|
);
|
|
3373
|
-
const storedPatch = Uint8Array.from(patch);
|
|
3374
|
-
return Object.freeze({
|
|
3375
|
-
evidence,
|
|
3376
|
-
get patch() {
|
|
3377
|
-
return Uint8Array.from(storedPatch);
|
|
3378
|
-
},
|
|
3379
|
-
[verifiedTaskOutcomeBrand]: true
|
|
3380
|
-
});
|
|
3381
3689
|
}
|
|
3382
3690
|
async function persistCandidateBenchmarkResult(state, termination, outcome, grader, outputArtifacts, protectedValues, signal) {
|
|
3383
3691
|
signal?.throwIfAborted();
|
|
@@ -3386,6 +3694,7 @@ async function persistCandidateBenchmarkResult(state, termination, outcome, grad
|
|
|
3386
3694
|
executionId: state.executionId,
|
|
3387
3695
|
termination: frozenTermination,
|
|
3388
3696
|
outcome,
|
|
3697
|
+
expectedGrader: state.benchmarkTask.grader,
|
|
3389
3698
|
grader,
|
|
3390
3699
|
artifacts: outputArtifacts,
|
|
3391
3700
|
signal
|
|
@@ -3401,24 +3710,13 @@ async function persistCandidateBenchmarkResult(state, termination, outcome, grad
|
|
|
3401
3710
|
bytes: rawEvidence,
|
|
3402
3711
|
signal
|
|
3403
3712
|
});
|
|
3404
|
-
const task = state.executionPlan.value.material.task;
|
|
3405
3713
|
const material = {
|
|
3406
|
-
schemaVersion: 1,
|
|
3407
3714
|
kind: "agent-candidate-benchmark-result-material",
|
|
3408
3715
|
executionPlanDigest: state.executionPlan.value.digest,
|
|
3409
3716
|
taskOutcomeDigest: outcome.evidence.digest,
|
|
3410
|
-
|
|
3411
|
-
name: task.benchmark,
|
|
3412
|
-
version: task.benchmarkVersion,
|
|
3413
|
-
taskId: task.taskId,
|
|
3414
|
-
splitDigest: task.splitDigest
|
|
3415
|
-
},
|
|
3416
|
-
grader: {
|
|
3417
|
-
name: graded.grader.name,
|
|
3418
|
-
version: graded.grader.version,
|
|
3419
|
-
artifact: graded.grader.artifact
|
|
3420
|
-
},
|
|
3717
|
+
grader: graded.grader,
|
|
3421
3718
|
evidence: evidenceRef,
|
|
3719
|
+
grading: graded.grading,
|
|
3422
3720
|
score: evaluation.score,
|
|
3423
3721
|
passed: evaluation.passed,
|
|
3424
3722
|
dimensions: evaluation.dimensions
|
|
@@ -3433,7 +3731,6 @@ async function persistCandidateBenchmarkResult(state, termination, outcome, grad
|
|
|
3433
3731
|
});
|
|
3434
3732
|
return immutableCandidateValue(
|
|
3435
3733
|
agentCandidateBenchmarkResultEvidenceSchema.parse({
|
|
3436
|
-
schemaVersion: 1,
|
|
3437
3734
|
kind: "agent-candidate-benchmark-result",
|
|
3438
3735
|
digest,
|
|
3439
3736
|
material,
|
|
@@ -3442,7 +3739,7 @@ async function persistCandidateBenchmarkResult(state, termination, outcome, grad
|
|
|
3442
3739
|
);
|
|
3443
3740
|
}
|
|
3444
3741
|
async function verifyTaskOutcomeArchive(state, snapshot, archive, protectedValues) {
|
|
3445
|
-
const root = await
|
|
3742
|
+
const root = await mkdtemp2(join2(tmpdir2(), "agent-candidate-task-archive-"));
|
|
3446
3743
|
try {
|
|
3447
3744
|
await state.ports.workspaces.materialize({
|
|
3448
3745
|
role: "task",
|
|
@@ -3453,7 +3750,40 @@ async function verifyTaskOutcomeArchive(state, snapshot, archive, protectedValue
|
|
|
3453
3750
|
const files = await readMaterializedWorkspaceFiles(root, snapshot.material);
|
|
3454
3751
|
for (const file of files) assertNoProtectedBytes(file.bytes, protectedValues);
|
|
3455
3752
|
} finally {
|
|
3456
|
-
await
|
|
3753
|
+
await rm2(root, { recursive: true, force: true });
|
|
3754
|
+
}
|
|
3755
|
+
}
|
|
3756
|
+
async function verifyMemoryCapture(state, capture, protectedValues, signal) {
|
|
3757
|
+
if (state.memory.mode === "disabled") {
|
|
3758
|
+
if (capture.memoryAfter) throw new Error("disabled memory cannot return an after-state");
|
|
3759
|
+
return;
|
|
3760
|
+
}
|
|
3761
|
+
const memory = capture.memoryAfter;
|
|
3762
|
+
if (!memory) throw new Error("isolated memory is missing its protected after-state");
|
|
3763
|
+
if (memory.archive.byteLength === 0) throw new Error("isolated memory archive cannot be empty");
|
|
3764
|
+
const manifestBytes = canonicalCandidateBytes(memory.afterState);
|
|
3765
|
+
assertNoProtectedBytes(manifestBytes, protectedValues);
|
|
3766
|
+
assertNoProtectedBytes(memory.archive, protectedValues);
|
|
3767
|
+
const snapshot = agentCandidateWorkspaceSnapshotEvidenceSchema2.parse({
|
|
3768
|
+
kind: "agent-candidate-workspace-snapshot",
|
|
3769
|
+
digest: sha256Bytes(manifestBytes),
|
|
3770
|
+
material: memory.afterState,
|
|
3771
|
+
manifest: embeddedCandidateArtifact(manifestBytes),
|
|
3772
|
+
archive: embeddedCandidateArtifact(memory.archive)
|
|
3773
|
+
});
|
|
3774
|
+
const root = await mkdtemp2(join2(tmpdir2(), "agent-candidate-memory-after-"));
|
|
3775
|
+
try {
|
|
3776
|
+
await state.ports.workspaces.materialize({
|
|
3777
|
+
role: "memory",
|
|
3778
|
+
snapshot,
|
|
3779
|
+
archive: Uint8Array.from(memory.archive),
|
|
3780
|
+
destination: root
|
|
3781
|
+
});
|
|
3782
|
+
const files = await readMaterializedWorkspaceFiles(root, memory.afterState);
|
|
3783
|
+
for (const file of files) assertNoProtectedBytes(file.bytes, protectedValues);
|
|
3784
|
+
signal?.throwIfAborted();
|
|
3785
|
+
} finally {
|
|
3786
|
+
await rm2(root, { recursive: true, force: true });
|
|
3457
3787
|
}
|
|
3458
3788
|
}
|
|
3459
3789
|
function normalizeEvaluation(evaluation, termination) {
|
|
@@ -3636,9 +3966,29 @@ async function executePreparedAgentCandidate(prepared, options) {
|
|
|
3636
3966
|
} catch (error) {
|
|
3637
3967
|
return await failBeforeActivation(prepared, state, error, "failed", cleanupTimeoutMs);
|
|
3638
3968
|
}
|
|
3969
|
+
let preparationEvidence;
|
|
3970
|
+
try {
|
|
3971
|
+
const [executionPlan, materializationReceipt] = await Promise.all([
|
|
3972
|
+
persistCandidateOutputArtifact(options.outputArtifacts, {
|
|
3973
|
+
executionId: state.executionId,
|
|
3974
|
+
purpose: "execution-plan",
|
|
3975
|
+
bytes: state.executionPlan.bytes
|
|
3976
|
+
}),
|
|
3977
|
+
persistCandidateOutputArtifact(options.outputArtifacts, {
|
|
3978
|
+
executionId: state.executionId,
|
|
3979
|
+
purpose: "materialization-receipt",
|
|
3980
|
+
bytes: state.materializationReceipt.bytes
|
|
3981
|
+
})
|
|
3982
|
+
]);
|
|
3983
|
+
preparationEvidence = Object.freeze({ executionPlan, materializationReceipt });
|
|
3984
|
+
} catch (error) {
|
|
3985
|
+
return await failBeforeActivation(prepared, state, error, "failed", cleanupTimeoutMs);
|
|
3986
|
+
}
|
|
3639
3987
|
let acquired;
|
|
3640
3988
|
try {
|
|
3641
|
-
acquired = await options.claimStore.tryClaim(
|
|
3989
|
+
acquired = await options.claimStore.tryClaim(
|
|
3990
|
+
candidateExecutionClaim(prepared, preparationEvidence)
|
|
3991
|
+
);
|
|
3642
3992
|
} catch (error) {
|
|
3643
3993
|
return await failBeforeActivation(prepared, state, error, "failed", cleanupTimeoutMs);
|
|
3644
3994
|
}
|
|
@@ -3790,6 +4140,7 @@ async function executePreparedAgentCandidate(prepared, options) {
|
|
|
3790
4140
|
const execution = await runAndStopExecutor(
|
|
3791
4141
|
options.executor,
|
|
3792
4142
|
request,
|
|
4143
|
+
state.benchmarkTask.outcome,
|
|
3793
4144
|
protectedTraceStore,
|
|
3794
4145
|
deadlineAtMs,
|
|
3795
4146
|
cleanupTimeoutMs
|
|
@@ -3878,9 +4229,9 @@ async function executePreparedAgentCandidate(prepared, options) {
|
|
|
3878
4229
|
state.trace.runId,
|
|
3879
4230
|
settlementResult.settlement
|
|
3880
4231
|
);
|
|
3881
|
-
const taskOutcome = await
|
|
4232
|
+
const { persistedCapture, taskOutcome } = await persistVerifiedAgentCandidateExecutorCapture(
|
|
3882
4233
|
state,
|
|
3883
|
-
execution.finalCapture
|
|
4234
|
+
execution.finalCapture,
|
|
3884
4235
|
options.outputArtifacts,
|
|
3885
4236
|
protectedValues,
|
|
3886
4237
|
signal
|
|
@@ -3901,6 +4252,7 @@ async function executePreparedAgentCandidate(prepared, options) {
|
|
|
3901
4252
|
settlementResult.settlement,
|
|
3902
4253
|
{
|
|
3903
4254
|
finalCapture: execution.finalCapture,
|
|
4255
|
+
persistedCapture,
|
|
3904
4256
|
modelSettlement,
|
|
3905
4257
|
taskOutcome,
|
|
3906
4258
|
benchmarkResult,
|
|
@@ -3926,18 +4278,16 @@ async function executePreparedAgentCandidate(prepared, options) {
|
|
|
3926
4278
|
let terminal;
|
|
3927
4279
|
try {
|
|
3928
4280
|
terminal = result.succeeded ? {
|
|
3929
|
-
schemaVersion: 1,
|
|
3930
4281
|
status: "succeeded",
|
|
3931
|
-
usage: settlementResult.settlement.
|
|
4282
|
+
usage: settlementResult.settlement.usage,
|
|
3932
4283
|
modelSettlement: result.artifacts.modelSettlement,
|
|
3933
4284
|
taskOutcome: result.artifacts.taskOutcome,
|
|
3934
4285
|
benchmarkResult: result.artifacts.benchmarkResult,
|
|
3935
4286
|
runReceipt: result.artifacts.runReceipt
|
|
3936
4287
|
} : {
|
|
3937
|
-
schemaVersion: 1,
|
|
3938
4288
|
status: "failed",
|
|
3939
4289
|
failureClass,
|
|
3940
|
-
usage: settlementResult.settlement.
|
|
4290
|
+
usage: settlementResult.settlement.usage,
|
|
3941
4291
|
modelSettlement: modelSettlement.artifact,
|
|
3942
4292
|
failureEvidence: await withinCandidateCleanupDeadline(
|
|
3943
4293
|
() => persistFailureEvidence(
|
|
@@ -3984,7 +4334,7 @@ async function executePreparedAgentCandidate(prepared, options) {
|
|
|
3984
4334
|
settlementResult.settlement.usage
|
|
3985
4335
|
);
|
|
3986
4336
|
}
|
|
3987
|
-
async function runAndStopExecutor(executor, request, traceStore, deadlineAtMs, cleanupTimeoutMs) {
|
|
4337
|
+
async function runAndStopExecutor(executor, request, expectedOutcome, traceStore, deadlineAtMs, cleanupTimeoutMs) {
|
|
3988
4338
|
const timeoutMs = request.hardLimits.timeoutMs;
|
|
3989
4339
|
const timeoutError = new CandidateExecutionDeadlineError(timeoutMs);
|
|
3990
4340
|
if (Date.now() >= deadlineAtMs) {
|
|
@@ -4039,10 +4389,10 @@ async function runAndStopExecutor(executor, request, traceStore, deadlineAtMs, c
|
|
|
4039
4389
|
}
|
|
4040
4390
|
if (!capture || timedOut) controller.abort(executionError);
|
|
4041
4391
|
const stopReason = timedOut ? "timeout" : capture ? "completed" : "failed";
|
|
4042
|
-
|
|
4392
|
+
const cleanupDeadlineAtMs = Date.now() + cleanupTimeoutMs;
|
|
4043
4393
|
try {
|
|
4044
|
-
stopped = await withinCandidateCleanupDeadline(
|
|
4045
|
-
() => executor.
|
|
4394
|
+
const stopped = await withinCandidateCleanupDeadline(
|
|
4395
|
+
(cleanupSignal) => executor.stop(
|
|
4046
4396
|
{
|
|
4047
4397
|
executionId: request.executionId,
|
|
4048
4398
|
executionPlanDigest: request.executionPlan.value.digest
|
|
@@ -4050,35 +4400,65 @@ async function runAndStopExecutor(executor, request, traceStore, deadlineAtMs, c
|
|
|
4050
4400
|
{
|
|
4051
4401
|
traceStore,
|
|
4052
4402
|
reason: stopReason,
|
|
4053
|
-
signal:
|
|
4054
|
-
deadlineAtMs
|
|
4403
|
+
signal: cleanupSignal,
|
|
4404
|
+
deadlineAtMs: cleanupDeadlineAtMs
|
|
4055
4405
|
}
|
|
4056
4406
|
),
|
|
4057
|
-
|
|
4407
|
+
cleanupDeadlineAtMs,
|
|
4058
4408
|
"candidate process termination"
|
|
4059
4409
|
);
|
|
4060
|
-
|
|
4061
|
-
throw new Error("candidate executor did not acknowledge exact process termination");
|
|
4062
|
-
}
|
|
4410
|
+
sealAgentCandidateExecutorStopAcknowledgement(stopped);
|
|
4063
4411
|
} catch (stopError) {
|
|
4412
|
+
let disposalError2;
|
|
4413
|
+
try {
|
|
4414
|
+
await disposeExecutor(executor, request, cleanupDeadlineAtMs);
|
|
4415
|
+
} catch (error) {
|
|
4416
|
+
disposalError2 = error;
|
|
4417
|
+
}
|
|
4064
4418
|
if (timer) clearTimeout(timer);
|
|
4065
4419
|
controller.abort(stopError);
|
|
4066
4420
|
return {
|
|
4067
4421
|
kind: "error",
|
|
4068
|
-
error: new Error(joinErrors(executionError, stopError)),
|
|
4422
|
+
error: new Error(joinErrors(executionError, stopError, disposalError2)),
|
|
4069
4423
|
...timedOut ? { termination: { kind: "timeout", timeoutMs } } : {},
|
|
4070
4424
|
processStopped: false
|
|
4071
4425
|
};
|
|
4072
4426
|
}
|
|
4073
4427
|
let finalCapture;
|
|
4428
|
+
let finalCaptureError;
|
|
4074
4429
|
try {
|
|
4075
|
-
finalCapture = sealAgentCandidateExecutorFinalCapture(
|
|
4430
|
+
finalCapture = sealAgentCandidateExecutorFinalCapture(
|
|
4431
|
+
await withinCandidateCleanupDeadline(
|
|
4432
|
+
(cleanupSignal) => executor.capture(
|
|
4433
|
+
{
|
|
4434
|
+
executionId: request.executionId,
|
|
4435
|
+
executionPlanDigest: request.executionPlan.value.digest
|
|
4436
|
+
},
|
|
4437
|
+
{
|
|
4438
|
+
traceStore,
|
|
4439
|
+
signal: cleanupSignal
|
|
4440
|
+
}
|
|
4441
|
+
),
|
|
4442
|
+
cleanupDeadlineAtMs,
|
|
4443
|
+
"candidate final evidence capture"
|
|
4444
|
+
),
|
|
4445
|
+
expectedOutcome
|
|
4446
|
+
);
|
|
4076
4447
|
} catch (captureError) {
|
|
4448
|
+
finalCaptureError = captureError;
|
|
4449
|
+
}
|
|
4450
|
+
let disposalError;
|
|
4451
|
+
try {
|
|
4452
|
+
await disposeExecutor(executor, request, cleanupDeadlineAtMs);
|
|
4453
|
+
} catch (disposeError) {
|
|
4454
|
+
disposalError = disposeError;
|
|
4455
|
+
}
|
|
4456
|
+
if (finalCaptureError || disposalError || !finalCapture) {
|
|
4077
4457
|
if (timer) clearTimeout(timer);
|
|
4078
|
-
controller.abort(
|
|
4458
|
+
controller.abort(finalCaptureError ?? disposalError);
|
|
4079
4459
|
return {
|
|
4080
4460
|
kind: "error",
|
|
4081
|
-
error: new Error(joinErrors(executionError,
|
|
4461
|
+
error: new Error(joinErrors(executionError, finalCaptureError, disposalError)),
|
|
4082
4462
|
...timedOut ? { termination: { kind: "timeout", timeoutMs } } : {},
|
|
4083
4463
|
processStopped: true
|
|
4084
4464
|
};
|
|
@@ -4114,6 +4494,25 @@ async function runAndStopExecutor(executor, request, traceStore, deadlineAtMs, c
|
|
|
4114
4494
|
processStopped: true
|
|
4115
4495
|
};
|
|
4116
4496
|
}
|
|
4497
|
+
async function disposeExecutor(executor, request, cleanupDeadlineAtMs) {
|
|
4498
|
+
const dispose = executor.dispose;
|
|
4499
|
+
if (!dispose) return;
|
|
4500
|
+
const disposed = await withinCandidateCleanupDeadline(
|
|
4501
|
+
(cleanupSignal) => dispose.call(
|
|
4502
|
+
executor,
|
|
4503
|
+
{
|
|
4504
|
+
executionId: request.executionId,
|
|
4505
|
+
executionPlanDigest: request.executionPlan.value.digest
|
|
4506
|
+
},
|
|
4507
|
+
{ signal: cleanupSignal }
|
|
4508
|
+
),
|
|
4509
|
+
cleanupDeadlineAtMs,
|
|
4510
|
+
"candidate execution resource disposal"
|
|
4511
|
+
);
|
|
4512
|
+
if (!disposed || disposed.disposed !== true || Object.keys(disposed).some((key) => key !== "disposed")) {
|
|
4513
|
+
throw new Error("candidate executor did not acknowledge resource disposal");
|
|
4514
|
+
}
|
|
4515
|
+
}
|
|
4117
4516
|
async function failBeforeActivation(prepared, state, error, reason, cleanupTimeoutMs) {
|
|
4118
4517
|
beginPreparedCandidateSettlement(prepared);
|
|
4119
4518
|
const cleanupDeadlineAtMs = candidateCleanupDeadline(cleanupTimeoutMs);
|
|
@@ -4168,10 +4567,9 @@ async function failClaimedExecution(prepared, state, lease, claimStore, outputAr
|
|
|
4168
4567
|
claimStore,
|
|
4169
4568
|
lease,
|
|
4170
4569
|
{
|
|
4171
|
-
schemaVersion: 1,
|
|
4172
4570
|
status: "failed",
|
|
4173
4571
|
failureClass,
|
|
4174
|
-
usage: settled.settlement.
|
|
4572
|
+
usage: settled.settlement.usage,
|
|
4175
4573
|
modelSettlement: modelSettlement.artifact,
|
|
4176
4574
|
failureEvidence
|
|
4177
4575
|
},
|
|
@@ -4268,7 +4666,6 @@ async function finishClaim(store, lease, terminal, deadlineAtMs) {
|
|
|
4268
4666
|
}
|
|
4269
4667
|
async function persistFailureEvidence(state, reason, failureClass, termination, outputArtifacts) {
|
|
4270
4668
|
const bytes = canonicalCandidateBytes({
|
|
4271
|
-
schemaVersion: 1,
|
|
4272
4669
|
kind: "agent-candidate-execution-failure",
|
|
4273
4670
|
executionId: state.executionId,
|
|
4274
4671
|
bundleDigest: state.bundle.digest,
|
|
@@ -4300,10 +4697,24 @@ var CandidateExecutionDeadlineError = class extends Error {
|
|
|
4300
4697
|
};
|
|
4301
4698
|
|
|
4302
4699
|
// src/candidate-execution/verify.ts
|
|
4303
|
-
import { agentCandidateBundleSchema
|
|
4700
|
+
import { agentCandidateBundleSchema } from "@tangle-network/agent-interface";
|
|
4304
4701
|
var verifiedCandidateState = /* @__PURE__ */ new WeakMap();
|
|
4702
|
+
var AGENT_CANDIDATE_EXECUTION_SUPPORT = Object.freeze({
|
|
4703
|
+
outcomes: Object.freeze(["workspace", "output"]),
|
|
4704
|
+
code: Object.freeze(["disabled", "no-op", "git-patch"]),
|
|
4705
|
+
memory: Object.freeze(["disabled", "isolated"]),
|
|
4706
|
+
knowledge: true,
|
|
4707
|
+
profile: Object.freeze({
|
|
4708
|
+
mcpTransports: Object.freeze(["stdio"]),
|
|
4709
|
+
remoteMcp: false,
|
|
4710
|
+
tools: false,
|
|
4711
|
+
permissions: false,
|
|
4712
|
+
modes: false,
|
|
4713
|
+
confidential: false
|
|
4714
|
+
})
|
|
4715
|
+
});
|
|
4305
4716
|
async function verifyAgentCandidateBundle(input, ports) {
|
|
4306
|
-
const parsed =
|
|
4717
|
+
const parsed = agentCandidateBundleSchema.parse(input);
|
|
4307
4718
|
const withoutDigest = omitTopLevelDigest(parsed);
|
|
4308
4719
|
const actualDigest = canonicalCandidateDigest(withoutDigest);
|
|
4309
4720
|
if (actualDigest !== parsed.digest) {
|
|
@@ -4311,6 +4722,7 @@ async function verifyAgentCandidateBundle(input, ports) {
|
|
|
4311
4722
|
}
|
|
4312
4723
|
const canonicalBytes = canonicalCandidateBytes(withoutDigest);
|
|
4313
4724
|
verifyBytes(canonicalBytes, parsed.digest, canonicalBytes.byteLength, "candidate bundle");
|
|
4725
|
+
assertCandidateProfileExecutionSupport(parsed.profile);
|
|
4314
4726
|
const artifactBytes = /* @__PURE__ */ new Map();
|
|
4315
4727
|
const readArtifact = async (artifact) => {
|
|
4316
4728
|
const key = artifactCacheKey(artifact);
|
|
@@ -4345,7 +4757,16 @@ async function verifyAgentCandidateBundle(input, ports) {
|
|
|
4345
4757
|
artifactBytes.set(artifactCacheKey(parsed.execution.workspace.manifest), workspace.manifest);
|
|
4346
4758
|
artifactBytes.set(artifactCacheKey(parsed.execution.workspace.archive), workspace.archive);
|
|
4347
4759
|
}
|
|
4348
|
-
if (parsed.knowledge)
|
|
4760
|
+
if (parsed.knowledge) {
|
|
4761
|
+
const knowledge = await verifyWorkspaceSnapshotArtifacts(
|
|
4762
|
+
parsed.knowledge.snapshot,
|
|
4763
|
+
ports.artifacts
|
|
4764
|
+
);
|
|
4765
|
+
artifactBytes.set(artifactCacheKey(parsed.knowledge.snapshot.manifest), knowledge.manifest);
|
|
4766
|
+
artifactBytes.set(artifactCacheKey(parsed.knowledge.snapshot.archive), knowledge.archive);
|
|
4767
|
+
if (parsed.knowledge.retrievalConfig) await readArtifact(parsed.knowledge.retrievalConfig);
|
|
4768
|
+
await readArtifact(parsed.knowledge.evaluation);
|
|
4769
|
+
}
|
|
4349
4770
|
if (parsed.memory.mode === "isolated" && parsed.memory.seed)
|
|
4350
4771
|
await readArtifact(parsed.memory.seed);
|
|
4351
4772
|
deepFreezeCandidate(parsed);
|
|
@@ -4398,38 +4819,73 @@ function resourceKey(resource) {
|
|
|
4398
4819
|
return canonicalCandidateDigest(resource);
|
|
4399
4820
|
}
|
|
4400
4821
|
|
|
4822
|
+
// src/candidate-execution/knowledge.ts
|
|
4823
|
+
import { mkdtemp as mkdtemp3, rm as rm3 } from "fs/promises";
|
|
4824
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
4825
|
+
import { join as join3, posix } from "path";
|
|
4826
|
+
var CANDIDATE_KNOWLEDGE_ROOT_ENV = "TANGLE_CANDIDATE_KNOWLEDGE_ROOT";
|
|
4827
|
+
var CANDIDATE_KNOWLEDGE_RETRIEVAL_CONFIG_ENV = "TANGLE_CANDIDATE_KNOWLEDGE_RETRIEVAL_CONFIG";
|
|
4828
|
+
function candidateKnowledgeExecutionPaths(taskRoot, hasRetrievalConfig) {
|
|
4829
|
+
if (!posix.isAbsolute(taskRoot) || posix.normalize(taskRoot) !== taskRoot) {
|
|
4830
|
+
throw new Error("candidate knowledge requires a normalized absolute task root");
|
|
4831
|
+
}
|
|
4832
|
+
const parent = posix.join(taskRoot, ".tangle");
|
|
4833
|
+
return {
|
|
4834
|
+
root: posix.join(parent, "knowledge"),
|
|
4835
|
+
...hasRetrievalConfig ? { retrievalConfig: posix.join(parent, "knowledge-retrieval-config.json") } : {}
|
|
4836
|
+
};
|
|
4837
|
+
}
|
|
4838
|
+
async function prepareAgentCandidateKnowledge(candidate, ports) {
|
|
4839
|
+
const knowledge = candidate.bundle.knowledge;
|
|
4840
|
+
if (!knowledge) return void 0;
|
|
4841
|
+
const archive = await verifiedArtifactBytes(candidate, knowledge.snapshot.archive);
|
|
4842
|
+
const retrievalConfig = knowledge.retrievalConfig ? await verifiedArtifactBytes(candidate, knowledge.retrievalConfig) : void 0;
|
|
4843
|
+
const root = await mkdtemp3(join3(tmpdir3(), "agent-candidate-knowledge-"));
|
|
4844
|
+
try {
|
|
4845
|
+
await ports.workspaces.materialize({
|
|
4846
|
+
role: "knowledge",
|
|
4847
|
+
snapshot: knowledge.snapshot,
|
|
4848
|
+
archive,
|
|
4849
|
+
destination: root
|
|
4850
|
+
});
|
|
4851
|
+
const files = await readMaterializedWorkspaceFiles(root, knowledge.snapshot.material);
|
|
4852
|
+
return Object.freeze({
|
|
4853
|
+
candidate: knowledge.candidate,
|
|
4854
|
+
snapshot: knowledge.snapshot,
|
|
4855
|
+
files: Object.freeze(
|
|
4856
|
+
files.map(
|
|
4857
|
+
(file) => Object.freeze({ path: file.path, mode: file.mode, bytes: Uint8Array.from(file.bytes) })
|
|
4858
|
+
)
|
|
4859
|
+
),
|
|
4860
|
+
...retrievalConfig ? { retrievalConfig: Uint8Array.from(retrievalConfig) } : {}
|
|
4861
|
+
});
|
|
4862
|
+
} finally {
|
|
4863
|
+
await rm3(root, { recursive: true, force: true });
|
|
4864
|
+
}
|
|
4865
|
+
}
|
|
4866
|
+
|
|
4401
4867
|
// src/candidate-execution/prepare.ts
|
|
4402
4868
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
4403
4869
|
import { lstat as lstat2, readdir as readdir2 } from "fs/promises";
|
|
4404
|
-
import { isAbsolute, posix, relative as relative2, resolve as resolveHostPath } from "path";
|
|
4870
|
+
import { isAbsolute, posix as posix2, relative as relative2, resolve as resolveHostPath } from "path";
|
|
4405
4871
|
import {
|
|
4872
|
+
agentCandidateBenchmarkSuiteSchema as agentCandidateBenchmarkSuiteSchema2,
|
|
4873
|
+
agentCandidateBenchmarkTaskSchema as agentCandidateBenchmarkTaskSchema2,
|
|
4406
4874
|
agentCandidateContainerSchema,
|
|
4407
4875
|
agentCandidateExecutionLimitsSchema,
|
|
4408
4876
|
agentCandidateExecutionPlanEvidenceSchema as agentCandidateExecutionPlanEvidenceSchema2,
|
|
4409
4877
|
agentCandidateExecutionPlanMaterialSchema,
|
|
4410
4878
|
agentCandidateMaterializationReceiptSchema as agentCandidateMaterializationReceiptSchema2,
|
|
4411
4879
|
agentCandidateModelAccessNetworkSchema,
|
|
4412
|
-
|
|
4880
|
+
agentCandidateRunCellSchema,
|
|
4881
|
+
agentCandidateTaskOutcomeSpecSchema,
|
|
4882
|
+
agentCandidateWorkspaceSnapshotEvidenceSchema as agentCandidateWorkspaceSnapshotEvidenceSchema3,
|
|
4413
4883
|
sha256DigestSchema
|
|
4414
4884
|
} from "@tangle-network/agent-interface";
|
|
4415
4885
|
import {
|
|
4416
4886
|
applyAgentCandidateWorkspacePlan,
|
|
4417
4887
|
materializeCandidateProfile
|
|
4418
4888
|
} from "@tangle-network/agent-profile-materialize";
|
|
4419
|
-
var MATERIALIZER_HARNESSES = /* @__PURE__ */ new Set([
|
|
4420
|
-
"claude-code",
|
|
4421
|
-
"claude",
|
|
4422
|
-
"claudish",
|
|
4423
|
-
"nanoclaw",
|
|
4424
|
-
"codex",
|
|
4425
|
-
"opencode",
|
|
4426
|
-
"kimi-code",
|
|
4427
|
-
"kimi",
|
|
4428
|
-
"pi",
|
|
4429
|
-
"gemini",
|
|
4430
|
-
"hermes",
|
|
4431
|
-
"openclaw"
|
|
4432
|
-
]);
|
|
4433
4889
|
var MIN_RESERVATION_TTL_MS = 15 * 6e4;
|
|
4434
4890
|
var PREPARED_HOLD_MARGIN_MS = 5 * 6e4;
|
|
4435
4891
|
async function prepareAgentCandidateExecution(candidate, task, ports, options = {}) {
|
|
@@ -4437,12 +4893,23 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
|
|
|
4437
4893
|
const verifiedState = getVerifiedCandidateState(candidate);
|
|
4438
4894
|
assertSameVerificationPorts(verifiedState.ports, ports);
|
|
4439
4895
|
const bundle = candidate.bundle;
|
|
4440
|
-
|
|
4441
|
-
|
|
4896
|
+
if (task.runCell.bundleDigest !== bundle.digest) {
|
|
4897
|
+
throw new Error("candidate experiment cell does not bind the verified bundle");
|
|
4898
|
+
}
|
|
4899
|
+
const benchmarkTask = task.task;
|
|
4900
|
+
const attempt = {
|
|
4901
|
+
number: task.runCell.attempt,
|
|
4902
|
+
maxAttempts: benchmarkTask.attempt.maxAttempts,
|
|
4903
|
+
retryPolicy: benchmarkTask.attempt.retryPolicy
|
|
4904
|
+
};
|
|
4905
|
+
const harness = candidateMaterializerHarness(bundle.execution.harness);
|
|
4442
4906
|
assertTaskInput(task, bundle.execution.instructionDelivery);
|
|
4443
|
-
const resultTimeoutMs = candidateResultTimeout(
|
|
4907
|
+
const resultTimeoutMs = candidateResultTimeout(
|
|
4908
|
+
options.resultTimeoutMs,
|
|
4909
|
+
benchmarkTask.limits.timeoutMs
|
|
4910
|
+
);
|
|
4444
4911
|
const ownerWindowMs = candidateExecutionOwnerWindowMs(
|
|
4445
|
-
|
|
4912
|
+
benchmarkTask.limits.timeoutMs,
|
|
4446
4913
|
cleanupTimeoutMs,
|
|
4447
4914
|
resultTimeoutMs
|
|
4448
4915
|
);
|
|
@@ -4451,22 +4918,26 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
|
|
|
4451
4918
|
throw new Error("candidate reservation window exceeds the supported timer range");
|
|
4452
4919
|
}
|
|
4453
4920
|
assertDisjointHostStagingRoots(task);
|
|
4454
|
-
const instructionBytes = Buffer.from(
|
|
4455
|
-
const
|
|
4456
|
-
|
|
4921
|
+
const instructionBytes = Buffer.from(benchmarkTask.instruction, "utf8");
|
|
4922
|
+
const taskArtifacts = await verifyWorkspaceSnapshotArtifacts(
|
|
4923
|
+
benchmarkTask.workspace,
|
|
4924
|
+
ports.artifacts
|
|
4925
|
+
);
|
|
4457
4926
|
await ports.workspaces.materialize({
|
|
4458
4927
|
role: "task",
|
|
4459
|
-
snapshot:
|
|
4928
|
+
snapshot: benchmarkTask.workspace,
|
|
4460
4929
|
archive: taskArtifacts.archive,
|
|
4461
4930
|
destination: task.stagingRoots.taskRoot
|
|
4462
4931
|
});
|
|
4463
|
-
await verifyMaterializedWorkspace(task.stagingRoots.taskRoot,
|
|
4932
|
+
await verifyMaterializedWorkspace(task.stagingRoots.taskRoot, benchmarkTask.workspace.material, {
|
|
4464
4933
|
ignoredProtectedRootEntries: [".git", ".sidecar"]
|
|
4465
4934
|
});
|
|
4466
|
-
|
|
4935
|
+
if (benchmarkTask.repository) {
|
|
4936
|
+
await verifyTaskCheckout(task.stagingRoots.taskRoot, benchmarkTask.repository);
|
|
4937
|
+
}
|
|
4467
4938
|
const taskExecutorFiles = await readMaterializedWorkspaceFiles(
|
|
4468
4939
|
task.stagingRoots.taskRoot,
|
|
4469
|
-
|
|
4940
|
+
benchmarkTask.workspace.material,
|
|
4470
4941
|
{ ignoredProtectedRootEntries: [".git", ".sidecar"] }
|
|
4471
4942
|
);
|
|
4472
4943
|
let candidateArchive;
|
|
@@ -4504,30 +4975,33 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
|
|
|
4504
4975
|
);
|
|
4505
4976
|
await verifyMaterializedProfileWorkspace(
|
|
4506
4977
|
task.stagingRoots.profileRoot,
|
|
4507
|
-
profileApplication.profilePlan.material
|
|
4978
|
+
profileApplication.profileActivation.profilePlan.material
|
|
4508
4979
|
);
|
|
4509
4980
|
const profilePlanBytes = await readVerifiedArtifact(
|
|
4510
|
-
profileApplication.profilePlan.artifact,
|
|
4981
|
+
profileApplication.profileActivation.profilePlan.artifact,
|
|
4511
4982
|
ports.artifacts
|
|
4512
4983
|
);
|
|
4513
4984
|
if (!Buffer.from(profilePlanBytes).equals(
|
|
4514
|
-
Buffer.from(
|
|
4985
|
+
Buffer.from(
|
|
4986
|
+
canonicalCandidateBytes(profileApplication.profileActivation.profilePlan.material)
|
|
4987
|
+
)
|
|
4515
4988
|
)) {
|
|
4516
4989
|
throw new Error("profile materializer did not capture exact canonical plan bytes");
|
|
4517
4990
|
}
|
|
4991
|
+
const profileActivation = profileApplication.profileActivation;
|
|
4518
4992
|
const container = await resolveContainer(candidate, task, ports);
|
|
4519
4993
|
const resolvedModel = await resolveModel(candidate, task, ports);
|
|
4520
|
-
const preparationId = `candidate-preparation
|
|
4994
|
+
const preparationId = `candidate-preparation.${randomBytes2(32).toString("base64url")}`;
|
|
4521
4995
|
const reservationExpiresAtMs = Date.now() + Math.max(MIN_RESERVATION_TTL_MS, reservationWindowMs);
|
|
4522
4996
|
const modelReservation = await withinCandidateCleanupDeadline(
|
|
4523
4997
|
() => ports.models.reserveGrant({
|
|
4524
4998
|
executionId: task.executionId,
|
|
4525
4999
|
preparationId,
|
|
4526
5000
|
expiresAtMs: reservationExpiresAtMs,
|
|
4527
|
-
attempt
|
|
5001
|
+
attempt,
|
|
4528
5002
|
bundleDigest: bundle.digest,
|
|
4529
5003
|
resolved: resolvedModel,
|
|
4530
|
-
limits: modelLimits2(
|
|
5004
|
+
limits: modelLimits2(benchmarkTask.limits)
|
|
4531
5005
|
}),
|
|
4532
5006
|
candidateCleanupDeadline(cleanupTimeoutMs),
|
|
4533
5007
|
"protected model reservation"
|
|
@@ -4536,7 +5010,7 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
|
|
|
4536
5010
|
try {
|
|
4537
5011
|
validateProtectedModelReservation(
|
|
4538
5012
|
modelReservation,
|
|
4539
|
-
|
|
5013
|
+
benchmarkTask.limits,
|
|
4540
5014
|
preparationId,
|
|
4541
5015
|
reservationExpiresAtMs
|
|
4542
5016
|
);
|
|
@@ -4549,11 +5023,11 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
|
|
|
4549
5023
|
cleanupTimeoutMs
|
|
4550
5024
|
);
|
|
4551
5025
|
const memory = preparedMemory.value;
|
|
4552
|
-
const knowledge =
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
5026
|
+
const knowledge = await prepareAgentCandidateKnowledge(candidate, ports);
|
|
5027
|
+
const knowledgePaths = knowledge ? candidateKnowledgeExecutionPaths(
|
|
5028
|
+
task.executionRoots.taskRoot,
|
|
5029
|
+
knowledge.retrievalConfig !== void 0
|
|
5030
|
+
) : void 0;
|
|
4557
5031
|
const baseLaunch = buildLaunch(candidate, task, profileApplication.flags);
|
|
4558
5032
|
const publicEnv = mergePublicEnvironment(
|
|
4559
5033
|
bundle.execution.env ?? {},
|
|
@@ -4563,29 +5037,25 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
|
|
|
4563
5037
|
kind: "public",
|
|
4564
5038
|
value: bundle.execution.instructionDelivery.path
|
|
4565
5039
|
}
|
|
5040
|
+
} : {},
|
|
5041
|
+
knowledgePaths ? {
|
|
5042
|
+
[CANDIDATE_KNOWLEDGE_ROOT_ENV]: {
|
|
5043
|
+
kind: "public",
|
|
5044
|
+
value: knowledgePaths.root
|
|
5045
|
+
},
|
|
5046
|
+
...knowledgePaths.retrievalConfig ? {
|
|
5047
|
+
[CANDIDATE_KNOWLEDGE_RETRIEVAL_CONFIG_ENV]: {
|
|
5048
|
+
kind: "public",
|
|
5049
|
+
value: knowledgePaths.retrievalConfig
|
|
5050
|
+
}
|
|
5051
|
+
} : {}
|
|
4566
5052
|
} : {}
|
|
4567
5053
|
);
|
|
4568
|
-
const routes = modelRoutes(bundle.profile,
|
|
5054
|
+
const routes = modelRoutes(bundle.profile, benchmarkTask.model.requested);
|
|
4569
5055
|
const executionMaterial = {
|
|
4570
|
-
schemaVersion: 1,
|
|
4571
5056
|
kind: "agent-candidate-execution-plan-material",
|
|
4572
|
-
|
|
5057
|
+
runCell: task.runCell,
|
|
4573
5058
|
executionId: task.executionId,
|
|
4574
|
-
attempt: task.attempt,
|
|
4575
|
-
task: {
|
|
4576
|
-
benchmark: task.benchmark,
|
|
4577
|
-
benchmarkVersion: task.benchmarkVersion,
|
|
4578
|
-
taskId: task.taskId,
|
|
4579
|
-
splitDigest: task.splitDigest,
|
|
4580
|
-
instruction: {
|
|
4581
|
-
encoding: "utf8",
|
|
4582
|
-
sha256: instructionDigest,
|
|
4583
|
-
byteLength: instructionBytes.byteLength,
|
|
4584
|
-
delivery: bundle.execution.instructionDelivery
|
|
4585
|
-
},
|
|
4586
|
-
repository: task.repository,
|
|
4587
|
-
workspace: task.workspace
|
|
4588
|
-
},
|
|
4589
5059
|
workspaces: {
|
|
4590
5060
|
taskRoot: task.executionRoots.taskRoot,
|
|
4591
5061
|
...task.executionRoots.candidateRoot ? { candidateRoot: task.executionRoots.candidateRoot } : {}
|
|
@@ -4595,6 +5065,8 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
|
|
|
4595
5065
|
profile: profileApplication.application,
|
|
4596
5066
|
harness: bundle.execution.harness,
|
|
4597
5067
|
harnessVersion: bundle.execution.harnessVersion,
|
|
5068
|
+
instructionDelivery: bundle.execution.instructionDelivery,
|
|
5069
|
+
limits: benchmarkTask.limits,
|
|
4598
5070
|
container,
|
|
4599
5071
|
model: {
|
|
4600
5072
|
policy: "single",
|
|
@@ -4606,16 +5078,14 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
|
|
|
4606
5078
|
},
|
|
4607
5079
|
routes
|
|
4608
5080
|
},
|
|
4609
|
-
grader: task.grader,
|
|
4610
5081
|
launch: {
|
|
4611
5082
|
executable: baseLaunch.executable,
|
|
4612
5083
|
args: baseLaunch.args,
|
|
4613
5084
|
env: publicEnv,
|
|
4614
5085
|
cwd: bundle.execution.cwd
|
|
4615
5086
|
},
|
|
4616
|
-
...bundle.knowledge ? { knowledgeManifestDigest: bundle.knowledge.
|
|
5087
|
+
...bundle.knowledge ? { knowledgeManifestDigest: bundle.knowledge.snapshot.digest } : {},
|
|
4617
5088
|
memory,
|
|
4618
|
-
limits: task.limits,
|
|
4619
5089
|
network: { mode: "disabled" }
|
|
4620
5090
|
};
|
|
4621
5091
|
agentCandidateExecutionPlanMaterialSchema.parse(executionMaterial);
|
|
@@ -4625,7 +5095,6 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
|
|
|
4625
5095
|
throw new Error("execution plan canonical serializers disagree");
|
|
4626
5096
|
}
|
|
4627
5097
|
const executionPlan = agentCandidateExecutionPlanEvidenceSchema2.parse({
|
|
4628
|
-
schemaVersion: 1,
|
|
4629
5098
|
kind: "agent-candidate-execution-plan",
|
|
4630
5099
|
digest: executionDigest,
|
|
4631
5100
|
material: executionMaterial,
|
|
@@ -4634,11 +5103,24 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
|
|
|
4634
5103
|
const entrypoint = candidateEntrypointReceipt(candidate);
|
|
4635
5104
|
const materializationReceipt = canonicalCandidateDocument(
|
|
4636
5105
|
{
|
|
4637
|
-
schemaVersion: 1,
|
|
4638
5106
|
kind: "agent-candidate-materialization",
|
|
4639
5107
|
digestAlgorithm: "rfc8785-sha256",
|
|
4640
5108
|
bundleDigest: bundle.digest,
|
|
4641
|
-
|
|
5109
|
+
benchmark: {
|
|
5110
|
+
suite: {
|
|
5111
|
+
digest: task.benchmarkSuite.digest,
|
|
5112
|
+
material: embeddedCandidateArtifact(
|
|
5113
|
+
canonicalCandidateBytes(omitTopLevelDigest(task.benchmarkSuite))
|
|
5114
|
+
)
|
|
5115
|
+
},
|
|
5116
|
+
task: {
|
|
5117
|
+
digest: benchmarkTask.digest,
|
|
5118
|
+
material: embeddedCandidateArtifact(
|
|
5119
|
+
canonicalCandidateBytes(omitTopLevelDigest(benchmarkTask))
|
|
5120
|
+
)
|
|
5121
|
+
}
|
|
5122
|
+
},
|
|
5123
|
+
profileActivation,
|
|
4642
5124
|
executionPlan,
|
|
4643
5125
|
...bundle.execution.workspace ? { candidateWorkspace: bundle.execution.workspace } : {},
|
|
4644
5126
|
codeKind: bundle.code.kind,
|
|
@@ -4647,12 +5129,12 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
|
|
|
4647
5129
|
harnessVersion: bundle.execution.harnessVersion,
|
|
4648
5130
|
container,
|
|
4649
5131
|
resolvedModel,
|
|
4650
|
-
...bundle.knowledge ? { knowledgeManifestDigest: bundle.knowledge.
|
|
5132
|
+
...bundle.knowledge ? { knowledgeManifestDigest: bundle.knowledge.snapshot.digest } : {},
|
|
4651
5133
|
...entrypoint ? { entrypoint } : {}
|
|
4652
5134
|
}
|
|
4653
5135
|
);
|
|
4654
5136
|
agentCandidateMaterializationReceiptSchema2.parse(materializationReceipt.value);
|
|
4655
|
-
const traceRunId = `${task.executionId}:attempt-${
|
|
5137
|
+
const traceRunId = `${task.executionId}:attempt-${attempt.number}:${canonicalCandidateDigest({ preparationId }).slice(7, 23)}`;
|
|
4656
5138
|
const traceTags = {
|
|
4657
5139
|
[CANDIDATE_TRACE_TAGS.executionId]: task.executionId,
|
|
4658
5140
|
[CANDIDATE_TRACE_TAGS.bundleDigest]: bundle.digest,
|
|
@@ -4670,16 +5152,19 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
|
|
|
4670
5152
|
return createPreparedCandidateExecution({
|
|
4671
5153
|
ports,
|
|
4672
5154
|
bundle,
|
|
5155
|
+
benchmarkSuite: task.benchmarkSuite,
|
|
5156
|
+
benchmarkTask,
|
|
4673
5157
|
executionId: task.executionId,
|
|
4674
5158
|
roots: {
|
|
4675
5159
|
execution: { ...task.executionRoots },
|
|
4676
5160
|
staging: { ...task.stagingRoots }
|
|
4677
5161
|
},
|
|
4678
5162
|
profilePlan: {
|
|
4679
|
-
value: profileApplication.profilePlan,
|
|
5163
|
+
value: profileApplication.profileActivation.profilePlan,
|
|
4680
5164
|
bytes: profilePlanBytes,
|
|
4681
5165
|
written: [...profileApplication.application.mountPaths]
|
|
4682
5166
|
},
|
|
5167
|
+
profileActivation,
|
|
4683
5168
|
executionPlan: { value: executionPlan, bytes: executionBytes },
|
|
4684
5169
|
materializationReceipt,
|
|
4685
5170
|
launch: {
|
|
@@ -4710,7 +5195,7 @@ async function prepareAgentCandidateExecution(candidate, task, ports, options =
|
|
|
4710
5195
|
...candidateExecutorFiles ? { candidateFiles: candidateExecutorFiles } : {},
|
|
4711
5196
|
profileFiles: exactProfileExecutorFiles(
|
|
4712
5197
|
profileWorkspacePlan.files,
|
|
4713
|
-
profileApplication.profilePlan.material.files
|
|
5198
|
+
profileApplication.profileActivation.profilePlan.material.files
|
|
4714
5199
|
)
|
|
4715
5200
|
},
|
|
4716
5201
|
...preparedMemory.accessDigest && preparedMemory.value.mode === "isolated" ? {
|
|
@@ -4795,34 +5280,54 @@ function assertSameVerificationPorts(verified, execution) {
|
|
|
4795
5280
|
}
|
|
4796
5281
|
}
|
|
4797
5282
|
function assertTaskInput(task, delivery) {
|
|
5283
|
+
const benchmarkTask = agentCandidateBenchmarkTaskSchema2.parse(task.task);
|
|
5284
|
+
const benchmarkSuite = agentCandidateBenchmarkSuiteSchema2.parse(task.benchmarkSuite);
|
|
5285
|
+
const runCell = agentCandidateRunCellSchema.parse(task.runCell);
|
|
4798
5286
|
const requiredStrings = [
|
|
4799
5287
|
["executionId", task.executionId],
|
|
4800
|
-
["benchmark",
|
|
4801
|
-
["benchmarkVersion",
|
|
4802
|
-
["taskId",
|
|
4803
|
-
["repository identity", task.repository.identity],
|
|
4804
|
-
["repository root identity", task.repository.rootIdentity]
|
|
5288
|
+
["benchmark", benchmarkTask.benchmark.name],
|
|
5289
|
+
["benchmarkVersion", benchmarkTask.benchmark.version],
|
|
5290
|
+
["taskId", benchmarkTask.scenario.id]
|
|
4805
5291
|
];
|
|
5292
|
+
if (benchmarkTask.outcome.kind === "workspace" && !benchmarkTask.repository) {
|
|
5293
|
+
throw new Error("workspace task outcome requires repository identity");
|
|
5294
|
+
}
|
|
5295
|
+
if (benchmarkTask.repository) {
|
|
5296
|
+
requiredStrings.push(
|
|
5297
|
+
["repository identity", benchmarkTask.repository.identity],
|
|
5298
|
+
["repository root identity", benchmarkTask.repository.rootIdentity]
|
|
5299
|
+
);
|
|
5300
|
+
}
|
|
4806
5301
|
for (const [name, value] of requiredStrings) {
|
|
4807
5302
|
if (!value.trim()) throw new Error(`${name} must be non-empty`);
|
|
4808
5303
|
}
|
|
4809
5304
|
if (!/^[A-Za-z0-9._:-]{1,200}$/.test(task.executionId)) {
|
|
4810
5305
|
throw new Error("executionId must be a stable filesystem-neutral identifier");
|
|
4811
5306
|
}
|
|
4812
|
-
if (!
|
|
5307
|
+
if (!benchmarkTask.instruction || !isWellFormedUnicode(benchmarkTask.instruction)) {
|
|
4813
5308
|
throw new Error("task instruction must be non-empty well-formed Unicode");
|
|
4814
5309
|
}
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
agentCandidateExecutionLimitsSchema.parse(task.limits);
|
|
4818
|
-
if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(task.repository.baseCommit)) {
|
|
4819
|
-
throw new Error("task repository base commit is not a full Git object id");
|
|
5310
|
+
if (canonicalCandidateDigest(omitTopLevelDigest(benchmarkTask)) !== benchmarkTask.digest || canonicalCandidateDigest(omitTopLevelDigest(benchmarkSuite)) !== benchmarkSuite.digest || canonicalCandidateDigest(omitTopLevelDigest(runCell)) !== runCell.digest) {
|
|
5311
|
+
throw new Error("candidate experiment cell contains an invalid content digest");
|
|
4820
5312
|
}
|
|
4821
|
-
|
|
4822
|
-
|
|
5313
|
+
const cellIndex = runCell.taskIndex * benchmarkSuite.reps + runCell.repetition;
|
|
5314
|
+
if (runCell.suiteDigest !== benchmarkSuite.digest || runCell.taskDigest !== benchmarkTask.digest || benchmarkSuite.taskDigests[runCell.taskIndex] !== benchmarkTask.digest || runCell.repetition >= benchmarkSuite.reps || benchmarkSuite.seeds[cellIndex] !== runCell.seed || runCell.attempt > benchmarkTask.attempt.maxAttempts) {
|
|
5315
|
+
throw new Error("candidate experiment cell does not match its signed suite and task");
|
|
4823
5316
|
}
|
|
4824
|
-
|
|
4825
|
-
|
|
5317
|
+
sha256DigestSchema.parse(benchmarkTask.benchmark.splitDigest);
|
|
5318
|
+
agentCandidateTaskOutcomeSpecSchema.parse(benchmarkTask.outcome);
|
|
5319
|
+
agentCandidateWorkspaceSnapshotEvidenceSchema3.parse(benchmarkTask.workspace);
|
|
5320
|
+
agentCandidateExecutionLimitsSchema.parse(benchmarkTask.limits);
|
|
5321
|
+
if (benchmarkTask.repository) {
|
|
5322
|
+
if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(benchmarkTask.repository.baseCommit)) {
|
|
5323
|
+
throw new Error("task repository base commit is not a full Git object id");
|
|
5324
|
+
}
|
|
5325
|
+
if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(benchmarkTask.repository.baseTree)) {
|
|
5326
|
+
throw new Error("task repository base tree is not a full Git object id");
|
|
5327
|
+
}
|
|
5328
|
+
if (benchmarkTask.repository.baseCommit.length !== benchmarkTask.repository.baseTree.length) {
|
|
5329
|
+
throw new Error("task repository Git object formats disagree");
|
|
5330
|
+
}
|
|
4826
5331
|
}
|
|
4827
5332
|
for (const [name, root] of [
|
|
4828
5333
|
["execution task root", task.executionRoots.taskRoot],
|
|
@@ -4832,34 +5337,36 @@ function assertTaskInput(task, delivery) {
|
|
|
4832
5337
|
["staging profile root", task.stagingRoots.profileRoot]
|
|
4833
5338
|
]) {
|
|
4834
5339
|
if (root === void 0) continue;
|
|
4835
|
-
const canonical = name.startsWith("execution") ?
|
|
5340
|
+
const canonical = name.startsWith("execution") ? posix2.isAbsolute(root) && posix2.normalize(root) === root : isAbsolute(root) && resolveHostPath(root) === root;
|
|
4836
5341
|
if (!canonical) throw new Error(`${name} must be a canonical absolute path`);
|
|
4837
5342
|
}
|
|
4838
|
-
if (!Number.isInteger(
|
|
5343
|
+
if (!Number.isInteger(runCell.attempt) || !Number.isInteger(benchmarkTask.attempt.maxAttempts) || runCell.attempt < 1 || runCell.attempt > benchmarkTask.attempt.maxAttempts || benchmarkTask.attempt.retryPolicy === "none" && benchmarkTask.attempt.maxAttempts !== 1) {
|
|
4839
5344
|
throw new Error("task attempt policy is invalid");
|
|
4840
5345
|
}
|
|
4841
|
-
const limits =
|
|
5346
|
+
const limits = benchmarkTask.limits;
|
|
4842
5347
|
if (!Number.isInteger(limits.timeoutMs) || limits.timeoutMs <= 0 || limits.timeoutMs > MAX_CANDIDATE_TIMER_INTERVAL_MS || !Number.isInteger(limits.maxSteps) || limits.maxSteps <= 0 || !Number.isInteger(limits.maxModelCalls) || limits.maxModelCalls < 0 || !Number.isInteger(limits.maxInputTokens) || limits.maxInputTokens < 0 || !Number.isInteger(limits.maxOutputTokens) || limits.maxOutputTokens < 0 || !Number.isFinite(limits.maxCostUsd) || limits.maxCostUsd < 0) {
|
|
4843
5348
|
throw new Error("task execution limits are invalid");
|
|
4844
5349
|
}
|
|
4845
5350
|
usdToNanos(limits.maxCostUsd, "task maxCostUsd");
|
|
4846
|
-
if (!
|
|
4847
|
-
|
|
5351
|
+
if (!benchmarkTask.model.requested.trim()) {
|
|
5352
|
+
throw new Error("evaluator model request must be non-empty");
|
|
5353
|
+
}
|
|
5354
|
+
if (!benchmarkTask.grader.name.trim() || !benchmarkTask.grader.version.trim()) {
|
|
4848
5355
|
throw new Error("evaluator benchmark grader identity must be non-empty");
|
|
4849
5356
|
}
|
|
4850
|
-
if (!Number.isInteger(
|
|
5357
|
+
if (!Number.isInteger(benchmarkTask.grader.artifact.byteLength) || benchmarkTask.grader.artifact.byteLength <= 0) {
|
|
4851
5358
|
throw new Error("evaluator benchmark grader artifact must be non-empty");
|
|
4852
5359
|
}
|
|
4853
|
-
sha256DigestSchema.parse(
|
|
4854
|
-
if (
|
|
4855
|
-
if (
|
|
5360
|
+
sha256DigestSchema.parse(benchmarkTask.grader.artifact.sha256);
|
|
5361
|
+
if (benchmarkTask.evaluatorTaskContainer) {
|
|
5362
|
+
if (benchmarkTask.evaluatorTaskContainer.source !== "evaluator-task-container" || !benchmarkTask.evaluatorTaskContainer.image.trim() || !benchmarkTask.evaluatorTaskContainer.platform.os.trim() || !benchmarkTask.evaluatorTaskContainer.platform.architecture.trim()) {
|
|
4856
5363
|
throw new Error("evaluator task container evidence is incomplete");
|
|
4857
5364
|
}
|
|
4858
|
-
sha256DigestSchema.parse(
|
|
4859
|
-
sha256DigestSchema.parse(
|
|
5365
|
+
sha256DigestSchema.parse(benchmarkTask.evaluatorTaskContainer.indexDigest);
|
|
5366
|
+
sha256DigestSchema.parse(benchmarkTask.evaluatorTaskContainer.manifestDigest);
|
|
4860
5367
|
agentCandidateContainerSchema.parse({
|
|
4861
|
-
image:
|
|
4862
|
-
indexDigest:
|
|
5368
|
+
image: benchmarkTask.evaluatorTaskContainer.image,
|
|
5369
|
+
indexDigest: benchmarkTask.evaluatorTaskContainer.indexDigest
|
|
4863
5370
|
});
|
|
4864
5371
|
}
|
|
4865
5372
|
if (delivery.kind === "utf8-file") {
|
|
@@ -4869,8 +5376,8 @@ function assertTaskInput(task, delivery) {
|
|
|
4869
5376
|
}
|
|
4870
5377
|
}
|
|
4871
5378
|
function executionPathsOverlap(left, right) {
|
|
4872
|
-
const a =
|
|
4873
|
-
const b =
|
|
5379
|
+
const a = posix2.normalize(left);
|
|
5380
|
+
const b = posix2.normalize(right);
|
|
4874
5381
|
return a === b || b.startsWith(a === "/" ? "/" : `${a}/`) || a.startsWith(b === "/" ? "/" : `${b}/`);
|
|
4875
5382
|
}
|
|
4876
5383
|
function assertDisjointHostStagingRoots(task) {
|
|
@@ -4902,51 +5409,45 @@ async function assertEmptyDirectory(path) {
|
|
|
4902
5409
|
throw new Error("profile staging root must be empty before materialization");
|
|
4903
5410
|
}
|
|
4904
5411
|
}
|
|
4905
|
-
function materializerHarness(harness) {
|
|
4906
|
-
if (!MATERIALIZER_HARNESSES.has(harness)) {
|
|
4907
|
-
throw new Error(
|
|
4908
|
-
`sealed candidate profile materialization is unsupported for harness ${harness}`
|
|
4909
|
-
);
|
|
4910
|
-
}
|
|
4911
|
-
return harness;
|
|
4912
|
-
}
|
|
4913
5412
|
async function resolveContainer(candidate, task, ports) {
|
|
4914
5413
|
const environment = candidate.bundle.execution.environment;
|
|
5414
|
+
const evaluatorTaskContainer = task.task.evaluatorTaskContainer;
|
|
4915
5415
|
const pinned = environment.kind === "pinned-container" ? environment.container : void 0;
|
|
4916
|
-
if (environment.kind === "evaluator-task-container" && !
|
|
5416
|
+
if (environment.kind === "evaluator-task-container" && !evaluatorTaskContainer) {
|
|
4917
5417
|
throw new Error("evaluator-task-container candidate requires an evaluator-owned task image");
|
|
4918
5418
|
}
|
|
4919
|
-
if (environment.kind === "pinned-container" &&
|
|
5419
|
+
if (environment.kind === "pinned-container" && evaluatorTaskContainer) {
|
|
4920
5420
|
throw new Error("pinned candidate containers cannot be replaced by a task image");
|
|
4921
5421
|
}
|
|
4922
5422
|
const resolved = await ports.containers.resolve({
|
|
4923
5423
|
candidate: pinned,
|
|
4924
|
-
evaluatorTaskContainer
|
|
5424
|
+
evaluatorTaskContainer
|
|
4925
5425
|
});
|
|
4926
5426
|
if (resolved.source !== environment.kind) throw new Error("resolved container source drifted");
|
|
4927
5427
|
if (pinned && (resolved.image !== pinned.image || resolved.indexDigest !== pinned.indexDigest)) {
|
|
4928
5428
|
throw new Error("resolved pinned container does not match the candidate image index");
|
|
4929
5429
|
}
|
|
4930
|
-
if (
|
|
5430
|
+
if (evaluatorTaskContainer && canonicalCandidateDigest(resolved) !== canonicalCandidateDigest(evaluatorTaskContainer)) {
|
|
4931
5431
|
throw new Error("resolved task container does not match evaluator-owned image evidence");
|
|
4932
5432
|
}
|
|
4933
5433
|
return resolved;
|
|
4934
5434
|
}
|
|
4935
5435
|
async function resolveModel(candidate, task, ports) {
|
|
4936
5436
|
const hints = candidate.bundle.profile.model;
|
|
4937
|
-
|
|
5437
|
+
const expected = task.task.model;
|
|
5438
|
+
if (hints?.default !== void 0 && hints.default !== expected.requested) {
|
|
4938
5439
|
throw new Error("candidate model preference conflicts with the evaluator-owned model");
|
|
4939
5440
|
}
|
|
4940
|
-
if (hints?.reasoningEffort !== void 0 && hints.reasoningEffort !==
|
|
5441
|
+
if (hints?.reasoningEffort !== void 0 && hints.reasoningEffort !== expected.reasoningEffort) {
|
|
4941
5442
|
throw new Error("candidate reasoning effort conflicts with the evaluator-owned effort");
|
|
4942
5443
|
}
|
|
4943
5444
|
const resolved = await ports.models.resolve({
|
|
4944
|
-
requested:
|
|
5445
|
+
requested: expected.requested,
|
|
4945
5446
|
harness: candidate.bundle.execution.harness,
|
|
4946
|
-
reasoningEffort:
|
|
5447
|
+
reasoningEffort: expected.reasoningEffort
|
|
4947
5448
|
});
|
|
4948
|
-
if (resolved
|
|
4949
|
-
throw new Error("model resolver drifted from the
|
|
5449
|
+
if (canonicalCandidateDigest(resolved) !== canonicalCandidateDigest(expected)) {
|
|
5450
|
+
throw new Error("model resolver drifted from the signed benchmark model");
|
|
4950
5451
|
}
|
|
4951
5452
|
return resolved;
|
|
4952
5453
|
}
|
|
@@ -4955,7 +5456,7 @@ async function prepareMemory(candidate, task, ports, preparationId, expiresAtMs,
|
|
|
4955
5456
|
if (policy.mode === "disabled") return { value: { mode: "disabled" } };
|
|
4956
5457
|
const seed = policy.seed ? await verifiedArtifactBytes(candidate, policy.seed) : void 0;
|
|
4957
5458
|
const executionSegment = canonicalCandidateDigest({ executionId: task.executionId }).slice(7);
|
|
4958
|
-
const taskSegment = canonicalCandidateDigest({
|
|
5459
|
+
const taskSegment = canonicalCandidateDigest({ taskDigest: task.task.digest }).slice(7);
|
|
4959
5460
|
const preparationSegment = canonicalCandidateDigest({ preparationId }).slice(7, 23);
|
|
4960
5461
|
const effectiveNamespace = `candidate/${candidate.bundle.digest.slice(7, 23)}/${executionSegment}/${taskSegment}/${preparationSegment}`;
|
|
4961
5462
|
const reset = await withinCandidateCleanupDeadline(
|
|
@@ -5022,7 +5523,7 @@ function buildLaunch(candidate, task, profileFlags) {
|
|
|
5022
5523
|
}
|
|
5023
5524
|
const candidateRoot = task.executionRoots.candidateRoot;
|
|
5024
5525
|
if (!candidateRoot) throw new Error("candidate entrypoint requires a container candidate root");
|
|
5025
|
-
const entrypoint =
|
|
5526
|
+
const entrypoint = posix2.join(candidateRoot, launch.entrypoint);
|
|
5026
5527
|
const candidateArgs = launch.args ?? [];
|
|
5027
5528
|
if (launch.interpreter) {
|
|
5028
5529
|
return {
|
|
@@ -5072,7 +5573,7 @@ function candidateEntrypointReceipt(candidate) {
|
|
|
5072
5573
|
function absoluteExecutionCwd(cwd, roots) {
|
|
5073
5574
|
const root = cwd.workspace === "task" ? roots.taskRoot : roots.candidateRoot;
|
|
5074
5575
|
if (!root) throw new Error("candidate cwd is missing its execution workspace root");
|
|
5075
|
-
const absolute = cwd.path === "." ? root :
|
|
5576
|
+
const absolute = cwd.path === "." ? root : posix2.join(root, cwd.path);
|
|
5076
5577
|
if (absolute !== root && !absolute.startsWith(`${root}/`)) {
|
|
5077
5578
|
throw new Error("candidate cwd escapes its execution workspace");
|
|
5078
5579
|
}
|
|
@@ -5119,7 +5620,7 @@ function exactProfileExecutorFiles(sourceFiles, expectedFiles) {
|
|
|
5119
5620
|
const source = byPath.get(expected.relPath);
|
|
5120
5621
|
const mode = source?.mode ?? 420;
|
|
5121
5622
|
const bytes = Buffer.from(source?.content ?? "", "utf8");
|
|
5122
|
-
if (!source || mode
|
|
5623
|
+
if (!source || !Number.isInteger(mode) || mode < 0 || mode > 511 || mode !== expected.mode || sha256Bytes(bytes) !== expected.contentSha256) {
|
|
5123
5624
|
throw new Error("profile source files do not match the signed profile plan");
|
|
5124
5625
|
}
|
|
5125
5626
|
return { path: expected.relPath, mode, bytes: Uint8Array.from(bytes) };
|
|
@@ -5148,20 +5649,19 @@ export {
|
|
|
5148
5649
|
canonicalCandidateDigest,
|
|
5149
5650
|
immutableCandidateValue,
|
|
5150
5651
|
canonicalCandidateDocument,
|
|
5652
|
+
verifyCanonicalCandidateDocument,
|
|
5151
5653
|
embeddedCandidateArtifact,
|
|
5152
5654
|
omitTopLevelDigest,
|
|
5153
5655
|
deepFreezeCandidate,
|
|
5154
|
-
|
|
5656
|
+
candidateMaterializerHarness,
|
|
5657
|
+
createAgentCandidateProfileActivation,
|
|
5658
|
+
parseAgentCandidateProfileActivation,
|
|
5155
5659
|
freezeGenericAgentCandidateProfile,
|
|
5156
|
-
assertCandidateProfileBinding,
|
|
5157
5660
|
parseExactAgentProfile,
|
|
5158
5661
|
parseExactAgentProfileDiff,
|
|
5159
5662
|
applyExactAgentProfileDiff,
|
|
5160
5663
|
parseExactCandidateProfile,
|
|
5161
|
-
|
|
5162
|
-
PENDING_FORMAT_VERSION,
|
|
5163
|
-
TERMINAL_FORMAT_VERSION,
|
|
5164
|
-
PHASE_FORMAT_VERSION,
|
|
5664
|
+
agentCandidateProfileAsAgentProfile,
|
|
5165
5665
|
assertExactObjectKeys,
|
|
5166
5666
|
terminalRecord,
|
|
5167
5667
|
recoveredTerminalRecord,
|
|
@@ -5176,9 +5676,11 @@ export {
|
|
|
5176
5676
|
candidateCleanupTimeout,
|
|
5177
5677
|
candidateCleanupDeadline,
|
|
5178
5678
|
withinCandidateCleanupDeadline,
|
|
5679
|
+
readVerifiedArtifact,
|
|
5179
5680
|
verifyBytes,
|
|
5180
5681
|
verifyMaterializedWorkspace,
|
|
5181
5682
|
captureMaterializedWorkspace,
|
|
5683
|
+
candidateWorkspaceManifest,
|
|
5182
5684
|
assertNoGitIndirection,
|
|
5183
5685
|
readCandidateGitTreeFiles,
|
|
5184
5686
|
runCandidateGit,
|
|
@@ -5192,12 +5694,17 @@ export {
|
|
|
5192
5694
|
candidateClaimFileInternals,
|
|
5193
5695
|
sealAgentCandidateModelSettlement,
|
|
5194
5696
|
usdToNanos,
|
|
5195
|
-
|
|
5697
|
+
sealAgentCandidateExecutorStopAcknowledgement,
|
|
5196
5698
|
persistCandidateOutputArtifact,
|
|
5197
5699
|
persistCandidateModelSettlementEvidence,
|
|
5198
5700
|
RecoveryAgentCandidateTraceStore,
|
|
5199
5701
|
executePreparedAgentCandidate,
|
|
5702
|
+
AGENT_CANDIDATE_EXECUTION_SUPPORT,
|
|
5200
5703
|
verifyAgentCandidateBundle,
|
|
5704
|
+
verifiedResourceTextByDigest,
|
|
5705
|
+
CANDIDATE_KNOWLEDGE_ROOT_ENV,
|
|
5706
|
+
CANDIDATE_KNOWLEDGE_RETRIEVAL_CONFIG_ENV,
|
|
5707
|
+
candidateKnowledgeExecutionPaths,
|
|
5201
5708
|
prepareAgentCandidateExecution
|
|
5202
5709
|
};
|
|
5203
|
-
//# sourceMappingURL=chunk-
|
|
5710
|
+
//# sourceMappingURL=chunk-WTZ37EQY.js.map
|