@tangle-network/agent-eval 0.119.1 → 0.120.1
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/CHANGELOG.md +25 -3
- package/README.md +0 -26
- package/dist/benchmarks/index.d.ts +11 -5
- package/dist/benchmarks/index.js +4 -4
- package/dist/campaign/index.d.ts +93 -37
- package/dist/campaign/index.js +23 -7
- package/dist/{chunk-PSXJ32SR.js → chunk-32BZXMSO.js} +229 -118
- package/dist/chunk-32BZXMSO.js.map +1 -0
- package/dist/{chunk-XJ7JVCHB.js → chunk-3A246TSA.js} +2 -2
- package/dist/{chunk-XMBOU5W7.js → chunk-JN2FCO5W.js} +4 -5
- package/dist/chunk-JN2FCO5W.js.map +1 -0
- package/dist/{chunk-D7AEXSM5.js → chunk-PICTDURQ.js} +2 -2
- package/dist/{chunk-PAHNGS65.js → chunk-XDIRG3TO.js} +175 -11
- package/dist/chunk-XDIRG3TO.js.map +1 -0
- package/dist/contract/index.d.ts +55 -28
- package/dist/contract/index.js +351 -62
- package/dist/contract/index.js.map +1 -1
- package/dist/index.d.ts +22 -8
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/openapi.json +1 -1
- package/dist/rl.d.ts +11 -5
- package/dist/{run-campaign-OBXSN5WK.js → run-campaign-HNFPJET4.js} +2 -2
- package/package.json +1 -6
- package/dist/chunk-PAHNGS65.js.map +0 -1
- package/dist/chunk-PSXJ32SR.js.map +0 -1
- package/dist/chunk-XMBOU5W7.js.map +0 -1
- package/dist/primeintellect/index.d.ts +0 -311
- package/dist/primeintellect/index.js +0 -348
- package/dist/primeintellect/index.js.map +0 -1
- /package/dist/{chunk-XJ7JVCHB.js.map → chunk-3A246TSA.js.map} +0 -0
- /package/dist/{chunk-D7AEXSM5.js.map → chunk-PICTDURQ.js.map} +0 -0
- /package/dist/{run-campaign-OBXSN5WK.js.map → run-campaign-HNFPJET4.js.map} +0 -0
package/dist/contract/index.js
CHANGED
|
@@ -13,12 +13,15 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
analyzeRuns,
|
|
15
15
|
summarizeExecution
|
|
16
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-3A246TSA.js";
|
|
17
17
|
import {
|
|
18
18
|
REFERENCE_EQUIVALENCE_INPUT_LIMITS,
|
|
19
19
|
REFERENCE_EQUIVALENCE_JUDGE_VERSION,
|
|
20
20
|
buildEvidenceVector,
|
|
21
|
+
buildLoopProvenanceRecord,
|
|
22
|
+
campaignBreakdown,
|
|
21
23
|
campaignMeanComposite,
|
|
24
|
+
canonicalDigest,
|
|
22
25
|
composeGate,
|
|
23
26
|
createReferenceEquivalenceJudge,
|
|
24
27
|
defaultProductionGate,
|
|
@@ -26,24 +29,30 @@ import {
|
|
|
26
29
|
evolutionaryProposer,
|
|
27
30
|
gepaProposer,
|
|
28
31
|
heldOutGate,
|
|
32
|
+
loopProvenanceArgsFromResult,
|
|
29
33
|
pairArms,
|
|
30
34
|
paretoPolicy,
|
|
31
35
|
paretoSignificanceGate,
|
|
32
36
|
powerPreflight,
|
|
37
|
+
renderSurfaceDiff,
|
|
33
38
|
runEval,
|
|
34
39
|
runImprovementLoop,
|
|
35
40
|
runReferenceEquivalenceJudge,
|
|
36
41
|
surfaceContentHash,
|
|
37
|
-
surfaceHash
|
|
38
|
-
|
|
42
|
+
surfaceHash,
|
|
43
|
+
verifyLoopProvenanceRecord
|
|
44
|
+
} from "../chunk-32BZXMSO.js";
|
|
39
45
|
import {
|
|
40
|
-
|
|
46
|
+
assertCampaignSplitIdentity,
|
|
47
|
+
assertRealAgentReceipts,
|
|
48
|
+
campaignCoverage,
|
|
49
|
+
campaignSplitDigest,
|
|
41
50
|
createRunCostLedger,
|
|
42
51
|
fsCampaignStorage,
|
|
43
52
|
inMemoryCampaignStorage,
|
|
44
53
|
resolveRunDir,
|
|
45
54
|
runCampaign
|
|
46
|
-
} from "../chunk-
|
|
55
|
+
} from "../chunk-XDIRG3TO.js";
|
|
47
56
|
import {
|
|
48
57
|
buildDefaultAnalystRegistry,
|
|
49
58
|
createChatClient
|
|
@@ -60,7 +69,9 @@ import "../chunk-DPZAEKA6.js";
|
|
|
60
69
|
import {
|
|
61
70
|
pairedBootstrap
|
|
62
71
|
} from "../chunk-PJQFMIOX.js";
|
|
63
|
-
import
|
|
72
|
+
import {
|
|
73
|
+
CostLedger
|
|
74
|
+
} from "../chunk-JHOJHHU7.js";
|
|
64
75
|
import "../chunk-VI2UW6B6.js";
|
|
65
76
|
import {
|
|
66
77
|
recordAggregateMeasurements,
|
|
@@ -198,6 +209,7 @@ async function runSelfImprove(opts, costLedger, startedAt, runDir, storage) {
|
|
|
198
209
|
runDir,
|
|
199
210
|
maxConcurrency,
|
|
200
211
|
cellPlacement: opts.cellPlacement,
|
|
212
|
+
dispatchTimeoutMs: opts.dispatchTimeoutMs,
|
|
201
213
|
costLedger,
|
|
202
214
|
expectUsage,
|
|
203
215
|
labeledStore: opts.labeledStore,
|
|
@@ -253,29 +265,17 @@ async function runSelfImprove(opts, costLedger, startedAt, runDir, storage) {
|
|
|
253
265
|
candidateCandidateId: "winner"
|
|
254
266
|
});
|
|
255
267
|
const durationMs = Date.now() - startedAt;
|
|
256
|
-
const workerRecords = opts.collectWorkerRecords?.() ?? cellsToRunRecords(result.winnerOnHoldout.cells, "winner", runDir, result.winnerSurface);
|
|
257
268
|
const { record: provenance } = await emitLoopProvenance({
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
generationIndex: g.record.generationIndex,
|
|
269
|
-
candidates: g.record.candidates,
|
|
270
|
-
promoted: g.record.promoted,
|
|
271
|
-
surfaces: g.surfaces.map((s) => ({ surfaceHash: s.surfaceHash, surface: s.surface }))
|
|
272
|
-
})),
|
|
273
|
-
gate: result.gateResult,
|
|
274
|
-
baselineOnHoldout: result.baselineOnHoldout,
|
|
275
|
-
winnerOnHoldout: result.winnerOnHoldout,
|
|
276
|
-
workerRecords,
|
|
277
|
-
totalCostUsd: totalCost,
|
|
278
|
-
totalDurationMs: durationMs,
|
|
269
|
+
...loopProvenanceArgsFromResult({
|
|
270
|
+
runId: `${runDir}#${startedAt}`,
|
|
271
|
+
runDir,
|
|
272
|
+
timestamp: new Date(startedAt).toISOString(),
|
|
273
|
+
baselineSurface: opts.baselineSurface,
|
|
274
|
+
result,
|
|
275
|
+
costReceipts: costLedger.list(),
|
|
276
|
+
totalCostUsd: totalCost,
|
|
277
|
+
totalDurationMs: durationMs
|
|
278
|
+
}),
|
|
279
279
|
storage,
|
|
280
280
|
hostedClient: opts.hostedTenant ? createHostedClient(opts.hostedTenant) : void 0
|
|
281
281
|
});
|
|
@@ -423,7 +423,13 @@ function cellsToRunRecords(cells, candidateId, runId, surface) {
|
|
|
423
423
|
commitSha: "cell",
|
|
424
424
|
wallMs: cell.durationMs,
|
|
425
425
|
costUsd: cell.costUsd,
|
|
426
|
-
tokenUsage: {
|
|
426
|
+
tokenUsage: {
|
|
427
|
+
input: cell.tokenUsage.input,
|
|
428
|
+
output: cell.tokenUsage.output,
|
|
429
|
+
...cell.tokenUsage.reasoning === void 0 ? {} : { reasoning: cell.tokenUsage.reasoning },
|
|
430
|
+
...cell.tokenUsage.cached === void 0 ? {} : { cached: cell.tokenUsage.cached },
|
|
431
|
+
...cell.tokenUsage.cacheWrite === void 0 ? {} : { cacheWrite: cell.tokenUsage.cacheWrite }
|
|
432
|
+
},
|
|
427
433
|
outcome: {
|
|
428
434
|
holdoutScore: composite,
|
|
429
435
|
raw: {},
|
|
@@ -541,17 +547,35 @@ function requirePositiveInteger(value, field) {
|
|
|
541
547
|
}
|
|
542
548
|
|
|
543
549
|
// src/contract/measured-comparison.ts
|
|
544
|
-
import { createHash as createHash2 } from "crypto";
|
|
545
550
|
import {
|
|
546
551
|
agentImprovementMeasuredComparisonSchema
|
|
547
552
|
} from "@tangle-network/agent-interface";
|
|
548
553
|
function measuredComparisonFromSelfImproveResult(options) {
|
|
549
554
|
const { result } = options;
|
|
555
|
+
verifyLoopProvenanceRecord(result.provenance);
|
|
550
556
|
const power = result.power;
|
|
551
557
|
if (!power) throw new Error("agent improvement comparison requires heldout power analysis");
|
|
552
558
|
if (result.provenance.gate.reasons.length === 0) {
|
|
553
559
|
throw new Error("agent improvement comparison requires measured decision reasons");
|
|
554
560
|
}
|
|
561
|
+
const receiptLedger = new CostLedger({ receipts: result.receipts });
|
|
562
|
+
const receiptCost = receiptLedger.summary();
|
|
563
|
+
const receipts = receiptLedger.list();
|
|
564
|
+
assertRealAgentReceipts(receipts, { allowMixed: false });
|
|
565
|
+
const receiptsById = new Map(receipts.map((receipt) => [receipt.callId, receipt]));
|
|
566
|
+
const receiptIdsByCell = indexReceiptIdsByCell(receipts);
|
|
567
|
+
assertCompleteMeasuredCampaign(
|
|
568
|
+
result.raw.baselineOnHoldout,
|
|
569
|
+
"heldout baseline",
|
|
570
|
+
receiptsById,
|
|
571
|
+
receiptIdsByCell
|
|
572
|
+
);
|
|
573
|
+
assertCompleteMeasuredCampaign(
|
|
574
|
+
result.raw.winnerOnHoldout,
|
|
575
|
+
"heldout candidate",
|
|
576
|
+
receiptsById,
|
|
577
|
+
receiptIdsByCell
|
|
578
|
+
);
|
|
555
579
|
const pairs = pairMeasuredCells(
|
|
556
580
|
result.raw.baselineOnHoldout.cells,
|
|
557
581
|
result.raw.winnerOnHoldout.cells
|
|
@@ -569,10 +593,103 @@ function measuredComparisonFromSelfImproveResult(options) {
|
|
|
569
593
|
assertMeasuredNumber(result.lift, composite.delta, "heldout lift");
|
|
570
594
|
assertMeasuredNumber(result.baseline.compositeMean, composite.baseline, "heldout baseline");
|
|
571
595
|
assertMeasuredNumber(result.winner.compositeMean, composite.candidate, "heldout candidate");
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
596
|
+
const baselineContentHash = surfaceContentHash(options.baselineSurface);
|
|
597
|
+
const candidateContentHash = surfaceContentHash(result.winner.surface);
|
|
598
|
+
const canonicalDiff = baselineContentHash === candidateContentHash ? "" : renderSurfaceDiff(result.raw.winnerSurface, options.baselineSurface);
|
|
599
|
+
assertMeasuredIdentity(result.gateDecision, result.raw.gateResult.decision, "raw decision");
|
|
600
|
+
assertMeasuredIdentity(
|
|
601
|
+
candidateContentHash,
|
|
602
|
+
surfaceContentHash(result.raw.winnerSurface),
|
|
603
|
+
"raw winner surface"
|
|
604
|
+
);
|
|
605
|
+
assertMeasuredIdentity(result.diff, canonicalDiff, "surface diff");
|
|
606
|
+
assertMeasuredIdentity(result.raw.promotedDiff, canonicalDiff, "raw surface diff");
|
|
607
|
+
if (result.gateDecision === "ship" && (baselineContentHash === candidateContentHash || result.diff.trim().length === 0)) {
|
|
608
|
+
throw new Error("a shipped improvement requires a changed surface and non-empty diff");
|
|
609
|
+
}
|
|
610
|
+
assertMeasuredIdentity(
|
|
611
|
+
canonicalDigest(power),
|
|
612
|
+
canonicalDigest(
|
|
613
|
+
powerPreflight({
|
|
614
|
+
baselineComposites: pairs.map(([cell]) => measuredComposite(cell)),
|
|
615
|
+
sharedScorerChannel: true
|
|
616
|
+
})
|
|
617
|
+
),
|
|
618
|
+
"power analysis"
|
|
619
|
+
);
|
|
620
|
+
assertMeasuredNumber(power.n, composite.n, "power sample size");
|
|
621
|
+
assertMeasuredNumber(power.confidence, 0.95, "power confidence");
|
|
622
|
+
assertCompleteMeasuredCampaign(
|
|
623
|
+
result.raw.baselineCampaign,
|
|
624
|
+
"search baseline",
|
|
625
|
+
receiptsById,
|
|
626
|
+
receiptIdsByCell
|
|
627
|
+
);
|
|
628
|
+
assertGenerationMeasurements(result.raw.generations, receiptsById, receiptIdsByCell);
|
|
629
|
+
if (result.raw.neutralizedOnHoldout === void 0 !== (result.raw.neutralizedSurface === void 0)) {
|
|
630
|
+
throw new Error("neutralized surface and campaign must be supplied together");
|
|
631
|
+
}
|
|
632
|
+
if (result.raw.neutralizedOnHoldout) {
|
|
633
|
+
assertCompleteMeasuredCampaign(
|
|
634
|
+
result.raw.neutralizedOnHoldout,
|
|
635
|
+
"heldout neutralized",
|
|
636
|
+
receiptsById,
|
|
637
|
+
receiptIdsByCell
|
|
638
|
+
);
|
|
639
|
+
pairMeasuredCells(result.raw.baselineOnHoldout.cells, result.raw.neutralizedOnHoldout.cells);
|
|
640
|
+
}
|
|
641
|
+
const rebuiltProvenance = buildLoopProvenanceRecord(
|
|
642
|
+
loopProvenanceArgsFromResult({
|
|
643
|
+
runId: result.provenance.runId,
|
|
644
|
+
runDir: result.provenance.runDir,
|
|
645
|
+
timestamp: result.provenance.timestamp,
|
|
646
|
+
baselineSurface: options.baselineSurface,
|
|
647
|
+
result: result.raw,
|
|
648
|
+
costReceipts: receipts,
|
|
649
|
+
totalCostUsd: result.totalCostUsd,
|
|
650
|
+
totalDurationMs: result.durationMs
|
|
651
|
+
})
|
|
652
|
+
);
|
|
653
|
+
assertMeasuredIdentity(
|
|
654
|
+
result.provenance.recordDigest,
|
|
655
|
+
rebuiltProvenance.recordDigest,
|
|
656
|
+
"provenance record"
|
|
657
|
+
);
|
|
658
|
+
assertMeasuredIdentity(
|
|
659
|
+
options.benchmark.splitDigest,
|
|
660
|
+
rebuiltProvenance.evidence.holdout.splitDigest,
|
|
661
|
+
"benchmark heldout split"
|
|
662
|
+
);
|
|
663
|
+
const generationsExplored = result.raw.generations.length;
|
|
664
|
+
assertMeasuredNumber(result.generationsExplored, generationsExplored, "generation count");
|
|
665
|
+
assertMeasuredNumber(result.totalCostUsd, result.cost.totalCostUsd, "cost summary");
|
|
666
|
+
assertMeasuredIdentity(
|
|
667
|
+
canonicalDigest(result.cost),
|
|
668
|
+
canonicalDigest(result.raw.cost),
|
|
669
|
+
"raw cost summary"
|
|
670
|
+
);
|
|
671
|
+
if (!result.cost.accountingComplete) {
|
|
672
|
+
throw new Error(
|
|
673
|
+
`cost accounting is incomplete: ${result.cost.incompleteReasons.join("; ") || "unknown reason"}`
|
|
674
|
+
);
|
|
675
|
+
}
|
|
676
|
+
if (!receiptCost.accountingComplete) {
|
|
677
|
+
throw new Error(
|
|
678
|
+
`cost accounting is incomplete: ${receiptCost.incompleteReasons.join("; ") || "unknown reason"}`
|
|
679
|
+
);
|
|
575
680
|
}
|
|
681
|
+
assertMeasuredIdentity(
|
|
682
|
+
canonicalDigest(result.cost),
|
|
683
|
+
canonicalDigest(receiptCost),
|
|
684
|
+
"cost receipt summary"
|
|
685
|
+
);
|
|
686
|
+
assertMeasuredNumber(result.totalCostUsd, receiptCost.totalCostUsd, "cost receipts");
|
|
687
|
+
assertMeasuredOptional(result.winner.label, result.raw.winnerLabel, "raw winner label");
|
|
688
|
+
assertMeasuredOptional(
|
|
689
|
+
result.winner.rationale,
|
|
690
|
+
result.raw.winnerRationale,
|
|
691
|
+
"raw winner rationale"
|
|
692
|
+
);
|
|
576
693
|
return agentImprovementMeasuredComparisonSchema.parse({
|
|
577
694
|
schemaVersion: 1,
|
|
578
695
|
kind: "agent-improvement-measured-comparison",
|
|
@@ -598,8 +715,8 @@ function measuredComparisonFromSelfImproveResult(options) {
|
|
|
598
715
|
} : {},
|
|
599
716
|
decision: {
|
|
600
717
|
outcome: result.gateDecision,
|
|
601
|
-
reasons:
|
|
602
|
-
contributingChecks:
|
|
718
|
+
reasons: rebuiltProvenance.gate.reasons,
|
|
719
|
+
contributingChecks: rebuiltProvenance.gate.contributingGates.map((check) => ({
|
|
603
720
|
name: check.name,
|
|
604
721
|
passed: check.passed
|
|
605
722
|
}))
|
|
@@ -615,20 +732,98 @@ function measuredComparisonFromSelfImproveResult(options) {
|
|
|
615
732
|
},
|
|
616
733
|
provenance: {
|
|
617
734
|
kind: "agent-eval-loop",
|
|
618
|
-
schema:
|
|
619
|
-
runId:
|
|
620
|
-
recordDigest:
|
|
621
|
-
baselineContentHash
|
|
622
|
-
candidateContentHash
|
|
735
|
+
schema: rebuiltProvenance.schema,
|
|
736
|
+
runId: rebuiltProvenance.runId,
|
|
737
|
+
recordDigest: rebuiltProvenance.recordDigest,
|
|
738
|
+
baselineContentHash,
|
|
739
|
+
candidateContentHash
|
|
623
740
|
},
|
|
624
|
-
diff:
|
|
741
|
+
diff: canonicalDiff,
|
|
625
742
|
evaluation: {
|
|
626
|
-
generationsExplored
|
|
743
|
+
generationsExplored,
|
|
627
744
|
durationMs: result.durationMs,
|
|
628
745
|
totalCostUsd: result.totalCostUsd
|
|
629
746
|
}
|
|
630
747
|
});
|
|
631
748
|
}
|
|
749
|
+
function assertGenerationMeasurements(generations, receiptsById, receiptIdsByCell) {
|
|
750
|
+
for (const generation of generations) {
|
|
751
|
+
for (const measured of generation.surfaces) {
|
|
752
|
+
const candidate = generation.record.candidates.find(
|
|
753
|
+
(entry) => entry.surfaceHash === measured.surfaceHash
|
|
754
|
+
);
|
|
755
|
+
if (!candidate) {
|
|
756
|
+
throw new Error(
|
|
757
|
+
`generation ${generation.record.generationIndex} is missing candidate ${measured.surfaceHash}`
|
|
758
|
+
);
|
|
759
|
+
}
|
|
760
|
+
const composite = campaignMeanComposite(measured.campaign);
|
|
761
|
+
const breakdown = campaignBreakdown(measured.campaign);
|
|
762
|
+
const coverage = campaignCoverage(
|
|
763
|
+
measured.campaign.cells,
|
|
764
|
+
measured.campaign.scenarios,
|
|
765
|
+
measured.campaign.reps,
|
|
766
|
+
true
|
|
767
|
+
);
|
|
768
|
+
assertScorableMeasuredCells(
|
|
769
|
+
measured.campaign,
|
|
770
|
+
coverage.scorableCellIds,
|
|
771
|
+
receiptsById,
|
|
772
|
+
receiptIdsByCell
|
|
773
|
+
);
|
|
774
|
+
assertMeasuredNumber(
|
|
775
|
+
candidate.composite,
|
|
776
|
+
composite,
|
|
777
|
+
`candidate ${measured.surfaceHash} composite`
|
|
778
|
+
);
|
|
779
|
+
if (!candidate.coverage) {
|
|
780
|
+
throw new Error(`candidate ${measured.surfaceHash} does not report campaign coverage`);
|
|
781
|
+
}
|
|
782
|
+
assertMeasuredIdentity(
|
|
783
|
+
canonicalDigest(candidate.coverage),
|
|
784
|
+
canonicalDigest({
|
|
785
|
+
expectedCells: coverage.expectedCellIds.length,
|
|
786
|
+
scorableCells: coverage.scorableCellIds.length,
|
|
787
|
+
unscorableCells: coverage.unscorableCells
|
|
788
|
+
}),
|
|
789
|
+
`candidate ${measured.surfaceHash} coverage`
|
|
790
|
+
);
|
|
791
|
+
assertMeasuredIdentity(
|
|
792
|
+
String(candidate.eligibleForPromotion),
|
|
793
|
+
String(coverage.complete),
|
|
794
|
+
`candidate ${measured.surfaceHash} eligibility`
|
|
795
|
+
);
|
|
796
|
+
assertMeasuredIdentity(
|
|
797
|
+
canonicalDigest(candidate.dimensions),
|
|
798
|
+
canonicalDigest(breakdown.dimensions),
|
|
799
|
+
`candidate ${measured.surfaceHash} dimensions`
|
|
800
|
+
);
|
|
801
|
+
assertMeasuredIdentity(
|
|
802
|
+
canonicalDigest(candidate.scenarios),
|
|
803
|
+
canonicalDigest(breakdown.scenarios),
|
|
804
|
+
`candidate ${measured.surfaceHash} scenarios`
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
function assertCompleteMeasuredCampaign(campaign, name, receiptsById, receiptIdsByCell) {
|
|
810
|
+
assertCampaignSplitIdentity(campaign.scenarios, campaign.reps, campaign.splitDigest);
|
|
811
|
+
const coverage = campaignCoverage(campaign.cells, campaign.scenarios, campaign.reps, true);
|
|
812
|
+
if (!coverage.complete) {
|
|
813
|
+
throw new Error(
|
|
814
|
+
`${name} is incomplete (${coverage.scorableCellIds.length}/${coverage.expectedCellIds.length} designed cells scorable)`
|
|
815
|
+
);
|
|
816
|
+
}
|
|
817
|
+
assertScorableMeasuredCells(campaign, coverage.scorableCellIds, receiptsById, receiptIdsByCell);
|
|
818
|
+
}
|
|
819
|
+
function assertScorableMeasuredCells(campaign, scorableCellIds, receiptsById, receiptIdsByCell) {
|
|
820
|
+
const cellsById = new Map(campaign.cells.map((cell) => [cell.cellId, cell]));
|
|
821
|
+
for (const cellId of scorableCellIds) {
|
|
822
|
+
const cell = cellsById.get(cellId);
|
|
823
|
+
if (!cell) throw new Error(`measured campaign is missing scorable cell ${cellId}`);
|
|
824
|
+
assertMeasuredCell(cell, receiptsById, receiptIdsByCell, campaign.runDir);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
632
827
|
function measuredObjectives(pairs) {
|
|
633
828
|
const qualityColumns = /* @__PURE__ */ new Map();
|
|
634
829
|
for (const [baseline, candidate] of pairs) {
|
|
@@ -673,19 +868,6 @@ function measuredObjectives(pairs) {
|
|
|
673
868
|
function measuredCostObjective(pairs) {
|
|
674
869
|
const cells = pairs.flat();
|
|
675
870
|
for (const cell of cells) finiteMeasuredValue(cell.costUsd, "cost:cost");
|
|
676
|
-
const reported = cells.some(
|
|
677
|
-
(cell) => cell.costUsd !== 0 || cell.tokenUsage !== void 0 && (cell.tokenUsage.input > 0 || cell.tokenUsage.output > 0)
|
|
678
|
-
);
|
|
679
|
-
if (!reported) {
|
|
680
|
-
return {
|
|
681
|
-
kind: "cost",
|
|
682
|
-
name: "cost",
|
|
683
|
-
availability: "unavailable",
|
|
684
|
-
reason: "heldout cells did not report model usage or cost",
|
|
685
|
-
direction: "lower-is-better",
|
|
686
|
-
unit: "usd"
|
|
687
|
-
};
|
|
688
|
-
}
|
|
689
871
|
return measuredObjective(
|
|
690
872
|
{
|
|
691
873
|
kind: "cost",
|
|
@@ -705,7 +887,8 @@ function measuredComposite(cell) {
|
|
|
705
887
|
return measuredMean(values);
|
|
706
888
|
}
|
|
707
889
|
function pairMeasuredCells(baselineCells, candidateCells) {
|
|
708
|
-
const
|
|
890
|
+
const cells = [...baselineCells, ...candidateCells];
|
|
891
|
+
const errors = cells.filter((cell) => cell.error);
|
|
709
892
|
if (errors.length > 0) {
|
|
710
893
|
throw new Error(
|
|
711
894
|
`measured objectives cannot publish ${errors.length} errored heldout cells: ${errors.map((cell) => measuredCellKey(cell)).join(", ")}`
|
|
@@ -729,9 +912,88 @@ function pairMeasuredCells(baselineCells, candidateCells) {
|
|
|
729
912
|
if (paired.pairs.length === 0 || paired.unpairedBaseline.length > 0 || paired.unpairedTreatment.length > 0) {
|
|
730
913
|
throw new Error("measured objectives require the same non-empty paired heldout cells");
|
|
731
914
|
}
|
|
732
|
-
return paired.pairs.map(
|
|
733
|
-
|
|
915
|
+
return paired.pairs.map((pair) => {
|
|
916
|
+
const baseline = pair.baseline.cell;
|
|
917
|
+
const candidate = pair.treatment.cell;
|
|
918
|
+
if (baseline.seed !== candidate.seed) {
|
|
919
|
+
throw new Error(`heldout cell ${baseline.cellId} does not share one paired seed`);
|
|
920
|
+
}
|
|
921
|
+
return [baseline, candidate];
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
function assertMeasuredCell(cell, receiptsById, receiptIdsByCell, runDir) {
|
|
925
|
+
if (!cell.scenarioId.trim() || !Number.isSafeInteger(cell.rep) || cell.rep < 0 || !Number.isSafeInteger(cell.seed) || cell.cellId !== measuredCellKey(cell)) {
|
|
926
|
+
throw new Error(`heldout cell '${cell.cellId}' has an invalid scenario/rep identity`);
|
|
927
|
+
}
|
|
928
|
+
nonnegativeMeasuredValue(cell.costUsd, `heldout cell ${cell.cellId} cost`);
|
|
929
|
+
nonnegativeMeasuredValue(cell.durationMs, `heldout cell ${cell.cellId} latency`);
|
|
930
|
+
if (!cell.tokenUsage) {
|
|
931
|
+
throw new Error(`heldout cell ${cell.cellId} does not report token usage`);
|
|
932
|
+
}
|
|
933
|
+
nonnegativeMeasuredInteger(cell.tokenUsage.input, `heldout cell ${cell.cellId} input tokens`);
|
|
934
|
+
nonnegativeMeasuredInteger(cell.tokenUsage.output, `heldout cell ${cell.cellId} output tokens`);
|
|
935
|
+
if (cell.tokenUsage.cached !== void 0) {
|
|
936
|
+
nonnegativeMeasuredInteger(cell.tokenUsage.cached, `heldout cell ${cell.cellId} cached tokens`);
|
|
937
|
+
}
|
|
938
|
+
if (!Array.isArray(cell.costCallIds)) {
|
|
939
|
+
throw new Error(`heldout cell ${cell.cellId} does not identify its cost receipts`);
|
|
940
|
+
}
|
|
941
|
+
if (new Set(cell.costCallIds).size !== cell.costCallIds.length) {
|
|
942
|
+
throw new Error(`heldout cell ${cell.cellId} repeats a cost receipt`);
|
|
943
|
+
}
|
|
944
|
+
const linkedReceipts = cell.costCallIds.map((callId) => {
|
|
945
|
+
const receipt = receiptsById.get(callId);
|
|
946
|
+
if (!receipt)
|
|
947
|
+
throw new Error(`heldout cell ${cell.cellId} references missing cost receipt ${callId}`);
|
|
948
|
+
if (receipt.tags?.runDir !== runDir || receipt.tags.cellId !== cell.cellId || receipt.tags.scenarioId !== cell.scenarioId || receipt.tags.rep !== String(cell.rep)) {
|
|
949
|
+
throw new Error(`heldout cell ${cell.cellId} references a cost receipt from another cell`);
|
|
950
|
+
}
|
|
951
|
+
return receipt;
|
|
952
|
+
});
|
|
953
|
+
assertMeasuredIdentity(
|
|
954
|
+
canonicalDigest([...cell.costCallIds].sort()),
|
|
955
|
+
canonicalDigest(
|
|
956
|
+
[
|
|
957
|
+
...receiptIdsByCell.get(receiptCellKey(runDir, cell.cellId, cell.scenarioId, cell.rep)) ?? []
|
|
958
|
+
].sort()
|
|
959
|
+
),
|
|
960
|
+
`heldout cell ${cell.cellId} cost receipt IDs`
|
|
734
961
|
);
|
|
962
|
+
const agentReceipts = linkedReceipts.filter((receipt) => receipt.channel === "agent");
|
|
963
|
+
if (agentReceipts.some((receipt) => receipt.error)) {
|
|
964
|
+
throw new Error(`measured cell ${cell.cellId} links a failed agent receipt`);
|
|
965
|
+
}
|
|
966
|
+
assertRealAgentReceipts(agentReceipts, { allowMixed: false });
|
|
967
|
+
assertMeasuredNumber(
|
|
968
|
+
cell.costUsd,
|
|
969
|
+
agentReceipts.reduce((total, receipt) => total + receipt.costUsd, 0),
|
|
970
|
+
`heldout cell ${cell.cellId} cost receipts`
|
|
971
|
+
);
|
|
972
|
+
assertMeasuredNumber(
|
|
973
|
+
cell.tokenUsage.input,
|
|
974
|
+
agentReceipts.reduce((total, receipt) => total + receipt.inputTokens, 0),
|
|
975
|
+
`heldout cell ${cell.cellId} input receipts`
|
|
976
|
+
);
|
|
977
|
+
assertMeasuredNumber(
|
|
978
|
+
cell.tokenUsage.output,
|
|
979
|
+
agentReceipts.reduce((total, receipt) => total + receipt.outputTokens, 0),
|
|
980
|
+
`heldout cell ${cell.cellId} output receipts`
|
|
981
|
+
);
|
|
982
|
+
assertMeasuredNumber(
|
|
983
|
+
cell.tokenUsage.cached ?? 0,
|
|
984
|
+
agentReceipts.reduce((total, receipt) => total + (receipt.cachedTokens ?? 0), 0),
|
|
985
|
+
`heldout cell ${cell.cellId} cached receipts`
|
|
986
|
+
);
|
|
987
|
+
for (const [judge, score] of Object.entries(cell.judgeScores)) {
|
|
988
|
+
if (score.failed) {
|
|
989
|
+
throw new Error(`heldout cell ${cell.cellId} contains failed judge '${judge}'`);
|
|
990
|
+
}
|
|
991
|
+
finiteMeasuredValue(score.composite, `objective:${judge}`);
|
|
992
|
+
for (const [dimension, value] of Object.entries(score.dimensions)) {
|
|
993
|
+
finiteMeasuredValue(value, `dimension:${judge}:${dimension}`);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
measuredComposite(cell);
|
|
735
997
|
}
|
|
736
998
|
function measuredObjective(identity, pairs, value) {
|
|
737
999
|
const key = measuredObjectiveKey(identity);
|
|
@@ -788,6 +1050,16 @@ function finiteMeasuredValue(value, name) {
|
|
|
788
1050
|
if (!Number.isFinite(value)) throw new Error(`measured objective '${name}' is not finite`);
|
|
789
1051
|
return value;
|
|
790
1052
|
}
|
|
1053
|
+
function nonnegativeMeasuredValue(value, name) {
|
|
1054
|
+
if (!Number.isFinite(value) || value < 0) throw new Error(`${name} must be non-negative`);
|
|
1055
|
+
return value;
|
|
1056
|
+
}
|
|
1057
|
+
function nonnegativeMeasuredInteger(value, name) {
|
|
1058
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
1059
|
+
throw new Error(`${name} must be a non-negative safe integer`);
|
|
1060
|
+
}
|
|
1061
|
+
return value;
|
|
1062
|
+
}
|
|
791
1063
|
function measuredMean(values) {
|
|
792
1064
|
if (values.length === 0) throw new Error("measured objective has no paired values");
|
|
793
1065
|
return values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
@@ -805,10 +1077,26 @@ function assertMeasuredNumber(actual, expected, name) {
|
|
|
805
1077
|
throw new Error(`${name} does not agree across the measured comparison`);
|
|
806
1078
|
}
|
|
807
1079
|
}
|
|
808
|
-
function
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
1080
|
+
function assertMeasuredIdentity(actual, expected, name) {
|
|
1081
|
+
if (actual !== expected) throw new Error(`${name} does not agree across the measured comparison`);
|
|
1082
|
+
}
|
|
1083
|
+
function assertMeasuredOptional(actual, expected, name) {
|
|
1084
|
+
if (actual !== expected) throw new Error(`${name} does not agree across the measured comparison`);
|
|
1085
|
+
}
|
|
1086
|
+
function indexReceiptIdsByCell(receipts) {
|
|
1087
|
+
const idsByCell = /* @__PURE__ */ new Map();
|
|
1088
|
+
for (const receipt of receipts) {
|
|
1089
|
+
const tags = receipt.tags;
|
|
1090
|
+
if (!tags?.runDir || !tags.cellId || !tags.scenarioId || tags.rep === void 0) continue;
|
|
1091
|
+
const key = receiptCellKey(tags.runDir, tags.cellId, tags.scenarioId, tags.rep);
|
|
1092
|
+
const ids = idsByCell.get(key) ?? [];
|
|
1093
|
+
ids.push(receipt.callId);
|
|
1094
|
+
idsByCell.set(key, ids);
|
|
1095
|
+
}
|
|
1096
|
+
return idsByCell;
|
|
1097
|
+
}
|
|
1098
|
+
function receiptCellKey(runDir, cellId, scenarioId, rep) {
|
|
1099
|
+
return JSON.stringify([runDir, cellId, scenarioId, String(rep)]);
|
|
812
1100
|
}
|
|
813
1101
|
|
|
814
1102
|
// src/contract/eval-reporting-suite.ts
|
|
@@ -1326,6 +1614,7 @@ export {
|
|
|
1326
1614
|
analyzeRuns,
|
|
1327
1615
|
buildDefaultAnalystRegistry,
|
|
1328
1616
|
buildEvidenceVector,
|
|
1617
|
+
campaignSplitDigest,
|
|
1329
1618
|
composeGate,
|
|
1330
1619
|
createChatClient,
|
|
1331
1620
|
createReferenceEquivalenceJudge,
|