@tangle-network/agent-eval 0.191.0 → 0.193.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 +61 -0
- package/dist/adapters/http.d.ts +2 -2
- package/dist/analyst/index.d.ts +6 -6
- package/dist/analyst/index.js +3 -3
- package/dist/{analyze-runs-SCSWYpy0.js → analyze-runs-B6gv7vAT.js} +2 -2
- package/dist/{analyze-runs-SCSWYpy0.js.map → analyze-runs-B6gv7vAT.js.map} +1 -1
- package/dist/{benchmark-command-3tZJnD82.js → benchmark-command-DVhUPU7H.js} +7 -7
- package/dist/{benchmark-command-3tZJnD82.js.map → benchmark-command-DVhUPU7H.js.map} +1 -1
- package/dist/benchmarks/index.d.ts +3 -3
- package/dist/benchmarks/index.js +3 -3
- package/dist/campaign/index.d.ts +5 -5
- package/dist/campaign/index.js +12 -12
- package/dist/{campaign-C8iWEF0M.js → campaign-DdE6S80e.js} +15 -328
- package/dist/campaign-DdE6S80e.js.map +1 -0
- package/dist/{campaign-evidence-BqjlTM3P.js → campaign-evidence-DJc60F9C.js} +11 -46
- package/dist/campaign-evidence-DJc60F9C.js.map +1 -0
- package/dist/cli.js +47 -10
- package/dist/cli.js.map +1 -1
- package/dist/{client-wFyDisxi.d.ts → client-dMMKoQNS.d.ts} +2 -2
- package/dist/{client-wFyDisxi.d.ts.map → client-dMMKoQNS.d.ts.map} +1 -1
- package/dist/contract/index.d.ts +7 -7
- package/dist/contract/index.js +10 -10
- package/dist/{default-registry-DK_9aVJf.d.ts → default-registry-C3HTE08O.d.ts} +3 -3
- package/dist/{default-registry-DK_9aVJf.d.ts.map → default-registry-C3HTE08O.d.ts.map} +1 -1
- package/dist/{define-agent-eval-P28y7mI1.d.ts → define-agent-eval-DQJvVa1P.d.ts} +15 -24
- package/dist/{define-agent-eval-P28y7mI1.d.ts.map → define-agent-eval-DQJvVa1P.d.ts.map} +1 -1
- package/dist/{define-agent-eval-BE43YTm4.js → define-agent-eval-DkPbnJEY.js} +9 -10
- package/dist/define-agent-eval-DkPbnJEY.js.map +1 -0
- package/dist/diagnosis/index.js +1 -1
- package/dist/{dspy-rlm-engine-MfpwoEaj.js → dspy-rlm-engine-BX34vPVY.js} +2 -2
- package/dist/{dspy-rlm-engine-MfpwoEaj.js.map → dspy-rlm-engine-BX34vPVY.js.map} +1 -1
- package/dist/{engine-vNiM02Ub.d.ts → engine-DjRV55F9.d.ts} +2 -2
- package/dist/{engine-vNiM02Ub.d.ts.map → engine-DjRV55F9.d.ts.map} +1 -1
- package/dist/evaluation.d.ts +1 -1
- package/dist/experiment/index.d.ts +2 -2
- package/dist/experiment/index.js +4 -4
- package/dist/{external-optimizer-process-xFTliuiK.js → external-optimizer-process-D-Sab4v3.js} +3 -62
- package/dist/external-optimizer-process-D-Sab4v3.js.map +1 -0
- package/dist/{external-optimizer-subprocess-B234V9V0.js → external-optimizer-subprocess-kbqC-iWf.js} +64 -3
- package/dist/external-optimizer-subprocess-kbqC-iWf.js.map +1 -0
- package/dist/hosted/index.d.ts +2 -2
- package/dist/hosted/index.js +1 -1
- package/dist/{index-D-TN7ZRM.d.ts → index-0jEtpSM7.d.ts} +3 -3
- package/dist/{index-D-TN7ZRM.d.ts.map → index-0jEtpSM7.d.ts.map} +1 -1
- package/dist/{index-I4UJGRno.d.ts → index-Bj96W0jZ.d.ts} +28 -2
- package/dist/{index-I4UJGRno.d.ts.map → index-Bj96W0jZ.d.ts.map} +1 -1
- package/dist/{index-CzfnASj_.d.ts → index-DMPLG226.d.ts} +400 -374
- package/dist/index-DMPLG226.d.ts.map +1 -0
- package/dist/{index-DH-MWH5f.d.ts → index-DWQNDqPd.d.ts} +7 -7
- package/dist/{index-DH-MWH5f.d.ts.map → index-DWQNDqPd.d.ts.map} +1 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.js +9 -292
- package/dist/index.js.map +1 -1
- package/dist/jev.d.ts +1 -1
- package/dist/{journal-c3qY0SDP.js → journal-DvKCvjty.js} +94 -2
- package/dist/{journal-c3qY0SDP.js.map → journal-DvKCvjty.js.map} +1 -1
- package/dist/ledger-core/index.d.ts +2 -2
- package/dist/ledger-core/index.js +2 -2
- package/dist/{llm-judge-NJOHM0iA.js → llm-judge-ChbWfeWl.js} +2653 -656
- package/dist/llm-judge-ChbWfeWl.js.map +1 -0
- package/dist/{matrix-CgqdFm5N.d.ts → matrix-CNu13gg8.d.ts} +2 -2
- package/dist/{matrix-CgqdFm5N.d.ts.map → matrix-CNu13gg8.d.ts.map} +1 -1
- package/dist/multishot/golden/index.d.ts +1 -1
- package/dist/multishot/index.d.ts +2 -2
- package/dist/openapi.json +1 -1
- package/dist/paired-delta-test-BF-FEP8V.js +78 -0
- package/dist/paired-delta-test-BF-FEP8V.js.map +1 -0
- package/dist/{paired-promotion-decision-6cn3bLc3.js → paired-promotion-decision-DTKl6-G8.js} +4 -77
- package/dist/paired-promotion-decision-DTKl6-G8.js.map +1 -0
- package/dist/{produced-state-CY-L7CqS.js → produced-state-BqeIaIp2.js} +3 -3
- package/dist/{produced-state-CY-L7CqS.js.map → produced-state-BqeIaIp2.js.map} +1 -1
- package/dist/{promotion-policy-CfMNUro2.js → promotion-policy-Cy5OV8BV.js} +3 -3
- package/dist/{promotion-policy-CfMNUro2.js.map → promotion-policy-Cy5OV8BV.js.map} +1 -1
- package/dist/rl.d.ts +1 -1
- package/dist/rl.js +1 -1
- package/dist/{search-ledger-CQ8Uy4FK.js → search-ledger-CJiAEU3j.js} +164 -36
- package/dist/search-ledger-CJiAEU3j.js.map +1 -0
- package/dist/{search-ledger-file-EvdDZRhv.js → search-ledger-file-DY0AXX3W.js} +2 -2
- package/dist/{search-ledger-file-EvdDZRhv.js.map → search-ledger-file-DY0AXX3W.js.map} +1 -1
- package/dist/{search-ledger-types-C9anU2DX.d.ts → search-ledger-types-B3El5xgS.d.ts} +95 -11
- package/dist/search-ledger-types-B3El5xgS.d.ts.map +1 -0
- package/dist/{search-shipper-C55V7HE3.js → search-shipper-DUlwlCsK.js} +3 -3
- package/dist/{search-shipper-C55V7HE3.js.map → search-shipper-DUlwlCsK.js.map} +1 -1
- package/dist/search-summary-BhY8p0Av.js +378 -0
- package/dist/search-summary-BhY8p0Av.js.map +1 -0
- package/dist/{semantic-concept-judge-Bt7bXAAo.js → semantic-concept-judge-Bg-560H0.js} +3 -3
- package/dist/{semantic-concept-judge-Bt7bXAAo.js.map → semantic-concept-judge-Bg-560H0.js.map} +1 -1
- package/dist/{sequential-lwJOTRON.js → sequential-C21_PP7F.js} +2 -2
- package/dist/{sequential-lwJOTRON.js.map → sequential-C21_PP7F.js.map} +1 -1
- package/dist/{skillopt-optimization-method-DwO3TOAV.js → skillopt-optimization-method-DXQdaBjx.js} +7 -7
- package/dist/{skillopt-optimization-method-DwO3TOAV.js.map → skillopt-optimization-method-DXQdaBjx.js.map} +1 -1
- package/dist/{statistical-heldout-BED3wBtX.d.ts → statistical-heldout-D-xBpbrd.d.ts} +2 -2
- package/dist/{statistical-heldout-BED3wBtX.d.ts.map → statistical-heldout-D-xBpbrd.d.ts.map} +1 -1
- package/dist/{statistical-heldout-GcLIPxk4.js → statistical-heldout-DANVmyug.js} +2 -2
- package/dist/{statistical-heldout-GcLIPxk4.js.map → statistical-heldout-DANVmyug.js.map} +1 -1
- package/dist/{store-tool-spans-Cfh9XUCm.d.ts → store-tool-spans-BxrfuU2t.d.ts} +4 -4
- package/dist/{store-tool-spans-Cfh9XUCm.d.ts.map → store-tool-spans-BxrfuU2t.d.ts.map} +1 -1
- package/dist/{tool-groups-D-mkeN0N.d.ts → tool-groups-BC9O7Epn.d.ts} +2 -2
- package/dist/tool-groups-BC9O7Epn.d.ts.map +1 -0
- package/dist/trace-repair/index.d.ts +1 -1
- package/dist/traces.d.ts +2 -2
- package/dist/{types-BmQRs661.d.ts → types-BWwRXofp.d.ts} +340 -17
- package/dist/types-BWwRXofp.d.ts.map +1 -0
- package/dist/{types-ClK-sHs8.d.ts → types-qoxUfKQg.d.ts} +2 -2
- package/dist/{types-ClK-sHs8.d.ts.map → types-qoxUfKQg.d.ts.map} +1 -1
- package/docs/campaign-proposers.md +14 -16
- package/docs/search-ledger.md +129 -3
- package/package.json +1 -1
- package/dist/campaign-C8iWEF0M.js.map +0 -1
- package/dist/campaign-evidence-BqjlTM3P.js.map +0 -1
- package/dist/claim-BGOUqoMq.d.ts +0 -38
- package/dist/claim-BGOUqoMq.d.ts.map +0 -1
- package/dist/define-agent-eval-BE43YTm4.js.map +0 -1
- package/dist/external-optimizer-process-xFTliuiK.js.map +0 -1
- package/dist/external-optimizer-subprocess-B234V9V0.js.map +0 -1
- package/dist/index-CzfnASj_.d.ts.map +0 -1
- package/dist/llm-judge-NJOHM0iA.js.map +0 -1
- package/dist/paired-promotion-decision-6cn3bLc3.js.map +0 -1
- package/dist/search-ledger-CQ8Uy4FK.js.map +0 -1
- package/dist/search-ledger-types-C9anU2DX.d.ts.map +0 -1
- package/dist/tool-groups-D-mkeN0N.d.ts.map +0 -1
- package/dist/types-BmQRs661.d.ts.map +0 -1
|
@@ -0,0 +1,378 @@
|
|
|
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-CJiAEU3j.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-BhY8p0Av.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-summary-BhY8p0Av.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":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { i as CostLedger } from "./cost-ledger-_IbkejCF.js";
|
|
2
|
-
import {
|
|
2
|
+
import { p as Mutex } from "./journal-DvKCvjty.js";
|
|
3
3
|
import { N as RawAnalystFindingSchema } from "./kind-factory-CdPPHtGZ.js";
|
|
4
4
|
import { c as extractJsonPayload } from "./llm-client-KYQBh9C8.js";
|
|
5
5
|
import { n as paidJsonChat, t as paidChat } from "./chat-json-call-CXHBvUz8.js";
|
|
6
|
-
import { n as decodeRawFindingArray } from "./dspy-rlm-engine-
|
|
6
|
+
import { n as decodeRawFindingArray } from "./dspy-rlm-engine-BX34vPVY.js";
|
|
7
7
|
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import { dirname } from "node:path";
|
|
@@ -777,4 +777,4 @@ async function runSemanticConceptJudge(input, options) {
|
|
|
777
777
|
//#endregion
|
|
778
778
|
export { diffFindings as a, defaultIsMaterial as i, runSemanticConceptJudge as n, createChatTraceEngine as o, FindingsStore as r, SEMANTIC_CONCEPT_JUDGE_VERSION as t };
|
|
779
779
|
|
|
780
|
-
//# sourceMappingURL=semantic-concept-judge-
|
|
780
|
+
//# sourceMappingURL=semantic-concept-judge-Bg-560H0.js.map
|