@tangle-network/agent-eval 0.184.0 → 0.185.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 +12 -0
- package/dist/adapters/http.d.ts +1 -1
- package/dist/analyst/index.d.ts +6 -331
- package/dist/analyst/index.d.ts.map +1 -1
- package/dist/analyst/index.js +7 -6
- package/dist/analyst/index.js.map +1 -1
- package/dist/analyze-runs-CrYhqXop.d.ts +75 -0
- package/dist/analyze-runs-CrYhqXop.d.ts.map +1 -0
- package/dist/{define-agent-eval-RTekxhUE.js → analyze-runs-sTygaDyD.js} +4 -811
- package/dist/analyze-runs-sTygaDyD.js.map +1 -0
- package/dist/{benchmark-command-DlSePljH.js → benchmark-command-kvq7yFY4.js} +9 -47
- package/dist/benchmark-command-kvq7yFY4.js.map +1 -0
- package/dist/benchmarks/index.js +2 -2
- package/dist/campaign/index.js +7 -6
- package/dist/{campaign-D6puiGFO.js → campaign-eJgtRs-W.js} +8 -7
- package/dist/{campaign-D6puiGFO.js.map → campaign-eJgtRs-W.js.map} +1 -1
- package/dist/{campaign-evidence-aWEmfROB.js → campaign-evidence-BsrCmBSE.js} +4 -255
- package/dist/campaign-evidence-BsrCmBSE.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/contract/index.d.ts +3 -3
- package/dist/contract/index.js +10 -279
- package/dist/contract/index.js.map +1 -1
- package/dist/{default-registry-DYB4aHVn.d.ts → default-registry-CXv9kHMt.d.ts} +3 -3
- package/dist/{default-registry-DYB4aHVn.d.ts.map → default-registry-CXv9kHMt.d.ts.map} +1 -1
- package/dist/{default-registry-CpLko4jB.js → default-registry-xiHrldW8.js} +3 -2
- package/dist/{default-registry-CpLko4jB.js.map → default-registry-xiHrldW8.js.map} +1 -1
- package/dist/define-agent-eval-D4uumjl3.js +813 -0
- package/dist/define-agent-eval-D4uumjl3.js.map +1 -0
- package/dist/diagnosis/index.d.ts +319 -0
- package/dist/diagnosis/index.d.ts.map +1 -0
- package/dist/diagnosis/index.js +1328 -0
- package/dist/diagnosis/index.js.map +1 -0
- package/dist/{dspy-rlm-engine-Da-l3CpD.js → dspy-rlm-engine-BE9lCzzL.js} +2 -2
- package/dist/{dspy-rlm-engine-Da-l3CpD.js.map → dspy-rlm-engine-BE9lCzzL.js.map} +1 -1
- package/dist/{engine-D1ykrAKR.d.ts → engine-cXUK-WHS.d.ts} +3 -75
- package/dist/engine-cXUK-WHS.d.ts.map +1 -0
- package/dist/equal-terms-Blx9Zk5I.js +25 -0
- package/dist/equal-terms-Blx9Zk5I.js.map +1 -0
- package/dist/experiment/index.js +4 -3
- package/dist/experiment/index.js.map +1 -1
- package/dist/{index-58wex7KV.d.ts → index-BQWfAFeH.d.ts} +3 -3
- package/dist/{index-58wex7KV.d.ts.map → index-BQWfAFeH.d.ts.map} +1 -1
- package/dist/{index-DVrtLO5j.d.ts → index-C8_iU8KL.d.ts} +3 -3
- package/dist/{index-DVrtLO5j.d.ts.map → index-C8_iU8KL.d.ts.map} +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -11
- package/dist/index.js.map +1 -1
- package/dist/{kind-factory-DE088Zhv.js → kind-factory-V79Hw0AU.js} +4 -82
- package/dist/kind-factory-V79Hw0AU.js.map +1 -0
- package/dist/{llm-judge-C5wbADA5.js → llm-judge-FWWhEb31.js} +5 -3
- package/dist/{llm-judge-C5wbADA5.js.map → llm-judge-FWWhEb31.js.map} +1 -1
- package/dist/openapi.json +1 -1
- package/dist/otel-spans-CQY1pNiN.js +275 -0
- package/dist/otel-spans-CQY1pNiN.js.map +1 -0
- package/dist/otlp-attributes-BpC_blLF.js +83 -0
- package/dist/otlp-attributes-BpC_blLF.js.map +1 -0
- package/dist/{run-record-BhMVsHR1.js → paired-promotion-decision-ClJh_9nK.js} +2 -215
- package/dist/paired-promotion-decision-ClJh_9nK.js.map +1 -0
- package/dist/prime-bridge-transport-Z3cpKGoV.js +43 -0
- package/dist/prime-bridge-transport-Z3cpKGoV.js.map +1 -0
- package/dist/prime-protocol-CDBcL9NM.d.ts +331 -0
- package/dist/prime-protocol-CDBcL9NM.d.ts.map +1 -0
- package/dist/{prime-protocol-6tZTVsWm.js → prime-protocol-DcAK9pC8.js} +2 -23
- package/dist/prime-protocol-DcAK9pC8.js.map +1 -0
- package/dist/{produced-state-D3uWsY8t.js → produced-state-CmB02tr2.js} +3 -3
- package/dist/{produced-state-D3uWsY8t.js.map → produced-state-CmB02tr2.js.map} +1 -1
- package/dist/{promotion-policy-CD-bUeyR.js → promotion-policy-DdrYWHDh.js} +3 -3
- package/dist/{promotion-policy-CD-bUeyR.js.map → promotion-policy-DdrYWHDh.js.map} +1 -1
- package/dist/rl.js +2 -1
- package/dist/rl.js.map +1 -1
- package/dist/run-record-CNNzWGpB.js +216 -0
- package/dist/run-record-CNNzWGpB.js.map +1 -0
- package/dist/{semantic-concept-judge-5r9hDEBA.js → semantic-concept-judge-Cnt0TWp0.js} +3 -3
- package/dist/{semantic-concept-judge-5r9hDEBA.js.map → semantic-concept-judge-Cnt0TWp0.js.map} +1 -1
- package/dist/{sequential-BfDkCBGo.js → sequential-PgLEqcTJ.js} +2 -2
- package/dist/{sequential-BfDkCBGo.js.map → sequential-PgLEqcTJ.js.map} +1 -1
- package/dist/{skillopt-optimization-method-B2zxoDk0.js → skillopt-optimization-method-FSk8b5FQ.js} +4 -3
- package/dist/{skillopt-optimization-method-B2zxoDk0.js.map → skillopt-optimization-method-FSk8b5FQ.js.map} +1 -1
- package/dist/statistical-heldout-CeWT_W7y.js +256 -0
- package/dist/statistical-heldout-CeWT_W7y.js.map +1 -0
- package/dist/{store-otlp-rU5PFlOB.js → store-otlp-2gYCy-v0.js} +2 -2
- package/dist/{store-otlp-rU5PFlOB.js.map → store-otlp-2gYCy-v0.js.map} +1 -1
- package/dist/{store-tool-spans-zrtftcRe.js → store-tool-spans-B1e6Auc2.js} +4 -3
- package/dist/{store-tool-spans-zrtftcRe.js.map → store-tool-spans-B1e6Auc2.js.map} +1 -1
- package/dist/{store-tool-spans-DwdokbHg.d.ts → store-tool-spans-BrdfPaVh.d.ts} +3 -3
- package/dist/{store-tool-spans-DwdokbHg.d.ts.map → store-tool-spans-BrdfPaVh.d.ts.map} +1 -1
- package/dist/{task-failure-attributes-BOxjfbhr.js → task-failure-attributes-B34TiMBe.js} +2 -2
- package/dist/{task-failure-attributes-BOxjfbhr.js.map → task-failure-attributes-B34TiMBe.js.map} +1 -1
- package/dist/{tool-groups-qHMydbAH.d.ts → tool-groups-eOOgYGaM.d.ts} +2 -2
- package/dist/tool-groups-eOOgYGaM.d.ts.map +1 -0
- package/dist/trace-repair/index.d.ts +1 -1
- package/dist/trace-repair/index.js +2 -1
- package/dist/trace-repair/index.js.map +1 -1
- package/dist/traces.d.ts +2 -2
- package/dist/traces.js +5 -4
- package/dist/traces.js.map +1 -1
- package/docs/diagnosis.md +42 -0
- package/package.json +7 -1
- package/dist/benchmark-command-DlSePljH.js.map +0 -1
- package/dist/campaign-evidence-aWEmfROB.js.map +0 -1
- package/dist/define-agent-eval-RTekxhUE.js.map +0 -1
- package/dist/engine-D1ykrAKR.d.ts.map +0 -1
- package/dist/kind-factory-DE088Zhv.js.map +0 -1
- package/dist/prime-protocol-6tZTVsWm.js.map +0 -1
- package/dist/run-record-BhMVsHR1.js.map +0 -1
- package/dist/tool-groups-qHMydbAH.d.ts.map +0 -1
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { s as ValidationError } from "./errors-Dngq5h35.js";
|
|
2
1
|
import { a as spearmanR, r as pearsonR } from "./descriptive-1V17A-qa.js";
|
|
3
2
|
import { r as continuousAgreement } from "./judge-calibration-DYmaBtJr.js";
|
|
4
3
|
import { i as pairedCohensDz } from "./effect-sizes-DiH8MGOH.js";
|
|
@@ -6,15 +5,11 @@ import { i as requiredPairedSampleSize, r as pairedMde } from "./power-and-mde-B
|
|
|
6
5
|
import { r as pairRunRecords } from "./paired-arms-JSDcs2zx.js";
|
|
7
6
|
import { o as pairedTTest, r as pairedBootstrap } from "./paired-tests-C8iCsioC.js";
|
|
8
7
|
import { r as welchsTTest } from "./baseline-BC-eBZ7U.js";
|
|
9
|
-
import {
|
|
10
|
-
import { B as surfaceDispatchRef, N as defineEvaluationClaim, T as pairedCampaignComposites, V as surfaceHash, Z as campaignSplitDigest, f as campaignMeasurementDigest, h as loopProvenanceArgsFromResult, k as powerPreflight, m as emitLoopProvenance, p as canonicalDigest, t as createCampaignEvidenceReceipt, tt as aggregatePairedHoldout, z as surfaceContentHash } from "./campaign-evidence-aWEmfROB.js";
|
|
8
|
+
import { n as aggregatePairedHoldout } from "./statistical-heldout-CeWT_W7y.js";
|
|
11
9
|
import "./query-DlV0pdx4.js";
|
|
12
10
|
import { r as observedSplitScore } from "./reward-nw2xZGZG.js";
|
|
13
|
-
import { c as validateRunRecord
|
|
11
|
+
import { c as validateRunRecord } from "./run-record-tg_5H2IK.js";
|
|
14
12
|
import { r as paretoChart } from "./summary-report-BMvou2oZ.js";
|
|
15
|
-
import { C as assertSearchHistoryAdmissionOptions, G as assertIndependentEvaluationSplit, I as runFinalComparison, J as reserveFinalEvidence, K as captureFinalEvidencePolicy, L as openAutoPr, Q as resolveRunDir, R as captureJudge, Y as runEval, d as combineComparisonCosts, f as costFromLedgerSummary, h as runImprovementLoop, q as evaluationUnitMap, u as executeOptimizationMethod, z as defaultProductionGate } from "./llm-judge-C5wbADA5.js";
|
|
16
|
-
import { C as inMemoryCampaignStorage, S as fsCampaignStorage, x as createRunCostLedger } from "./external-optimizer-subprocess-DMgmqTB6.js";
|
|
17
|
-
import { t as createHostedClient } from "./client-CXE-U1SA.js";
|
|
18
13
|
//#region src/contamination-guard.ts
|
|
19
14
|
function checkCanaries(output, scenarios) {
|
|
20
15
|
const leaks = [];
|
|
@@ -977,808 +972,6 @@ function buildRecommendations(ctx) {
|
|
|
977
972
|
return out;
|
|
978
973
|
}
|
|
979
974
|
//#endregion
|
|
980
|
-
|
|
981
|
-
function pairedCompositeSummary(baseline, winner, independentUnitByScenarioId) {
|
|
982
|
-
const scores = pairedCampaignComposites(baseline, winner, independentUnitByScenarioId);
|
|
983
|
-
const perScenario = (campaign) => Object.fromEntries(Object.entries(campaign.aggregates.byScenario).map(([id, aggregate]) => [id, aggregate.meanComposite]));
|
|
984
|
-
return {
|
|
985
|
-
baseline: {
|
|
986
|
-
compositeMean: scores.beforeMean,
|
|
987
|
-
perScenario: perScenario(baseline)
|
|
988
|
-
},
|
|
989
|
-
winner: {
|
|
990
|
-
compositeMean: scores.afterMean,
|
|
991
|
-
perScenario: perScenario(winner)
|
|
992
|
-
},
|
|
993
|
-
baselineComposites: scores.before,
|
|
994
|
-
observations: scores.observations
|
|
995
|
-
};
|
|
996
|
-
}
|
|
997
|
-
/** 32-bit FNV-1a over raw UTF-16 code units, rendered as hex for a cell key.
|
|
998
|
-
*
|
|
999
|
-
* Frozen: the key names a persisted cell, so a change orphans every cell
|
|
1000
|
-
* already written. This is a cell-key function, not a general-purpose hash. */
|
|
1001
|
-
function hashString(s) {
|
|
1002
|
-
let h = 2166136261;
|
|
1003
|
-
for (let i = 0; i < s.length; i++) {
|
|
1004
|
-
h ^= s.charCodeAt(i);
|
|
1005
|
-
h = Math.imul(h, 16777619) >>> 0;
|
|
1006
|
-
}
|
|
1007
|
-
return h.toString(16).padStart(8, "0");
|
|
1008
|
-
}
|
|
1009
|
-
/**
|
|
1010
|
-
* Adapt campaign cells into the `RunRecord` shape `analyzeRuns()` consumes.
|
|
1011
|
-
* Each cell becomes one run; `candidateId` is the caller-supplied label so
|
|
1012
|
-
* baseline + winner pair cleanly on `(experimentId, scenarioId, seed)`.
|
|
1013
|
-
*
|
|
1014
|
-
* `promptHash` identifies the executed surface; `configHash` identifies the candidate label.
|
|
1015
|
-
*/
|
|
1016
|
-
function cellsToRunRecords(cells, candidateId, runId, surface, splitTag, fallbackModel) {
|
|
1017
|
-
const promptHash = surfaceContentHash(surface);
|
|
1018
|
-
const configHash = surfaceContentHash(candidateId);
|
|
1019
|
-
return cells.map((cell) => {
|
|
1020
|
-
const receiptModels = cell.resolvedModels ?? (cell.resolvedModel ? [cell.resolvedModel] : []);
|
|
1021
|
-
if (receiptModels.length > 1) throw new ValidationError(`selfImprove cell ${cell.cellId} used multiple agent models: ${receiptModels.join(", ")}`);
|
|
1022
|
-
const model = receiptModels[0] ?? fallbackModel;
|
|
1023
|
-
if (!model) throw new ValidationError(`selfImprove.model is required when cell ${cell.cellId} has no paid-call model receipt`);
|
|
1024
|
-
if (!modelHasSnapshot(model)) throw new ValidationError(`selfImprove model "${model}" lacks a snapshot version for cell ${cell.cellId}`);
|
|
1025
|
-
return campaignCellToRunRecord(cell, {
|
|
1026
|
-
runId: `${runId}::${candidateId}::${cell.cellId}`,
|
|
1027
|
-
experimentId: runId,
|
|
1028
|
-
candidateId,
|
|
1029
|
-
seed: cell.rep * 1e6 + hashString(cell.scenarioId).slice(0, 6).split("").reduce((a, c) => a * 31 + c.charCodeAt(0) >>> 0, 0),
|
|
1030
|
-
model,
|
|
1031
|
-
promptHash,
|
|
1032
|
-
configHash,
|
|
1033
|
-
commitSha: "cell",
|
|
1034
|
-
splitTag
|
|
1035
|
-
});
|
|
1036
|
-
});
|
|
1037
|
-
}
|
|
1038
|
-
//#endregion
|
|
1039
|
-
//#region src/contract/self-improve-method.ts
|
|
1040
|
-
/** Complete methods own search and selection; this path only measures their final choice. */
|
|
1041
|
-
async function runSelfImproveMethod(args) {
|
|
1042
|
-
const { opts, train, selection, holdout, costLedger, storage, runDir, startedAt } = args;
|
|
1043
|
-
const budget = opts.budget ?? {};
|
|
1044
|
-
if (opts.autoOnPromote === "pr" && (!opts.ghOwner || !opts.ghRepo)) throw new Error("selfImprove: autoOnPromote='pr' requires ghOwner + ghRepo");
|
|
1045
|
-
const evidenceContext = opts.evidence === void 0 ? void 0 : structuredClone(opts.evidence);
|
|
1046
|
-
if (evidenceContext && budget.holdout === "deferred") throw new Error("selfImprove: evidence receipts require measured holdout");
|
|
1047
|
-
const baselineSurface = structuredClone(opts.baselineSurface);
|
|
1048
|
-
const judge = opts.judge;
|
|
1049
|
-
const { selected, cost: methodCost, history } = await executeOptimizationMethod({
|
|
1050
|
-
method: opts.method,
|
|
1051
|
-
storage,
|
|
1052
|
-
searchHistoryPolicy: opts.searchHistoryPolicy,
|
|
1053
|
-
searchHistoryVerification: opts.searchHistoryVerification,
|
|
1054
|
-
input: {
|
|
1055
|
-
baselineSurface,
|
|
1056
|
-
trainScenarios: train,
|
|
1057
|
-
selectionScenarios: selection,
|
|
1058
|
-
dispatchWithSurface: opts.agent,
|
|
1059
|
-
judges: [judge],
|
|
1060
|
-
runDir: `${runDir}/optimization/${opts.method.name.replace(/[^a-zA-Z0-9._-]/g, "_")}`,
|
|
1061
|
-
seed: 42,
|
|
1062
|
-
runOptions: {
|
|
1063
|
-
storage,
|
|
1064
|
-
maxConcurrency: budget.maxConcurrency ?? 2,
|
|
1065
|
-
reps: budget.reps,
|
|
1066
|
-
dispatchRef: opts.dispatchRef,
|
|
1067
|
-
dispatchTimeoutMs: opts.dispatchTimeoutMs,
|
|
1068
|
-
cellRetry: opts.cellRetry,
|
|
1069
|
-
cellPlacement: opts.cellPlacement,
|
|
1070
|
-
labeledStore: opts.labeledStore,
|
|
1071
|
-
captureSource: opts.captureSource,
|
|
1072
|
-
expectUsage: opts.expectUsage ?? "assert"
|
|
1073
|
-
},
|
|
1074
|
-
costLedger
|
|
1075
|
-
}
|
|
1076
|
-
});
|
|
1077
|
-
const finalPhase = "selfImprove.method-final";
|
|
1078
|
-
const finalCost = () => combineComparisonCosts([
|
|
1079
|
-
"holdout.baseline",
|
|
1080
|
-
"holdout.winner",
|
|
1081
|
-
"holdout.neutralized",
|
|
1082
|
-
"promotion.gate"
|
|
1083
|
-
].map((phase) => ({
|
|
1084
|
-
label: phase,
|
|
1085
|
-
cost: costFromLedgerSummary(costLedger.summary({ phase: `${finalPhase}.${phase}` }))
|
|
1086
|
-
})));
|
|
1087
|
-
const totalCost = () => combineComparisonCosts([{
|
|
1088
|
-
label: opts.method.name,
|
|
1089
|
-
cost: methodCost
|
|
1090
|
-
}, {
|
|
1091
|
-
label: "final comparison",
|
|
1092
|
-
cost: finalCost()
|
|
1093
|
-
}]);
|
|
1094
|
-
const gate = opts.gate ?? defaultProductionGate({
|
|
1095
|
-
holdoutScenarios: holdout,
|
|
1096
|
-
deltaThreshold: opts.claim?.minimumEffect ?? .05,
|
|
1097
|
-
independentUnitByScenarioId: opts.claim ? evaluationUnitMap(opts.claim, holdout) : void 0
|
|
1098
|
-
});
|
|
1099
|
-
const comparison = await runFinalComparison({
|
|
1100
|
-
claim: opts.claim,
|
|
1101
|
-
finalEvidence: opts.finalEvidence,
|
|
1102
|
-
baselineSurface,
|
|
1103
|
-
winnerSurface: selected.winnerSurface,
|
|
1104
|
-
scenarios: holdout,
|
|
1105
|
-
dispatchWithSurface: opts.agent,
|
|
1106
|
-
dispatchRef: opts.dispatchRef,
|
|
1107
|
-
judges: [judge],
|
|
1108
|
-
holdout: budget.holdout,
|
|
1109
|
-
neutralize: opts.neutralize,
|
|
1110
|
-
gate: {
|
|
1111
|
-
...gate,
|
|
1112
|
-
async decide(context) {
|
|
1113
|
-
const cost = totalCost();
|
|
1114
|
-
if (budget.dollars !== void 0 && (!cost.accountingComplete || cost.totalCostUsd > budget.dollars)) return {
|
|
1115
|
-
decision: "hold",
|
|
1116
|
-
reasons: ["complete method spend cannot satisfy the declared run budget"],
|
|
1117
|
-
contributingGates: [{
|
|
1118
|
-
name: "budget",
|
|
1119
|
-
status: "fail",
|
|
1120
|
-
detail: {
|
|
1121
|
-
cost,
|
|
1122
|
-
budgetUsd: budget.dollars
|
|
1123
|
-
}
|
|
1124
|
-
}]
|
|
1125
|
-
};
|
|
1126
|
-
return gate.decide(context);
|
|
1127
|
-
}
|
|
1128
|
-
},
|
|
1129
|
-
runDir,
|
|
1130
|
-
storage,
|
|
1131
|
-
costLedger,
|
|
1132
|
-
costPhase: finalPhase,
|
|
1133
|
-
reps: budget.reps,
|
|
1134
|
-
maxConcurrency: budget.maxConcurrency ?? 2,
|
|
1135
|
-
dispatchTimeoutMs: opts.dispatchTimeoutMs,
|
|
1136
|
-
cellRetry: opts.cellRetry,
|
|
1137
|
-
cellPlacement: opts.cellPlacement,
|
|
1138
|
-
expectUsage: opts.expectUsage ?? "assert",
|
|
1139
|
-
label: "selfImprove"
|
|
1140
|
-
});
|
|
1141
|
-
const evidence = evidenceContext ? {
|
|
1142
|
-
baseline: createCampaignEvidenceReceipt({
|
|
1143
|
-
campaign: comparison.baselineOnHoldout,
|
|
1144
|
-
surface: baselineSurface,
|
|
1145
|
-
context: evidenceContext
|
|
1146
|
-
}),
|
|
1147
|
-
winner: createCampaignEvidenceReceipt({
|
|
1148
|
-
campaign: comparison.winnerOnHoldout,
|
|
1149
|
-
surface: selected.winnerSurface,
|
|
1150
|
-
context: evidenceContext
|
|
1151
|
-
})
|
|
1152
|
-
} : void 0;
|
|
1153
|
-
const deferred = comparison.holdout === "deferred";
|
|
1154
|
-
const report = deferred ? null : pairedCompositeSummary(comparison.baselineOnHoldout, comparison.winnerOnHoldout, opts.claim ? evaluationUnitMap(opts.claim, holdout) : void 0);
|
|
1155
|
-
const baseline = report?.baseline ?? null;
|
|
1156
|
-
const winner = report?.winner ?? null;
|
|
1157
|
-
const lift = baseline && winner ? winner.compositeMean - baseline.compositeMean : void 0;
|
|
1158
|
-
const insight = deferred ? void 0 : await analyzeRuns({
|
|
1159
|
-
runs: [...cellsToRunRecords(comparison.baselineOnHoldout.cells, "baseline", runDir, baselineSurface, "holdout", opts.model), ...comparison.winnerOnHoldout === comparison.baselineOnHoldout ? [] : cellsToRunRecords(comparison.winnerOnHoldout.cells, "winner", runDir, selected.winnerSurface, "holdout", opts.model)],
|
|
1160
|
-
baselineCandidateId: "baseline",
|
|
1161
|
-
independentUnitByScenarioId: opts.claim ? evaluationUnitMap(opts.claim, holdout) : void 0,
|
|
1162
|
-
decisionThreshold: opts.claim?.minimumEffect ?? .05,
|
|
1163
|
-
...comparison.winnerOnHoldout === comparison.baselineOnHoldout ? {} : { candidateCandidateId: "winner" }
|
|
1164
|
-
});
|
|
1165
|
-
const cost = totalCost();
|
|
1166
|
-
const optimization = {
|
|
1167
|
-
name: opts.method.name,
|
|
1168
|
-
cost: methodCost,
|
|
1169
|
-
...selected.durationMs === void 0 ? {} : { durationMs: selected.durationMs },
|
|
1170
|
-
...selected.provenance === void 0 ? {} : { provenance: selected.provenance }
|
|
1171
|
-
};
|
|
1172
|
-
const durationMs = Date.now() - startedAt;
|
|
1173
|
-
const receipts = costLedger.list();
|
|
1174
|
-
const record = {
|
|
1175
|
-
schema: "tangle.method-improvement",
|
|
1176
|
-
runId: `${runDir}#${startedAt}`,
|
|
1177
|
-
runDir,
|
|
1178
|
-
timestamp: new Date(startedAt).toISOString(),
|
|
1179
|
-
baselineContentHash: surfaceContentHash(baselineSurface),
|
|
1180
|
-
winnerContentHash: surfaceContentHash(selected.winnerSurface),
|
|
1181
|
-
diff: comparison.promotedDiff,
|
|
1182
|
-
optimizationMethod: optimization,
|
|
1183
|
-
...opts.claim ? { claim: opts.claim } : {},
|
|
1184
|
-
evidence: {
|
|
1185
|
-
trainSplitDigest: campaignSplitDigest(train, budget.reps ?? 1),
|
|
1186
|
-
selectionSplitDigest: campaignSplitDigest(selection, budget.reps ?? 1),
|
|
1187
|
-
holdoutSplitDigest: campaignSplitDigest(holdout, budget.reps ?? 1),
|
|
1188
|
-
baselineCampaignDigest: campaignMeasurementDigest(comparison.baselineOnHoldout),
|
|
1189
|
-
winnerCampaignDigest: campaignMeasurementDigest(comparison.winnerOnHoldout),
|
|
1190
|
-
costReceiptsDigest: canonicalDigest(receipts),
|
|
1191
|
-
...report ? { holdoutObservations: report.observations } : {},
|
|
1192
|
-
...comparison.neutralizedOnHoldout ? { neutralizedCampaignDigest: campaignMeasurementDigest(comparison.neutralizedOnHoldout) } : {}
|
|
1193
|
-
},
|
|
1194
|
-
gate: comparison.gateResult,
|
|
1195
|
-
...deferred ? { holdout: "deferred" } : {},
|
|
1196
|
-
...baseline && winner ? {
|
|
1197
|
-
baselineHoldoutComposite: baseline.compositeMean,
|
|
1198
|
-
winnerHoldoutComposite: winner.compositeMean,
|
|
1199
|
-
heldOutLift: lift
|
|
1200
|
-
} : {},
|
|
1201
|
-
cost,
|
|
1202
|
-
totalCostUsd: cost.totalCostUsd,
|
|
1203
|
-
totalDurationMs: durationMs
|
|
1204
|
-
};
|
|
1205
|
-
const serialized = JSON.parse(JSON.stringify(record));
|
|
1206
|
-
const provenance = {
|
|
1207
|
-
...serialized,
|
|
1208
|
-
recordDigest: canonicalDigest(serialized)
|
|
1209
|
-
};
|
|
1210
|
-
storage.ensureDir(runDir);
|
|
1211
|
-
storage.write(`${runDir}/method-provenance.json`, JSON.stringify(provenance, null, 2));
|
|
1212
|
-
opts.onProvenance?.(provenance);
|
|
1213
|
-
opts.onProgress?.({
|
|
1214
|
-
kind: "gate.decided",
|
|
1215
|
-
decision: comparison.gateResult.decision,
|
|
1216
|
-
...lift === void 0 ? {} : { lift }
|
|
1217
|
-
});
|
|
1218
|
-
const prResult = opts.autoOnPromote === "pr" && comparison.gateResult.decision === "ship" ? openAutoPr({
|
|
1219
|
-
result: comparison.winnerOnHoldout,
|
|
1220
|
-
gate: comparison.gateResult,
|
|
1221
|
-
promotedDiff: comparison.promotedDiff,
|
|
1222
|
-
ghOwner: opts.ghOwner,
|
|
1223
|
-
ghRepo: opts.ghRepo
|
|
1224
|
-
}) : void 0;
|
|
1225
|
-
const result = {
|
|
1226
|
-
...evidence ? { evidence } : {},
|
|
1227
|
-
mode: "method",
|
|
1228
|
-
...opts.claim ? { claim: opts.claim } : {},
|
|
1229
|
-
...comparison.finalEvidence ? { finalEvidence: comparison.finalEvidence } : {},
|
|
1230
|
-
searchHistoryCoverage: history,
|
|
1231
|
-
baseline,
|
|
1232
|
-
winner: {
|
|
1233
|
-
surface: selected.winnerSurface,
|
|
1234
|
-
compositeMean: winner?.compositeMean ?? null,
|
|
1235
|
-
perScenario: winner?.perScenario ?? {},
|
|
1236
|
-
label: opts.method.name
|
|
1237
|
-
},
|
|
1238
|
-
...lift === void 0 ? {} : { lift },
|
|
1239
|
-
diff: comparison.promotedDiff,
|
|
1240
|
-
gateDecision: comparison.gateResult.decision,
|
|
1241
|
-
provenance,
|
|
1242
|
-
optimization,
|
|
1243
|
-
cost,
|
|
1244
|
-
ledgerCost: costLedger.summary(),
|
|
1245
|
-
totalCostUsd: cost.totalCostUsd,
|
|
1246
|
-
durationMs,
|
|
1247
|
-
receipts,
|
|
1248
|
-
...insight ? { insight } : {},
|
|
1249
|
-
...selected.searchHistory ? { searchHistory: selected.searchHistory } : {},
|
|
1250
|
-
raw: {
|
|
1251
|
-
...comparison,
|
|
1252
|
-
kind: "method",
|
|
1253
|
-
baselineSurface,
|
|
1254
|
-
winnerSurface: selected.winnerSurface,
|
|
1255
|
-
winnerSurfaceHash: surfaceHash(selected.winnerSurface),
|
|
1256
|
-
method: selected,
|
|
1257
|
-
cost,
|
|
1258
|
-
...prResult ? { prResult } : {}
|
|
1259
|
-
}
|
|
1260
|
-
};
|
|
1261
|
-
if (opts.hostedTenant) {
|
|
1262
|
-
const snapshot = (index, surface, campaign, compositeMean) => ({
|
|
1263
|
-
index,
|
|
1264
|
-
surfaceHash: surfaceHash(surface),
|
|
1265
|
-
surface,
|
|
1266
|
-
cells: campaign.cells.map((cell) => {
|
|
1267
|
-
const execution = campaignCellExecutionEvidence(cell);
|
|
1268
|
-
return {
|
|
1269
|
-
scenarioId: cell.scenarioId,
|
|
1270
|
-
rep: cell.rep,
|
|
1271
|
-
compositeMean: campaignCellTaskScore(cell) ?? null,
|
|
1272
|
-
dimensions: campaignCellJudgeDimensions(cell),
|
|
1273
|
-
terminalOutcome: execution.terminalOutcome,
|
|
1274
|
-
executionErrorCount: execution.executionErrorCount ?? null,
|
|
1275
|
-
...cell.error ? { errorMessage: cell.error } : {}
|
|
1276
|
-
};
|
|
1277
|
-
}),
|
|
1278
|
-
compositeMean,
|
|
1279
|
-
costUsd: campaign.aggregates.cost.totalCostUsd,
|
|
1280
|
-
durationMs: campaign.durationMs
|
|
1281
|
-
});
|
|
1282
|
-
try {
|
|
1283
|
-
await createHostedClient(opts.hostedTenant).ingestEvalRun({
|
|
1284
|
-
runId: provenance.runId,
|
|
1285
|
-
runDir,
|
|
1286
|
-
timestamp: provenance.timestamp,
|
|
1287
|
-
status: "finished",
|
|
1288
|
-
labels: {
|
|
1289
|
-
...opts.hostedLabels,
|
|
1290
|
-
mode: "method"
|
|
1291
|
-
},
|
|
1292
|
-
baseline: snapshot(0, baselineSurface, comparison.baselineOnHoldout, baseline?.compositeMean ?? null),
|
|
1293
|
-
generations: [snapshot(1, selected.winnerSurface, comparison.winnerOnHoldout, winner?.compositeMean ?? null)],
|
|
1294
|
-
gateDecision: result.gateDecision,
|
|
1295
|
-
...lift === void 0 ? {} : { holdoutLift: lift },
|
|
1296
|
-
totalCostUsd: result.totalCostUsd,
|
|
1297
|
-
totalDurationMs: durationMs,
|
|
1298
|
-
...insight ? { insightReport: insight } : {}
|
|
1299
|
-
});
|
|
1300
|
-
} catch (error) {
|
|
1301
|
-
console.warn(`[agent-eval] hosted ingest failed (continuing): ${error instanceof Error ? error.message : String(error)}`);
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
return result;
|
|
1305
|
-
}
|
|
1306
|
-
//#endregion
|
|
1307
|
-
//#region src/contract/self-improve.ts
|
|
1308
|
-
/** Failed self-improvement run with an immutable receipt snapshot. */
|
|
1309
|
-
var SelfImproveRunError = class extends Error {
|
|
1310
|
-
cost;
|
|
1311
|
-
receipts;
|
|
1312
|
-
constructor(cause, ledger) {
|
|
1313
|
-
const original = cause instanceof Error ? cause : new Error(String(cause));
|
|
1314
|
-
super(original.message, { cause: original });
|
|
1315
|
-
this.name = "SelfImproveRunError";
|
|
1316
|
-
this.cost = ledger.summary();
|
|
1317
|
-
this.receipts = ledger.list();
|
|
1318
|
-
}
|
|
1319
|
-
};
|
|
1320
|
-
function assertSelfImproveSearchMode(opts) {
|
|
1321
|
-
assertSearchHistoryAdmissionOptions(opts);
|
|
1322
|
-
if (!opts.method && (opts.searchHistoryPolicy !== void 0 || opts.searchHistoryVerification !== void 0 || opts.evidence !== void 0)) throw new Error("selfImprove: search history admission requires method");
|
|
1323
|
-
if (opts.method && opts.proposer) throw new Error("selfImprove: method and proposer are mutually exclusive");
|
|
1324
|
-
if (!opts.method) {
|
|
1325
|
-
if (opts.selectionScenarios !== void 0) throw new Error("selfImprove: selectionScenarios requires method");
|
|
1326
|
-
return;
|
|
1327
|
-
}
|
|
1328
|
-
if (typeof opts.method.name !== "string" || !opts.method.name.trim() || opts.method.name.trim() !== opts.method.name || typeof opts.method.optimize !== "function") throw new Error("selfImprove: method must have a trimmed name and optimize(input)");
|
|
1329
|
-
const budget = opts.budget;
|
|
1330
|
-
if (budget?.generations !== void 0) throw new Error("selfImprove: method owns its rounds; budget.generations applies only to proposer mode");
|
|
1331
|
-
if (budget?.populationSize !== void 0) throw new Error("selfImprove: method owns its candidates; budget.populationSize applies only to proposer mode");
|
|
1332
|
-
if (budget?.candidateConcurrency !== void 0 || budget?.maxImprovementShots !== void 0 || opts.analyzeGeneration !== void 0 || opts.findings !== void 0 || opts.selectParent !== void 0 || opts.premeasuredBaseline !== void 0 || opts.selectionRankKey !== void 0 || opts.searchLedger !== void 0) throw new Error("selfImprove: candidateConcurrency, maxImprovementShots, analyzeGeneration, findings, selectParent, premeasuredBaseline, selectionRankKey, and searchLedger apply only to proposer mode");
|
|
1333
|
-
}
|
|
1334
|
-
function splitMethodPartitions(searchScenarios, explicitSelection, fraction, unitByScenario) {
|
|
1335
|
-
if (!Number.isFinite(fraction) || fraction <= 0 || fraction >= 1) throw new Error("selfImprove: budget.selectionFraction must be in (0, 1)");
|
|
1336
|
-
const byId = /* @__PURE__ */ new Map();
|
|
1337
|
-
for (const scenario of searchScenarios) {
|
|
1338
|
-
if (byId.has(scenario.id)) throw new Error(`selfImprove: duplicate scenario id '${scenario.id}'`);
|
|
1339
|
-
byId.set(scenario.id, scenario);
|
|
1340
|
-
}
|
|
1341
|
-
if (explicitSelection) {
|
|
1342
|
-
if (explicitSelection.length === 0) throw new Error("selfImprove: selectionScenarios must not be empty");
|
|
1343
|
-
const selectionIds = /* @__PURE__ */ new Set();
|
|
1344
|
-
for (const scenario of explicitSelection) {
|
|
1345
|
-
if (!byId.has(scenario.id)) throw new Error(`selfImprove: selection scenario '${scenario.id}' is absent from the non-final cases`);
|
|
1346
|
-
if (selectionIds.has(scenario.id)) throw new Error(`selfImprove: duplicate selection scenario id '${scenario.id}'`);
|
|
1347
|
-
selectionIds.add(scenario.id);
|
|
1348
|
-
}
|
|
1349
|
-
const train = searchScenarios.filter((scenario) => !selectionIds.has(scenario.id));
|
|
1350
|
-
if (train.length === 0) throw new Error("selfImprove: method train split is empty");
|
|
1351
|
-
if (unitByScenario) {
|
|
1352
|
-
const selectedUnits = new Set([...selectionIds].map((id) => unitByScenario.get(id)));
|
|
1353
|
-
if (train.some((scenario) => selectedUnits.has(unitByScenario.get(scenario.id)))) throw new Error("selfImprove: training and selection share independent units");
|
|
1354
|
-
}
|
|
1355
|
-
return {
|
|
1356
|
-
train,
|
|
1357
|
-
selection: explicitSelection.map((scenario) => byId.get(scenario.id))
|
|
1358
|
-
};
|
|
1359
|
-
}
|
|
1360
|
-
if (searchScenarios.length < 2) throw new Error("selfImprove: method requires at least two non-final scenarios");
|
|
1361
|
-
if (unitByScenario) {
|
|
1362
|
-
const split = splitTrainHoldout(searchScenarios, fraction, unitByScenario);
|
|
1363
|
-
return {
|
|
1364
|
-
train: split.train,
|
|
1365
|
-
selection: split.holdout
|
|
1366
|
-
};
|
|
1367
|
-
}
|
|
1368
|
-
const sorted = [...searchScenarios].sort((a, b) => stableScenarioHash(a.id) - stableScenarioHash(b.id));
|
|
1369
|
-
const count = Math.max(1, Math.min(sorted.length - 1, Math.round(sorted.length * fraction)));
|
|
1370
|
-
return {
|
|
1371
|
-
selection: sorted.slice(0, count),
|
|
1372
|
-
train: sorted.slice(count)
|
|
1373
|
-
};
|
|
1374
|
-
}
|
|
1375
|
-
/** 32-bit FNV-1a over raw UTF-16 code units, read as an unsigned int and used
|
|
1376
|
-
* only to order scenarios deterministically.
|
|
1377
|
-
*
|
|
1378
|
-
* Frozen: the order it produces assigns scenarios to partitions, so a change
|
|
1379
|
-
* re-partitions decisions already recorded. It masks no byte, unlike
|
|
1380
|
-
* `fnv1a32` in `src/partition-held-out.ts`, so the two disagree on any
|
|
1381
|
-
* non-ASCII id and cannot be shared. */
|
|
1382
|
-
function stableScenarioHash(value) {
|
|
1383
|
-
let hash = 2166136261;
|
|
1384
|
-
for (let index = 0; index < value.length; index++) {
|
|
1385
|
-
hash ^= value.charCodeAt(index);
|
|
1386
|
-
hash = Math.imul(hash, 16777619) >>> 0;
|
|
1387
|
-
}
|
|
1388
|
-
return hash;
|
|
1389
|
-
}
|
|
1390
|
-
/** Deterministic split by scenario identity, or by source identity for new-unit claims. */
|
|
1391
|
-
function splitTrainHoldout(scenarios, fraction, unitByScenario) {
|
|
1392
|
-
if (unitByScenario) {
|
|
1393
|
-
const units = [...new Set(scenarios.map((scenario) => unitByScenario.get(scenario.id)))].sort((a, b) => stableScenarioHash(a) - stableScenarioHash(b) || (a < b ? -1 : a > b ? 1 : 0));
|
|
1394
|
-
if (units.length < 2) throw new Error("selfImprove: splitting needs at least two independent units");
|
|
1395
|
-
const count = Math.max(1, Math.min(units.length - 1, Math.round(units.length * fraction)));
|
|
1396
|
-
const finalUnits = new Set(units.slice(0, count));
|
|
1397
|
-
return {
|
|
1398
|
-
holdout: scenarios.filter((scenario) => finalUnits.has(unitByScenario.get(scenario.id))),
|
|
1399
|
-
train: scenarios.filter((scenario) => !finalUnits.has(unitByScenario.get(scenario.id)))
|
|
1400
|
-
};
|
|
1401
|
-
}
|
|
1402
|
-
const sorted = [...scenarios].sort((a, b) => stableScenarioHash(a.id) - stableScenarioHash(b.id));
|
|
1403
|
-
const nHoldout = Math.max(1, Math.min(sorted.length - 1, Math.round(sorted.length * fraction)));
|
|
1404
|
-
return {
|
|
1405
|
-
holdout: sorted.slice(0, nHoldout),
|
|
1406
|
-
train: sorted.slice(nHoldout)
|
|
1407
|
-
};
|
|
1408
|
-
}
|
|
1409
|
-
/**
|
|
1410
|
-
* Latest search campaign measured for the winner surface; the baseline search
|
|
1411
|
-
* campaign when the winner IS the baseline. Used by the deferred-holdout
|
|
1412
|
-
* summary, where no holdout campaign exists to summarize.
|
|
1413
|
-
*/
|
|
1414
|
-
function winnerSearchCampaign(result) {
|
|
1415
|
-
for (let i = result.generations.length - 1; i >= 0; i--) {
|
|
1416
|
-
const measured = result.generations[i]?.surfaces.find((s) => s.surfaceHash === result.winnerSurfaceHash);
|
|
1417
|
-
if (measured) return measured.campaign;
|
|
1418
|
-
}
|
|
1419
|
-
return result.baselineCampaign;
|
|
1420
|
-
}
|
|
1421
|
-
async function selfImprove(opts) {
|
|
1422
|
-
opts = {
|
|
1423
|
-
...opts,
|
|
1424
|
-
judge: captureJudge(opts.judge),
|
|
1425
|
-
...opts.claim || opts.finalEvidence ? {
|
|
1426
|
-
claim: opts.claim && defineEvaluationClaim(opts.claim),
|
|
1427
|
-
finalEvidence: opts.finalEvidence && captureFinalEvidencePolicy(opts.finalEvidence),
|
|
1428
|
-
scenarios: structuredClone(opts.scenarios),
|
|
1429
|
-
selectionScenarios: opts.selectionScenarios && structuredClone(opts.selectionScenarios),
|
|
1430
|
-
budget: opts.budget && structuredClone(opts.budget)
|
|
1431
|
-
} : {}
|
|
1432
|
-
};
|
|
1433
|
-
const startedAt = Date.now();
|
|
1434
|
-
const runDir = resolveRunDir(opts.runDir ?? (opts.method ? `.agent-eval/runs/self-improve-${startedAt}` : `mem://selfImprove-${startedAt}`));
|
|
1435
|
-
const storage = opts.storage ?? (runDir.startsWith("mem://") ? inMemoryCampaignStorage() : fsCampaignStorage());
|
|
1436
|
-
const costLedger = createRunCostLedger({
|
|
1437
|
-
storage,
|
|
1438
|
-
runDir,
|
|
1439
|
-
costCeilingUsd: opts.budget?.dollars
|
|
1440
|
-
});
|
|
1441
|
-
try {
|
|
1442
|
-
return await runSelfImprove(opts, costLedger, startedAt, runDir, storage);
|
|
1443
|
-
} catch (error) {
|
|
1444
|
-
throw new SelfImproveRunError(error, costLedger);
|
|
1445
|
-
}
|
|
1446
|
-
}
|
|
1447
|
-
async function runSelfImprove(opts, costLedger, startedAt, runDir, storage) {
|
|
1448
|
-
const budget = opts.budget ?? {};
|
|
1449
|
-
assertSelfImproveSearchMode(opts);
|
|
1450
|
-
const maxConcurrency = budget.maxConcurrency ?? 2;
|
|
1451
|
-
const holdoutFraction = budget.holdoutFraction ?? .25;
|
|
1452
|
-
const holdoutMode = budget.holdout ?? "measured";
|
|
1453
|
-
const holdoutDeferred = holdoutMode === "deferred";
|
|
1454
|
-
const expectUsage = opts.expectUsage ?? "assert";
|
|
1455
|
-
const unitByScenario = opts.claim ? evaluationUnitMap(opts.claim, opts.scenarios) : void 0;
|
|
1456
|
-
const splitUnitByScenario = opts.claim?.generalization === "new-units" ? unitByScenario : void 0;
|
|
1457
|
-
const explicitHoldout = budget.holdoutScenarios;
|
|
1458
|
-
const { train, holdout } = explicitHoldout ? {
|
|
1459
|
-
train: opts.scenarios.filter((s) => !explicitHoldout.some((h) => h.id === s.id)),
|
|
1460
|
-
holdout: explicitHoldout
|
|
1461
|
-
} : holdoutDeferred ? {
|
|
1462
|
-
train: opts.scenarios,
|
|
1463
|
-
holdout: []
|
|
1464
|
-
} : splitTrainHoldout(opts.scenarios, holdoutFraction, splitUnitByScenario);
|
|
1465
|
-
if (train.length === 0) throw new Error("selfImprove: train split is empty. Reduce holdoutFraction or pass more scenarios.");
|
|
1466
|
-
if (holdout.length === 0 && !holdoutDeferred) throw new Error("selfImprove: holdout split is empty. Pass more scenarios.");
|
|
1467
|
-
if (opts.claim?.generalization === "new-units") assertIndependentEvaluationSplit(opts.claim, holdout, train);
|
|
1468
|
-
if (opts.finalEvidence) {
|
|
1469
|
-
if (holdoutDeferred) throw new Error("final evidence requires measured holdout");
|
|
1470
|
-
if (opts.method) await reserveFinalEvidence(opts.finalEvidence, opts.claim, holdout, train);
|
|
1471
|
-
}
|
|
1472
|
-
if (opts.method) {
|
|
1473
|
-
const partitions = splitMethodPartitions(train, opts.selectionScenarios, budget.selectionFraction ?? .25, splitUnitByScenario);
|
|
1474
|
-
return runSelfImproveMethod({
|
|
1475
|
-
opts: {
|
|
1476
|
-
...opts,
|
|
1477
|
-
method: opts.method
|
|
1478
|
-
},
|
|
1479
|
-
train: partitions.train,
|
|
1480
|
-
selection: partitions.selection,
|
|
1481
|
-
holdout,
|
|
1482
|
-
costLedger,
|
|
1483
|
-
storage,
|
|
1484
|
-
runDir,
|
|
1485
|
-
startedAt
|
|
1486
|
-
});
|
|
1487
|
-
}
|
|
1488
|
-
const generations = budget.generations ?? 3;
|
|
1489
|
-
const populationSize = budget.populationSize ?? 2;
|
|
1490
|
-
if (generations > 0 && !opts.proposer) throw new Error("selfImprove: method or proposer is required when budget.generations is greater than zero");
|
|
1491
|
-
const proposer = opts.proposer ?? {
|
|
1492
|
-
kind: "baseline-only",
|
|
1493
|
-
propose: async () => []
|
|
1494
|
-
};
|
|
1495
|
-
const gate = opts.gate ?? defaultProductionGate({
|
|
1496
|
-
holdoutScenarios: holdout,
|
|
1497
|
-
deltaThreshold: opts.claim?.minimumEffect ?? .05,
|
|
1498
|
-
independentUnitByScenarioId: opts.claim ? evaluationUnitMap(opts.claim, holdout) : void 0
|
|
1499
|
-
});
|
|
1500
|
-
if (opts.onProgress) opts.onProgress({
|
|
1501
|
-
kind: "baseline.started",
|
|
1502
|
-
scenarios: opts.scenarios.length
|
|
1503
|
-
});
|
|
1504
|
-
const result = await runImprovementLoop({
|
|
1505
|
-
scenarios: train,
|
|
1506
|
-
baselineSurface: opts.baselineSurface,
|
|
1507
|
-
premeasuredBaseline: opts.premeasuredBaseline,
|
|
1508
|
-
dispatchWithSurface: opts.agent,
|
|
1509
|
-
dispatchRef: opts.dispatchRef,
|
|
1510
|
-
proposer,
|
|
1511
|
-
judges: [opts.judge],
|
|
1512
|
-
populationSize,
|
|
1513
|
-
maxGenerations: generations,
|
|
1514
|
-
candidateConcurrency: budget.candidateConcurrency,
|
|
1515
|
-
reps: budget.reps,
|
|
1516
|
-
maxImprovementShots: budget.maxImprovementShots,
|
|
1517
|
-
holdoutScenarios: holdout,
|
|
1518
|
-
claim: opts.claim,
|
|
1519
|
-
finalEvidence: opts.finalEvidence,
|
|
1520
|
-
holdout: holdoutMode,
|
|
1521
|
-
gate,
|
|
1522
|
-
neutralize: opts.neutralize,
|
|
1523
|
-
autoOnPromote: opts.autoOnPromote ?? "none",
|
|
1524
|
-
ghOwner: opts.ghOwner,
|
|
1525
|
-
ghRepo: opts.ghRepo,
|
|
1526
|
-
storage,
|
|
1527
|
-
runDir,
|
|
1528
|
-
maxConcurrency,
|
|
1529
|
-
cellPlacement: opts.cellPlacement,
|
|
1530
|
-
dispatchTimeoutMs: opts.dispatchTimeoutMs,
|
|
1531
|
-
cellRetry: opts.cellRetry,
|
|
1532
|
-
costLedger,
|
|
1533
|
-
expectUsage,
|
|
1534
|
-
labeledStore: opts.labeledStore,
|
|
1535
|
-
captureSource: opts.captureSource,
|
|
1536
|
-
analyzeGeneration: opts.analyzeGeneration,
|
|
1537
|
-
findings: opts.findings,
|
|
1538
|
-
selectionRankKey: opts.selectionRankKey,
|
|
1539
|
-
selectParent: opts.selectParent,
|
|
1540
|
-
searchLedger: opts.searchLedger
|
|
1541
|
-
});
|
|
1542
|
-
const reportSplit = holdoutDeferred ? "search" : "holdout";
|
|
1543
|
-
const reportBaselineCampaign = holdoutDeferred ? result.baselineCampaign : result.baselineOnHoldout;
|
|
1544
|
-
const reportWinnerCampaign = holdoutDeferred ? winnerSearchCampaign(result) : result.winnerOnHoldout;
|
|
1545
|
-
const reportUnitMap = opts.claim ? evaluationUnitMap(opts.claim, holdoutDeferred ? train : holdout) : void 0;
|
|
1546
|
-
const report = pairedCompositeSummary(reportBaselineCampaign, reportWinnerCampaign, reportUnitMap);
|
|
1547
|
-
const baseline = report.baseline;
|
|
1548
|
-
const winnerStats = report.winner;
|
|
1549
|
-
let power;
|
|
1550
|
-
const baselineHoldoutComposites = holdoutDeferred ? [] : report.baselineComposites;
|
|
1551
|
-
if (baselineHoldoutComposites.length >= 3) {
|
|
1552
|
-
power = powerPreflight({
|
|
1553
|
-
baselineComposites: baselineHoldoutComposites,
|
|
1554
|
-
deltaThreshold: opts.claim?.minimumEffect ?? .05,
|
|
1555
|
-
sharedScorerChannel: true
|
|
1556
|
-
});
|
|
1557
|
-
if (opts.onProgress) opts.onProgress({
|
|
1558
|
-
kind: "power.estimated",
|
|
1559
|
-
n: power.n,
|
|
1560
|
-
sd: power.sd,
|
|
1561
|
-
mde: power.mde,
|
|
1562
|
-
underpowered: power.underpowered
|
|
1563
|
-
});
|
|
1564
|
-
if (power.underpowered && generations > 0) console.warn(`[selfImprove] ${power.recommendation}`);
|
|
1565
|
-
}
|
|
1566
|
-
if (opts.onProgress) {
|
|
1567
|
-
opts.onProgress({
|
|
1568
|
-
kind: "baseline.completed",
|
|
1569
|
-
compositeMean: baseline.compositeMean,
|
|
1570
|
-
durationMs: Date.now() - startedAt
|
|
1571
|
-
});
|
|
1572
|
-
opts.onProgress({
|
|
1573
|
-
kind: "gate.decided",
|
|
1574
|
-
decision: result.gateResult.decision,
|
|
1575
|
-
...holdoutDeferred ? {} : { lift: winnerStats.compositeMean - baseline.compositeMean }
|
|
1576
|
-
});
|
|
1577
|
-
}
|
|
1578
|
-
const cost = result.cost;
|
|
1579
|
-
const totalCost = cost.totalCostUsd;
|
|
1580
|
-
const insight = await analyzeRuns({
|
|
1581
|
-
runs: [...cellsToRunRecords(reportBaselineCampaign.cells, "baseline", runDir, opts.baselineSurface, reportSplit, opts.model), ...reportWinnerCampaign === reportBaselineCampaign ? [] : cellsToRunRecords(reportWinnerCampaign.cells, "winner", runDir, result.winnerSurface, reportSplit, opts.model)],
|
|
1582
|
-
baselineCandidateId: "baseline",
|
|
1583
|
-
independentUnitByScenarioId: reportUnitMap,
|
|
1584
|
-
decisionThreshold: opts.claim?.minimumEffect ?? .05,
|
|
1585
|
-
...reportWinnerCampaign === reportBaselineCampaign ? {} : { candidateCandidateId: "winner" }
|
|
1586
|
-
});
|
|
1587
|
-
const durationMs = Date.now() - startedAt;
|
|
1588
|
-
const { record: provenance } = await emitLoopProvenance({
|
|
1589
|
-
...loopProvenanceArgsFromResult({
|
|
1590
|
-
runId: `${runDir}#${startedAt}`,
|
|
1591
|
-
runDir,
|
|
1592
|
-
timestamp: new Date(startedAt).toISOString(),
|
|
1593
|
-
baselineSurface: opts.baselineSurface,
|
|
1594
|
-
result,
|
|
1595
|
-
costReceipts: costLedger.list(),
|
|
1596
|
-
totalCostUsd: totalCost,
|
|
1597
|
-
totalDurationMs: durationMs,
|
|
1598
|
-
independentUnitByScenarioId: holdoutDeferred ? void 0 : reportUnitMap
|
|
1599
|
-
}),
|
|
1600
|
-
storage,
|
|
1601
|
-
hostedClient: opts.hostedTenant ? createHostedClient(opts.hostedTenant) : void 0
|
|
1602
|
-
});
|
|
1603
|
-
if (opts.onProvenance) opts.onProvenance(provenance);
|
|
1604
|
-
const summary = {
|
|
1605
|
-
...opts.claim ? { claim: opts.claim } : {},
|
|
1606
|
-
...result.finalEvidence ? { finalEvidence: result.finalEvidence } : {},
|
|
1607
|
-
mode: "proposer",
|
|
1608
|
-
baseline,
|
|
1609
|
-
winner: {
|
|
1610
|
-
...winnerStats,
|
|
1611
|
-
surface: result.winnerSurface,
|
|
1612
|
-
...result.winnerLabel ? { label: result.winnerLabel } : {},
|
|
1613
|
-
...result.winnerRationale ? { rationale: result.winnerRationale } : {}
|
|
1614
|
-
},
|
|
1615
|
-
...holdoutDeferred ? {} : { lift: winnerStats.compositeMean - baseline.compositeMean },
|
|
1616
|
-
diff: result.promotedDiff,
|
|
1617
|
-
provenance,
|
|
1618
|
-
gateDecision: result.gateResult.decision,
|
|
1619
|
-
generationsExplored: result.generations.length,
|
|
1620
|
-
durationMs,
|
|
1621
|
-
totalCostUsd: totalCost,
|
|
1622
|
-
cost,
|
|
1623
|
-
receipts: costLedger.list(),
|
|
1624
|
-
...result.searchHistory ? { searchHistory: result.searchHistory } : {},
|
|
1625
|
-
insight,
|
|
1626
|
-
...power ? { power } : {},
|
|
1627
|
-
raw: result
|
|
1628
|
-
};
|
|
1629
|
-
if (opts.hostedTenant) try {
|
|
1630
|
-
await shipEvalRunToHosted(opts.hostedTenant, opts, summary, result, runDir);
|
|
1631
|
-
} catch (err) {
|
|
1632
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1633
|
-
console.warn(`[agent-eval] hosted ingest failed (continuing): ${msg}`);
|
|
1634
|
-
}
|
|
1635
|
-
return summary;
|
|
1636
|
-
}
|
|
1637
|
-
async function shipEvalRunToHosted(tenant, opts, summary, raw, runDir) {
|
|
1638
|
-
const client = createHostedClient(tenant);
|
|
1639
|
-
function snapshotFromCampaign(index, surface, campaign, durationMs) {
|
|
1640
|
-
const cells = campaign.cells.map((cell) => {
|
|
1641
|
-
const execution = campaignCellExecutionEvidence(cell);
|
|
1642
|
-
return {
|
|
1643
|
-
scenarioId: cell.scenarioId,
|
|
1644
|
-
rep: cell.rep,
|
|
1645
|
-
compositeMean: campaignCellTaskScore(cell) ?? null,
|
|
1646
|
-
dimensions: campaignCellJudgeDimensions(cell),
|
|
1647
|
-
terminalOutcome: execution.terminalOutcome,
|
|
1648
|
-
executionErrorCount: execution.executionErrorCount ?? null,
|
|
1649
|
-
errorMessage: cell.error ?? void 0
|
|
1650
|
-
};
|
|
1651
|
-
});
|
|
1652
|
-
const scoredCells = cells.flatMap((cell) => cell.compositeMean === null ? [] : [cell.compositeMean]);
|
|
1653
|
-
const compositeMean = scoredCells.length === 0 ? null : scoredCells.reduce((sum, score) => sum + score, 0) / scoredCells.length;
|
|
1654
|
-
return {
|
|
1655
|
-
index,
|
|
1656
|
-
surfaceHash: surfaceHash(surface),
|
|
1657
|
-
surface,
|
|
1658
|
-
cells,
|
|
1659
|
-
compositeMean,
|
|
1660
|
-
costUsd: campaign.aggregates.cost.totalCostUsd,
|
|
1661
|
-
durationMs
|
|
1662
|
-
};
|
|
1663
|
-
}
|
|
1664
|
-
const generations = [];
|
|
1665
|
-
generations.push(snapshotFromCampaign(0, opts.baselineSurface, raw.baselineCampaign, 0));
|
|
1666
|
-
for (const gen of raw.generations) {
|
|
1667
|
-
const winner = gen.surfaces.reduce((best, s) => s.campaign.aggregates.cellsExecuted > 0 && (best === void 0 || averageComposite(s.campaign) > averageComposite(best.campaign)) ? s : best, gen.surfaces[0]);
|
|
1668
|
-
if (!winner) continue;
|
|
1669
|
-
generations.push(snapshotFromCampaign(gen.record.generationIndex + 1, winner.surface, winner.campaign, 0));
|
|
1670
|
-
}
|
|
1671
|
-
const event = {
|
|
1672
|
-
runId: `${runDir}#${Date.now()}`,
|
|
1673
|
-
runDir,
|
|
1674
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1675
|
-
status: "finished",
|
|
1676
|
-
labels: opts.hostedLabels ?? {},
|
|
1677
|
-
baseline: generations[0],
|
|
1678
|
-
generations,
|
|
1679
|
-
gateDecision: summary.gateDecision,
|
|
1680
|
-
holdoutLift: summary.lift,
|
|
1681
|
-
totalCostUsd: summary.totalCostUsd,
|
|
1682
|
-
totalDurationMs: summary.durationMs,
|
|
1683
|
-
insightReport: summary.insight
|
|
1684
|
-
};
|
|
1685
|
-
await client.ingestEvalRun(event);
|
|
1686
|
-
}
|
|
1687
|
-
function averageComposite(campaign) {
|
|
1688
|
-
const aggs = Object.values(campaign.aggregates.byScenario);
|
|
1689
|
-
return aggs.length === 0 ? 0 : aggs.reduce((s, a) => s + a.meanComposite, 0) / aggs.length;
|
|
1690
|
-
}
|
|
1691
|
-
//#endregion
|
|
1692
|
-
//#region src/contract/define-agent-eval.ts
|
|
1693
|
-
/**
|
|
1694
|
-
* Define an agent eval once, then either score a surface with `evaluate()` or
|
|
1695
|
-
* run the closed loop with `improve()`.
|
|
1696
|
-
*
|
|
1697
|
-
* This is a DX wrapper only: it delegates to `runEval()` and `selfImprove()` and
|
|
1698
|
-
* returns their native result shapes.
|
|
1699
|
-
*/
|
|
1700
|
-
function defineAgentEval(defaults) {
|
|
1701
|
-
const defaultEvaluateOptions = evaluateDefaults(defaults);
|
|
1702
|
-
return {
|
|
1703
|
-
scenarios: defaults.scenarios,
|
|
1704
|
-
baselineSurface: defaults.baselineSurface,
|
|
1705
|
-
async evaluate(opts = {}) {
|
|
1706
|
-
const { agent, judge, judges, runDir, scenarios, surface, ...campaignOpts } = opts;
|
|
1707
|
-
const selectedAgent = agent ?? defaults.agent;
|
|
1708
|
-
const selectedSurface = surface ?? defaults.baselineSurface;
|
|
1709
|
-
const selectedRunDir = runDir ?? defaults.runDir ?? `mem://defineAgentEval-${Date.now()}`;
|
|
1710
|
-
const selectedStorage = campaignOpts.storage ?? defaultEvaluateOptions.storage ?? (selectedRunDir.startsWith("mem://") ? inMemoryCampaignStorage() : void 0);
|
|
1711
|
-
const evalOptions = {
|
|
1712
|
-
...defaultEvaluateOptions,
|
|
1713
|
-
...campaignOpts,
|
|
1714
|
-
...selectedStorage ? { storage: selectedStorage } : {},
|
|
1715
|
-
runDir: selectedRunDir,
|
|
1716
|
-
scenarios: scenarios ?? defaults.scenarios,
|
|
1717
|
-
dispatch: (scenario, ctx) => selectedAgent(selectedSurface, scenario, ctx),
|
|
1718
|
-
dispatchRef: surfaceDispatchRef(selectedSurface, campaignOpts.dispatchRef ?? defaults.dispatchRef),
|
|
1719
|
-
judges: evaluateJudges(judges, judge ?? defaults.judge)
|
|
1720
|
-
};
|
|
1721
|
-
if (evalOptions.reps !== void 0) evalOptions.reps = requirePositiveInteger(evalOptions.reps, "reps");
|
|
1722
|
-
return runEval(evalOptions);
|
|
1723
|
-
},
|
|
1724
|
-
async improve(opts = {}) {
|
|
1725
|
-
const { budget: budgetOverride, hostedTenant: hostedTenantOverride, ...topLevelOverrides } = opts;
|
|
1726
|
-
const merged = mergeDefined(defaults, topLevelOverrides);
|
|
1727
|
-
const budget = mergeBudget(defaults.budget, budgetOverride);
|
|
1728
|
-
const hostedTenant = mergeHostedTenant(defaults.hostedTenant, hostedTenantOverride);
|
|
1729
|
-
return selfImprove({
|
|
1730
|
-
...merged,
|
|
1731
|
-
...budget ? { budget } : {},
|
|
1732
|
-
...hostedTenant ? { hostedTenant } : {}
|
|
1733
|
-
});
|
|
1734
|
-
}
|
|
1735
|
-
};
|
|
1736
|
-
}
|
|
1737
|
-
function evaluateDefaults(defaults) {
|
|
1738
|
-
const out = {};
|
|
1739
|
-
if (defaults.storage) out.storage = defaults.storage;
|
|
1740
|
-
if (defaults.labeledStore) out.labeledStore = defaults.labeledStore;
|
|
1741
|
-
if (defaults.captureSource) out.captureSource = defaults.captureSource;
|
|
1742
|
-
if (defaults.cellPlacement) out.cellPlacement = defaults.cellPlacement;
|
|
1743
|
-
if (defaults.expectUsage) out.expectUsage = defaults.expectUsage;
|
|
1744
|
-
if (defaults.budget?.dollars !== void 0) out.costCeiling = defaults.budget.dollars;
|
|
1745
|
-
if (defaults.budget?.maxConcurrency !== void 0) out.maxConcurrency = defaults.budget.maxConcurrency;
|
|
1746
|
-
if (defaults.budget?.reps !== void 0) out.reps = requirePositiveInteger(defaults.budget.reps, "budget.reps");
|
|
1747
|
-
return out;
|
|
1748
|
-
}
|
|
1749
|
-
function mergeBudget(defaults, overrides) {
|
|
1750
|
-
const merged = mergeOptionalObject(defaults, overrides);
|
|
1751
|
-
if (merged?.reps !== void 0) merged.reps = requirePositiveInteger(merged.reps, "budget.reps");
|
|
1752
|
-
return merged;
|
|
1753
|
-
}
|
|
1754
|
-
function mergeHostedTenant(defaults, overrides) {
|
|
1755
|
-
const merged = mergeOptionalObject(defaults, overrides);
|
|
1756
|
-
if (!merged) return void 0;
|
|
1757
|
-
if (!merged.endpoint?.trim() || !merged.apiKey?.trim() || !merged.tenantId?.trim()) throw new Error("defineAgentEval.improve: hostedTenant requires endpoint, apiKey, and tenantId after merging defaults and overrides");
|
|
1758
|
-
return merged;
|
|
1759
|
-
}
|
|
1760
|
-
function mergeDefined(defaults, overrides) {
|
|
1761
|
-
if (!overrides) return defaults;
|
|
1762
|
-
const merged = { ...defaults };
|
|
1763
|
-
for (const [key, value] of Object.entries(overrides)) if (value !== void 0) merged[key] = value;
|
|
1764
|
-
return merged;
|
|
1765
|
-
}
|
|
1766
|
-
function mergeOptionalObject(defaults, overrides) {
|
|
1767
|
-
if (!defaults && !overrides) return void 0;
|
|
1768
|
-
return mergeDefined(defaults ?? {}, overrides);
|
|
1769
|
-
}
|
|
1770
|
-
function evaluateJudges(judges, defaultJudge) {
|
|
1771
|
-
if (judges !== void 0) {
|
|
1772
|
-
if (judges.length === 0) throw new Error("defineAgentEval.evaluate: judges must not be empty");
|
|
1773
|
-
return judges;
|
|
1774
|
-
}
|
|
1775
|
-
return [defaultJudge];
|
|
1776
|
-
}
|
|
1777
|
-
function requirePositiveInteger(value, field) {
|
|
1778
|
-
if (!Number.isInteger(value) || value < 1) throw new Error(`defineAgentEval: ${field} must be a positive integer`);
|
|
1779
|
-
return value;
|
|
1780
|
-
}
|
|
1781
|
-
//#endregion
|
|
1782
|
-
export { summarizeExecution as a, analyzeRuns as i, SelfImproveRunError as n, checkCanaries as o, selfImprove as r, defineAgentEval as t };
|
|
975
|
+
export { summarizeExecution as n, checkCanaries as r, analyzeRuns as t };
|
|
1783
976
|
|
|
1784
|
-
//# sourceMappingURL=
|
|
977
|
+
//# sourceMappingURL=analyze-runs-sTygaDyD.js.map
|