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