@tangle-network/agent-eval 0.197.0 → 0.198.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 +55 -0
- package/README.md +3 -1
- package/dist/active-curriculum-B_Lc9kfO.js +61 -0
- package/dist/active-curriculum-B_Lc9kfO.js.map +1 -0
- package/dist/adapters/http.d.ts +2 -2
- package/dist/analyst/index.d.ts +5 -5
- package/dist/analyst/index.js +3 -3
- package/dist/{analyze-runs-B6gv7vAT.js → analyze-runs-DFbp2gB8.js} +5 -5
- package/dist/{analyze-runs-B6gv7vAT.js.map → analyze-runs-DFbp2gB8.js.map} +1 -1
- package/dist/{benchmark-command-DB7pxlks.js → benchmark-command-DKQuLrrD.js} +6 -5
- package/dist/{benchmark-command-DB7pxlks.js.map → benchmark-command-DKQuLrrD.js.map} +1 -1
- package/dist/benchmarks/index.d.ts +4 -3
- package/dist/benchmarks/index.d.ts.map +1 -1
- package/dist/benchmarks/index.js +3 -3
- package/dist/campaign/index.d.ts +5 -4
- package/dist/campaign/index.js +13 -11
- package/dist/{campaign-BUFSOI36.js → campaign-DRdKwxm-.js} +13 -12
- package/dist/{campaign-BUFSOI36.js.map → campaign-DRdKwxm-.js.map} +1 -1
- package/dist/{campaign-evidence-DJc60F9C.js → campaign-evidence-jL_U7Ikv.js} +2 -2
- package/dist/{campaign-evidence-DJc60F9C.js.map → campaign-evidence-jL_U7Ikv.js.map} +1 -1
- package/dist/cli.js +247 -13
- package/dist/cli.js.map +1 -1
- package/dist/contract/index.d.ts +7 -6
- package/dist/contract/index.js +9 -9
- package/dist/{default-registry-D2csUBBQ.d.ts → default-registry-oK9hHfX_.d.ts} +3 -3
- package/dist/{default-registry-D2csUBBQ.d.ts.map → default-registry-oK9hHfX_.d.ts.map} +1 -1
- package/dist/{define-agent-eval-ulRlLvse.d.ts → define-agent-eval-9JYoCkDI.d.ts} +5 -4
- package/dist/define-agent-eval-9JYoCkDI.d.ts.map +1 -0
- package/dist/{define-agent-eval-4J02MdF7.js → define-agent-eval-DkfcqaCF.js} +6 -6
- package/dist/{define-agent-eval-4J02MdF7.js.map → define-agent-eval-DkfcqaCF.js.map} +1 -1
- package/dist/diagnosis/index.js +1 -1
- package/dist/{dspy-rlm-engine-k_QdEBZo.js → dspy-rlm-engine-B5T43BkZ.js} +2 -2
- package/dist/{dspy-rlm-engine-k_QdEBZo.js.map → dspy-rlm-engine-B5T43BkZ.js.map} +1 -1
- package/dist/{engine-De2hfuiQ.d.ts → engine-Dc996kAg.d.ts} +2 -2
- package/dist/{engine-De2hfuiQ.d.ts.map → engine-Dc996kAg.d.ts.map} +1 -1
- package/dist/{eval-campaign-CXT2WYUe.js → eval-campaign-GapmPHIA.js} +2 -2
- package/dist/{eval-campaign-CXT2WYUe.js.map → eval-campaign-GapmPHIA.js.map} +1 -1
- package/dist/evaluation.d.ts +1 -1
- package/dist/experiment/index.d.ts +1 -1
- package/dist/experiment/index.js +8 -6
- package/dist/experiment/index.js.map +1 -1
- package/dist/{external-optimizer-process-_YIECYJ7.js → external-optimizer-process-CEXcCKqd.js} +2 -2
- package/dist/{external-optimizer-process-_YIECYJ7.js.map → external-optimizer-process-CEXcCKqd.js.map} +1 -1
- package/dist/{external-optimizer-subprocess-BrghTvEp.js → external-optimizer-subprocess-laM1-UDV.js} +2 -61
- package/dist/external-optimizer-subprocess-laM1-UDV.js.map +1 -0
- package/dist/fuzz.d.ts.map +1 -1
- package/dist/fuzz.js +2 -3
- package/dist/fuzz.js.map +1 -1
- package/dist/hosted/index.js +1 -1
- package/dist/{index-DJKZEldg.d.ts → index-BXJHJ_jE.d.ts} +12 -947
- package/dist/index-BXJHJ_jE.d.ts.map +1 -0
- package/dist/{index-CRsmcAGl.d.ts → index-DzQ6T34s.d.ts} +6 -6
- package/dist/{index-CRsmcAGl.d.ts.map → index-DzQ6T34s.d.ts.map} +1 -1
- package/dist/{index-kKECJfib.d.ts → index-lbwvO9vJ.d.ts} +3 -3
- package/dist/{index-kKECJfib.d.ts.map → index-lbwvO9vJ.d.ts.map} +1 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.js +15 -13
- package/dist/index.js.map +1 -1
- package/dist/jev.d.ts +1 -1
- package/dist/{llm-judge-fhkFQL1N.js → llm-judge-3ncNcWNT.js} +415 -1981
- package/dist/llm-judge-3ncNcWNT.js.map +1 -0
- package/dist/{matrix-C1X-fIVX.d.ts → matrix-BnksRaDD.d.ts} +2 -2
- package/dist/{matrix-C1X-fIVX.d.ts.map → matrix-BnksRaDD.d.ts.map} +1 -1
- package/dist/multiplicity-D9cjmStq.js +101 -0
- package/dist/multiplicity-D9cjmStq.js.map +1 -0
- package/dist/multishot/golden/index.d.ts +1 -1
- package/dist/multishot/golden/index.js +1 -1
- package/dist/multishot/index.d.ts +2 -2
- package/dist/multishot/index.js +1 -1
- package/dist/openapi.json +1 -1
- package/dist/{paired-arms-JSDcs2zx.js → paired-arms-DKZFVPt8.js} +4 -398
- package/dist/paired-arms-DKZFVPt8.js.map +1 -0
- package/dist/paired-binary-fzkwENI4.js +399 -0
- package/dist/paired-binary-fzkwENI4.js.map +1 -0
- package/dist/{paired-promotion-decision-DTKl6-G8.js → paired-promotion-decision-D5B1Cxc2.js} +78 -5
- package/dist/paired-promotion-decision-D5B1Cxc2.js.map +1 -0
- package/dist/{power-and-mde-BJOpt6pq.js → power-and-mde-K_CmO3dc.js} +3 -101
- package/dist/power-and-mde-K_CmO3dc.js.map +1 -0
- package/dist/{produced-state-1RnbLrSa.js → produced-state-qIhqN3V5.js} +3 -3
- package/dist/{produced-state-1RnbLrSa.js.map → produced-state-qIhqN3V5.js.map} +1 -1
- package/dist/{promotion-policy-Cy5OV8BV.js → promotion-policy-C6FAJvmZ.js} +3 -3
- package/dist/{promotion-policy-Cy5OV8BV.js.map → promotion-policy-C6FAJvmZ.js.map} +1 -1
- package/dist/reporting.js +3 -3
- package/dist/rl.d.ts +17 -39
- package/dist/rl.d.ts.map +1 -1
- package/dist/rl.js +5 -5
- package/dist/search/index.d.ts +1187 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +187 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search-kernel-CumYAjA3.js +2427 -0
- package/dist/search-kernel-CumYAjA3.js.map +1 -0
- package/dist/search-kernel-TLoiMMcq.d.ts +1185 -0
- package/dist/search-kernel-TLoiMMcq.d.ts.map +1 -0
- package/dist/{search-ledger-9W0g5FP6.js → search-ledger-BnUytR8X.js} +3 -1
- package/dist/search-ledger-BnUytR8X.js.map +1 -0
- package/dist/{search-shipper-CYbmJQx8.js → search-shipper-Cn8cxcyp.js} +2 -2
- package/dist/{search-shipper-CYbmJQx8.js.map → search-shipper-Cn8cxcyp.js.map} +1 -1
- package/dist/search-summary-dJOaZ3Dw.js +133 -0
- package/dist/search-summary-dJOaZ3Dw.js.map +1 -0
- package/dist/{semantic-concept-judge-Bh5lvKGg.js → semantic-concept-judge-2SE_kXGF.js} +2 -2
- package/dist/{semantic-concept-judge-Bh5lvKGg.js.map → semantic-concept-judge-2SE_kXGF.js.map} +1 -1
- package/dist/{sequential-C21_PP7F.js → sequential-Yz3OSskl.js} +2 -2
- package/dist/{sequential-C21_PP7F.js.map → sequential-Yz3OSskl.js.map} +1 -1
- package/dist/single-run-lock-fVu3MZWH.js +62 -0
- package/dist/single-run-lock-fVu3MZWH.js.map +1 -0
- package/dist/{skillopt-optimization-method-CHUcZ8w6.js → skillopt-optimization-method-BL_j6mX8.js} +8 -7
- package/dist/{skillopt-optimization-method-CHUcZ8w6.js.map → skillopt-optimization-method-BL_j6mX8.js.map} +1 -1
- package/dist/{statistical-heldout-DANVmyug.js → statistical-heldout-BAFDCo07.js} +2 -2
- package/dist/{statistical-heldout-DANVmyug.js.map → statistical-heldout-BAFDCo07.js.map} +1 -1
- package/dist/{statistical-heldout-BedVSZb2.d.ts → statistical-heldout-CMpxMjlQ.d.ts} +2 -2
- package/dist/{statistical-heldout-BedVSZb2.d.ts.map → statistical-heldout-CMpxMjlQ.d.ts.map} +1 -1
- package/dist/{store-tool-spans-CawP-WxM.d.ts → store-tool-spans-CUwWSXoj.d.ts} +3 -3
- package/dist/{store-tool-spans-CawP-WxM.d.ts.map → store-tool-spans-CUwWSXoj.d.ts.map} +1 -1
- package/dist/{summary-report-BMvou2oZ.js → summary-report-BeYnvddy.js} +4 -3
- package/dist/{summary-report-BMvou2oZ.js.map → summary-report-BeYnvddy.js.map} +1 -1
- package/dist/{tool-groups-B4JVrH3g.d.ts → tool-groups-DVJAR1GE.d.ts} +2 -2
- package/dist/tool-groups-DVJAR1GE.d.ts.map +1 -0
- package/dist/trace-repair/index.d.ts +1 -1
- package/dist/traces.d.ts +2 -2
- package/dist/tree-DxGfhISA.js +4100 -0
- package/dist/tree-DxGfhISA.js.map +1 -0
- package/dist/{types-B3jzCp0p.js → types-B3jzCp0p2.js} +1 -1
- package/dist/types-B3jzCp0p2.js.map +1 -0
- package/dist/{types-CjFDKMDe.d.ts → types-D94EanDL.d.ts} +2 -2
- package/dist/{types-CjFDKMDe.d.ts.map → types-D94EanDL.d.ts.map} +1 -1
- package/dist/{types-B2673PBj.d.ts → types-EBUav9Bu.d.ts} +8 -4
- package/dist/types-EBUav9Bu.d.ts.map +1 -0
- package/docs/campaign-proposers.md +2 -0
- package/docs/design/statistics-decisions.md +1 -1
- package/docs/search-ledger.md +145 -8
- package/docs/trace-contracts.md +1 -3
- package/package.json +6 -1
- package/dist/active-curriculum-OjIWgrUJ.js +0 -204
- package/dist/active-curriculum-OjIWgrUJ.js.map +0 -1
- package/dist/define-agent-eval-ulRlLvse.d.ts.map +0 -1
- package/dist/external-optimizer-subprocess-BrghTvEp.js.map +0 -1
- package/dist/index-DJKZEldg.d.ts.map +0 -1
- package/dist/llm-judge-fhkFQL1N.js.map +0 -1
- package/dist/paired-arms-JSDcs2zx.js.map +0 -1
- package/dist/paired-delta-test-BF-FEP8V.js +0 -78
- package/dist/paired-delta-test-BF-FEP8V.js.map +0 -1
- package/dist/paired-promotion-decision-DTKl6-G8.js.map +0 -1
- package/dist/power-and-mde-BJOpt6pq.js.map +0 -1
- package/dist/search-ledger-9W0g5FP6.js.map +0 -1
- package/dist/search-summary-CcavvYLe.js +0 -378
- package/dist/search-summary-CcavvYLe.js.map +0 -1
- package/dist/tool-groups-B4JVrH3g.d.ts.map +0 -1
- package/dist/types-B2673PBj.d.ts.map +0 -1
- package/dist/types-B3jzCp0p.js.map +0 -1
|
@@ -1,378 +0,0 @@
|
|
|
1
|
-
import { a as hashCanonical, i as compareCodeUnits } from "./canonical-BsZVgBhW.js";
|
|
2
|
-
import { n as DECISION_PAIRED_DELTA_STATISTIC } from "./paired-tests-C8iCsioC.js";
|
|
3
|
-
import { n as pairedDeltaTest, t as minimumPairsForPairedDeltaTest } from "./paired-delta-test-BF-FEP8V.js";
|
|
4
|
-
import { a as SearchLedgerError } from "./search-ledger-file-DY0AXX3W.js";
|
|
5
|
-
import { f as searchUnitScores } from "./search-ledger-9W0g5FP6.js";
|
|
6
|
-
//#region src/campaign/estimate-node.ts
|
|
7
|
-
/**
|
|
8
|
-
* Per-node statistics of a search.
|
|
9
|
-
*
|
|
10
|
-
* `estimateNode` is the one paired contrast of two nodes: it averages each
|
|
11
|
-
* node's cells inside their units, pairs the units both nodes scored, and runs
|
|
12
|
-
* `pairedDeltaTest` on the per-unit deltas. `estimateNodeFromCells` is the same
|
|
13
|
-
* computation over cells a caller already holds, such as rows a server read
|
|
14
|
-
* from its database. The bootstrap seed comes from `cellSetDigest`, the digest
|
|
15
|
-
* of exactly the cells used, so a producer and a verifier that hold the same
|
|
16
|
-
* cells report the same bits.
|
|
17
|
-
*
|
|
18
|
-
* `searchPosterior` gives every node a normal posterior on its improvement over
|
|
19
|
-
* the root, which expansion policies sample parents from. Its numbers steer
|
|
20
|
-
* spend and claim nothing.
|
|
21
|
-
*/
|
|
22
|
-
const CONFIDENCE = .95;
|
|
23
|
-
const RESAMPLES = 2e3;
|
|
24
|
-
/** 6 at 95 %: the smallest sample an exact one-sided sign test can resolve. */
|
|
25
|
-
const DESCRIPTIVE_FROM$1 = minimumPairsForPairedDeltaTest(CONFIDENCE);
|
|
26
|
-
/** The estimator every `NodeEstimate` names. */
|
|
27
|
-
const SEARCH_ESTIMATOR = {
|
|
28
|
-
uri: "npm:@tangle-network/agent-eval#estimateNode",
|
|
29
|
-
revision: hashCanonical({
|
|
30
|
-
name: "tangle.estimate-node.2026-09",
|
|
31
|
-
unit: "mean of the unit’s scored cells, summed in cellId order",
|
|
32
|
-
pairing: "units both nodes scored, in unitId order",
|
|
33
|
-
statistic: DECISION_PAIRED_DELTA_STATISTIC,
|
|
34
|
-
interval: "percentile paired bootstrap",
|
|
35
|
-
confidence: CONFIDENCE,
|
|
36
|
-
resamples: RESAMPLES,
|
|
37
|
-
rng: "mulberry32",
|
|
38
|
-
seed: "the first 32 bits of cellSetDigest",
|
|
39
|
-
signTest: "exact, one-sided toward improvement in the objective direction",
|
|
40
|
-
methods: {
|
|
41
|
-
none: "below 2 pairs",
|
|
42
|
-
insufficient: `below ${DESCRIPTIVE_FROM$1} pairs`,
|
|
43
|
-
descriptive: `below 20 pairs`,
|
|
44
|
-
bootstrap: `from 20 pairs`
|
|
45
|
-
},
|
|
46
|
-
indeterminate: "every paired delta equal: no interval and no sign p"
|
|
47
|
-
})
|
|
48
|
-
};
|
|
49
|
-
/** The method a paired sample of `pairs` units supports. */
|
|
50
|
-
function searchEstimateMethod(pairs) {
|
|
51
|
-
if (pairs < 2) return "none";
|
|
52
|
-
if (pairs < DESCRIPTIVE_FROM$1) return "insufficient";
|
|
53
|
-
if (pairs < 20) return "descriptive";
|
|
54
|
-
return "bootstrap";
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Digest of the cells an estimate reads, with the contrast they serve. Cells
|
|
58
|
-
* are listed in cellId order, so the digest names the set, not the order it
|
|
59
|
-
* was read in.
|
|
60
|
-
*/
|
|
61
|
-
function searchCellSetDigest(input) {
|
|
62
|
-
const list = (cells) => [...cells].sort((left, right) => compareCodeUnits(left.cellId, right.cellId)).map((cell) => [
|
|
63
|
-
cell.cellId,
|
|
64
|
-
cell.unitId,
|
|
65
|
-
cell.attempt,
|
|
66
|
-
cell.score
|
|
67
|
-
]);
|
|
68
|
-
return hashCanonical({
|
|
69
|
-
contrast: [input.nodeId, input.against],
|
|
70
|
-
split: input.split,
|
|
71
|
-
nodeCells: list(input.nodeCells),
|
|
72
|
-
againstCells: list(input.againstCells)
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* The paired contrast of `nodeId` against `against` on the units both scored.
|
|
77
|
-
*
|
|
78
|
-
* `delta` is the mean per-unit difference, node minus `against`, in the
|
|
79
|
-
* metric's own units; for a `minimize` objective an improvement is negative.
|
|
80
|
-
* The exact sign test is one-sided toward improvement in the objective's
|
|
81
|
-
* direction. Unscored cells (errored, cancelled or in flight) are absent from
|
|
82
|
-
* the inputs, never zero.
|
|
83
|
-
*
|
|
84
|
-
* - `none` (0 or 1 pair): no delta.
|
|
85
|
-
* - `insufficient` (2 to 5): the delta only.
|
|
86
|
-
* - `descriptive` (6 to 19): the bootstrap interval as spread, and the sign-test p.
|
|
87
|
-
* - `bootstrap` (20 or more): the decision-grade bootstrap interval.
|
|
88
|
-
*
|
|
89
|
-
* When every paired delta is equal the interval would have zero width, which
|
|
90
|
-
* is an absence of evidence; the estimate is then `indeterminate` and carries
|
|
91
|
-
* neither an interval nor a p-value.
|
|
92
|
-
*/
|
|
93
|
-
function estimateNodeFromCells(input) {
|
|
94
|
-
const { nodeId, against, split, direction } = input;
|
|
95
|
-
if (nodeId === against) throw new SearchLedgerError(`node ${nodeId} cannot be estimated against itself`);
|
|
96
|
-
assertDistinctCells([...input.nodeCells, ...input.againstCells], nodeId, against);
|
|
97
|
-
const cellSetDigest = searchCellSetDigest(input);
|
|
98
|
-
const nodeUnits = searchUnitScores(input.nodeCells);
|
|
99
|
-
const { node, other } = pairUnits(nodeUnits, unitMeans(searchUnitScores(input.againstCells)));
|
|
100
|
-
const pairs = node.length;
|
|
101
|
-
const method = searchEstimateMethod(pairs);
|
|
102
|
-
const base = {
|
|
103
|
-
against,
|
|
104
|
-
split,
|
|
105
|
-
units: nodeUnits.length,
|
|
106
|
-
pairs,
|
|
107
|
-
method,
|
|
108
|
-
cellSetDigest,
|
|
109
|
-
estimator: SEARCH_ESTIMATOR
|
|
110
|
-
};
|
|
111
|
-
if (method === "none") return {
|
|
112
|
-
...base,
|
|
113
|
-
delta: null,
|
|
114
|
-
interval: null,
|
|
115
|
-
exactSignP: null,
|
|
116
|
-
indeterminate: false
|
|
117
|
-
};
|
|
118
|
-
const maximize = direction === "maximize";
|
|
119
|
-
const test = pairedDeltaTest(maximize ? other : node, maximize ? node : other, {
|
|
120
|
-
statistic: DECISION_PAIRED_DELTA_STATISTIC,
|
|
121
|
-
confidence: CONFIDENCE,
|
|
122
|
-
resamples: RESAMPLES,
|
|
123
|
-
seed: seedFromDigest(cellSetDigest)
|
|
124
|
-
});
|
|
125
|
-
const { mean, low, high } = test.bootstrap;
|
|
126
|
-
const indeterminate = test.indeterminate;
|
|
127
|
-
const spread = (method === "descriptive" || method === "bootstrap") && !indeterminate;
|
|
128
|
-
return {
|
|
129
|
-
...base,
|
|
130
|
-
delta: plain(maximize ? mean : -mean),
|
|
131
|
-
interval: spread ? maximize ? [plain(low), plain(high)] : [plain(-high), plain(-low)] : null,
|
|
132
|
-
exactSignP: method === "descriptive" && !indeterminate ? test.pValue : null,
|
|
133
|
-
indeterminate
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* `estimateNodeFromCells` over the cells a search state holds: `nodeId`
|
|
138
|
-
* against `against` on one split, in the direction the search's objective
|
|
139
|
-
* declares.
|
|
140
|
-
*/
|
|
141
|
-
function estimateNode(state, nodeId, options) {
|
|
142
|
-
const header = state.header;
|
|
143
|
-
if (!header) throw new SearchLedgerError(`search ${state.searchId} has not been opened`);
|
|
144
|
-
for (const id of [nodeId, options.against]) if (!state.hasNode(id)) throw new SearchLedgerError(`node ${id} is not in search ${state.searchId}`);
|
|
145
|
-
return estimateNodeFromCells({
|
|
146
|
-
nodeId,
|
|
147
|
-
against: options.against,
|
|
148
|
-
split: options.split,
|
|
149
|
-
direction: header.objective.direction,
|
|
150
|
-
nodeCells: state.scoredCells(nodeId, options.split),
|
|
151
|
-
againstCells: state.scoredCells(options.against, options.split)
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* The posterior every node's parent-selection draw uses. Each node's mean is
|
|
156
|
-
* its improvement over the root on shared units; its variance is the search's
|
|
157
|
-
* pooled between-unit variance divided by its unit count, so a node measured
|
|
158
|
-
* on one unit has a wide posterior rather than none. The root is the reference
|
|
159
|
-
* and sits at exactly 0.
|
|
160
|
-
*/
|
|
161
|
-
function searchPosterior(state, options = {}) {
|
|
162
|
-
const split = options.split ?? "selection";
|
|
163
|
-
const header = state.header;
|
|
164
|
-
if (!header) throw new SearchLedgerError(`search ${state.searchId} has not been opened`);
|
|
165
|
-
const rootNodeId = state.rootNodeId;
|
|
166
|
-
if (rootNodeId === null) throw new SearchLedgerError(`search ${state.searchId} has no root node yet`);
|
|
167
|
-
const sign = header.objective.direction === "maximize" ? 1 : -1;
|
|
168
|
-
const root = searchUnitScores(state.scoredCells(rootNodeId, split));
|
|
169
|
-
const rootMeans = unitMeans(root);
|
|
170
|
-
const nodes = [];
|
|
171
|
-
let squares = 0;
|
|
172
|
-
let degreesOfFreedom = 0;
|
|
173
|
-
for (const nodeId of state.nodeIds()) {
|
|
174
|
-
if (nodeId === rootNodeId) {
|
|
175
|
-
const measured = root.length > 0;
|
|
176
|
-
nodes.push({
|
|
177
|
-
nodeId,
|
|
178
|
-
pairs: root.length,
|
|
179
|
-
mean: measured ? 0 : null,
|
|
180
|
-
variance: measured ? 0 : null
|
|
181
|
-
});
|
|
182
|
-
continue;
|
|
183
|
-
}
|
|
184
|
-
const { node, other } = pairUnits(searchUnitScores(state.scoredCells(nodeId, split)), rootMeans);
|
|
185
|
-
const gains = node.map((value, index) => sign * (value - other[index]));
|
|
186
|
-
const mean = gains.length > 0 ? sum(gains) / gains.length : null;
|
|
187
|
-
if (mean !== null && gains.length >= 2) {
|
|
188
|
-
squares += sum(gains.map((gain) => (gain - mean) ** 2));
|
|
189
|
-
degreesOfFreedom += gains.length - 1;
|
|
190
|
-
}
|
|
191
|
-
nodes.push({
|
|
192
|
-
nodeId,
|
|
193
|
-
pairs: gains.length,
|
|
194
|
-
mean: mean === null ? null : plain(mean),
|
|
195
|
-
variance: null
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
const pooledVariance = degreesOfFreedom > 0 ? squares / degreesOfFreedom : null;
|
|
199
|
-
if (pooledVariance !== null) {
|
|
200
|
-
for (const posterior of nodes) if (posterior.nodeId !== rootNodeId && posterior.pairs > 0) posterior.variance = pooledVariance / posterior.pairs;
|
|
201
|
-
}
|
|
202
|
-
return {
|
|
203
|
-
split,
|
|
204
|
-
rootNodeId,
|
|
205
|
-
pooledVariance,
|
|
206
|
-
degreesOfFreedom,
|
|
207
|
-
nodes
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
function unitMeans(units) {
|
|
211
|
-
return new Map(units.map((unit) => [unit.unitId, unit.mean]));
|
|
212
|
-
}
|
|
213
|
-
/** Unit means of two nodes on the units both scored, aligned in the node's
|
|
214
|
-
* unitId order. */
|
|
215
|
-
function pairUnits(node, otherMeans) {
|
|
216
|
-
const paired = {
|
|
217
|
-
node: [],
|
|
218
|
-
other: []
|
|
219
|
-
};
|
|
220
|
-
for (const unit of node) {
|
|
221
|
-
const mean = otherMeans.get(unit.unitId);
|
|
222
|
-
if (mean === void 0) continue;
|
|
223
|
-
paired.node.push(unit.mean);
|
|
224
|
-
paired.other.push(mean);
|
|
225
|
-
}
|
|
226
|
-
return paired;
|
|
227
|
-
}
|
|
228
|
-
function assertDistinctCells(cells, nodeId, against) {
|
|
229
|
-
const seen = /* @__PURE__ */ new Set();
|
|
230
|
-
for (const cell of cells) {
|
|
231
|
-
if (seen.has(cell.cellId)) throw new SearchLedgerError(`cell ${cell.cellId} appears twice in the estimate of ${nodeId} against ${against}`);
|
|
232
|
-
if (!Number.isFinite(cell.score)) throw new SearchLedgerError(`cell ${cell.cellId} has a non-finite score ${cell.score}`);
|
|
233
|
-
seen.add(cell.cellId);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
/** The first 32 bits of a `sha256:` digest, as a bootstrap's seed. */
|
|
237
|
-
function seedFromDigest(digest) {
|
|
238
|
-
return Number.parseInt(digest.slice(7, 15), 16) | 0;
|
|
239
|
-
}
|
|
240
|
-
function sum(values) {
|
|
241
|
-
let total = 0;
|
|
242
|
-
for (const value of values) total += value;
|
|
243
|
-
return total;
|
|
244
|
-
}
|
|
245
|
-
/** Canonical JSON has one zero; never hand it a negative one. */
|
|
246
|
-
function plain(value) {
|
|
247
|
-
return value === 0 ? 0 : value;
|
|
248
|
-
}
|
|
249
|
-
//#endregion
|
|
250
|
-
//#region src/campaign/search-summary.ts
|
|
251
|
-
/**
|
|
252
|
-
* The agent's view of a search: the same projection a human reads.
|
|
253
|
-
*
|
|
254
|
-
* `renderSearchSummary` turns a `SearchStateView` into compact text — the
|
|
255
|
-
* leading nodes with their estimates, the most recently discarded ideas with
|
|
256
|
-
* why they were discarded, and a log of recent proposals — as AIDE's journal
|
|
257
|
-
* summary does for its own search. `agent-eval search show <ledger>` prints
|
|
258
|
-
* the same text for a terminal; `runOptimization` puts it on every
|
|
259
|
-
* `ProposeContext` a proposer receives.
|
|
260
|
-
*
|
|
261
|
-
* `searchProposerView` is the train-only read `ProposeContext.train` carries.
|
|
262
|
-
* It has no parameter that can select another split, so a proposer built on
|
|
263
|
-
* it cannot reach the selection or test split even by mistake: the sealed
|
|
264
|
-
* splits (§6.6 of the search-tree design) are unreachable by construction,
|
|
265
|
-
* not by convention.
|
|
266
|
-
*/
|
|
267
|
-
const DESCRIPTIVE_FROM = minimumPairsForPairedDeltaTest(.95);
|
|
268
|
-
/** The train-only view `ProposeContext.train` carries. */
|
|
269
|
-
function searchProposerView(state) {
|
|
270
|
-
const header = state.header;
|
|
271
|
-
if (!header) throw new SearchLedgerError(`search ${state.searchId} has not been opened`);
|
|
272
|
-
return {
|
|
273
|
-
searchId: state.searchId,
|
|
274
|
-
direction: header.objective.direction,
|
|
275
|
-
scoredCells: (nodeId) => state.scoredCells(nodeId, "train"),
|
|
276
|
-
unitScores: (nodeId) => state.unitScores(nodeId, "train")
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
/**
|
|
280
|
-
* `SearchState` as compact text: a header line with the search's shape and
|
|
281
|
-
* spend, the leading nodes against the root with their estimates, the most
|
|
282
|
-
* recently discarded nodes with the measurement that discarded them, and a
|
|
283
|
-
* log of recent proposals (operator and label — the ledger's inline,
|
|
284
|
-
* redacted summary of each rationale; the full rationale is a blob this
|
|
285
|
-
* function never reads, so it stays a pure, I/O-free projection of the
|
|
286
|
-
* state already in hand).
|
|
287
|
-
*/
|
|
288
|
-
function renderSearchSummary(state, options) {
|
|
289
|
-
const header = state.header;
|
|
290
|
-
if (!header) return `search ${state.searchId}: not yet opened`;
|
|
291
|
-
const limit = options.limit ?? 5;
|
|
292
|
-
if (limit < 1 || !Number.isInteger(limit)) throw new SearchLedgerError(`renderSearchSummary: limit must be a positive integer, got ${limit}`);
|
|
293
|
-
const split = options.split;
|
|
294
|
-
const direction = header.objective.direction;
|
|
295
|
-
const root = state.rootNodeId;
|
|
296
|
-
const lines = [
|
|
297
|
-
headerLine(state),
|
|
298
|
-
spendLine(state),
|
|
299
|
-
statusLine(state)
|
|
300
|
-
];
|
|
301
|
-
if (root === null) {
|
|
302
|
-
lines.push("", "No nodes yet.");
|
|
303
|
-
return lines.join("\n");
|
|
304
|
-
}
|
|
305
|
-
const others = state.nodes().filter((node) => node.nodeId !== root);
|
|
306
|
-
const leading = others.filter((node) => node.status !== "invalid").map((node) => ({
|
|
307
|
-
node,
|
|
308
|
-
estimate: estimateNode(state, node.nodeId, {
|
|
309
|
-
against: root,
|
|
310
|
-
split
|
|
311
|
-
})
|
|
312
|
-
})).filter(({ estimate }) => estimate.delta !== null).sort((a, b) => signed(b.estimate, direction) - signed(a.estimate, direction)).slice(0, limit);
|
|
313
|
-
lines.push("", `Leading nodes (vs root, ${split} split):`);
|
|
314
|
-
if (leading.length === 0) lines.push(" none measured yet");
|
|
315
|
-
for (const { node, estimate } of leading) lines.push(` ${nodeLine(node)}: ${formatEstimate(estimate)}`);
|
|
316
|
-
const discarded = others.filter((node) => node.status === "pruned" || node.status === "rejected" || node.status === "invalid").sort((a, b) => b.updatedSequence - a.updatedSequence).slice(0, limit);
|
|
317
|
-
lines.push("", "Recently discarded:");
|
|
318
|
-
if (discarded.length === 0) lines.push(" none yet");
|
|
319
|
-
for (const node of discarded) lines.push(` ${nodeLine(node)}: ${discardLine(node)}`);
|
|
320
|
-
const recent = [...state.edges()].reverse().slice(0, limit);
|
|
321
|
-
lines.push("", "Recent proposals:");
|
|
322
|
-
if (recent.length === 0) lines.push(" none yet");
|
|
323
|
-
for (const edge of recent) {
|
|
324
|
-
const childId = edge.childNodeId;
|
|
325
|
-
const label = edge.label.length > 0 ? edge.label : "(no label)";
|
|
326
|
-
lines.push(` ${edge.operator} → ${childId}: ${label}`);
|
|
327
|
-
}
|
|
328
|
-
return lines.join("\n");
|
|
329
|
-
}
|
|
330
|
-
function headerLine(state) {
|
|
331
|
-
const header = state.header;
|
|
332
|
-
return `search ${state.searchId} — ${header.subject} — ${header.objective.direction} ${header.objective.metric}`;
|
|
333
|
-
}
|
|
334
|
-
function spendLine(state) {
|
|
335
|
-
const { audit } = state;
|
|
336
|
-
const known = audit.spend.knownUsd.toFixed(2);
|
|
337
|
-
const floor = audit.spend.floorUsd.toFixed(2);
|
|
338
|
-
const unknown = audit.spend.unknownCostCells;
|
|
339
|
-
const floorPart = unknown > 0 ? ` + floor $${floor} across ${unknown} unknown-cost cell${unknown === 1 ? "" : "s"}` : "";
|
|
340
|
-
return ` ${audit.nodes} nodes · ${audit.cells.settled} settled cells (${audit.cells.open} open) · $${known} known${floorPart}`;
|
|
341
|
-
}
|
|
342
|
-
function statusLine(state) {
|
|
343
|
-
if (!state.closed) return " status: open";
|
|
344
|
-
const claim = state.closed.claim;
|
|
345
|
-
const claimText = claim === null ? "" : claim.decision === "ship" ? ` · claim: ship ${claim.selected}` : ` · claim: ${claim.decision}`;
|
|
346
|
-
return ` status: closed (${state.closed.reason})${claimText}`;
|
|
347
|
-
}
|
|
348
|
-
function nodeLine(node) {
|
|
349
|
-
const rung = node.status === "advanced" ? ` rung ${node.rung}` : "";
|
|
350
|
-
return `${node.nodeId} (${node.status ?? "undecided"}${rung})`;
|
|
351
|
-
}
|
|
352
|
-
function discardLine(node) {
|
|
353
|
-
const decision = node.decisions.at(-1);
|
|
354
|
-
if (!decision) return "no decision recorded";
|
|
355
|
-
return `${decision.basis === null ? "no measured basis" : formatEstimate(decision.basis)} — ${decision.rule}: ${decision.reason}`;
|
|
356
|
-
}
|
|
357
|
-
/** `estimate.delta` in the objective's own units; positive is always better. */
|
|
358
|
-
function signed(estimate, direction) {
|
|
359
|
-
if (estimate.delta === null) return Number.NEGATIVE_INFINITY;
|
|
360
|
-
return direction === "maximize" ? estimate.delta : -estimate.delta;
|
|
361
|
-
}
|
|
362
|
-
/** The display rules of search-tree-design §6.4: no whisker below 6 shared
|
|
363
|
-
* units, a dashed descriptive interval with its exact sign p from 6 to 19,
|
|
364
|
-
* a decision-grade whisker from `BOOTSTRAP_GATE_MIN_N`. */
|
|
365
|
-
function formatEstimate(estimate) {
|
|
366
|
-
const unit = (n) => `${n} unit${n === 1 ? "" : "s"}`;
|
|
367
|
-
if (estimate.method === "none") return `unknown (${unit(estimate.pairs)})`;
|
|
368
|
-
if (estimate.indeterminate) return `no measurable difference (indeterminate, ${unit(estimate.pairs)})`;
|
|
369
|
-
const delta = estimate.delta === null ? "null" : (estimate.delta >= 0 ? "+" : "") + estimate.delta.toFixed(4);
|
|
370
|
-
if (estimate.method === "insufficient") return `Δ=${delta} (${estimate.pairs} of ${DESCRIPTIVE_FROM} units, insufficient)`;
|
|
371
|
-
const interval = estimate.interval ? ` [${estimate.interval[0].toFixed(4)}, ${estimate.interval[1].toFixed(4)}]` : "";
|
|
372
|
-
if (estimate.method === "descriptive") return `Δ=${delta}${interval} dashed, sign p=${estimate.exactSignP === null ? "null" : estimate.exactSignP.toPrecision(3)} (${unit(estimate.pairs)})`;
|
|
373
|
-
return `Δ=${delta}${interval} (${unit(estimate.pairs)}, ≥20)`;
|
|
374
|
-
}
|
|
375
|
-
//#endregion
|
|
376
|
-
export { estimateNodeFromCells as a, seedFromDigest as c, estimateNode as i, searchProposerView as n, searchCellSetDigest as o, SEARCH_ESTIMATOR as r, searchPosterior as s, renderSearchSummary as t };
|
|
377
|
-
|
|
378
|
-
//# sourceMappingURL=search-summary-CcavvYLe.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"search-summary-CcavvYLe.js","names":["DESCRIPTIVE_FROM"],"sources":["../src/campaign/estimate-node.ts","../src/campaign/search-summary.ts"],"sourcesContent":["/**\n * Per-node statistics of a search.\n *\n * `estimateNode` is the one paired contrast of two nodes: it averages each\n * node's cells inside their units, pairs the units both nodes scored, and runs\n * `pairedDeltaTest` on the per-unit deltas. `estimateNodeFromCells` is the same\n * computation over cells a caller already holds, such as rows a server read\n * from its database. The bootstrap seed comes from `cellSetDigest`, the digest\n * of exactly the cells used, so a producer and a verifier that hold the same\n * cells report the same bits.\n *\n * `searchPosterior` gives every node a normal posterior on its improvement over\n * the root, which expansion policies sample parents from. Its numbers steer\n * spend and claim nothing.\n */\n\nimport { compareCodeUnits, hashCanonical } from '../ledger-core/canonical'\nimport { minimumPairsForPairedDeltaTest, pairedDeltaTest } from '../paired-delta-test'\nimport { BOOTSTRAP_GATE_MIN_N, DECISION_PAIRED_DELTA_STATISTIC } from '../statistics'\nimport { SearchLedgerError } from './search-ledger-errors'\nimport type {\n NodeEstimate,\n SearchEstimateMethod,\n SearchLedgerHash,\n SearchSourceRef,\n SearchSplit,\n} from './search-ledger-types'\nimport {\n type SearchScoredCell,\n type SearchStateView,\n type SearchUnitScore,\n searchUnitScores,\n} from './search-state'\n\nconst CONFIDENCE = 0.95\nconst RESAMPLES = 2000\n/** 6 at 95 %: the smallest sample an exact one-sided sign test can resolve. */\nconst DESCRIPTIVE_FROM = minimumPairsForPairedDeltaTest(CONFIDENCE)\n\n/**\n * Every choice the numbers depend on. Its digest is the estimator's revision:\n * a producer and a verifier that report the same revision and the same\n * `cellSetDigest` report the same estimate. Change a value here whenever the\n * computation changes, so the revision moves with it.\n */\nconst ESTIMATOR_DEFINITION = {\n name: 'tangle.estimate-node.2026-09',\n unit: 'mean of the unit’s scored cells, summed in cellId order',\n pairing: 'units both nodes scored, in unitId order',\n statistic: DECISION_PAIRED_DELTA_STATISTIC,\n interval: 'percentile paired bootstrap',\n confidence: CONFIDENCE,\n resamples: RESAMPLES,\n rng: 'mulberry32',\n seed: 'the first 32 bits of cellSetDigest',\n signTest: 'exact, one-sided toward improvement in the objective direction',\n methods: {\n none: 'below 2 pairs',\n insufficient: `below ${DESCRIPTIVE_FROM} pairs`,\n descriptive: `below ${BOOTSTRAP_GATE_MIN_N} pairs`,\n bootstrap: `from ${BOOTSTRAP_GATE_MIN_N} pairs`,\n },\n indeterminate: 'every paired delta equal: no interval and no sign p',\n} as const\n\n/** The estimator every `NodeEstimate` names. */\nexport const SEARCH_ESTIMATOR: SearchSourceRef = {\n uri: 'npm:@tangle-network/agent-eval#estimateNode',\n revision: hashCanonical(ESTIMATOR_DEFINITION),\n}\n\n/** The method a paired sample of `pairs` units supports. */\nfunction searchEstimateMethod(pairs: number): SearchEstimateMethod {\n if (pairs < 2) return 'none'\n if (pairs < DESCRIPTIVE_FROM) return 'insufficient'\n if (pairs < BOOTSTRAP_GATE_MIN_N) return 'descriptive'\n return 'bootstrap'\n}\n\nexport interface EstimateNodeCellsInput {\n nodeId: string\n against: string\n split: SearchSplit\n direction: 'maximize' | 'minimize'\n /** Every scored cell of `nodeId` on `split`. */\n nodeCells: readonly SearchScoredCell[]\n /** Every scored cell of `against` on `split`. */\n againstCells: readonly SearchScoredCell[]\n}\n\n/**\n * Digest of the cells an estimate reads, with the contrast they serve. Cells\n * are listed in cellId order, so the digest names the set, not the order it\n * was read in.\n */\nexport function searchCellSetDigest(\n input: Omit<EstimateNodeCellsInput, 'direction'>,\n): SearchLedgerHash {\n const list = (cells: readonly SearchScoredCell[]) =>\n [...cells]\n .sort((left, right) => compareCodeUnits(left.cellId, right.cellId))\n .map((cell) => [cell.cellId, cell.unitId, cell.attempt, cell.score])\n return hashCanonical({\n contrast: [input.nodeId, input.against],\n split: input.split,\n nodeCells: list(input.nodeCells),\n againstCells: list(input.againstCells),\n })\n}\n\n/**\n * The paired contrast of `nodeId` against `against` on the units both scored.\n *\n * `delta` is the mean per-unit difference, node minus `against`, in the\n * metric's own units; for a `minimize` objective an improvement is negative.\n * The exact sign test is one-sided toward improvement in the objective's\n * direction. Unscored cells (errored, cancelled or in flight) are absent from\n * the inputs, never zero.\n *\n * - `none` (0 or 1 pair): no delta.\n * - `insufficient` (2 to 5): the delta only.\n * - `descriptive` (6 to 19): the bootstrap interval as spread, and the sign-test p.\n * - `bootstrap` (20 or more): the decision-grade bootstrap interval.\n *\n * When every paired delta is equal the interval would have zero width, which\n * is an absence of evidence; the estimate is then `indeterminate` and carries\n * neither an interval nor a p-value.\n */\nexport function estimateNodeFromCells(input: EstimateNodeCellsInput): NodeEstimate {\n const { nodeId, against, split, direction } = input\n if (nodeId === against) {\n throw new SearchLedgerError(`node ${nodeId} cannot be estimated against itself`)\n }\n assertDistinctCells([...input.nodeCells, ...input.againstCells], nodeId, against)\n const cellSetDigest = searchCellSetDigest(input)\n const nodeUnits = searchUnitScores(input.nodeCells)\n const { node, other } = pairUnits(nodeUnits, unitMeans(searchUnitScores(input.againstCells)))\n const pairs = node.length\n const method = searchEstimateMethod(pairs)\n const base = {\n against,\n split,\n units: nodeUnits.length,\n pairs,\n method,\n cellSetDigest,\n estimator: SEARCH_ESTIMATOR,\n }\n if (method === 'none') {\n return { ...base, delta: null, interval: null, exactSignP: null, indeterminate: false }\n }\n // The test's `after - before` is the improvement: node minus against when\n // larger is better, against minus node when smaller is.\n const maximize = direction === 'maximize'\n const test = pairedDeltaTest(maximize ? other : node, maximize ? node : other, {\n statistic: DECISION_PAIRED_DELTA_STATISTIC,\n confidence: CONFIDENCE,\n resamples: RESAMPLES,\n seed: seedFromDigest(cellSetDigest),\n })\n const { mean, low, high } = test.bootstrap\n const indeterminate = test.indeterminate\n const spread = (method === 'descriptive' || method === 'bootstrap') && !indeterminate\n return {\n ...base,\n delta: plain(maximize ? mean : -mean),\n interval: spread ? (maximize ? [plain(low), plain(high)] : [plain(-high), plain(-low)]) : null,\n exactSignP: method === 'descriptive' && !indeterminate ? test.pValue : null,\n indeterminate,\n }\n}\n\n/**\n * `estimateNodeFromCells` over the cells a search state holds: `nodeId`\n * against `against` on one split, in the direction the search's objective\n * declares.\n */\nexport function estimateNode(\n state: SearchStateView,\n nodeId: string,\n options: { against: string; split: SearchSplit },\n): NodeEstimate {\n const header = state.header\n if (!header) throw new SearchLedgerError(`search ${state.searchId} has not been opened`)\n for (const id of [nodeId, options.against]) {\n if (!state.hasNode(id)) {\n throw new SearchLedgerError(`node ${id} is not in search ${state.searchId}`)\n }\n }\n return estimateNodeFromCells({\n nodeId,\n against: options.against,\n split: options.split,\n direction: header.objective.direction,\n nodeCells: state.scoredCells(nodeId, options.split),\n againstCells: state.scoredCells(options.against, options.split),\n })\n}\n\n/** A node's normal posterior on its improvement over the root. */\nexport interface NodePosterior {\n nodeId: string\n /** Units the node and the root both scored. */\n pairs: number\n /** Mean per-unit improvement over the root in the objective's direction,\n * so larger is better for either direction. Null without a shared unit. */\n mean: number | null\n /** The pooled variance divided by `pairs`. Null when either is unknown. */\n variance: number | null\n}\n\nexport interface SearchPosterior {\n split: SearchSplit\n rootNodeId: string\n /**\n * Between-unit variance of the per-unit improvements over the root, pooled\n * across every non-root node with at least 2 shared units. Null until some\n * node has 2.\n */\n pooledVariance: number | null\n /** Sum over the pooled nodes of their shared units minus one. */\n degreesOfFreedom: number\n /** Every node in registration order; the root first, at exactly 0. */\n nodes: NodePosterior[]\n}\n\n/**\n * The posterior every node's parent-selection draw uses. Each node's mean is\n * its improvement over the root on shared units; its variance is the search's\n * pooled between-unit variance divided by its unit count, so a node measured\n * on one unit has a wide posterior rather than none. The root is the reference\n * and sits at exactly 0.\n */\nexport function searchPosterior(\n state: SearchStateView,\n options: { split?: SearchSplit } = {},\n): SearchPosterior {\n const split = options.split ?? 'selection'\n const header = state.header\n if (!header) throw new SearchLedgerError(`search ${state.searchId} has not been opened`)\n const rootNodeId = state.rootNodeId\n if (rootNodeId === null) {\n throw new SearchLedgerError(`search ${state.searchId} has no root node yet`)\n }\n const sign = header.objective.direction === 'maximize' ? 1 : -1\n const root = searchUnitScores(state.scoredCells(rootNodeId, split))\n const rootMeans = unitMeans(root)\n const nodes: NodePosterior[] = []\n let squares = 0\n let degreesOfFreedom = 0\n for (const nodeId of state.nodeIds()) {\n if (nodeId === rootNodeId) {\n const measured = root.length > 0\n nodes.push({\n nodeId,\n pairs: root.length,\n mean: measured ? 0 : null,\n variance: measured ? 0 : null,\n })\n continue\n }\n const { node, other } = pairUnits(searchUnitScores(state.scoredCells(nodeId, split)), rootMeans)\n const gains = node.map((value, index) => sign * (value - other[index]!))\n const mean = gains.length > 0 ? sum(gains) / gains.length : null\n if (mean !== null && gains.length >= 2) {\n squares += sum(gains.map((gain) => (gain - mean) ** 2))\n degreesOfFreedom += gains.length - 1\n }\n nodes.push({\n nodeId,\n pairs: gains.length,\n mean: mean === null ? null : plain(mean),\n variance: null,\n })\n }\n const pooledVariance = degreesOfFreedom > 0 ? squares / degreesOfFreedom : null\n if (pooledVariance !== null) {\n for (const posterior of nodes) {\n if (posterior.nodeId !== rootNodeId && posterior.pairs > 0) {\n posterior.variance = pooledVariance / posterior.pairs\n }\n }\n }\n return { split, rootNodeId, pooledVariance, degreesOfFreedom, nodes }\n}\n\nfunction unitMeans(units: readonly SearchUnitScore[]): ReadonlyMap<string, number> {\n return new Map(units.map((unit) => [unit.unitId, unit.mean]))\n}\n\n/** Unit means of two nodes on the units both scored, aligned in the node's\n * unitId order. */\nfunction pairUnits(\n node: readonly SearchUnitScore[],\n otherMeans: ReadonlyMap<string, number>,\n): { node: number[]; other: number[] } {\n const paired = { node: [] as number[], other: [] as number[] }\n for (const unit of node) {\n const mean = otherMeans.get(unit.unitId)\n if (mean === undefined) continue\n paired.node.push(unit.mean)\n paired.other.push(mean)\n }\n return paired\n}\n\nfunction assertDistinctCells(\n cells: readonly SearchScoredCell[],\n nodeId: string,\n against: string,\n): void {\n const seen = new Set<string>()\n for (const cell of cells) {\n if (seen.has(cell.cellId)) {\n throw new SearchLedgerError(\n `cell ${cell.cellId} appears twice in the estimate of ${nodeId} against ${against}`,\n )\n }\n if (!Number.isFinite(cell.score)) {\n throw new SearchLedgerError(`cell ${cell.cellId} has a non-finite score ${cell.score}`)\n }\n seen.add(cell.cellId)\n }\n}\n\n/** The first 32 bits of a `sha256:` digest, as a bootstrap's seed. */\nexport function seedFromDigest(digest: SearchLedgerHash): number {\n return Number.parseInt(digest.slice('sha256:'.length, 'sha256:'.length + 8), 16) | 0\n}\n\nfunction sum(values: readonly number[]): number {\n let total = 0\n for (const value of values) total += value\n return total\n}\n\n/** Canonical JSON has one zero; never hand it a negative one. */\nfunction plain(value: number): number {\n return value === 0 ? 0 : value\n}\n","/**\n * The agent's view of a search: the same projection a human reads.\n *\n * `renderSearchSummary` turns a `SearchStateView` into compact text — the\n * leading nodes with their estimates, the most recently discarded ideas with\n * why they were discarded, and a log of recent proposals — as AIDE's journal\n * summary does for its own search. `agent-eval search show <ledger>` prints\n * the same text for a terminal; `runOptimization` puts it on every\n * `ProposeContext` a proposer receives.\n *\n * `searchProposerView` is the train-only read `ProposeContext.train` carries.\n * It has no parameter that can select another split, so a proposer built on\n * it cannot reach the selection or test split even by mistake: the sealed\n * splits (§6.6 of the search-tree design) are unreachable by construction,\n * not by convention.\n */\n\nimport { minimumPairsForPairedDeltaTest } from '../paired-delta-test'\nimport { BOOTSTRAP_GATE_MIN_N } from '../statistics'\nimport { estimateNode } from './estimate-node'\nimport { SearchLedgerError } from './search-ledger-errors'\nimport type { NodeEstimate, SearchSplit } from './search-ledger-types'\nimport type { SearchNode, SearchScoredCell, SearchStateView, SearchUnitScore } from './search-state'\n\nconst DESCRIPTIVE_FROM = minimumPairsForPairedDeltaTest(0.95)\n\n/** The proposer's own read of a search: its node's cells on the train split,\n * the only split a proposer may ever see. */\nexport interface SearchProposerView {\n readonly searchId: string\n readonly direction: 'maximize' | 'minimize'\n /** `nodeId`'s scored train cells. Unscored cells (errored, cancelled or in\n * flight) are absent, never zero. */\n scoredCells(nodeId: string): readonly SearchScoredCell[]\n /** Per-unit train-split means of `nodeId`, in unitId order. */\n unitScores(nodeId: string): readonly SearchUnitScore[]\n}\n\n/** The train-only view `ProposeContext.train` carries. */\nexport function searchProposerView(state: SearchStateView): SearchProposerView {\n const header = state.header\n if (!header) throw new SearchLedgerError(`search ${state.searchId} has not been opened`)\n return {\n searchId: state.searchId,\n direction: header.objective.direction,\n scoredCells: (nodeId) => state.scoredCells(nodeId, 'train'),\n unitScores: (nodeId) => state.unitScores(nodeId, 'train'),\n }\n}\n\nexport interface SearchSummaryOptions {\n /**\n * The split every estimate in the summary is computed on. A proposer's\n * context must always pass `'train'`: the selection and test splits stay\n * unread by anything a proposer's text can reach. The CLI passes the\n * search's own ranking split, `'selection'` when the search declares one\n * else `'train'`, matching `searchPolicyView`.\n */\n split: SearchSplit\n /** Nodes shown under \"Leading\" and under \"Recently discarded\". Default 5. */\n limit?: number\n}\n\n/**\n * `SearchState` as compact text: a header line with the search's shape and\n * spend, the leading nodes against the root with their estimates, the most\n * recently discarded nodes with the measurement that discarded them, and a\n * log of recent proposals (operator and label — the ledger's inline,\n * redacted summary of each rationale; the full rationale is a blob this\n * function never reads, so it stays a pure, I/O-free projection of the\n * state already in hand).\n */\nexport function renderSearchSummary(state: SearchStateView, options: SearchSummaryOptions): string {\n const header = state.header\n if (!header) return `search ${state.searchId}: not yet opened`\n const limit = options.limit ?? 5\n if (limit < 1 || !Number.isInteger(limit)) {\n throw new SearchLedgerError(\n `renderSearchSummary: limit must be a positive integer, got ${limit}`,\n )\n }\n const split = options.split\n const direction = header.objective.direction\n const root = state.rootNodeId\n const lines: string[] = [headerLine(state), spendLine(state), statusLine(state)]\n\n if (root === null) {\n lines.push('', 'No nodes yet.')\n return lines.join('\\n')\n }\n\n const others = state.nodes().filter((node) => node.nodeId !== root)\n const estimated = others\n .filter((node) => node.status !== 'invalid')\n .map((node) => ({ node, estimate: estimateNode(state, node.nodeId, { against: root, split }) }))\n\n const leading = estimated\n .filter(({ estimate }) => estimate.delta !== null)\n .sort((a, b) => signed(b.estimate, direction) - signed(a.estimate, direction))\n .slice(0, limit)\n lines.push('', `Leading nodes (vs root, ${split} split):`)\n if (leading.length === 0) lines.push(' none measured yet')\n for (const { node, estimate } of leading)\n lines.push(` ${nodeLine(node)}: ${formatEstimate(estimate)}`)\n\n const discarded = others\n .filter(\n (node) => node.status === 'pruned' || node.status === 'rejected' || node.status === 'invalid',\n )\n .sort((a, b) => b.updatedSequence - a.updatedSequence)\n .slice(0, limit)\n lines.push('', 'Recently discarded:')\n if (discarded.length === 0) lines.push(' none yet')\n for (const node of discarded) lines.push(` ${nodeLine(node)}: ${discardLine(node)}`)\n\n const recent = [...state.edges()].reverse().slice(0, limit)\n lines.push('', 'Recent proposals:')\n if (recent.length === 0) lines.push(' none yet')\n for (const edge of recent) {\n const childId = edge.childNodeId\n const label = edge.label.length > 0 ? edge.label : '(no label)'\n lines.push(` ${edge.operator} → ${childId}: ${label}`)\n }\n\n return lines.join('\\n')\n}\n\nfunction headerLine(state: SearchStateView): string {\n const header = state.header!\n return `search ${state.searchId} — ${header.subject} — ${header.objective.direction} ${header.objective.metric}`\n}\n\nfunction spendLine(state: SearchStateView): string {\n const { audit } = state\n const known = audit.spend.knownUsd.toFixed(2)\n const floor = audit.spend.floorUsd.toFixed(2)\n const unknown = audit.spend.unknownCostCells\n const floorPart =\n unknown > 0\n ? ` + floor $${floor} across ${unknown} unknown-cost cell${unknown === 1 ? '' : 's'}`\n : ''\n return ` ${audit.nodes} nodes · ${audit.cells.settled} settled cells (${audit.cells.open} open) · $${known} known${floorPart}`\n}\n\nfunction statusLine(state: SearchStateView): string {\n if (!state.closed) return ' status: open'\n const claim = state.closed.claim\n const claimText =\n claim === null\n ? ''\n : claim.decision === 'ship'\n ? ` · claim: ship ${claim.selected}`\n : ` · claim: ${claim.decision}`\n return ` status: closed (${state.closed.reason})${claimText}`\n}\n\nfunction nodeLine(node: SearchNode): string {\n const rung = node.status === 'advanced' ? ` rung ${node.rung}` : ''\n return `${node.nodeId} (${node.status ?? 'undecided'}${rung})`\n}\n\nfunction discardLine(node: SearchNode): string {\n const decision = node.decisions.at(-1)\n if (!decision) return 'no decision recorded'\n const basis = decision.basis === null ? 'no measured basis' : formatEstimate(decision.basis)\n return `${basis} — ${decision.rule}: ${decision.reason}`\n}\n\n/** `estimate.delta` in the objective's own units; positive is always better. */\nfunction signed(estimate: NodeEstimate, direction: 'maximize' | 'minimize'): number {\n if (estimate.delta === null) return Number.NEGATIVE_INFINITY\n return direction === 'maximize' ? estimate.delta : -estimate.delta\n}\n\n/** The display rules of search-tree-design §6.4: no whisker below 6 shared\n * units, a dashed descriptive interval with its exact sign p from 6 to 19,\n * a decision-grade whisker from `BOOTSTRAP_GATE_MIN_N`. */\nfunction formatEstimate(estimate: NodeEstimate): string {\n const unit = (n: number) => `${n} unit${n === 1 ? '' : 's'}`\n if (estimate.method === 'none') return `unknown (${unit(estimate.pairs)})`\n if (estimate.indeterminate)\n return `no measurable difference (indeterminate, ${unit(estimate.pairs)})`\n const delta =\n estimate.delta === null ? 'null' : (estimate.delta >= 0 ? '+' : '') + estimate.delta.toFixed(4)\n if (estimate.method === 'insufficient') {\n return `Δ=${delta} (${estimate.pairs} of ${DESCRIPTIVE_FROM} units, insufficient)`\n }\n const interval = estimate.interval\n ? ` [${estimate.interval[0].toFixed(4)}, ${estimate.interval[1].toFixed(4)}]`\n : ''\n if (estimate.method === 'descriptive') {\n const signP = estimate.exactSignP === null ? 'null' : estimate.exactSignP.toPrecision(3)\n return `Δ=${delta}${interval} dashed, sign p=${signP} (${unit(estimate.pairs)})`\n }\n return `Δ=${delta}${interval} (${unit(estimate.pairs)}, ≥${BOOTSTRAP_GATE_MIN_N})`\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAkCA,MAAM,aAAa;AACnB,MAAM,YAAY;;AAElB,MAAMA,qBAAmB,+BAA+B,UAAU;;AA6BlE,MAAa,mBAAoC;CAC/C,KAAK;CACL,UAAU,cAAc;EAtBxB,MAAM;EACN,MAAM;EACN,SAAS;EACT,WAAW;EACX,UAAU;EACV,YAAY;EACZ,WAAW;EACX,KAAK;EACL,MAAM;EACN,UAAU;EACV,SAAS;GACP,MAAM;GACN,cAAc,SAASA,mBAAiB;GACxC,aAAa;GACb,WAAW;EACb;EACA,eAAe;CAMS,CAAoB;AAC9C;;AAGA,SAAS,qBAAqB,OAAqC;CACjE,IAAI,QAAQ,GAAG,OAAO;CACtB,IAAI,QAAQA,oBAAkB,OAAO;CACrC,IAAI,QAAA,IAA8B,OAAO;CACzC,OAAO;AACT;;;;;;AAkBA,SAAgB,oBACd,OACkB;CAClB,MAAM,QAAQ,UACZ,CAAC,GAAG,KAAK,CAAC,CACP,MAAM,MAAM,UAAU,iBAAiB,KAAK,QAAQ,MAAM,MAAM,CAAC,CAAC,CAClE,KAAK,SAAS;EAAC,KAAK;EAAQ,KAAK;EAAQ,KAAK;EAAS,KAAK;CAAK,CAAC;CACvE,OAAO,cAAc;EACnB,UAAU,CAAC,MAAM,QAAQ,MAAM,OAAO;EACtC,OAAO,MAAM;EACb,WAAW,KAAK,MAAM,SAAS;EAC/B,cAAc,KAAK,MAAM,YAAY;CACvC,CAAC;AACH;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,sBAAsB,OAA6C;CACjF,MAAM,EAAE,QAAQ,SAAS,OAAO,cAAc;CAC9C,IAAI,WAAW,SACb,MAAM,IAAI,kBAAkB,QAAQ,OAAO,oCAAoC;CAEjF,oBAAoB,CAAC,GAAG,MAAM,WAAW,GAAG,MAAM,YAAY,GAAG,QAAQ,OAAO;CAChF,MAAM,gBAAgB,oBAAoB,KAAK;CAC/C,MAAM,YAAY,iBAAiB,MAAM,SAAS;CAClD,MAAM,EAAE,MAAM,UAAU,UAAU,WAAW,UAAU,iBAAiB,MAAM,YAAY,CAAC,CAAC;CAC5F,MAAM,QAAQ,KAAK;CACnB,MAAM,SAAS,qBAAqB,KAAK;CACzC,MAAM,OAAO;EACX;EACA;EACA,OAAO,UAAU;EACjB;EACA;EACA;EACA,WAAW;CACb;CACA,IAAI,WAAW,QACb,OAAO;EAAE,GAAG;EAAM,OAAO;EAAM,UAAU;EAAM,YAAY;EAAM,eAAe;CAAM;CAIxF,MAAM,WAAW,cAAc;CAC/B,MAAM,OAAO,gBAAgB,WAAW,QAAQ,MAAM,WAAW,OAAO,OAAO;EAC7E,WAAW;EACX,YAAY;EACZ,WAAW;EACX,MAAM,eAAe,aAAa;CACpC,CAAC;CACD,MAAM,EAAE,MAAM,KAAK,SAAS,KAAK;CACjC,MAAM,gBAAgB,KAAK;CAC3B,MAAM,UAAU,WAAW,iBAAiB,WAAW,gBAAgB,CAAC;CACxE,OAAO;EACL,GAAG;EACH,OAAO,MAAM,WAAW,OAAO,CAAC,IAAI;EACpC,UAAU,SAAU,WAAW,CAAC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAK;EAC1F,YAAY,WAAW,iBAAiB,CAAC,gBAAgB,KAAK,SAAS;EACvE;CACF;AACF;;;;;;AAOA,SAAgB,aACd,OACA,QACA,SACc;CACd,MAAM,SAAS,MAAM;CACrB,IAAI,CAAC,QAAQ,MAAM,IAAI,kBAAkB,UAAU,MAAM,SAAS,qBAAqB;CACvF,KAAK,MAAM,MAAM,CAAC,QAAQ,QAAQ,OAAO,GACvC,IAAI,CAAC,MAAM,QAAQ,EAAE,GACnB,MAAM,IAAI,kBAAkB,QAAQ,GAAG,oBAAoB,MAAM,UAAU;CAG/E,OAAO,sBAAsB;EAC3B;EACA,SAAS,QAAQ;EACjB,OAAO,QAAQ;EACf,WAAW,OAAO,UAAU;EAC5B,WAAW,MAAM,YAAY,QAAQ,QAAQ,KAAK;EAClD,cAAc,MAAM,YAAY,QAAQ,SAAS,QAAQ,KAAK;CAChE,CAAC;AACH;;;;;;;;AAoCA,SAAgB,gBACd,OACA,UAAmC,CAAC,GACnB;CACjB,MAAM,QAAQ,QAAQ,SAAS;CAC/B,MAAM,SAAS,MAAM;CACrB,IAAI,CAAC,QAAQ,MAAM,IAAI,kBAAkB,UAAU,MAAM,SAAS,qBAAqB;CACvF,MAAM,aAAa,MAAM;CACzB,IAAI,eAAe,MACjB,MAAM,IAAI,kBAAkB,UAAU,MAAM,SAAS,sBAAsB;CAE7E,MAAM,OAAO,OAAO,UAAU,cAAc,aAAa,IAAI;CAC7D,MAAM,OAAO,iBAAiB,MAAM,YAAY,YAAY,KAAK,CAAC;CAClE,MAAM,YAAY,UAAU,IAAI;CAChC,MAAM,QAAyB,CAAC;CAChC,IAAI,UAAU;CACd,IAAI,mBAAmB;CACvB,KAAK,MAAM,UAAU,MAAM,QAAQ,GAAG;EACpC,IAAI,WAAW,YAAY;GACzB,MAAM,WAAW,KAAK,SAAS;GAC/B,MAAM,KAAK;IACT;IACA,OAAO,KAAK;IACZ,MAAM,WAAW,IAAI;IACrB,UAAU,WAAW,IAAI;GAC3B,CAAC;GACD;EACF;EACA,MAAM,EAAE,MAAM,UAAU,UAAU,iBAAiB,MAAM,YAAY,QAAQ,KAAK,CAAC,GAAG,SAAS;EAC/F,MAAM,QAAQ,KAAK,KAAK,OAAO,UAAU,QAAQ,QAAQ,MAAM,OAAQ;EACvE,MAAM,OAAO,MAAM,SAAS,IAAI,IAAI,KAAK,IAAI,MAAM,SAAS;EAC5D,IAAI,SAAS,QAAQ,MAAM,UAAU,GAAG;GACtC,WAAW,IAAI,MAAM,KAAK,UAAU,OAAO,SAAS,CAAC,CAAC;GACtD,oBAAoB,MAAM,SAAS;EACrC;EACA,MAAM,KAAK;GACT;GACA,OAAO,MAAM;GACb,MAAM,SAAS,OAAO,OAAO,MAAM,IAAI;GACvC,UAAU;EACZ,CAAC;CACH;CACA,MAAM,iBAAiB,mBAAmB,IAAI,UAAU,mBAAmB;CAC3E,IAAI,mBAAmB,MAChB;OAAA,MAAM,aAAa,OACtB,IAAI,UAAU,WAAW,cAAc,UAAU,QAAQ,GACvD,UAAU,WAAW,iBAAiB,UAAU;CAAA;CAItD,OAAO;EAAE;EAAO;EAAY;EAAgB;EAAkB;CAAM;AACtE;AAEA,SAAS,UAAU,OAAgE;CACjF,OAAO,IAAI,IAAI,MAAM,KAAK,SAAS,CAAC,KAAK,QAAQ,KAAK,IAAI,CAAC,CAAC;AAC9D;;;AAIA,SAAS,UACP,MACA,YACqC;CACrC,MAAM,SAAS;EAAE,MAAM,CAAC;EAAe,OAAO,CAAC;CAAc;CAC7D,KAAK,MAAM,QAAQ,MAAM;EACvB,MAAM,OAAO,WAAW,IAAI,KAAK,MAAM;EACvC,IAAI,SAAS,KAAA,GAAW;EACxB,OAAO,KAAK,KAAK,KAAK,IAAI;EAC1B,OAAO,MAAM,KAAK,IAAI;CACxB;CACA,OAAO;AACT;AAEA,SAAS,oBACP,OACA,QACA,SACM;CACN,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,KAAK,IAAI,KAAK,MAAM,GACtB,MAAM,IAAI,kBACR,QAAQ,KAAK,OAAO,oCAAoC,OAAO,WAAW,SAC5E;EAEF,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,GAC7B,MAAM,IAAI,kBAAkB,QAAQ,KAAK,OAAO,0BAA0B,KAAK,OAAO;EAExF,KAAK,IAAI,KAAK,MAAM;CACtB;AACF;;AAGA,SAAgB,eAAe,QAAkC;CAC/D,OAAO,OAAO,SAAS,OAAO,MAAM,GAAkB,EAAoB,GAAG,EAAE,IAAI;AACrF;AAEA,SAAS,IAAI,QAAmC;CAC9C,IAAI,QAAQ;CACZ,KAAK,MAAM,SAAS,QAAQ,SAAS;CACrC,OAAO;AACT;;AAGA,SAAS,MAAM,OAAuB;CACpC,OAAO,UAAU,IAAI,IAAI;AAC3B;;;;;;;;;;;;;;;;;;;AC3TA,MAAM,mBAAmB,+BAA+B,GAAI;;AAe5D,SAAgB,mBAAmB,OAA4C;CAC7E,MAAM,SAAS,MAAM;CACrB,IAAI,CAAC,QAAQ,MAAM,IAAI,kBAAkB,UAAU,MAAM,SAAS,qBAAqB;CACvF,OAAO;EACL,UAAU,MAAM;EAChB,WAAW,OAAO,UAAU;EAC5B,cAAc,WAAW,MAAM,YAAY,QAAQ,OAAO;EAC1D,aAAa,WAAW,MAAM,WAAW,QAAQ,OAAO;CAC1D;AACF;;;;;;;;;;AAwBA,SAAgB,oBAAoB,OAAwB,SAAuC;CACjG,MAAM,SAAS,MAAM;CACrB,IAAI,CAAC,QAAQ,OAAO,UAAU,MAAM,SAAS;CAC7C,MAAM,QAAQ,QAAQ,SAAS;CAC/B,IAAI,QAAQ,KAAK,CAAC,OAAO,UAAU,KAAK,GACtC,MAAM,IAAI,kBACR,8DAA8D,OAChE;CAEF,MAAM,QAAQ,QAAQ;CACtB,MAAM,YAAY,OAAO,UAAU;CACnC,MAAM,OAAO,MAAM;CACnB,MAAM,QAAkB;EAAC,WAAW,KAAK;EAAG,UAAU,KAAK;EAAG,WAAW,KAAK;CAAC;CAE/E,IAAI,SAAS,MAAM;EACjB,MAAM,KAAK,IAAI,eAAe;EAC9B,OAAO,MAAM,KAAK,IAAI;CACxB;CAEA,MAAM,SAAS,MAAM,MAAM,CAAC,CAAC,QAAQ,SAAS,KAAK,WAAW,IAAI;CAKlE,MAAM,UAJY,OACf,QAAQ,SAAS,KAAK,WAAW,SAAS,CAAC,CAC3C,KAAK,UAAU;EAAE;EAAM,UAAU,aAAa,OAAO,KAAK,QAAQ;GAAE,SAAS;GAAM;EAAM,CAAC;CAAE,EAEvE,CAAC,CACtB,QAAQ,EAAE,eAAe,SAAS,UAAU,IAAI,CAAC,CACjD,MAAM,GAAG,MAAM,OAAO,EAAE,UAAU,SAAS,IAAI,OAAO,EAAE,UAAU,SAAS,CAAC,CAAC,CAC7E,MAAM,GAAG,KAAK;CACjB,MAAM,KAAK,IAAI,2BAA2B,MAAM,SAAS;CACzD,IAAI,QAAQ,WAAW,GAAG,MAAM,KAAK,qBAAqB;CAC1D,KAAK,MAAM,EAAE,MAAM,cAAc,SAC/B,MAAM,KAAK,KAAK,SAAS,IAAI,EAAE,IAAI,eAAe,QAAQ,GAAG;CAE/D,MAAM,YAAY,OACf,QACE,SAAS,KAAK,WAAW,YAAY,KAAK,WAAW,cAAc,KAAK,WAAW,SACtF,CAAC,CACA,MAAM,GAAG,MAAM,EAAE,kBAAkB,EAAE,eAAe,CAAC,CACrD,MAAM,GAAG,KAAK;CACjB,MAAM,KAAK,IAAI,qBAAqB;CACpC,IAAI,UAAU,WAAW,GAAG,MAAM,KAAK,YAAY;CACnD,KAAK,MAAM,QAAQ,WAAW,MAAM,KAAK,KAAK,SAAS,IAAI,EAAE,IAAI,YAAY,IAAI,GAAG;CAEpF,MAAM,SAAS,CAAC,GAAG,MAAM,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,KAAK;CAC1D,MAAM,KAAK,IAAI,mBAAmB;CAClC,IAAI,OAAO,WAAW,GAAG,MAAM,KAAK,YAAY;CAChD,KAAK,MAAM,QAAQ,QAAQ;EACzB,MAAM,UAAU,KAAK;EACrB,MAAM,QAAQ,KAAK,MAAM,SAAS,IAAI,KAAK,QAAQ;EACnD,MAAM,KAAK,KAAK,KAAK,SAAS,KAAK,QAAQ,IAAI,OAAO;CACxD;CAEA,OAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,WAAW,OAAgC;CAClD,MAAM,SAAS,MAAM;CACrB,OAAO,UAAU,MAAM,SAAS,KAAK,OAAO,QAAQ,KAAK,OAAO,UAAU,UAAU,GAAG,OAAO,UAAU;AAC1G;AAEA,SAAS,UAAU,OAAgC;CACjD,MAAM,EAAE,UAAU;CAClB,MAAM,QAAQ,MAAM,MAAM,SAAS,QAAQ,CAAC;CAC5C,MAAM,QAAQ,MAAM,MAAM,SAAS,QAAQ,CAAC;CAC5C,MAAM,UAAU,MAAM,MAAM;CAC5B,MAAM,YACJ,UAAU,IACN,aAAa,MAAM,UAAU,QAAQ,oBAAoB,YAAY,IAAI,KAAK,QAC9E;CACN,OAAO,KAAK,MAAM,MAAM,WAAW,MAAM,MAAM,QAAQ,kBAAkB,MAAM,MAAM,KAAK,YAAY,MAAM,QAAQ;AACtH;AAEA,SAAS,WAAW,OAAgC;CAClD,IAAI,CAAC,MAAM,QAAQ,OAAO;CAC1B,MAAM,QAAQ,MAAM,OAAO;CAC3B,MAAM,YACJ,UAAU,OACN,KACA,MAAM,aAAa,SACjB,kBAAkB,MAAM,aACxB,aAAa,MAAM;CAC3B,OAAO,qBAAqB,MAAM,OAAO,OAAO,GAAG;AACrD;AAEA,SAAS,SAAS,MAA0B;CAC1C,MAAM,OAAO,KAAK,WAAW,aAAa,SAAS,KAAK,SAAS;CACjE,OAAO,GAAG,KAAK,OAAO,IAAI,KAAK,UAAU,cAAc,KAAK;AAC9D;AAEA,SAAS,YAAY,MAA0B;CAC7C,MAAM,WAAW,KAAK,UAAU,GAAG,EAAE;CACrC,IAAI,CAAC,UAAU,OAAO;CAEtB,OAAO,GADO,SAAS,UAAU,OAAO,sBAAsB,eAAe,SAAS,KAAK,EAC3E,KAAK,SAAS,KAAK,IAAI,SAAS;AAClD;;AAGA,SAAS,OAAO,UAAwB,WAA4C;CAClF,IAAI,SAAS,UAAU,MAAM,OAAO,OAAO;CAC3C,OAAO,cAAc,aAAa,SAAS,QAAQ,CAAC,SAAS;AAC/D;;;;AAKA,SAAS,eAAe,UAAgC;CACtD,MAAM,QAAQ,MAAc,GAAG,EAAE,OAAO,MAAM,IAAI,KAAK;CACvD,IAAI,SAAS,WAAW,QAAQ,OAAO,YAAY,KAAK,SAAS,KAAK,EAAE;CACxE,IAAI,SAAS,eACX,OAAO,4CAA4C,KAAK,SAAS,KAAK,EAAE;CAC1E,MAAM,QACJ,SAAS,UAAU,OAAO,UAAU,SAAS,SAAS,IAAI,MAAM,MAAM,SAAS,MAAM,QAAQ,CAAC;CAChG,IAAI,SAAS,WAAW,gBACtB,OAAO,KAAK,MAAM,IAAI,SAAS,MAAM,MAAM,iBAAiB;CAE9D,MAAM,WAAW,SAAS,WACtB,KAAK,SAAS,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,IAAI,SAAS,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,KACzE;CACJ,IAAI,SAAS,WAAW,eAEtB,OAAO,KAAK,QAAQ,SAAS,kBADf,SAAS,eAAe,OAAO,SAAS,SAAS,WAAW,YAAY,CAAC,EAClC,IAAI,KAAK,SAAS,KAAK,EAAE;CAEhF,OAAO,KAAK,QAAQ,SAAS,IAAI,KAAK,SAAS,KAAK,EAAE;AACxD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tool-groups-B4JVrH3g.d.ts","names":[],"sources":["../src/analyst/tool-groups.ts"],"mappings":";;;;KAmBY;;;;;;;;;;;;;;;;;;;;iBAyDI,wBACd,OAAO,oBACP,OAAO,qBACN"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types-B2673PBj.d.ts","names":[],"sources":["../src/campaign/search-state.ts","../src/campaign/search-summary.ts","../src/campaign/types.ts"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types-B3jzCp0p.js","names":[],"sources":["../src/multishot/types.ts"],"sourcesContent":["// Public types for the multishot substrate.\n\nimport type { CostProvenance } from '../cost-ledger'\n\nexport interface MultishotMessage {\n role: 'user' | 'assistant' | 'tool'\n content: string\n toolCallId?: string\n toolCalls?: Array<{ id: string; name: string; args: Record<string, unknown> }>\n}\n\nexport interface MultishotArtifact {\n type: string\n turn: number\n invocation: { name: string; args: Record<string, unknown> }\n content: string\n}\n\nexport interface MultishotResult {\n transcript: MultishotMessage[]\n artifacts: MultishotArtifact[]\n toolCalls: number\n durationMs: number\n /** Known spend. A subtotal, not a total, when `costProvenance.kind` is\n * `uncaptured`. */\n costUsd: number\n /** Origin of `costUsd`. A shot that priced every call reports `estimated`\n * or `observed`; a shot with a call the router priced at nothing reports\n * `uncaptured`, and the matrix records the cell as under-counted instead of\n * presenting the subtotal as a complete estimate.\n *\n * Optional so an engine written before this field keeps working; the matrix\n * then judges the cell on judge receipts alone, as it did before. */\n costProvenance?: CostProvenance\n}\n\nexport interface MultishotToolDefinition {\n type: 'function'\n function: {\n name: string\n description: string\n parameters: Record<string, unknown>\n }\n}\n\n/** One chat-completion request the multishot loop issues for a single agent\n * (or driver) inference step. Mirrors the OpenAI-compat body the loop would\n * otherwise POST to the Tangle router. */\nexport interface MultishotTransportRequest {\n model: string\n messages: Array<Record<string, unknown>>\n tools?: MultishotToolDefinition[]\n temperature?: number\n maxTokens?: number\n signal?: AbortSignal\n}\n\nexport interface MultishotTransportToolCall {\n id: string\n type: 'function'\n function: { name: string; arguments: string }\n}\n\nexport interface MultishotTransportResponse {\n message: { content?: string | null; tool_calls?: MultishotTransportToolCall[] }\n usage?: { prompt_tokens?: number; completion_tokens?: number }\n /** Actual spend for this call. When omitted, the loop meters cost from\n * `usage` via the per-model estimator (estimateMultishotCost). */\n costUsd?: number\n /** Model identity the provider reported, when the transport observed one.\n * Omitted means unreported, and the requested model is used for\n * attribution — which is not proof that model answered. */\n model?: string\n}\n\n/** Execution seam for one leg of the multishot loop. The caller owns model\n * execution: agent-eval issues no provider request and holds no credential.\n * The loop still owns turn scheduling, tool dispatch, transcript capture, and\n * cost metering. agent-eval has no dependency on agent-runtime; adapt\n * agent-runtime's `profileChatClient` (or any sandbox, bridge, or router\n * client) into this signature product-side. */\nexport type MultishotTransport = (\n req: MultishotTransportRequest,\n) => Promise<MultishotTransportResponse>\n\nexport type MultishotToolExecutor = (\n args: Record<string, unknown>,\n ctx: {\n /** Caller-owned execution seam for the specialist leg this tool runs. */\n transport: MultishotTransport\n signal?: AbortSignal\n },\n) => Promise<{ content: string; costUsd: number }>\n\nexport interface MultishotPersona {\n /** Stable identifier — used for per-cell artifact paths + matrix axis keys. */\n id: string\n /** Per-domain payload (income/profile/voice/etc.) shaped by the consumer. */\n [k: string]: unknown\n}\n\n/**\n * Persona-shaping callbacks. Both are OPTIONAL: when omitted, the loop derives\n * them from the `AgentProfile` + persona payload (see `defaultShapeFromProfile`)\n * so a pure-profile call — `runMultishot({ profile, persona })` — works with no\n * role-builder functions. Provide callbacks only to override the derived shape.\n */\nexport interface MultishotShape<TPersona extends MultishotPersona> {\n /** Opening user message (turn 0) — the persona's first ask. */\n buildOpener?: (persona: TPersona) => string\n /** System prompt the driver LLM uses to roleplay the persona. Should set\n * voice, goals, constraints, time-pressure, and the \"never go silent\" rule. */\n buildDriverSystemPrompt?: (persona: TPersona) => string\n}\n\nexport class MultishotDriverEmptyError extends Error {\n constructor(public readonly turn: number) {\n super(`multishot: driver returned empty content twice at turn ${turn} — failing loud`)\n this.name = 'MultishotDriverEmptyError'\n }\n}\n\nexport class MultishotFatalToolError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MultishotFatalToolError'\n }\n}\n\nexport class MultishotShotResultError extends Error {\n constructor(reason: string) {\n super(`multishot: shot returned an invalid MultishotResult — ${reason}`)\n this.name = 'MultishotShotResultError'\n }\n}\n\nconst MULTISHOT_ROLES = new Set(['user', 'assistant', 'tool'])\n\n/** Contract guard for the value a caller-supplied shot resolves with. The\n * matrix writes per-cell artifacts, builds judge inputs, and meters cost from\n * this value, so a malformed result must stop the cell instead of scoring a\n * degraded one. Two silent degradations this closes: an artifact with no\n * `type` matches neither the code nor the content artifact set, so the cell\n * scores as though the artifact was never produced; a non-finite `costUsd`\n * reaches `summary.totalCostUsd` and makes every cost number NaN.\n *\n * A rejected cell is still billed: the matrix cell reads the shot's own\n * `costUsd` when it is a usable amount and declares that spend on the throw,\n * so money the shot spent before returning a malformed result stays in the\n * cumulative sum the cost ceiling reads. A result whose `costUsd` is itself\n * malformed carries no usable amount, and the cell records as `uncaptured`.\n *\n * Every required field of `MultishotMessage` and `MultishotArtifact` is\n * checked, including `toolCalls` elements and `invocation.args`. Optional\n * fields are checked only when present. */\nexport function assertMultishotShotResult(value: unknown): asserts value is MultishotResult {\n if (typeof value !== 'object' || value === null) {\n throw new MultishotShotResultError(`expected an object, received ${describeValue(value)}`)\n }\n const result = value as Record<string, unknown>\n if (!Array.isArray(result.transcript)) {\n throw new MultishotShotResultError(\n `transcript must be an array, received ${describeValue(result.transcript)}`,\n )\n }\n if (!Array.isArray(result.artifacts)) {\n throw new MultishotShotResultError(\n `artifacts must be an array, received ${describeValue(result.artifacts)}`,\n )\n }\n result.transcript.forEach(assertMessage)\n result.artifacts.forEach(assertArtifact)\n assertFiniteCount(result.toolCalls, 'toolCalls')\n assertFiniteCount(result.durationMs, 'durationMs')\n assertFiniteCount(result.costUsd, 'costUsd')\n if (result.costProvenance !== undefined) assertCostProvenance(result.costProvenance)\n}\n\nfunction assertCostProvenance(value: unknown): void {\n const row = requireRow(value, 'costProvenance')\n if (row.kind !== 'observed' && row.kind !== 'estimated' && row.kind !== 'uncaptured') {\n throw new MultishotShotResultError(\n `costProvenance.kind must be observed, estimated or uncaptured, received ${describeValue(row.kind)}`,\n )\n }\n // The matrix reads the amount from `costUsd`; `usd` only has to agree with\n // the kind, so an uncaptured provenance cannot smuggle in a total.\n if (row.kind === 'uncaptured') {\n if (row.usd !== null) {\n throw new MultishotShotResultError(\n `uncaptured costProvenance.usd must be null, received ${describeValue(row.usd)}`,\n )\n }\n return\n }\n assertFiniteCount(row.usd, 'costProvenance.usd')\n}\n\nfunction assertMessage(value: unknown, index: number): void {\n const row = requireRow(value, `transcript[${index}]`)\n if (typeof row.role !== 'string' || !MULTISHOT_ROLES.has(row.role)) {\n throw new MultishotShotResultError(\n `transcript[${index}].role must be user, assistant or tool, received ${describeValue(row.role)}`,\n )\n }\n assertString(row.content, `transcript[${index}].content`)\n if (row.toolCallId !== undefined) {\n assertString(row.toolCallId, `transcript[${index}].toolCallId`)\n }\n if (row.toolCalls === undefined) return\n if (!Array.isArray(row.toolCalls)) {\n throw new MultishotShotResultError(\n `transcript[${index}].toolCalls must be an array when present, received ${describeValue(row.toolCalls)}`,\n )\n }\n row.toolCalls.forEach((call, callIndex) => {\n const field = `transcript[${index}].toolCalls[${callIndex}]`\n const row = requireRow(call, field)\n assertString(row.id, `${field}.id`)\n assertString(row.name, `${field}.name`)\n requireRow(row.args, `${field}.args`)\n })\n}\n\nfunction assertArtifact(value: unknown, index: number): void {\n const row = requireRow(value, `artifacts[${index}]`)\n assertString(row.type, `artifacts[${index}].type`)\n assertString(row.content, `artifacts[${index}].content`)\n assertFiniteCount(row.turn, `artifacts[${index}].turn`)\n const invocation = requireRow(row.invocation, `artifacts[${index}].invocation`)\n assertString(invocation.name, `artifacts[${index}].invocation.name`)\n requireRow(invocation.args, `artifacts[${index}].invocation.args`)\n}\n\nfunction requireRow(value: unknown, field: string): Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new MultishotShotResultError(\n `${field} must be an object, received ${describeValue(value)}`,\n )\n }\n return value as Record<string, unknown>\n}\n\nfunction assertString(value: unknown, field: string): void {\n if (typeof value !== 'string') {\n throw new MultishotShotResultError(\n `${field} must be a string, received ${describeValue(value)}`,\n )\n }\n}\n\nfunction assertFiniteCount(value: unknown, field: string): void {\n if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {\n throw new MultishotShotResultError(\n `${field} must be a finite number >= 0, received ${describeValue(value)}`,\n )\n }\n}\n\nfunction describeValue(value: unknown): string {\n if (value === null) return 'null'\n if (Array.isArray(value)) return 'an array'\n if (typeof value === 'object') return 'an object'\n return `${typeof value} ${String(value)}`\n}\n"],"mappings":"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"}
|