@tangle-network/agent-eval 0.117.0 → 0.118.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 +30 -0
- package/dist/analyst/index.d.ts +2772 -21
- package/dist/analyst/index.js +7 -6
- package/dist/analyst/index.js.map +1 -1
- package/dist/belief-state/index.d.ts +706 -10
- package/dist/belief-state/index.js +2 -1
- package/dist/belief-state/index.js.map +1 -1
- package/dist/benchmarks/index.d.ts +958 -14
- package/dist/benchmarks/index.js +12 -10
- package/dist/builder-eval/index.d.ts +449 -4
- package/dist/builder-eval/index.js +4 -3
- package/dist/builder-eval/index.js.map +1 -1
- package/dist/campaign/index.d.ts +4276 -74
- package/dist/campaign/index.js +12 -10
- package/dist/{chunk-VF3XSYTI.js → chunk-33JA4TFA.js} +6 -6
- package/dist/{chunk-4JLWXDYA.js → chunk-3EHHMC6E.js} +2 -2
- package/dist/{chunk-CCZIVI3F.js → chunk-BFW56GTT.js} +2 -2
- package/dist/{chunk-YZPO4UHR.js → chunk-DP3BBMYJ.js} +100 -143
- package/dist/chunk-DP3BBMYJ.js.map +1 -0
- package/dist/{chunk-E4BUPP7Z.js → chunk-HKUCJ437.js} +38 -66
- package/dist/chunk-HKUCJ437.js.map +1 -0
- package/dist/{chunk-HZHNRYHK.js → chunk-K6N6XJJX.js} +2 -2
- package/dist/chunk-KSDQVPLR.js +286 -0
- package/dist/chunk-KSDQVPLR.js.map +1 -0
- package/dist/chunk-MA6HLL3S.js +65 -0
- package/dist/chunk-MA6HLL3S.js.map +1 -0
- package/dist/{chunk-MGEHEHSN.js → chunk-OIIMMLRB.js} +11 -11
- package/dist/{chunk-DXZRATT5.js → chunk-OYZAPX5G.js} +3 -3
- package/dist/chunk-PXE2VKMX.js +140 -0
- package/dist/chunk-PXE2VKMX.js.map +1 -0
- package/dist/{chunk-ZUXV7UWZ.js → chunk-Q442S5AS.js} +73 -19
- package/dist/{chunk-ZUXV7UWZ.js.map → chunk-Q442S5AS.js.map} +1 -1
- package/dist/{chunk-ODVOOEWQ.js → chunk-QBRSJK47.js} +2 -2
- package/dist/{chunk-S2F4J57L.js → chunk-QKEGNI5B.js} +77 -32
- package/dist/chunk-QKEGNI5B.js.map +1 -0
- package/dist/{chunk-5UF54T55.js → chunk-S3UZOQ5Y.js} +34 -7
- package/dist/chunk-S3UZOQ5Y.js.map +1 -0
- package/dist/{chunk-FQNLDL4D.js → chunk-SVH2ANFD.js} +136 -4
- package/dist/chunk-SVH2ANFD.js.map +1 -0
- package/dist/{chunk-GQCZRZ7L.js → chunk-U5CHZ5M3.js} +9 -9
- package/dist/{chunk-TVVP3ZZQ.js → chunk-VQMK5FMP.js} +2 -1
- package/dist/{chunk-TVVP3ZZQ.js.map → chunk-VQMK5FMP.js.map} +1 -1
- package/dist/chunk-WDHBCA3M.js +31 -0
- package/dist/chunk-WDHBCA3M.js.map +1 -0
- package/dist/{chunk-HQPHZGL6.js → chunk-YLMUS4MM.js} +9 -9
- package/dist/{chunk-LQUTGLOZ.js → chunk-ZET2UAYW.js} +15 -65
- package/dist/chunk-ZET2UAYW.js.map +1 -0
- package/dist/contract/index.d.ts +4012 -38
- package/dist/contract/index.js +56 -29
- package/dist/contract/index.js.map +1 -1
- package/dist/control.d.ts +1013 -9
- package/dist/control.js +4 -3
- package/dist/fuzz.d.ts +194 -4
- package/dist/fuzz.js +3 -3
- package/dist/hosted/index.d.ts +498 -17
- package/dist/index.d.ts +10982 -1286
- package/dist/index.js +97 -80
- package/dist/index.js.map +1 -1
- package/dist/matrix/index.d.ts +139 -4
- package/dist/meta-eval/index.d.ts +862 -15
- package/dist/meta-eval/index.js +2 -1
- package/dist/meta-eval/index.js.map +1 -1
- package/dist/multishot/index.d.ts +214 -14
- package/dist/openapi.json +1 -1
- package/dist/pipelines/index.d.ts +392 -7
- package/dist/pipelines/index.js +5 -3
- package/dist/pipelines/index.js.map +1 -1
- package/dist/reporting.d.ts +1277 -17
- package/dist/rl.d.ts +2359 -28
- package/dist/rl.js +6 -5
- package/dist/rl.js.map +1 -1
- package/dist/storyboard/index.d.ts +86 -1
- package/dist/trace-attributes.d.ts +16 -0
- package/dist/trace-attributes.js +32 -0
- package/dist/trace-attributes.js.map +1 -0
- package/dist/traces.d.ts +1970 -697
- package/dist/traces.js +49 -32
- package/dist/wire/index.d.ts +655 -9
- package/docs/insight-report.md +44 -0
- package/package.json +9 -3
- package/dist/adversarial-B7loGVVX.d.ts +0 -19
- package/dist/analyst-C8HHvfJp.d.ts +0 -88
- package/dist/analyze-runs--2x39HZ7.d.ts +0 -81
- package/dist/baseline-DKq3gJpP.d.ts +0 -141
- package/dist/calibration-C8MTS7cw.d.ts +0 -101
- package/dist/chunk-5UF54T55.js.map +0 -1
- package/dist/chunk-E4BUPP7Z.js.map +0 -1
- package/dist/chunk-FQNLDL4D.js.map +0 -1
- package/dist/chunk-LQUTGLOZ.js.map +0 -1
- package/dist/chunk-S2F4J57L.js.map +0 -1
- package/dist/chunk-YZPO4UHR.js.map +0 -1
- package/dist/code-agent-session-CjZsVd19.d.ts +0 -87
- package/dist/control-6vuGfmDH.d.ts +0 -258
- package/dist/cost-ledger-DWy3XdJc.d.ts +0 -183
- package/dist/dataset-NENEzRgk.d.ts +0 -115
- package/dist/default-registry-DaK8b3fv.d.ts +0 -155
- package/dist/emitter-CjD7vUwv.d.ts +0 -122
- package/dist/errors-oeQrLqXC.d.ts +0 -74
- package/dist/failure-cluster-DOAcSJ87.d.ts +0 -76
- package/dist/feedback-trajectory-BUnM58xL.d.ts +0 -348
- package/dist/gepa-eESocoDi.d.ts +0 -642
- package/dist/index-PdX4VnPA.d.ts +0 -423
- package/dist/insight-report-DY4nDW9Q.d.ts +0 -310
- package/dist/integrity-DqlBiLyK.d.ts +0 -81
- package/dist/judge-calibration-7C-IDmKr.d.ts +0 -145
- package/dist/kind-factory-ClZmO25A.d.ts +0 -171
- package/dist/llm-client-qoDd18Qz.d.ts +0 -289
- package/dist/multi-layer-verifier-BsqKuLyN.d.ts +0 -150
- package/dist/off-policy-DiwuKKg7.d.ts +0 -132
- package/dist/outcome-store-rnXLEqSn.d.ts +0 -63
- package/dist/policy-edit-wG9uFEFm.d.ts +0 -455
- package/dist/pre-registration-BWQhJ3vz.d.ts +0 -761
- package/dist/provenance-DpjwyseI.d.ts +0 -541
- package/dist/query-CF7PG61p.d.ts +0 -35
- package/dist/raw-provider-sink-C46HDghv.d.ts +0 -132
- package/dist/release-report-C8G2i5Xi.d.ts +0 -236
- package/dist/researcher-C8XyxQsu.d.ts +0 -387
- package/dist/rubric-predictive-validity-p49lLVrE.d.ts +0 -105
- package/dist/run-record-BDH49H2E.d.ts +0 -360
- package/dist/runtime-trajectory-DGBIUt4B.d.ts +0 -49
- package/dist/schema-B3Q3l9Z_.d.ts +0 -201
- package/dist/semantic-concept-judge-CXnPEJbf.d.ts +0 -723
- package/dist/sequential-5iSVfzl2.d.ts +0 -139
- package/dist/series-convergence-D5OWMBg6.d.ts +0 -33
- package/dist/statistics-KUnG73jH.d.ts +0 -494
- package/dist/storage-DrX3v_5B.d.ts +0 -50
- package/dist/store-C1YxJDEK.d.ts +0 -248
- package/dist/store-DGqD0Pyo.d.ts +0 -116
- package/dist/summary-report-C5bKFfm-.d.ts +0 -445
- package/dist/test-graded-scenario-B0ybnPY7.d.ts +0 -166
- package/dist/types-BSw1rOUB.d.ts +0 -634
- package/dist/types-BUxNaJ8c.d.ts +0 -108
- package/dist/types-BkfcQnxV.d.ts +0 -313
- package/dist/verdict-C9MlYujm.d.ts +0 -35
- /package/dist/{chunk-VF3XSYTI.js.map → chunk-33JA4TFA.js.map} +0 -0
- /package/dist/{chunk-4JLWXDYA.js.map → chunk-3EHHMC6E.js.map} +0 -0
- /package/dist/{chunk-CCZIVI3F.js.map → chunk-BFW56GTT.js.map} +0 -0
- /package/dist/{chunk-HZHNRYHK.js.map → chunk-K6N6XJJX.js.map} +0 -0
- /package/dist/{chunk-MGEHEHSN.js.map → chunk-OIIMMLRB.js.map} +0 -0
- /package/dist/{chunk-DXZRATT5.js.map → chunk-OYZAPX5G.js.map} +0 -0
- /package/dist/{chunk-ODVOOEWQ.js.map → chunk-QBRSJK47.js.map} +0 -0
- /package/dist/{chunk-GQCZRZ7L.js.map → chunk-U5CHZ5M3.js.map} +0 -0
- /package/dist/{chunk-HQPHZGL6.js.map → chunk-YLMUS4MM.js.map} +0 -0
|
@@ -1,14 +1,958 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
type AgentProfileCellSchemaVersion = 'agent-profile-cell/v1';
|
|
2
|
+
type AgentProfileJson = string | number | boolean | null | AgentProfileJson[] | {
|
|
3
|
+
[key: string]: AgentProfileJson;
|
|
4
|
+
};
|
|
5
|
+
type AgentProfileDimensionValue = string | number | boolean | null;
|
|
6
|
+
interface AgentProfileSource {
|
|
7
|
+
/** Runtime/profile contract being fingerprinted, e.g. `agent-interface-profile`. */
|
|
8
|
+
kind: string;
|
|
9
|
+
/** sha256 over the canonical source profile object. */
|
|
10
|
+
hash: string;
|
|
11
|
+
}
|
|
12
|
+
interface AgentProfileHarness {
|
|
13
|
+
id: string;
|
|
14
|
+
version?: string;
|
|
15
|
+
hash?: string;
|
|
16
|
+
}
|
|
17
|
+
interface AgentProfileCell {
|
|
18
|
+
schemaVersion: AgentProfileCellSchemaVersion;
|
|
19
|
+
cellId: string;
|
|
20
|
+
profileId: string;
|
|
21
|
+
sourceProfile: AgentProfileSource;
|
|
22
|
+
harness?: AgentProfileHarness;
|
|
23
|
+
model?: string;
|
|
24
|
+
promptHash?: string;
|
|
25
|
+
dimensions?: Record<string, AgentProfileDimensionValue>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Paper-grade RunRecord schema + runtime validator.
|
|
30
|
+
*
|
|
31
|
+
* Every run that participates in a promotion gate, paper table, or
|
|
32
|
+
* researcher loop SHOULD be recorded as a `RunRecord`. The mandatory
|
|
33
|
+
* fields are exactly those the paper "Two Loops, Three Roles" requires
|
|
34
|
+
* for reproducibility: who/what/when/cost/seed/hash, plus the search vs
|
|
35
|
+
* holdout split tag and either a `searchScore` or a `holdoutScore`.
|
|
36
|
+
*
|
|
37
|
+
* This is intentionally NOT a replacement for the rich `Run` /
|
|
38
|
+
* `ProposeReviewReport` / `ScenarioResult` types already in the
|
|
39
|
+
* package. Those are runtime structures with full provenance. A
|
|
40
|
+
* `RunRecord` is the analysis-time projection — the JSON-friendly
|
|
41
|
+
* row you'd put in a parquet file or paste into a notebook.
|
|
42
|
+
*
|
|
43
|
+
* Validate at the boundary:
|
|
44
|
+
*
|
|
45
|
+
* const rec = validateRunRecord(rawJson) // throws on missing
|
|
46
|
+
* const ok = isRunRecord(rawJson) // boolean check
|
|
47
|
+
* const rec = parseRunRecordSafe(rawJson) // { ok, value | error }
|
|
48
|
+
*
|
|
49
|
+
* The validator runs in pure TS — zod is intentionally NOT a
|
|
50
|
+
* dependency. Round-trip tested in `tests/run-record.test.ts`.
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/** Search/dev/holdout split tag. 'search' is the paper-grade alias for the
|
|
54
|
+
* combined train+test pool that the optimizer is allowed to read. */
|
|
55
|
+
type RunSplitTag = 'search' | 'dev' | 'holdout';
|
|
56
|
+
interface RunTokenUsage {
|
|
57
|
+
input: number;
|
|
58
|
+
/** All generated tokens charged as output, including reasoning tokens. */
|
|
59
|
+
output: number;
|
|
60
|
+
/** Reasoning-token subset of `output`, when the provider reports it. */
|
|
61
|
+
reasoning?: number;
|
|
62
|
+
/** Prompt tokens served from a provider cache. */
|
|
63
|
+
cached?: number;
|
|
64
|
+
/** Prompt tokens written into a provider cache. */
|
|
65
|
+
cacheWrite?: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
type CostChannel = 'agent' | 'judge' | 'verifier' | 'analyst' | 'driver' | (string & {});
|
|
69
|
+
interface CostUsage {
|
|
70
|
+
inputTokens: number;
|
|
71
|
+
outputTokens: number;
|
|
72
|
+
cachedTokens?: number;
|
|
73
|
+
}
|
|
74
|
+
interface CostCallBase {
|
|
75
|
+
callId: string;
|
|
76
|
+
channel: CostChannel;
|
|
77
|
+
phase: string;
|
|
78
|
+
actor: string;
|
|
79
|
+
model: string;
|
|
80
|
+
maximumCostUsd?: number;
|
|
81
|
+
tags?: Record<string, string>;
|
|
82
|
+
timestamp: number;
|
|
83
|
+
}
|
|
84
|
+
interface CostReceipt extends CostCallBase, CostUsage {
|
|
85
|
+
status: 'settled';
|
|
86
|
+
costUsd: number;
|
|
87
|
+
costUnknown: boolean;
|
|
88
|
+
usageUnknown?: boolean;
|
|
89
|
+
pricing?: {
|
|
90
|
+
inputUsdPerThousand: number;
|
|
91
|
+
outputUsdPerThousand: number;
|
|
92
|
+
};
|
|
93
|
+
actualCostUsd?: number;
|
|
94
|
+
error?: string;
|
|
95
|
+
}
|
|
96
|
+
interface CostReceiptInput extends CostUsage {
|
|
97
|
+
model: string;
|
|
98
|
+
actualCostUsd?: number;
|
|
99
|
+
costUnknown?: boolean;
|
|
100
|
+
usageUnknown?: boolean;
|
|
101
|
+
}
|
|
102
|
+
type MaximumCharge = {
|
|
103
|
+
externallyEnforcedMaximumUsd: number;
|
|
104
|
+
} | ({
|
|
105
|
+
model: string;
|
|
106
|
+
} & CostUsage);
|
|
107
|
+
interface RunPaidCallInput<T> {
|
|
108
|
+
callId?: string;
|
|
109
|
+
channel: CostChannel;
|
|
110
|
+
phase: string;
|
|
111
|
+
actor: string;
|
|
112
|
+
/** Used before a provider receipt exists and on failures without one. */
|
|
113
|
+
model?: string;
|
|
114
|
+
tags?: Record<string, string>;
|
|
115
|
+
signal?: AbortSignal;
|
|
116
|
+
/** Provider-enforced dollar maximum, or maximum priced token usage. Required when capped. */
|
|
117
|
+
maximumCharge?: MaximumCharge;
|
|
118
|
+
/** `callId` can be forwarded as the provider's idempotency key. */
|
|
119
|
+
execute(signal: AbortSignal, callId: string): Promise<T>;
|
|
120
|
+
receipt(value: T): CostReceiptInput;
|
|
121
|
+
receiptFromError?(error: Error): CostReceiptInput | undefined;
|
|
122
|
+
}
|
|
123
|
+
type PaidCallResult<T> = {
|
|
124
|
+
succeeded: true;
|
|
125
|
+
callId: string;
|
|
126
|
+
value: T;
|
|
127
|
+
receipt: CostReceipt;
|
|
128
|
+
} | {
|
|
129
|
+
succeeded: false;
|
|
130
|
+
callId?: string;
|
|
131
|
+
error: Error;
|
|
132
|
+
receipt?: CostReceipt;
|
|
133
|
+
};
|
|
134
|
+
interface ChannelRollup {
|
|
135
|
+
channel: CostChannel;
|
|
136
|
+
calls: number;
|
|
137
|
+
inputTokens: number;
|
|
138
|
+
outputTokens: number;
|
|
139
|
+
cachedTokens: number;
|
|
140
|
+
costUsd: number;
|
|
141
|
+
unpricedCalls: number;
|
|
142
|
+
unknownUsageCalls: number;
|
|
143
|
+
}
|
|
144
|
+
interface CostLedgerSummary {
|
|
145
|
+
totalCalls: number;
|
|
146
|
+
pendingCalls: number;
|
|
147
|
+
unresolvedCalls: number;
|
|
148
|
+
reservedCostUsd: number;
|
|
149
|
+
inputTokens: number;
|
|
150
|
+
outputTokens: number;
|
|
151
|
+
cachedTokens: number;
|
|
152
|
+
totalCostUsd: number;
|
|
153
|
+
byChannel: ChannelRollup[];
|
|
154
|
+
unpricedModels: string[];
|
|
155
|
+
fullyPriced: boolean;
|
|
156
|
+
usageComplete: boolean;
|
|
157
|
+
accountingComplete: boolean;
|
|
158
|
+
incompleteReasons: string[];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* LLM client with graceful degrade.
|
|
163
|
+
*
|
|
164
|
+
* OpenAI-compatible `/v1/chat/completions` client with:
|
|
165
|
+
* - Exponential-backoff retry on 429 + 5xx gateway errors (502/503/504).
|
|
166
|
+
* - Retry on transient network errors (fetch failed, AbortError, ECONNRESET).
|
|
167
|
+
* - Graceful json_schema → json_object degrade on 400 with schema-reject body.
|
|
168
|
+
* - Fenced-JSON stripping (```json ... ```) for models that wrap structured output.
|
|
169
|
+
* - Configurable base URL + api key / bearer, works with LiteLLM proxies, OpenAI
|
|
170
|
+
* directly, cli-bridge subscriptions, and any router that speaks the spec.
|
|
171
|
+
*
|
|
172
|
+
* Usage:
|
|
173
|
+
* const { value, result } = await callLlmJson<MyType>(
|
|
174
|
+
* { model: 'gpt-4o', messages: [...], jsonSchema: { name: 'x', schema: {...} } },
|
|
175
|
+
* { baseUrl: 'https://router.tangle.tools/v1', apiKey: process.env.KEY },
|
|
176
|
+
* )
|
|
177
|
+
*
|
|
178
|
+
* This is THE llm-calling seam for agent-eval primitives that need structured
|
|
179
|
+
* output (semantic concept judge, reviewer directives, critic scores). Primitives
|
|
180
|
+
* that need free-form text use `callLlm` and parse output themselves.
|
|
181
|
+
*/
|
|
182
|
+
|
|
183
|
+
interface LlmUsage {
|
|
184
|
+
promptTokens: number;
|
|
185
|
+
completionTokens: number;
|
|
186
|
+
totalTokens: number;
|
|
187
|
+
/** False when the provider omitted or malformed prompt/completion usage. */
|
|
188
|
+
captured?: boolean;
|
|
189
|
+
/** Proxies populate this when prompt caching is on. */
|
|
190
|
+
cachedPromptTokens?: number;
|
|
191
|
+
}
|
|
192
|
+
interface LlmCallResult {
|
|
193
|
+
/** The text content of the first choice. Empty string if none. */
|
|
194
|
+
content: string;
|
|
195
|
+
usage: LlmUsage;
|
|
196
|
+
/**
|
|
197
|
+
* Cost in USD. Pulled from proxy's `_response_cost` field when present;
|
|
198
|
+
* `null` when neither the proxy nor the caller can derive it.
|
|
199
|
+
*/
|
|
200
|
+
costUsd: number | null;
|
|
201
|
+
/** Model name actually used (echoed from response). */
|
|
202
|
+
model: string;
|
|
203
|
+
/** Wall-clock duration of the HTTP call (last attempt, if retried). */
|
|
204
|
+
durationMs: number;
|
|
205
|
+
/**
|
|
206
|
+
* `finish_reason` echoed from the first choice (`stop`, `length`,
|
|
207
|
+
* `content_filter`, `tool_calls`, ...). `null` when the provider omits it.
|
|
208
|
+
* Exposed so a free-form `callLlm` caller CAN detect a truncated answer
|
|
209
|
+
* (`length`) instead of treating a cut-off completion as complete. Note:
|
|
210
|
+
* `callLlm` does not itself reject on it — acting on this signal is the
|
|
211
|
+
* caller's responsibility (in-repo free-form drivers do not yet enforce it).
|
|
212
|
+
*/
|
|
213
|
+
finishReason?: string | null;
|
|
214
|
+
/**
|
|
215
|
+
* True when `content.trim()` is empty. An empty completion is a silent zero
|
|
216
|
+
* for free-form `callLlm` callers; this flag is the signal a caller can
|
|
217
|
+
* inspect to fail loud rather than proceed on an empty string. `callLlm`
|
|
218
|
+
* surfaces it but does not throw on it.
|
|
219
|
+
*/
|
|
220
|
+
contentEmpty?: boolean;
|
|
221
|
+
/** Raw response body. */
|
|
222
|
+
raw: Record<string, unknown>;
|
|
223
|
+
}
|
|
224
|
+
type LlmCallMetadata = Pick<LlmCallResult, 'usage' | 'costUsd' | 'model' | 'durationMs'>;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Analyst contract — the missing orchestration layer over agent-eval's
|
|
228
|
+
* existing analyzers (analyzeTraces, MultiLayerVerifier, RunCritic,
|
|
229
|
+
* SemanticConceptJudge, JudgeFn, ...).
|
|
230
|
+
*
|
|
231
|
+
* Each existing primitive returns its own output shape. The Analyst
|
|
232
|
+
* contract is the single envelope every primitive lifts into, so a
|
|
233
|
+
* registry can run N analysts against a run and a single renderer can
|
|
234
|
+
* compose findings without knowing which analyzer produced them.
|
|
235
|
+
*
|
|
236
|
+
* The contract is intentionally domain-agnostic: nothing here knows
|
|
237
|
+
* about code, voice, RAG, or any particular agent stack. Analysts
|
|
238
|
+
* declare what INPUT KIND they need (a trace store, an artifact dir,
|
|
239
|
+
* a RunRecord, a JudgeInput, or `custom`), and the registry routes
|
|
240
|
+
* the matching input from `AnalystRunInputs`.
|
|
241
|
+
*/
|
|
242
|
+
|
|
243
|
+
interface EvidenceRef {
|
|
244
|
+
/**
|
|
245
|
+
* Where the evidence lives. `span` and `event` refer to OTLP trace
|
|
246
|
+
* elements; `artifact` to a file inside the run's artifact tree;
|
|
247
|
+
* `finding` to another AnalystFinding (cross-analyst chaining);
|
|
248
|
+
* `metric` to a named scalar reading the renderer knows how to read.
|
|
249
|
+
*/
|
|
250
|
+
kind: 'span' | 'event' | 'artifact' | 'finding' | 'metric';
|
|
251
|
+
uri: string;
|
|
252
|
+
excerpt?: string;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
type PolicyEditSchemaVersion = 'policy-edit/v1';
|
|
256
|
+
declare const POLICY_EDIT_AXES: readonly ["carrier", "representation", "budget", "sampling", "output_contract", "tool_contract", "routing", "memory", "agent_profile", "deployment_target"];
|
|
257
|
+
type PolicyEditAxis = (typeof POLICY_EDIT_AXES)[number];
|
|
258
|
+
declare const POLICY_EDIT_TARGET_SURFACES: readonly ["prompt", "tool-contract", "runtime-config", "memory", "agent-profile", "code", "deployment"];
|
|
259
|
+
type PolicyEditTargetSurface = (typeof POLICY_EDIT_TARGET_SURFACES)[number];
|
|
260
|
+
type PolicyEditRisk = 'low' | 'medium' | 'high' | 'unknown';
|
|
261
|
+
type PolicyEditGainDirection = 'increase' | 'decrease';
|
|
262
|
+
type PolicyEditGainUnit = 'absolute' | 'relative' | 'percent' | 'score';
|
|
263
|
+
interface PolicyEditTarget {
|
|
264
|
+
surface: PolicyEditTargetSurface;
|
|
265
|
+
/** Stable path inside the target surface, for example `system-prompt:tools`
|
|
266
|
+
* or `budget.maxTurns`. */
|
|
267
|
+
path?: string;
|
|
268
|
+
/** Optional canonical deployment identity. Store the existing cell, not a
|
|
269
|
+
* local profile shape. */
|
|
270
|
+
agentProfileCell?: AgentProfileCell;
|
|
271
|
+
/** Human label when the path is not enough for a readable audit trail. */
|
|
272
|
+
label?: string;
|
|
273
|
+
}
|
|
274
|
+
type PolicyEditChange = {
|
|
275
|
+
kind: 'text';
|
|
276
|
+
mode: 'append' | 'prepend' | 'replace';
|
|
277
|
+
value: string;
|
|
278
|
+
/** Required when `mode === 'replace'`; exact match only. */
|
|
279
|
+
find?: string;
|
|
280
|
+
} | {
|
|
281
|
+
kind: 'json';
|
|
282
|
+
mode: 'set' | 'merge' | 'remove';
|
|
283
|
+
path: string;
|
|
284
|
+
value?: AgentProfileJson;
|
|
285
|
+
};
|
|
286
|
+
interface PolicyEditExpectedGain {
|
|
287
|
+
/** Metric this edit is expected to move, e.g. `holdout.composite`. */
|
|
288
|
+
metric: string;
|
|
289
|
+
direction: PolicyEditGainDirection;
|
|
290
|
+
/** Positive magnitude in the metric's native units. */
|
|
291
|
+
amount: number;
|
|
292
|
+
unit?: PolicyEditGainUnit;
|
|
293
|
+
rationale?: string;
|
|
294
|
+
}
|
|
295
|
+
interface PolicyEditSource {
|
|
296
|
+
findingIds: string[];
|
|
297
|
+
analystIds: string[];
|
|
298
|
+
evidenceRefs: EvidenceRef[];
|
|
299
|
+
/** Mirrors `AnalystFinding.derived_from_judge`; admission rejects it. */
|
|
300
|
+
derivedFromJudge?: boolean;
|
|
301
|
+
}
|
|
302
|
+
interface PolicyEdit {
|
|
303
|
+
schemaVersion: PolicyEditSchemaVersion;
|
|
304
|
+
editId: string;
|
|
305
|
+
axis: PolicyEditAxis;
|
|
306
|
+
target: PolicyEditTarget;
|
|
307
|
+
change: PolicyEditChange;
|
|
308
|
+
claim: string;
|
|
309
|
+
expectedGain: PolicyEditExpectedGain;
|
|
310
|
+
confidence: number;
|
|
311
|
+
risk: PolicyEditRisk;
|
|
312
|
+
source: PolicyEditSource;
|
|
313
|
+
rationale?: string;
|
|
314
|
+
validationPlan?: string;
|
|
315
|
+
metadata?: Record<string, unknown>;
|
|
316
|
+
}
|
|
317
|
+
declare const POLICY_EDIT_CANDIDATE_RECORD_SCHEMA: "tangle.policy-edit-candidate.v1";
|
|
318
|
+
/** JSON-safe attribution carried with a measured candidate and its scores. */
|
|
319
|
+
interface PolicyEditCandidateRecord {
|
|
320
|
+
schema: typeof POLICY_EDIT_CANDIDATE_RECORD_SCHEMA;
|
|
321
|
+
policyEdit: PolicyEdit;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Pass A substrate types — `runCampaign` is the one primitive every
|
|
326
|
+
* eval flow composes from. Three contracts in this file:
|
|
327
|
+
*
|
|
328
|
+
* - `Scenario` input set
|
|
329
|
+
* - `DispatchFn` how to run one scenario → artifact
|
|
330
|
+
* - `CampaignResult` defined output schema (the contract downstream tools depend on)
|
|
331
|
+
*
|
|
332
|
+
* Three more lifted from earlier substrate work (re-exported):
|
|
333
|
+
*
|
|
334
|
+
* - `JudgeConfig` pluggable dimensional scorer (0.38)
|
|
335
|
+
* - `Mutator` optimization-loop surface mutator
|
|
336
|
+
* - `Gate` promotion gate (`HeldOutGate` and friends adapt to this)
|
|
337
|
+
*
|
|
338
|
+
* No new architecture vs 0.38 — Pass A formalizes the shapes so consumers
|
|
339
|
+
* can build dashboards / CI gates / regression diffs against a stable schema.
|
|
340
|
+
*/
|
|
341
|
+
|
|
342
|
+
/** Stable identifier + kind tag for any scenario. Consumers
|
|
343
|
+
* extend with their per-domain payload (persona, task, requirement, ...). */
|
|
344
|
+
interface Scenario {
|
|
345
|
+
id: string;
|
|
346
|
+
kind: string;
|
|
347
|
+
tags?: string[];
|
|
348
|
+
}
|
|
349
|
+
/** Context handed to every dispatch invocation. Scoped — every
|
|
350
|
+
* trace/span carries the cellId, every artifact write lands under the cell's
|
|
351
|
+
* artifact root, the cost meter accumulates per cell. */
|
|
352
|
+
interface DispatchContext {
|
|
353
|
+
cellId: string;
|
|
354
|
+
rep: number;
|
|
355
|
+
generation?: number;
|
|
356
|
+
seed: number;
|
|
357
|
+
signal: AbortSignal;
|
|
358
|
+
trace: CampaignTraceWriter;
|
|
359
|
+
artifacts: CampaignArtifactWriter;
|
|
360
|
+
cost: CampaignCostMeter;
|
|
361
|
+
/** Populated when this run is part of a multi-cycle improvement loop. */
|
|
362
|
+
cycleId?: string;
|
|
363
|
+
/** Populated when the substrate resumed from a prior cache hit. */
|
|
364
|
+
resumedFrom?: string;
|
|
365
|
+
/**
|
|
366
|
+
* Opaque placement key supplied by `RunCampaignOptions.cellPlacement`.
|
|
367
|
+
* The substrate forwards it through unchanged; placement-aware Dispatch
|
|
368
|
+
* implementations (e.g. `httpDispatch` from `/adapters/http`) read it to
|
|
369
|
+
* route the cell to the right worker / region / sandbox. `undefined`
|
|
370
|
+
* when no placement strategy is configured.
|
|
371
|
+
*/
|
|
372
|
+
placement?: string;
|
|
373
|
+
}
|
|
374
|
+
/** The canonical judge verdict shape — one declaration, shared by campaign
|
|
375
|
+
* judges and the multishot judge runner (which re-exports this type).
|
|
376
|
+
*
|
|
377
|
+
* Scale is PRODUCER-DEFINED: campaign convention is [0,1]; the legacy
|
|
378
|
+
* multishot runner emits 0-10. Cross-scale comparison must go through
|
|
379
|
+
* `detectScale` (src/campaign/gates/statistical-heldout.ts, used by
|
|
380
|
+
* promotion-policy) — never renormalize a producer's values in place, as
|
|
381
|
+
* downstream thresholds (`composite >= 5` in multishot/matrix.ts, live-soak
|
|
382
|
+
* `>= 7` gates) key on the producer's native scale. */
|
|
383
|
+
interface JudgeScore {
|
|
384
|
+
dimensions: Record<string, number>;
|
|
385
|
+
composite: number;
|
|
386
|
+
notes: string;
|
|
387
|
+
/** Provider metadata for display and diagnostics; accounting uses CostLedger receipts. */
|
|
388
|
+
llmCall?: LlmCallMetadata;
|
|
389
|
+
/** Set when the judge itself failed (call error, unparseable output).
|
|
390
|
+
* `composite`/`dimensions` carry no signal — aggregators MUST exclude
|
|
391
|
+
* failed scores from means instead of folding them into zeros. */
|
|
392
|
+
failed?: true;
|
|
393
|
+
/** Ensemble extras (populated by `ensembleJudge`): max per-dimension
|
|
394
|
+
* spread across surviving judges — the inter-rater signal. */
|
|
395
|
+
maxDisagreement?: number;
|
|
396
|
+
/** Ensemble extras: judge identities whose verdict failed. */
|
|
397
|
+
failedJudges?: string[];
|
|
398
|
+
/** Ensemble extras: each surviving judge's per-dimension scores. */
|
|
399
|
+
perJudge?: Record<string, Record<string, number>>;
|
|
400
|
+
}
|
|
401
|
+
/** Five-valued verdict taxonomy (MOSS-paper alignment). */
|
|
402
|
+
type GateDecision = 'ship' | 'hold' | 'need_more_work' | 'model_ceiling' | 'arch_ceiling';
|
|
403
|
+
interface GateResult {
|
|
404
|
+
decision: GateDecision;
|
|
405
|
+
reasons: string[];
|
|
406
|
+
contributingGates: Array<{
|
|
407
|
+
name: string;
|
|
408
|
+
passed: boolean;
|
|
409
|
+
detail: unknown;
|
|
410
|
+
}>;
|
|
411
|
+
delta?: number;
|
|
412
|
+
}
|
|
413
|
+
/** Scoped trace writer handed to each dispatch — every span
|
|
414
|
+
* auto-tagged with the cellId so traces filter cleanly. */
|
|
415
|
+
interface CampaignTraceWriter {
|
|
416
|
+
span(name: string, attributes?: Record<string, unknown>): TraceSpan;
|
|
417
|
+
flush(): Promise<void>;
|
|
418
|
+
}
|
|
419
|
+
interface TraceSpan {
|
|
420
|
+
end(attributes?: Record<string, unknown>): void;
|
|
421
|
+
setAttribute(key: string, value: unknown): void;
|
|
422
|
+
}
|
|
423
|
+
/** Scoped artifact writer — `write(path, content)` lands under
|
|
424
|
+
* `<runDir>/<cellId>/<path>`. */
|
|
425
|
+
interface CampaignArtifactWriter {
|
|
426
|
+
write(path: string, content: string | Uint8Array): Promise<string>;
|
|
427
|
+
writeJson(path: string, value: unknown): Promise<string>;
|
|
428
|
+
}
|
|
429
|
+
/** Token usage accumulated for a cell. Aliased to the canonical `RunTokenUsage`
|
|
430
|
+
* (run-record.ts, same package) so a cell maps onto a `RunRecord` for the
|
|
431
|
+
* backend-integrity guard with ONE source of truth — a field added to
|
|
432
|
+
* `RunTokenUsage` is a compile error here, not a silent drift. */
|
|
433
|
+
type CampaignTokenUsage = RunTokenUsage;
|
|
434
|
+
/** Cell-scoped paid-call entry point. The dispatch places every paid operation
|
|
435
|
+
* inside `runPaidCall`; the returned provider result supplies one receipt with
|
|
436
|
+
* cost, tokens, and resolved model. Calls made outside this method are not
|
|
437
|
+
* admitted or captured. */
|
|
438
|
+
interface CampaignCostMeter {
|
|
439
|
+
/** The only paid-call path. Returns a typed result; callers must inspect it. */
|
|
440
|
+
runPaidCall<T>(input: Omit<RunPaidCallInput<T>, 'channel' | 'phase' | 'tags'> & {
|
|
441
|
+
channel?: CostChannel;
|
|
442
|
+
}): Promise<PaidCallResult<T>>;
|
|
443
|
+
}
|
|
444
|
+
interface CampaignCellResult<TArtifact> {
|
|
445
|
+
/** Manifest that produced this cell. Resumability refuses to reuse a cell
|
|
446
|
+
* whose manifest differs from the current run. */
|
|
447
|
+
manifestHash?: string;
|
|
448
|
+
cellId: string;
|
|
449
|
+
scenarioId: string;
|
|
450
|
+
rep: number;
|
|
451
|
+
generation?: number;
|
|
452
|
+
artifact: TArtifact;
|
|
453
|
+
judgeScores: Record<string, JudgeScore>;
|
|
454
|
+
costUsd: number;
|
|
455
|
+
/** True when at least one priced receipt used the model table instead of a provider bill. */
|
|
456
|
+
costEstimated?: boolean;
|
|
457
|
+
/** Exact durable receipts required to reuse this cached result. */
|
|
458
|
+
costCallIds?: string[];
|
|
459
|
+
/** Agent-call token usage committed by `ctx.cost.runPaidCall`.
|
|
460
|
+
* `{ input: 0, output: 0 }` when no paid agent call was recorded. */
|
|
461
|
+
tokenUsage: CampaignTokenUsage;
|
|
462
|
+
/** Concrete model from the latest committed agent receipt. Consumed by
|
|
463
|
+
* `buildRunRecord` to pin the model when the declared profile uses a
|
|
464
|
+
* runtime-resolved sentinel. */
|
|
465
|
+
resolvedModel?: string;
|
|
466
|
+
durationMs: number;
|
|
467
|
+
seed: number;
|
|
468
|
+
cached: boolean;
|
|
469
|
+
error?: string;
|
|
470
|
+
}
|
|
471
|
+
interface JudgeAggregate {
|
|
472
|
+
mean: number;
|
|
473
|
+
stdev: number;
|
|
474
|
+
ci95: [number, number];
|
|
475
|
+
n: number;
|
|
476
|
+
}
|
|
477
|
+
interface ScenarioAggregate {
|
|
478
|
+
meanComposite: number;
|
|
479
|
+
ci95: [number, number];
|
|
480
|
+
n: number;
|
|
481
|
+
}
|
|
482
|
+
interface GenerationRecord {
|
|
483
|
+
generationIndex: number;
|
|
484
|
+
candidates: GenerationCandidate[];
|
|
485
|
+
promoted: string[];
|
|
486
|
+
}
|
|
487
|
+
/** One scored candidate surface in a generation. `dimensions` + `scenarios`
|
|
488
|
+
* let a reflective proposer ground its next proposal on WHICH
|
|
489
|
+
* dimensions the candidate is weakest on and WHICH scenarios it best/worst
|
|
490
|
+
* handled — the evidence a blind `Mutator` cannot see. */
|
|
491
|
+
interface GenerationCandidate {
|
|
492
|
+
surfaceHash: string;
|
|
493
|
+
composite: number;
|
|
494
|
+
ci95: [number, number];
|
|
495
|
+
/** Exact surface this candidate mutated. */
|
|
496
|
+
parentSurfaceHash?: string;
|
|
497
|
+
/** Measured search-split composite of the exact parent surface. */
|
|
498
|
+
parentComposite?: number;
|
|
499
|
+
/** Candidate composite minus its parent's composite. Present only when the
|
|
500
|
+
* candidate completed the designed denominator. */
|
|
501
|
+
observedDeltaFromParent?: number;
|
|
502
|
+
/** Whether this candidate had a scorable result for every designed campaign
|
|
503
|
+
* cell and was therefore eligible for ranking, promotion, and Pareto
|
|
504
|
+
* selection. Older externally-authored records may omit this field; loop
|
|
505
|
+
* records always populate it. */
|
|
506
|
+
eligibleForPromotion?: boolean;
|
|
507
|
+
/** Exact denominator receipt for selection eligibility. Scores stay
|
|
508
|
+
* descriptive: an incomplete candidate is retained with its observed score
|
|
509
|
+
* and errors instead of receiving an invented penalty. */
|
|
510
|
+
coverage?: {
|
|
511
|
+
expectedCells: number;
|
|
512
|
+
scorableCells: number;
|
|
513
|
+
unscorableCells: Array<{
|
|
514
|
+
cellId: string;
|
|
515
|
+
reason: string;
|
|
516
|
+
}>;
|
|
517
|
+
};
|
|
518
|
+
/** Mean score per judge dimension across all cells (scenarios × reps ×
|
|
519
|
+
* judges that reported the dimension). */
|
|
520
|
+
dimensions: Record<string, number>;
|
|
521
|
+
/** Per-scenario composite (mean over reps + judges), plus the judge's
|
|
522
|
+
* free-form `notes` for that scenario — the "why it scored low" evidence a
|
|
523
|
+
* reflective proposer grounds its next edit on. Keep `notes` GENERALIZABLE
|
|
524
|
+
* (which checks/lines/dimensions failed and how), NOT case-specific ground
|
|
525
|
+
* truth: leaking expected answers into the prompt is memorization, and the
|
|
526
|
+
* held-out gate would reject it anyway. */
|
|
527
|
+
scenarios: Array<{
|
|
528
|
+
scenarioId: string;
|
|
529
|
+
composite: number;
|
|
530
|
+
notes?: string;
|
|
531
|
+
}>;
|
|
532
|
+
/** Proposer-supplied short label for the change. Present when the proposer
|
|
533
|
+
* returned a `ProposedCandidate`; absent for bare-surface mutators. */
|
|
534
|
+
label?: string;
|
|
535
|
+
/** Proposer-supplied rationale — WHY this candidate was proposed. The
|
|
536
|
+
* "because rationale Z" the audit requires to survive to the result.
|
|
537
|
+
* Present when the proposer returned a `ProposedCandidate`. */
|
|
538
|
+
rationale?: string;
|
|
539
|
+
/** Exact structured cause threaded from the proposer, when available. */
|
|
540
|
+
candidateRecord?: PolicyEditCandidateRecord;
|
|
541
|
+
}
|
|
542
|
+
interface CampaignAggregates {
|
|
543
|
+
byJudge: Record<string, JudgeAggregate>;
|
|
544
|
+
byScenario: Record<string, ScenarioAggregate>;
|
|
545
|
+
/** Canonical campaign accounting, including worker and judge calls. */
|
|
546
|
+
cost: CostLedgerSummary;
|
|
547
|
+
/** Compatibility alias of `cost.totalCostUsd`. */
|
|
548
|
+
totalCostUsd: number;
|
|
549
|
+
cellsExecuted: number;
|
|
550
|
+
cellsSkipped: number;
|
|
551
|
+
cellsCached: number;
|
|
552
|
+
cellsFailed: number;
|
|
553
|
+
}
|
|
554
|
+
interface CampaignResult<TArtifact = unknown, TScenario extends Scenario = Scenario> {
|
|
555
|
+
/** sha256(scenarios, judges, dispatch source ref, optimizer config, seed). Stable identity for reruns. */
|
|
556
|
+
manifestHash: string;
|
|
557
|
+
seed: number;
|
|
558
|
+
startedAt: string;
|
|
559
|
+
endedAt: string;
|
|
560
|
+
durationMs: number;
|
|
561
|
+
cells: Array<CampaignCellResult<TArtifact>>;
|
|
562
|
+
aggregates: CampaignAggregates;
|
|
563
|
+
optimization?: {
|
|
564
|
+
generations: GenerationRecord[];
|
|
565
|
+
winnerSurfaceHash?: string;
|
|
566
|
+
};
|
|
567
|
+
gate?: GateResult;
|
|
568
|
+
prUrl?: string;
|
|
569
|
+
runDir: string;
|
|
570
|
+
artifactsByPath: Record<string, string>;
|
|
571
|
+
/** Substrate strips the input scenarios to id+kind for the result manifest;
|
|
572
|
+
* consumers needing full payload look it up via the original input. The
|
|
573
|
+
* type parameter `TScenario` is propagated for downstream consumers that
|
|
574
|
+
* want narrowed types when extending `CampaignResult`. */
|
|
575
|
+
scenarios: Array<Pick<TScenario, 'id' | 'kind'>>;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Shared types for the reference benchmark wrappers under
|
|
580
|
+
* `src/benchmarks/`. Each wrapper exports the three functions in
|
|
581
|
+
* `BenchmarkAdapter` plus its own typed `DatasetItem` shape.
|
|
582
|
+
*/
|
|
583
|
+
|
|
584
|
+
type BenchmarkTaskKind = 'retrieval' | 'rag-answer' | 'hallucination' | 'kb-improvement' | 'routing' | 'custom';
|
|
585
|
+
type BenchmarkFamily = 'beir' | 'mteb-retrieval' | 'msmarco' | 'trec-dl' | 'miracl' | 'lotte' | 'bright' | 'crag' | 'hotpotqa' | 'kilt' | 'ragtruth' | 'faithbench' | 'first-party' | 'custom';
|
|
586
|
+
interface BenchmarkDatasetItem<TPayload = unknown> {
|
|
587
|
+
/** Stable dataset-local item id (used for split assignment + paper
|
|
588
|
+
* references). Unique within a benchmark. */
|
|
589
|
+
id: string;
|
|
590
|
+
/** Free-form payload. Each benchmark defines its own shape. */
|
|
591
|
+
payload: TPayload;
|
|
592
|
+
/** Optional precomputed split. When absent, adapters use assignSplit(id). */
|
|
593
|
+
split?: RunSplitTag;
|
|
594
|
+
/** Benchmark family this row came from, e.g. `beir` or `crag`. */
|
|
595
|
+
family?: BenchmarkFamily | string;
|
|
596
|
+
/** Benchmark-local task kind, e.g. retrieval vs answer quality. */
|
|
597
|
+
taskKind?: BenchmarkTaskKind | string;
|
|
598
|
+
/** Slice labels such as language, domain, freshness, multihop, long-tail. */
|
|
599
|
+
tags?: string[];
|
|
600
|
+
/** Dataset provenance, version, URL, or license notes. */
|
|
601
|
+
source?: BenchmarkSource;
|
|
602
|
+
metadata?: Record<string, unknown>;
|
|
603
|
+
}
|
|
604
|
+
interface BenchmarkEvaluation {
|
|
605
|
+
/** [0, 1] score for the response on this item. Exact-match
|
|
606
|
+
* benchmarks use 0/1; partial-credit benchmarks may return
|
|
607
|
+
* fractional values. */
|
|
608
|
+
score: number;
|
|
609
|
+
/** Optional pass/fail projection. Defaults to `score > 0` when absent. */
|
|
610
|
+
passed?: boolean;
|
|
611
|
+
/** Numeric sub-metrics. These become report dimensions. */
|
|
612
|
+
dimensions?: Record<string, number>;
|
|
613
|
+
/** Optional bag of raw scoring signals — e.g. parsed numeric
|
|
614
|
+
* answer, regex match, judge sub-scores. */
|
|
615
|
+
raw: Record<string, unknown>;
|
|
616
|
+
notes?: string;
|
|
617
|
+
}
|
|
618
|
+
interface BenchmarkSource {
|
|
619
|
+
name?: string;
|
|
620
|
+
url?: string;
|
|
621
|
+
version?: string;
|
|
622
|
+
license?: string;
|
|
623
|
+
citation?: string;
|
|
624
|
+
}
|
|
625
|
+
/** Common signature implemented by every adapter under `src/benchmarks/*`. */
|
|
626
|
+
interface BenchmarkAdapter<_TItem = unknown, TPayload = unknown, TArtifact = string> {
|
|
627
|
+
/** Stable benchmark id such as `beir/nfcorpus` or `crag/smoke`. */
|
|
628
|
+
id?: string;
|
|
629
|
+
family?: BenchmarkFamily | string;
|
|
630
|
+
taskKind?: BenchmarkTaskKind | string;
|
|
631
|
+
description?: string;
|
|
632
|
+
source?: BenchmarkSource;
|
|
633
|
+
defaultMetric?: string;
|
|
634
|
+
/** Load the dataset for the given split. May hit the network on
|
|
635
|
+
* first call but should be cache-friendly. Adapters that don't
|
|
636
|
+
* ship the dataset itself MUST throw a clearly-marked error
|
|
637
|
+
* pointing the caller at the loader script. */
|
|
638
|
+
loadDataset(split: RunSplitTag): Promise<BenchmarkDatasetItem<TPayload>[]>;
|
|
639
|
+
/** Score a single response. Pure with respect to the inputs. */
|
|
640
|
+
evaluate(item: BenchmarkDatasetItem<TPayload>, artifact: TArtifact): Promise<BenchmarkEvaluation>;
|
|
641
|
+
/** Deterministic split assignment via item id hashing. The
|
|
642
|
+
* fraction of items in each split is implementation-defined but
|
|
643
|
+
* MUST be stable across processes and platforms. */
|
|
644
|
+
assignSplit(itemId: string): RunSplitTag;
|
|
645
|
+
}
|
|
646
|
+
interface BenchmarkScenario<TPayload = unknown> extends Scenario {
|
|
647
|
+
kind: 'benchmark';
|
|
648
|
+
benchmarkId: string;
|
|
649
|
+
family: BenchmarkFamily | string;
|
|
650
|
+
taskKind: BenchmarkTaskKind | string;
|
|
651
|
+
splitTag: RunSplitTag;
|
|
652
|
+
item: BenchmarkDatasetItem<TPayload>;
|
|
653
|
+
}
|
|
654
|
+
type BenchmarkResponder<TPayload = unknown, TArtifact = string> = (input: {
|
|
655
|
+
scenario: BenchmarkScenario<TPayload>;
|
|
656
|
+
item: BenchmarkDatasetItem<TPayload>;
|
|
657
|
+
context: DispatchContext;
|
|
658
|
+
}) => Promise<TArtifact> | TArtifact;
|
|
659
|
+
/** Split-assignment seed shared across all benchmarks. Bumping this
|
|
660
|
+
* value reshuffles every split — do NOT do that lightly. */
|
|
661
|
+
declare const BENCHMARK_SPLIT_SEED = "agent-eval-v1";
|
|
662
|
+
/**
|
|
663
|
+
* Assign an item id to one of `'search' | 'dev' | 'holdout'` using a
|
|
664
|
+
* stable 32-bit hash of `${seed}::${id}`. Default proportions:
|
|
665
|
+
*
|
|
666
|
+
* search: 60% (optimization-readable)
|
|
667
|
+
* dev: 20% (held-out for tuning, leak-on-purpose during dev)
|
|
668
|
+
* holdout:20% (paper-grade held-out, gated reads)
|
|
669
|
+
*/
|
|
670
|
+
declare function deterministicSplit(itemId: string, seed?: string): RunSplitTag;
|
|
671
|
+
|
|
672
|
+
interface BenchmarkMetricCalibrationOptions<TPayload = unknown, TArtifact = string> {
|
|
673
|
+
adapter: BenchmarkAdapter<BenchmarkDatasetItem<TPayload>, TPayload, TArtifact>;
|
|
674
|
+
item: BenchmarkDatasetItem<TPayload>;
|
|
675
|
+
weakArtifact: TArtifact;
|
|
676
|
+
strongArtifact: TArtifact;
|
|
677
|
+
maxWeakScore?: number;
|
|
678
|
+
minStrongScore?: number;
|
|
679
|
+
minGap?: number;
|
|
680
|
+
}
|
|
681
|
+
interface BenchmarkMetricCalibrationResult {
|
|
682
|
+
passed: boolean;
|
|
683
|
+
weak: BenchmarkEvaluation;
|
|
684
|
+
strong: BenchmarkEvaluation;
|
|
685
|
+
weakScore: number;
|
|
686
|
+
strongScore: number;
|
|
687
|
+
gap: number;
|
|
688
|
+
reasons: string[];
|
|
689
|
+
}
|
|
690
|
+
declare function calibrateBenchmarkMetric<TPayload = unknown, TArtifact = string>(options: BenchmarkMetricCalibrationOptions<TPayload, TArtifact>): Promise<BenchmarkMetricCalibrationResult>;
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Synthetic routing dataset. 16 tasks across 4 categories. Used as a
|
|
694
|
+
* deterministic, dependency-free benchmark for any router that maps a
|
|
695
|
+
* natural-language request to one of a fixed set of route labels.
|
|
696
|
+
*
|
|
697
|
+
* Format (see `routing/README.md` for prose):
|
|
698
|
+
*
|
|
699
|
+
* {
|
|
700
|
+
* id: stable per-task ID (matches across processes).
|
|
701
|
+
* category: one of the four route labels.
|
|
702
|
+
* prompt: the user-facing request the router must classify.
|
|
703
|
+
* route: the ground-truth route the router should pick.
|
|
704
|
+
* synonyms: other strings that count as a correct answer.
|
|
705
|
+
* hardNegatives:close-but-wrong route labels — used to detect the
|
|
706
|
+
* "always picks the popular route" failure mode.
|
|
707
|
+
* }
|
|
708
|
+
*
|
|
709
|
+
* The four categories are intentionally cross-domain (file ops,
|
|
710
|
+
* math, search, conversation) so a router that collapses to one
|
|
711
|
+
* category is easy to spot.
|
|
712
|
+
*/
|
|
713
|
+
interface RoutingItem {
|
|
714
|
+
id: string;
|
|
715
|
+
category: 'file' | 'math' | 'search' | 'chat';
|
|
716
|
+
prompt: string;
|
|
717
|
+
/** Canonical correct route label. */
|
|
718
|
+
route: string;
|
|
719
|
+
/** Alternate route labels that also count as correct. */
|
|
720
|
+
synonyms: string[];
|
|
721
|
+
/** Wrong-but-tempting route labels (for analysis, not grading). */
|
|
722
|
+
hardNegatives: string[];
|
|
723
|
+
}
|
|
724
|
+
declare const ROUTING_DATASET: RoutingItem[];
|
|
725
|
+
|
|
726
|
+
/**
|
|
727
|
+
* Routing benchmark — synthetic, dependency-free, ships in the
|
|
728
|
+
* package. 16 cross-category items in `dataset.ts`. See
|
|
729
|
+
* `routing/README.md` for the format.
|
|
730
|
+
*
|
|
731
|
+
* `evaluate` does case-insensitive exact match against the canonical
|
|
732
|
+
* route plus declared synonyms. The first valid route token in the
|
|
733
|
+
* response wins; everything else is ignored. Wrong answers also
|
|
734
|
+
* report whether they hit a hard negative — useful when triaging
|
|
735
|
+
* "always picks the popular route" failure modes.
|
|
736
|
+
*/
|
|
737
|
+
|
|
738
|
+
type RoutingPayload = RoutingItem;
|
|
739
|
+
type RoutingDatasetItem = BenchmarkDatasetItem<RoutingPayload>;
|
|
740
|
+
declare class RoutingAdapter implements BenchmarkAdapter<RoutingDatasetItem, RoutingPayload> {
|
|
741
|
+
readonly id = "first-party/routing";
|
|
742
|
+
readonly family = "first-party";
|
|
743
|
+
readonly taskKind = "routing";
|
|
744
|
+
readonly description = "Synthetic fixed-route classification smoke benchmark";
|
|
745
|
+
readonly defaultMetric = "route_exact_match";
|
|
746
|
+
loadDataset(split: RunSplitTag): Promise<RoutingDatasetItem[]>;
|
|
747
|
+
evaluate(item: RoutingDatasetItem, response: string): Promise<BenchmarkEvaluation>;
|
|
748
|
+
assignSplit(itemId: string): RunSplitTag;
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* Pull route-shaped tokens out of a model response. Routes look like
|
|
752
|
+
* `category.action` (`fs.write`, `chat.reply`). Bare alphanumerics
|
|
753
|
+
* are not routes, but `category.action` patterns are robust to most
|
|
754
|
+
* model wrappers (JSON output, prose explanations, code fences).
|
|
755
|
+
*/
|
|
756
|
+
declare function extractRouteTokens(response: string): string[];
|
|
757
|
+
declare const loadDataset: (split: RunSplitTag) => Promise<RoutingDatasetItem[]>;
|
|
758
|
+
declare const evaluate: (item: RoutingDatasetItem, response: string) => Promise<BenchmarkEvaluation>;
|
|
759
|
+
declare const assignSplit: (itemId: string) => RunSplitTag;
|
|
760
|
+
|
|
761
|
+
declare const index_ROUTING_DATASET: typeof ROUTING_DATASET;
|
|
762
|
+
type index_RoutingAdapter = RoutingAdapter;
|
|
763
|
+
declare const index_RoutingAdapter: typeof RoutingAdapter;
|
|
764
|
+
type index_RoutingDatasetItem = RoutingDatasetItem;
|
|
765
|
+
type index_RoutingItem = RoutingItem;
|
|
766
|
+
type index_RoutingPayload = RoutingPayload;
|
|
767
|
+
declare const index_assignSplit: typeof assignSplit;
|
|
768
|
+
declare const index_evaluate: typeof evaluate;
|
|
769
|
+
declare const index_extractRouteTokens: typeof extractRouteTokens;
|
|
770
|
+
declare const index_loadDataset: typeof loadDataset;
|
|
771
|
+
declare namespace index {
|
|
772
|
+
export { index_ROUTING_DATASET as ROUTING_DATASET, index_RoutingAdapter as RoutingAdapter, type index_RoutingDatasetItem as RoutingDatasetItem, type index_RoutingItem as RoutingItem, type index_RoutingPayload as RoutingPayload, index_assignSplit as assignSplit, index_evaluate as evaluate, index_extractRouteTokens as extractRouteTokens, index_loadDataset as loadDataset };
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* `CampaignStorage` — the filesystem seam `runCampaign` writes through
|
|
777
|
+
* (run/cell dirs, the resumability cache, per-cell artifacts, trace spans).
|
|
778
|
+
*
|
|
779
|
+
* The default (`fsCampaignStorage`) is the Node filesystem — identical
|
|
780
|
+
* behavior to the inline `node:fs` calls it replaces, so existing CLI
|
|
781
|
+
* consumers are unaffected. `inMemoryCampaignStorage` keeps everything in a
|
|
782
|
+
* `Map`, so the substrate runs in environments WITHOUT a filesystem
|
|
783
|
+
* (Cloudflare Workers, Deno Deploy, other edge runtimes) — the campaign
|
|
784
|
+
* still produces its `CampaignResult` (cells + aggregates) in memory;
|
|
785
|
+
* artifacts/traces simply aren't persisted to disk.
|
|
786
|
+
*
|
|
787
|
+
* Paths are opaque keys to the in-memory adapter — it does not parse them,
|
|
788
|
+
* so the same `join(...)`-built paths work unchanged across both adapters.
|
|
789
|
+
*/
|
|
790
|
+
interface CampaignStorage {
|
|
791
|
+
/** Ensure a directory exists (recursive). No-op for in-memory. */
|
|
792
|
+
ensureDir(dir: string): void;
|
|
793
|
+
/** Does this path exist (as a written file or an ensured dir)? */
|
|
794
|
+
exists(path: string): boolean;
|
|
795
|
+
/** Read a UTF-8 file; `undefined` when missing or unreadable. */
|
|
796
|
+
read(path: string): string | undefined;
|
|
797
|
+
/** Write a file (string or bytes). Parent dir is assumed ensured. */
|
|
798
|
+
write(path: string, content: string | Uint8Array): void;
|
|
799
|
+
/** Append only when the current UTF-8 byte length matches `expectedBytes`.
|
|
800
|
+
* Returns the new length, or undefined when another writer won. */
|
|
801
|
+
append?(path: string, content: string, expectedBytes: number): number | undefined;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
interface BenchmarkRunOptions<TPayload = unknown, TArtifact = string> {
|
|
805
|
+
adapter: BenchmarkAdapter<BenchmarkDatasetItem<TPayload>, TPayload, TArtifact>;
|
|
806
|
+
respond: BenchmarkResponder<TPayload, TArtifact>;
|
|
807
|
+
splits?: readonly RunSplitTag[];
|
|
808
|
+
runDir: string;
|
|
809
|
+
repo?: string;
|
|
810
|
+
seed?: number;
|
|
811
|
+
reps?: number;
|
|
812
|
+
resumable?: boolean;
|
|
813
|
+
costCeiling?: number;
|
|
814
|
+
maxConcurrency?: number;
|
|
815
|
+
dispatchTimeoutMs?: number;
|
|
816
|
+
expectUsage?: 'assert' | 'warn' | 'off';
|
|
817
|
+
storage?: CampaignStorage;
|
|
818
|
+
now?: () => Date;
|
|
819
|
+
}
|
|
820
|
+
interface BenchmarkReport {
|
|
821
|
+
benchmarkId: string;
|
|
822
|
+
family: BenchmarkFamily | string;
|
|
823
|
+
taskKind: BenchmarkTaskKind | string;
|
|
824
|
+
source?: BenchmarkAdapter['source'];
|
|
825
|
+
runDir: string;
|
|
826
|
+
manifestHash: string;
|
|
827
|
+
seed: number;
|
|
828
|
+
startedAt: string;
|
|
829
|
+
endedAt: string;
|
|
830
|
+
durationMs: number;
|
|
831
|
+
totalItems: number;
|
|
832
|
+
totalCells: number;
|
|
833
|
+
cellsFailed: number;
|
|
834
|
+
cellsCached: number;
|
|
835
|
+
totalCostUsd: number;
|
|
836
|
+
splits: Record<string, BenchmarkSliceSummary>;
|
|
837
|
+
tags: Record<string, BenchmarkSliceSummary>;
|
|
838
|
+
dimensions: Record<string, BenchmarkDistribution>;
|
|
839
|
+
score: BenchmarkDistribution;
|
|
840
|
+
costUsd: BenchmarkDistribution;
|
|
841
|
+
latencyMs: BenchmarkDistribution;
|
|
842
|
+
}
|
|
843
|
+
interface BenchmarkSliceSummary {
|
|
844
|
+
n: number;
|
|
845
|
+
meanScore: number;
|
|
846
|
+
passRate: number;
|
|
847
|
+
score: BenchmarkDistribution;
|
|
848
|
+
costUsd: BenchmarkDistribution;
|
|
849
|
+
latencyMs: BenchmarkDistribution;
|
|
850
|
+
}
|
|
851
|
+
interface BenchmarkDistribution {
|
|
852
|
+
n: number;
|
|
853
|
+
min: number;
|
|
854
|
+
mean: number;
|
|
855
|
+
median: number;
|
|
856
|
+
p90: number;
|
|
857
|
+
max: number;
|
|
858
|
+
}
|
|
859
|
+
interface BenchmarkRunResult<TPayload = unknown, TArtifact = string> {
|
|
860
|
+
scenarios: Array<BenchmarkScenario<TPayload>>;
|
|
861
|
+
campaign: CampaignResult<TArtifact, BenchmarkScenario<TPayload>>;
|
|
862
|
+
report: BenchmarkReport;
|
|
863
|
+
reportJsonPath: string;
|
|
864
|
+
reportMarkdownPath: string;
|
|
865
|
+
}
|
|
866
|
+
declare function runBenchmarkAdapter<TPayload = unknown, TArtifact = string>(options: BenchmarkRunOptions<TPayload, TArtifact>): Promise<BenchmarkRunResult<TPayload, TArtifact>>;
|
|
867
|
+
declare function summarizeBenchmarkCampaign<TPayload, TArtifact>(input: {
|
|
868
|
+
adapter: BenchmarkAdapter<BenchmarkDatasetItem<TPayload>, TPayload, TArtifact>;
|
|
869
|
+
scenarios: Array<BenchmarkScenario<TPayload>>;
|
|
870
|
+
campaign: CampaignResult<TArtifact, BenchmarkScenario<TPayload>>;
|
|
871
|
+
}): BenchmarkReport;
|
|
872
|
+
declare function renderBenchmarkReportMarkdown(report: BenchmarkReport): string;
|
|
873
|
+
|
|
874
|
+
interface StandardRetrievalDocument {
|
|
875
|
+
id: string;
|
|
876
|
+
title?: string;
|
|
877
|
+
text: string;
|
|
878
|
+
metadata?: Record<string, unknown>;
|
|
879
|
+
}
|
|
880
|
+
interface StandardRetrievalQuery {
|
|
881
|
+
id: string;
|
|
882
|
+
text: string;
|
|
883
|
+
metadata?: Record<string, unknown>;
|
|
884
|
+
}
|
|
885
|
+
interface StandardRetrievalQrel {
|
|
886
|
+
queryId: string;
|
|
887
|
+
documentId: string;
|
|
888
|
+
score: number;
|
|
889
|
+
}
|
|
890
|
+
interface StandardRetrievalPayload {
|
|
891
|
+
queryId: string;
|
|
892
|
+
query: string;
|
|
893
|
+
expectedDocumentIds: string[];
|
|
894
|
+
expectedScores: Record<string, number>;
|
|
895
|
+
corpus?: Record<string, StandardRetrievalDocument>;
|
|
896
|
+
metadata?: Record<string, unknown>;
|
|
897
|
+
}
|
|
898
|
+
interface BuildStandardRetrievalItemsOptions {
|
|
899
|
+
benchmarkId: string;
|
|
900
|
+
family: BenchmarkFamily | string;
|
|
901
|
+
queries: readonly StandardRetrievalQuery[];
|
|
902
|
+
qrels: readonly StandardRetrievalQrel[];
|
|
903
|
+
corpus?: readonly StandardRetrievalDocument[];
|
|
904
|
+
includeCorpusInPayload?: boolean;
|
|
905
|
+
source?: BenchmarkSource;
|
|
906
|
+
tags?: readonly string[];
|
|
907
|
+
splitOf?: (queryId: string) => RunSplitTag;
|
|
908
|
+
}
|
|
909
|
+
interface RetrievalIdAdapterOptions extends BuildStandardRetrievalItemsOptions {
|
|
910
|
+
responseIdPattern?: RegExp;
|
|
911
|
+
cutoffs?: readonly number[];
|
|
912
|
+
primaryMetric?: string;
|
|
913
|
+
passMetric?: string;
|
|
914
|
+
passThreshold?: number;
|
|
915
|
+
}
|
|
916
|
+
interface StandardRetrievalResult {
|
|
917
|
+
id?: string;
|
|
918
|
+
documentId?: string;
|
|
919
|
+
docId?: string;
|
|
920
|
+
score?: number;
|
|
921
|
+
}
|
|
922
|
+
type StandardRetrievalArtifact = string | readonly string[] | readonly StandardRetrievalResult[] | {
|
|
923
|
+
ids?: readonly string[];
|
|
924
|
+
documentIds?: readonly string[];
|
|
925
|
+
results?: readonly StandardRetrievalResult[];
|
|
926
|
+
};
|
|
927
|
+
interface StandardRetrievalEvaluationOptions {
|
|
928
|
+
responseIdPattern?: RegExp;
|
|
929
|
+
cutoffs?: readonly number[];
|
|
930
|
+
primaryMetric?: string;
|
|
931
|
+
passMetric?: string;
|
|
932
|
+
passThreshold?: number;
|
|
933
|
+
}
|
|
934
|
+
declare function parseJsonlRows<T = unknown>(text: string): T[];
|
|
935
|
+
declare function parseTsvRows(text: string): string[][];
|
|
936
|
+
declare function parseQrels(text: string): StandardRetrievalQrel[];
|
|
937
|
+
declare function parseBeirCorpusJsonl(text: string): StandardRetrievalDocument[];
|
|
938
|
+
declare function parseBeirQueriesJsonl(text: string): StandardRetrievalQuery[];
|
|
939
|
+
declare function buildStandardRetrievalItems(options: BuildStandardRetrievalItemsOptions): Array<BenchmarkDatasetItem<StandardRetrievalPayload>>;
|
|
940
|
+
declare function createRetrievalIdBenchmarkAdapter(options: RetrievalIdAdapterOptions): BenchmarkAdapter<BenchmarkDatasetItem<StandardRetrievalPayload>, StandardRetrievalPayload, StandardRetrievalArtifact>;
|
|
941
|
+
declare function evaluateStandardRetrieval(payload: StandardRetrievalPayload, artifact: StandardRetrievalArtifact, options?: StandardRetrievalEvaluationOptions): {
|
|
942
|
+
score: number;
|
|
943
|
+
passed: boolean;
|
|
944
|
+
dimensions: Record<string, number>;
|
|
945
|
+
raw: {
|
|
946
|
+
rankedDocumentIds: string[];
|
|
947
|
+
expectedDocumentIds: string[];
|
|
948
|
+
expectedScores: Record<string, number>;
|
|
949
|
+
};
|
|
950
|
+
};
|
|
951
|
+
declare function normalizeRetrievedDocumentIds(artifact: StandardRetrievalArtifact, responseIdPattern?: RegExp): string[];
|
|
952
|
+
declare function retrievalMetricsAtCutoff(input: {
|
|
953
|
+
rankedDocumentIds: readonly string[];
|
|
954
|
+
expectedScores: Record<string, number>;
|
|
955
|
+
cutoff: number;
|
|
956
|
+
}): Record<string, number>;
|
|
957
|
+
|
|
958
|
+
export { BENCHMARK_SPLIT_SEED, type BenchmarkAdapter, type BenchmarkDatasetItem, type BenchmarkDistribution, type BenchmarkEvaluation, type BenchmarkFamily, type BenchmarkMetricCalibrationOptions, type BenchmarkMetricCalibrationResult, type BenchmarkReport, type BenchmarkResponder, type BenchmarkRunOptions, type BenchmarkRunResult, type BenchmarkScenario, type BenchmarkSliceSummary, type BenchmarkSource, type BenchmarkTaskKind, type BuildStandardRetrievalItemsOptions, type RetrievalIdAdapterOptions, type StandardRetrievalArtifact, type StandardRetrievalDocument, type StandardRetrievalEvaluationOptions, type StandardRetrievalPayload, type StandardRetrievalQrel, type StandardRetrievalQuery, type StandardRetrievalResult, buildStandardRetrievalItems, calibrateBenchmarkMetric, createRetrievalIdBenchmarkAdapter, deterministicSplit, evaluateStandardRetrieval, normalizeRetrievedDocumentIds, parseBeirCorpusJsonl, parseBeirQueriesJsonl, parseJsonlRows, parseQrels, parseTsvRows, renderBenchmarkReportMarkdown, retrievalMetricsAtCutoff, index as routing, runBenchmarkAdapter, summarizeBenchmarkCampaign };
|