@tangle-network/agent-eval 0.145.13 → 0.145.15

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 CHANGED
@@ -8,6 +8,34 @@ All notable changes to `@tangle-network/agent-eval` and its sibling `agent-eval-
8
8
 
9
9
  ---
10
10
 
11
+ ## [0.145.15] — 2026-08-15
12
+
13
+ ### Added
14
+
15
+ - Add runnable entry points for evaluation, experiment planning, trace analysis, sealed experiments, verification, and optimizer adapters.
16
+ - Add measured unconditional-continuation and gated-stop studies for trace repair.
17
+
18
+ ### Changed
19
+
20
+ - Align the exact `@tangle-network/agent-core` dependency with `0.9.0`.
21
+ - Size gated-stop confirmation draws from the registered power curve and reject substituted served models before spend.
22
+
23
+ ### Fixed
24
+
25
+ - Read registered binary outcomes as `1` or `0` in paired estimates and intervals.
26
+ - Give each continuation rollout an independent seed and clear stale assay rewards before every run.
27
+
28
+ ---
29
+
30
+ ## [0.145.14] — 2026-08-15
31
+
32
+ ### Changed
33
+
34
+ - Align the exact `@tangle-network/agent-core` and `@tangle-network/agent-interface` dependencies with `0.8.1` and `0.53.0`.
35
+ - Packed consumers now resolve the one-copy `0.8.1` Core and `0.53.0` Interface cohort through Eval's release verification.
36
+
37
+ ---
38
+
11
39
  ## [0.145.13] — 2026-08-15
12
40
 
13
41
  ### Added
package/README.md CHANGED
@@ -1,22 +1,16 @@
1
1
  # `@tangle-network/agent-eval`
2
2
 
3
- Measure agent behavior, compare changes on the same cases, and improve prompts or skills without exposing final test cases to the optimizer.
3
+ Measure agent behavior, compare changes on the same cases, and improve prompts or skills without showing the final test cases to the optimizer.
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/@tangle-network/agent-eval.svg)](https://www.npmjs.com/package/@tangle-network/agent-eval)
6
6
  [![pypi](https://img.shields.io/pypi/v/agent-eval-rpc.svg)](https://pypi.org/project/agent-eval-rpc/)
7
7
  [![tests](https://github.com/tangle-network/agent-eval/actions/workflows/ci.yml/badge.svg)](https://github.com/tangle-network/agent-eval/actions/workflows/ci.yml)
8
8
  [![license: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
9
9
 
10
- Use this package to:
11
-
12
- - run an agent over representative cases and score every result,
13
- - compare a candidate with a baseline using paired statistics,
14
- - analyze existing runs, traces, or human feedback,
15
- - optimize a prompt or skill with official GEPA or SkillOpt,
16
- - supply your own candidate generator for product-specific changes.
17
-
18
10
  The evaluation path runs in your TypeScript process.
19
- Model calls occur only through the clients and agents you configure.
11
+ Model calls happen only through the clients and agents you configure.
12
+
13
+ New to the package? Read [concepts](./docs/concepts.md) first — it takes five minutes and defines every word used here.
20
14
 
21
15
  ## Install
22
16
 
@@ -24,56 +18,10 @@ Model calls occur only through the clients and agents you configure.
24
18
  pnpm add @tangle-network/agent-eval
25
19
  ```
26
20
 
27
- ## Configure Model Calls
28
-
29
- Benchmarks, user drivers, executors, built-in judges, completion checkers, and judge adapters accept the same `ChatClient`.
30
-
31
- ```ts
32
- import { createChatClient } from '@tangle-network/agent-eval'
33
-
34
- const chat = createChatClient({
35
- transport: 'router',
36
- apiKey: process.env.TANGLE_API_KEY!,
37
- defaultModel: 'openai/gpt-4.1',
38
- maximumAttempts: 3,
39
- })
40
- ```
41
-
42
- Use `direct-provider` for an OpenAI-compatible endpoint, `cli-bridge` for a local subscription, `sandbox-sdk` for Sandbox, or `custom` to adapt another SDK.
43
- A custom adapter must return `ChatResponse` and declare `maximumAttempts` before a capped cost ledger can dispatch it.
44
-
45
- The official optimizers use the Python bridge.
46
- Install only the optimizer you plan to run:
47
-
48
- ```sh
49
- # Microsoft SkillOpt at the tested source revision
50
- python -m pip install agent-eval-rpc
51
- python -m pip install \
52
- "skillopt @ git+https://github.com/microsoft/SkillOpt.git@61735e3922efc2b90c6d6cab561e62e98452ca90"
53
-
54
- # Standard GEPA engine from the published package
55
- python -m pip install agent-eval-rpc
56
- python -m pip install "gepa[full]==0.1.4"
57
-
58
- # GEPA Omni and source-only engines
59
- python -m pip install \
60
- "gepa[full] @ git+https://github.com/gepa-ai/gepa.git@f919db0a622e2e9f9204779b81fe00cc1b2d808f"
61
-
62
- # DSPy 3.2.1 with Agent Eval metrics
63
- python -m pip install "agent-eval-rpc[dspy]"
64
- ```
65
-
66
- The published GEPA package supports the standard `gepa` engine.
67
- Sequential, adaptive, best-of, vote, Omni, AutoResearch, Meta Harness, and Best-of-N currently require the tested official source revision.
68
- Move that revision only after both release and source compatibility tests pass.
69
- The published `skillopt==0.2.0` wheel omits the prompt files required by `ReflACTTrainer`, so the tested SkillOpt source revision is also intentional.
70
- DSPy 3.2.1 requires GEPA 0.0.27, while the general bridge requires GEPA 0.1.4.
71
- Install the DSPy adapter and the general GEPA bridge in separate Python environments.
21
+ ## Quickstart
72
22
 
73
- ## Evaluate An Agent
74
-
75
- This example is offline.
76
- Replace the agent and judge functions with your product code.
23
+ This example is offline and complete.
24
+ Copy it, run it, then replace the agent and the judge with your product code.
77
25
 
78
26
  ```ts
79
27
  import { defineAgentEval } from '@tangle-network/agent-eval/contract'
@@ -110,371 +58,106 @@ console.log(
110
58
  )
111
59
  ```
112
60
 
113
- Each call runs every case, records the artifact, applies the same judge, and returns score distributions.
114
- The surface is the value being changed, such as a prompt, skill, or serialized configuration.
115
-
116
- ### Inspect cached cells before rerunning
117
-
118
- `runCampaign()` refuses to start when an existing cache file is unreadable or lacks trustworthy cost data.
119
- This check covers the full schedule before concurrent work begins, so one bad cache cannot waste paid calls from earlier cells.
120
- Use `planCampaignRun()` to see which cells are reusable, runnable, or blocked:
121
-
122
- ```ts
123
- const plan = planCampaignRun({
124
- scenarios,
125
- dispatch,
126
- judges: [judge],
127
- runDir: 'release-candidate',
128
- })
129
-
130
- console.table(plan.cells)
131
- ```
132
-
133
- After inspecting the plan, set `rerunInvalidCachedCells: true` to rerun only blocked cells while retaining valid cached cells.
134
- Set `resumable: false` only when you intend to rerun every cell.
135
- When execution uses a shared `costLedger` or custom `costTags`, pass those same values to `planCampaignRun()` so both calls inspect the same receipts.
136
-
137
- ### Stop after the first failed cell
138
-
139
- `runCampaign()` normally records a dispatch or judge error on that cell and continues the remaining cases.
140
- Set `abortOnCellError: true` when another failed cell would only waste time or money:
141
-
142
- ```ts
143
- await runCampaign({
144
- scenarios,
145
- dispatch,
146
- judges: [judge],
147
- runDir: 'release-candidate',
148
- abortOnCellError: true,
149
- })
150
- ```
151
-
152
- The failed cell is written first to `<runDir>/<cell>/failure-receipt.json`.
153
- That receipt contains the original error, the cell result, exact call IDs, and settled agent-plus-judge cost and token totals.
154
- Active sibling cells are cancelled and allowed to finish recording their own receipts before the campaign rejects with the original cell error.
155
- Leaving `abortOnCellError` unset preserves continue-on-error behavior.
156
-
157
- When an external text optimizer uses that continue-on-error behavior, a failed evaluation returns a finite optimizer penalty of `0` with `info.status: 'failed'`.
158
- The campaign cell remains failed and unscored, so this protocol penalty is not a measured zero.
159
- The failed cell is not cached; a later request retries it with a fresh `ctx.runAttemptId`, while completed cells remain resumable.
160
- Set `abortOnCellError: true` to keep fail-fast behavior.
161
-
162
- `runProfileMatrix()` retains a failed cell when a moving model alias produced no served model snapshot.
163
- The row carries `model: 'unknown'`, uncaptured cost, and incomplete token usage so downstream reports can count the failure without inventing measurements.
164
- Successful moving-model cells still require one immutable served snapshot.
165
-
166
- ## Adapt Another Text Optimizer
167
-
168
- Use `externalTextOptimizationMethod()` when an existing package owns search and selection for a text prompt or named text components.
169
- Its `run` callback receives the starting candidate plus serialized train and selection cases, but it never receives final test cases.
170
- The optimizer must score candidates through `context.evaluate()` so Agent Eval can enforce the evaluation limit and use the configured execution and judges.
171
- Every optimizer-owned paid call must use `context.cost.runPaidCall()`.
172
- Set `source` to the package version and revision, and set `evaluationId` to a commit, content hash, or other stable identity for the execution and scoring behavior.
173
- Agent Eval derives the run identity from those values, the exact dispatch identity, the optimizer settings, the starting surface, the described data, and the seed.
174
- The callback returns the selected candidate, whether compatible state was restored, and how optimizer spend was recorded.
175
-
176
- See [Adapt A Third-Party Text Optimizer](./docs/campaign-proposers.md#adapt-a-third-party-text-optimizer) for a complete minimal adapter.
177
-
178
- ## Optimize With Official GEPA
179
-
180
- `gepaOptimizationMethod()` delegates candidate search and recipe composition to the installed GEPA package.
181
- Agent Eval supplies the train and selection cases, executes candidates, records cost, and evaluates the selected result on final cases after GEPA exits.
182
-
183
- ```ts
184
- import { gepaOptimizationMethod } from '@tangle-network/agent-eval/campaign'
185
-
186
- // Supplied by the package that owns model execution. Discovery uses Runtime
187
- // with one exact AgentProfile; Agent Eval receives no provider credential.
188
- declare const optimizerExecution: {
189
- call: import('@tangle-network/agent-eval/campaign').ExternalOptimizerModelCall
190
- callRef: string
191
- }
192
-
193
- const optimizerPricing = {
194
- inputUsdPerMillion: Number(process.env.OPTIMIZER_INPUT_USD_PER_MILLION),
195
- outputUsdPerMillion: Number(process.env.OPTIMIZER_OUTPUT_USD_PER_MILLION),
196
- }
197
-
198
- const gepa = gepaOptimizationMethod<MyCase, MyArtifact>({
199
- objective: 'Improve the instructions so the agent returns valid, complete JSON.',
200
- evaluationId: 'json-agent',
201
- recipe: {
202
- kind: 'engine',
203
- run: {
204
- engine: 'gepa',
205
- maxEvaluations: 40,
206
- maxProposerCostUsd: 5,
207
- },
208
- },
209
- optimizer: {
210
- model: 'gpt-4.1-mini',
211
- ...optimizerExecution,
212
- budget: {
213
- maxCostUsd: 5,
214
- maxRequests: 100,
215
- maxRequestBytes: 2_000_000,
216
- maxResponseBytes: 2_000_000,
217
- maxOutputTokensPerRequest: 32_768,
218
- pricing: optimizerPricing,
219
- },
220
- },
221
- describeScenario: (scenario) => ({ input: scenario.input }),
222
- describeArtifact: (artifact) => ({ output: artifact.output }),
223
- })
224
- ```
225
-
226
- GEPA also supports official sequential, adaptive, best-of, vote, and Omni recipes through the same factory.
227
- When every recipe stage uses the standard GEPA engine, Agent Eval gives Python only a loopback address and asks the caller-owned execution package to make every model call.
228
- Every call must return measured usage and finite JSON execution evidence; Agent Eval stores both and fails the attempt when either is missing.
229
- Other official GEPA engines can still run through `engineConfig`, but their model spend remains incomplete unless the engine reports it.
230
- Custom engines can register through GEPA's official registry by listing their Python modules in `engineModules`.
231
-
232
- Run the repository example:
233
-
234
- ```sh
235
- OPTIMIZERS=gepa \
236
- LLM_API_KEY="$OPENAI_API_KEY" \
237
- OPTIMIZER_EXECUTION_OWNER_MODULE=@acme/runtime-optimizer-owner \
238
- GEPA_PRICE_IN_PER_M=0.4 \
239
- GEPA_PRICE_OUT_PER_M=1.6 \
240
- pnpm tsx examples/compare-optimization-methods/index.ts
241
- ```
242
-
243
- Replace the example rates with the exact endpoint rates.
244
-
245
- ## Optimize With Official SkillOpt
246
-
247
- `skillOptOptimizationMethod()` runs Microsoft's `ReflACTTrainer` against the same TypeScript execution and scoring path.
248
- SkillOpt receives train and selection cases but never receives final cases.
249
-
250
- ```ts
251
- import { skillOptOptimizationMethod } from '@tangle-network/agent-eval/campaign'
252
-
253
- declare const optimizerExecution: {
254
- call: import('@tangle-network/agent-eval/campaign').ExternalOptimizerModelCall
255
- callRef: string
256
- }
257
-
258
- const optimizerPricing = {
259
- inputUsdPerMillion: Number(process.env.OPTIMIZER_INPUT_USD_PER_MILLION),
260
- outputUsdPerMillion: Number(process.env.OPTIMIZER_OUTPUT_USD_PER_MILLION),
261
- }
262
-
263
- const skillopt = skillOptOptimizationMethod<MyCase, MyArtifact>({
264
- objective: 'Improve the skill so the agent returns valid, complete JSON.',
265
- evaluationId: 'json-agent',
266
- trainer: {
267
- epochs: 2,
268
- batchSize: 4,
269
- },
270
- optimizer: {
271
- model: 'gpt-4.1-mini',
272
- ...optimizerExecution,
273
- budget: {
274
- maxCostUsd: 5,
275
- maxRequests: 100,
276
- maxRequestBytes: 2_000_000,
277
- maxResponseBytes: 2_000_000,
278
- maxOutputTokensPerRequest: 32_768,
279
- pricing: optimizerPricing,
280
- },
281
- },
282
- maxEvaluations: 80,
283
- describeScenario: (scenario) => ({ input: scenario.input }),
284
- describeArtifact: (artifact) => ({ output: artifact.output }),
285
- })
286
- ```
287
-
288
- Replace the example rates with the exact rates for your endpoint.
289
- Agent Eval places a local OpenAI-compatible proxy between each standard optimizer and the caller-owned execution package.
290
- The proxy enforces request, byte, and token limits before one callback invocation, records the caller's measured receipt and execution evidence, and does not accept a provider URL or credential.
291
- Dollar limits and pricing are optional; omit both when billed USD is unknown instead of supplying a catalog estimate as if it were observed billing.
292
-
293
- ## Optimize A DSPy Program
294
-
295
- DSPy owns its program optimizers.
296
- `DspyJudgeMetric` lets them use the same Agent Eval rubric as TypeScript agents.
297
-
298
- ```python
299
- import dspy
300
-
301
- from agent_eval_rpc import DspyJudgeMetric
302
-
303
- dspy.configure(lm=dspy.LM("openai/gpt-4.1-mini"))
304
- dspy.configure_cache(restrict_pickle=True)
305
- metric = DspyJudgeMetric(rubric_name="answer-quality")
306
-
307
- # GEPA needs both the numeric score and diagnostic feedback.
308
- optimizer = dspy.GEPA(
309
- metric=metric.feedback,
310
- reflection_lm=dspy.LM("openai/gpt-4.1-mini"),
311
- max_metric_calls=100,
312
- )
313
- optimized_program = optimizer.compile(program, trainset=train, valset=selection)
314
-
315
- # MIPROv2, SIMBA, and few-shot optimizers use the numeric metric directly.
316
- mipro = dspy.MIPROv2(metric=metric, auto="light")
317
- ```
318
-
319
- Use official DSPy directly for DSPy programs.
320
- Use `gepaOptimizationMethod()` for text or named component surfaces in non-DSPy agents.
321
- Use agent-runtime's worktree path for executable code changes.
322
-
323
- ## Compare Complete Methods
324
-
325
- `compareOptimizationMethods()` gives each method the same starting surface, execution function, judges, train cases, and selection cases.
326
- It waits for optimization to finish before it evaluates any selected surface on the final cases.
327
-
328
- ```ts
329
- import { compareOptimizationMethods } from '@tangle-network/agent-eval/campaign'
330
-
331
- const result = await compareOptimizationMethods({
332
- methods: [gepa, skillopt],
333
- baselineSurface,
334
- trainScenarios,
335
- selectionScenarios,
336
- testScenarios,
337
- dispatchWithSurface,
338
- judges,
339
- runDir: '.agent-eval/optimizer-comparison',
340
- })
341
-
342
- console.table(result.scores)
343
- ```
344
-
345
- Read `scores` for final-case lift and intervals.
346
- Read `pairwise` before claiming one method beat another.
347
- Read `totalCost.accountingComplete` before using the reported dollars as a complete total.
348
- Each official method score records the optimizer and bridge package versions, source revisions and source-tree hashes, Python runtime, configured optimizer model when present, custom engine module hashes, compatible run ID, exact attempt ID, resume status, evaluation count, artifact directory, and available optimizer token usage in `provenance`.
349
- Call `readExternalOptimizerObservationArtifact()` with `provenance.observations` to read every distinct callback-submitted candidate.
350
- The reader verifies the artifact digest, canonical rows, sequence, candidate identities, and summary counts before returning candidates.
351
- This verification proves that the bytes match the supplied summary; use a summary from trusted method provenance when authenticity matters.
352
- For a direct standard GEPA run, call `readGepaCandidatePopulationArtifact()` with `provenance.gepaCandidatePopulation`.
353
- It returns GEPA's accepted candidates with exact parent indices, aggregate scores, per-case selection scores, and discovery evaluation counts.
354
- The callback artifact remains the complete source for rejected or refused proposals that GEPA did not add to its accepted population.
355
-
356
- The [optimizer guide](./docs/campaign-proposers.md) covers recipes, budgets, resuming, and data separation.
357
- The [runnable comparison](./examples/compare-optimization-methods/) can run GEPA, SkillOpt, or both.
61
+ Each call runs every case, records what the agent produced, applies the same judge, and returns score distributions.
62
+
63
+ Three words carry this example.
64
+ A **case** is one task the agent must do.
65
+ A **surface** is the value being changed: a prompt, a skill, or a serialized configuration.
66
+ A **judge** is a function that scores one produced result.
67
+
68
+ `expectUsage: 'off'` is set because this agent makes no paid calls.
69
+ The default, `'assert'`, fails a run whose cells report no cost receipt.
70
+ Keep the default whenever real model calls happen.
71
+
72
+ Runnable copy: [`examples/evaluate-a-change`](./examples/evaluate-a-change/).
73
+
74
+ ## Which Front Door
75
+
76
+ Every row is a function you call. Each links to a runnable example.
77
+
78
+ | When to call it | What you give it | What you get back |
79
+ |---|---|---|
80
+ | [`defineAgentEval()`](./examples/evaluate-a-change/) — you changed a surface and must know whether it helped | cases, an agent, a judge, a starting surface | `evaluate()` for scores, `improve()` for a search plus a release decision |
81
+ | [`selfImprove()`](./examples/selfimprove-quickstart/) you want candidate generation, scoring, and a release decision in one call | cases, an agent, a judge, a starting surface | a report, a winner surface, and a `gateDecision` |
82
+ | [`analyzeRuns()`](./examples/analyze-existing-runs/) the runs already happened and no agent needs to run again | `RunRecord[]` | an `InsightReport`: distributions, paired lift, judge agreement, cost, failure clusters |
83
+ | `fromFeedbackTable()` ([example](./examples/customer-feedback-loop/)) / `fromOtelSpans()` ([example](./examples/customer-otel-traces/)) your data is in a table or an OTel collector, not in `RunRecord` shape | source rows or spans | `RunRecord[]` ready for `analyzeRuns()` |
84
+ | [`planCampaignRun()` / `runCampaign()`](./examples/plan-before-you-spend/) — you need direct control of the case grid, or you must see it before paying for it | cases, a dispatch function, judges, a run directory | a per-cell schedule, then a campaign result with cached cells |
85
+ | [`loadEvalFixtureScenarios()`](./examples/eval-fixtures-quickstart/) agents should add cases as folders on disk | `evals/<name>/PROMPT.md` plus checks | `Scenario[]` for `runCampaign()` |
86
+ | [`compareOptimizationMethods()`](./examples/compare-optimization-methods/) — two search methods must be compared at equal budget | methods, a starting surface, train, selection, and final cases | per-method final lift, intervals, pairwise contrasts, and cost |
87
+ | [`gepaOptimizationMethod()` / `skillOptOptimizationMethod()`](./examples/compare-optimization-methods/) — official GEPA or Microsoft SkillOpt should own the search | an objective, a recipe or trainer, an optimizer budget | an optimization method for the comparison above |
88
+ | [`externalTextOptimizationMethod()`](./examples/adapt-a-text-optimizer/) another package owns text search and you keep the scoring | the package identity, limits, and a `run` callback | the same, with the final cases never exposed |
89
+ | [`SurfaceProposer`](./examples/selfimprove-quickstart/) — candidate generation belongs to your product | a `propose()` function | candidates the campaign executes, scores, and gates |
90
+ | [`runProfileMatrix()`](./docs/eval-surface-map.md) — the same cases must run across models or profiles | axes of models and profiles, cases | one row per cell, with an explicit `unknown` model rather than an invented one |
91
+ | [`sealExperiment()` / `openSealedExperiment()`](./examples/sealed-experiment/) — the result must convince someone who does not trust you | arms, an admission funnel, an estimand, an interval, a decision table | a hashed rule tree, and executors that can run no other rule |
92
+ | [`runEquivalenceCheck()` / `VERIFICATION_STRATEGIES`](./examples/verify-without-an-answer-key/) — the work has no held-out test suite | a claim, two blind arms, an injected checker | a certification that names who vouched and how it can fail |
93
+ | [`AnalystRegistry.runExact()`](./examples/custom-trace-analyst/) — a batch of runs failed and you need cited findings | recorded evidence, a declared analyst list | findings with evidence references, an execution plan, and a receipt |
94
+ | [`runAnalystBenchmark()`](./docs/trace-analysis.md) — an analyst's accuracy must be measured, not assumed | labeled issues and exact span locations | scored findings, trace reads, model calls, tokens, cost, and runtime |
95
+ | [`deltaRepair()`](./docs/trace-repair-grader.md) — a finding must be graded by executing the repair it proposes | a trajectory, an analyst finding, a sandbox | the repair's measured effect against a no-fix control |
96
+ | [`replayVerify()`](./docs/trajectory-replay.md) — you must know whether a recorded failure still reproduces | a recorded shell trajectory and its pinned image | a re-execution verdict and the divergences found |
97
+ | [`analyzeSupervisorRun()`](./docs/adapters-observability.md) — a recursive or supervised run directory must be read | a run directory | counts that stay missing when a measurement is missing, never zero |
98
+ | [`buildRlDataset()`](./examples/publish-rl-dataset/) — scored runs should become training data | run records and preferences | reward, preference, and supervised rows |
358
99
 
359
- ## Supply Your Own Candidate Generator
100
+ ## Configure Model Calls
360
101
 
361
- Use `SurfaceProposer` when candidate creation belongs to your product or an agent runtime.
362
- The campaign still owns execution, scoring, history, stopping, and release decisions.
102
+ Benchmarks, user drivers, executors, built-in judges, completion checkers, and judge adapters all take the same `ChatClient`.
363
103
 
364
104
  ```ts
365
- import {
366
- defineAgentEval,
367
- type SurfaceProposer,
368
- } from '@tangle-network/agent-eval/contract'
369
-
370
- const proposer: SurfaceProposer = {
371
- kind: 'product-rules',
372
- async propose({ currentSurface, populationSize }) {
373
- const prompt = String(currentSurface)
374
- return [
375
- {
376
- surface: `${prompt}\nReturn JSON only.`,
377
- label: 'json-only',
378
- rationale: 'Training failures contained prose around the JSON object.',
379
- },
380
- ].slice(0, populationSize)
381
- },
382
- }
383
-
384
- const result = await defineAgentEval({
385
- scenarios,
386
- agent,
387
- model: 'gpt-4.1-2025-04-14',
388
- judge,
389
- baselineSurface,
390
- proposer,
391
- budget: { generations: 1, populationSize: 1, holdoutFraction: 0.3 },
392
- }).improve()
393
- ```
394
-
395
- `model` supplies the worker snapshot when the agent does not report paid calls through `ctx.cost.runPaidCall()`.
396
- When every cell reports a concrete model receipt, omit it.
397
-
398
- Run the complete offline example:
399
-
400
- ```sh
401
- pnpm tsx examples/selfimprove-quickstart/index.ts
402
- ```
403
-
404
- ## Start From Existing Runs
405
-
406
- You do not need a runnable agent to analyze data you already captured.
407
- Use `analyzeRuns()` for `RunRecord[]`.
408
- For traces, run a registry of built-in or custom analysts, measure it on labeled issues and exact span locations, then turn only reviewed findings into eval data.
409
- For a public quality check, convert CodeTraceBench with `traces import-codetracebench`, then run `agent-eval analyst-benchmark` against pinned labels.
410
- The command compares an empty baseline with the official DSPy `RLM` trace analyst and records its trace reads, model calls, tokens, cost, runtime, and cited findings.
411
-
412
- Use `AnalystRegistry.runExact()` when the caller, rather than registry defaults, must own every execution choice.
413
- The ordered `analystIds` array is the execution order, and `null` explicitly disables optional budget, timeout, cancellation, cost, tag, or prior-finding channels.
414
- Exact runs are serial; callers that need recursive or concurrent scheduling compose them through their runtime rather than adding a second scheduler here.
105
+ import { createChatClient } from '@tangle-network/agent-eval'
415
106
 
416
- ```ts
417
- const result = await registry.runExact('analysis-1', inputs, {
418
- analystIds: ['failure-mode', 'improvement'],
419
- budget: { kind: 'equal', totalUsd: 2 },
420
- totalTimeoutMs: 30_000,
421
- signal: null,
422
- costLedger: null,
423
- costLedgerIdentity: null,
424
- costPhase: null,
425
- tags: null,
426
- priorFindings: null,
427
- chainFindings: true,
428
- missingInputMode: 'abort',
429
- applyRegistryHooks: false,
430
- useRegistryChat: false,
107
+ const chat = createChatClient({
108
+ transport: 'router',
109
+ apiKey: process.env.TANGLE_API_KEY!,
110
+ defaultModel: 'openai/gpt-4.1',
111
+ maximumAttempts: 3,
431
112
  })
432
113
  ```
433
114
 
434
- Custom analysts passed to `runExact()` declare canonical `executionConfig`.
435
- The same `defineTraceAnalyst()` helper returns an exact-capable analyst when that field is present.
436
- Built-in analysts already declare it.
437
- Trace analysts selected by `runExact()` also require `aiIdentity`, using the same non-secret `id`, `version`, and canonical `config` shape as cost ledgers, registry hooks, and registry chat clients.
438
- Exact lifecycle hooks receive frozen snapshots for observation; they cannot rewrite the planned context.
439
- Persisted results store configuration digests, not raw configuration.
440
- The persisted plan records the exact equal or weighted allocation for every routed analyst, and archival validates summaries against that same plan.
441
- Every exact receipt says whether it is `complete` or `failed`; a complete receipt must cover the full plan, while a failed receipt may contain only the executed prefix.
442
- Any failure after an exact run starts rejects with `ExactAnalystRunExecutionError`; its immutable failed receipt preserves valid completed summaries, findings, usage, and cost.
115
+ Use `direct-provider` for an OpenAI-compatible endpoint, `cli-bridge` for a local subscription, `sandbox-sdk` for Sandbox, or `custom` to adapt another SDK.
116
+ A custom adapter must return a `ChatResponse` and declare `maximumAttempts` before a capped cost account can dispatch it.
443
117
 
444
- See [concepts](./docs/concepts.md), [customer paths](./docs/customer-journeys.md), and [trace analysis](./docs/trace-analysis.md).
118
+ The official GEPA and SkillOpt optimizers run through a Python bridge.
119
+ Install commands, version pins, and the reason for each pin:
120
+ [GEPA](./docs/campaign-proposers.md#install-official-gepa),
121
+ [SkillOpt](./docs/campaign-proposers.md#install-official-skillopt),
122
+ and [DSPy](./docs/campaign-proposers.md#use-official-dspy-optimizers).
445
123
 
446
124
  ## Entry Points
447
125
 
448
126
  | Import | Use |
449
127
  |---|---|
450
- | `@tangle-network/agent-eval/contract` | Define an evaluation, run it, improve with a custom candidate generator, and analyze runs. |
451
- | `@tangle-network/agent-eval/campaign` | Control campaigns, official optimization methods, comparisons, storage, and release rules. |
452
- | `@tangle-network/agent-eval/profile-cell` | Create and validate portable agent-profile identities. |
453
- | `@tangle-network/agent-eval/ledger-core` | Generic hash-chained append-only journal: idempotent append, chain verification, trusted-head pinning, replay-to-projection, cross-process locking. |
454
- | `@tangle-network/agent-eval/reporting` | Statistical comparisons and report rendering. |
128
+ | `@tangle-network/agent-eval/contract` | Define an evaluation, run it, improve it, and analyze existing runs. |
129
+ | `@tangle-network/agent-eval/campaign` | Campaigns, optimization methods, comparisons, storage, and release rules. |
130
+ | `@tangle-network/agent-eval/experiment` | Experiments as sealed objects: registered rules, funnels, estimands, refusals. |
455
131
  | `@tangle-network/agent-eval/analyst` | Built-in and custom trace analysts, labeled comparison, costs, and reports. |
132
+ | `@tangle-network/agent-eval/trace-repair` | Grade one analyst finding by executing the repair it proposes. |
133
+ | `@tangle-network/agent-eval/trajectory-replay` | Re-execute a recorded shell trajectory and check whether its failure reproduces. |
456
134
  | `@tangle-network/agent-eval/traces` | Store, replay, and inspect structured traces. |
457
- | `@tangle-network/agent-eval/supervisor-run` | Read loops or agent-runtime recursive run directories without collapsing missing measurements to zero. |
458
- | `@tangle-network/agent-eval/trajectory-replay` | Re-execute a recorded shell trajectory in its own image and check whether the recorded failure reproduces. |
459
- | `@tangle-network/agent-eval/trace-repair` | Grade one analyst finding by executing the repair it proposes, and measure Delta-repair against a no-fix control. |
135
+ | `@tangle-network/agent-eval/reporting` | Statistical comparisons and report rendering. |
136
+ | `@tangle-network/agent-eval/supervisor-run` | Read recursive run directories without collapsing missing measurements to zero. |
137
+ | `@tangle-network/agent-eval/profile-cell` | Create and validate portable agent-profile identities. |
138
+ | `@tangle-network/agent-eval/ledger-core` | Append-only hash-chained journal with idempotent append and chain verification. |
460
139
  | `@tangle-network/agent-eval/benchmarks` | Benchmark adapters and retrieval metrics. |
461
140
  | `@tangle-network/agent-eval/rl` | Export rewards, preferences, and training rows. |
462
141
  | `@tangle-network/agent-eval/wire` | HTTP and RPC schemas for other languages. |
463
142
 
464
- Use subpaths when you want an explicit capability boundary.
465
143
  Use the root import for common primitives.
144
+ Use a subpath when you want an explicit capability boundary.
466
145
 
467
- ## Examples
146
+ ## Documentation
468
147
 
469
- | Goal | Example |
148
+ | Question | Read |
470
149
  |---|---|
471
- | Evaluate and improve with a custom candidate generator | [`selfimprove-quickstart`](./examples/selfimprove-quickstart/) |
472
- | Run official GEPA or SkillOpt | [`compare-optimization-methods`](./examples/compare-optimization-methods/) |
473
- | Analyze human feedback | [`customer-feedback-loop`](./examples/customer-feedback-loop/) |
474
- | Analyze OpenTelemetry traces | [`customer-otel-traces`](./examples/customer-otel-traces/) |
475
- | Run public benchmark adapters | [`benchmarks`](./examples/benchmarks/) |
476
-
477
- See the [example index](./examples/README.md) for the full list.
150
+ | What do these words mean? | [`docs/concepts.md`](./docs/concepts.md) |
151
+ | Why does this package exist, and where is it going? | [`docs/charter.md`](./docs/charter.md) |
152
+ | Which `run*` function do I want? | [`docs/eval-surface-map.md`](./docs/eval-surface-map.md) |
153
+ | How do I choose a candidate-generation method? | [`docs/campaign-proposers.md`](./docs/campaign-proposers.md) |
154
+ | What is in an `InsightReport`? | [`docs/insight-report.md`](./docs/insight-report.md) |
155
+ | How do I register an experiment as a sealed object? | [`docs/experiment.md`](./docs/experiment.md) |
156
+ | How is something certified without an answer key? | [`docs/verification-strategies.md`](./docs/verification-strategies.md) |
157
+ | Where does every verifier land its result? | [`docs/verdicts.md`](./docs/verdicts.md) |
158
+ | How do I score a string from another language? | [`docs/wire-protocol.md`](./docs/wire-protocol.md) |
159
+
160
+ The [example index](./examples/README.md) lists every runnable example.
478
161
 
479
162
  ## Development
480
163
 
@@ -1299,7 +1299,7 @@ declare const ANALYST_BENCHMARK_HELP = "agent-eval analyst-benchmark\n\nRun the
1299
1299
  declare const ANALYST_BENCHMARK_IMPLEMENTATION_DIGEST_ALGORITHM = "sha256-canonical-source-manifest";
1300
1300
  declare const ANALYST_BENCHMARK_DEPENDENCY_LOCK_DIGEST_ALGORITHM = "sha256-canonical-file-manifest";
1301
1301
  declare const ANALYST_BENCHMARK_DEPENDENCY_LOCK_FILES: readonly string[];
1302
- declare const ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256 = "ca56679a57495f6d4012ed2b242586da36c231195bd802507ec18cc541b89fe5";
1302
+ declare const ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256 = "ccd8fbc5b9517c5a0297020cf0d1ca09cfb5d84e393d5d461d5899b315baa2ab";
1303
1303
  /** The published benchmark evidence was produced at this package version, by
1304
1304
  * the retired one-shot direct runner, before trace analysts moved to the
1305
1305
  * recursive DSPy RLM engine. Both evidence digests below are historical facts
@@ -7,7 +7,7 @@ import { a as assertExactRegistryRunOpts, c as KNOWLEDGE_GAP_KIND_SPEC, d as CON
7
7
  import { t as createDspyRlmTraceEngine } from "../dspy-rlm-engine-CqwhQQBw.js";
8
8
  import { a as diffFindings, i as defaultIsMaterial, n as runSemanticConceptJudge, r as FindingsStore, t as SEMANTIC_CONCEPT_JUDGE_VERSION } from "../semantic-concept-judge-C6M-qOeb.js";
9
9
  import { a as scoreAnalystFindings, i as summarizeAnalystBenchmarkRunner, n as runAnalystBenchmark, r as traceStoreEvidenceResolver, t as registryBenchmarkRunner } from "../benchmark-BhT16ep9.js";
10
- import { $ as analystBenchmarkDependencyLockDigest, A as compareAnalystRunners, B as DEFAULT_MAX_VERIFICATION_ARTIFACT_BYTES, C as analystDefinitionProtocolSha256, D as readAnalystBenchmarkArtifact, E as expandCodeTraceFailureBlocks, F as MAX_INCORRECT_BLOCKS, G as ANALYST_BENCHMARK_DEPENDENCY_LOCK_FILES, H as loadCodeTraceVerificationArtifacts, I as MAX_INCORRECT_BLOCK_STEPS, J as ANALYST_BENCHMARK_EVIDENCE_IMPLEMENTATION_SHA256, K as ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256, L as publicBenchmarkProtocolSha256, M as effectiveAnalystProtocolSha256, N as readAnalystInstructionsOverride, O as renderCodeTraceCalibrationMarkdown, P as CODE_TRACE_BENCH_ANALYST_PROMPT, Q as ANALYST_BENCHMARK_IMPLEMENTATION_SHA256, R as publicBenchmarkRlmInstructions, S as analystDefinitionAsymmetries, T as emptyPublicBenchmarkRunner, U as parseVerificationOutcome, V as appendVerificationArtifactsToOtlp, W as ANALYST_BENCHMARK_DEPENDENCY_LOCK_DIGEST_ALGORITHM, X as ANALYST_BENCHMARK_IMPLEMENTATION_DIGEST_ALGORITHM, Y as ANALYST_BENCHMARK_EVIDENCE_PACKAGE_VERSION, Z as ANALYST_BENCHMARK_IMPLEMENTATION_FILES, _ as runReplVariableAnalystDefinition, a as primeAnalystProtocolSha256, at as AGENT_RX_UPSTREAM_REVISION, b as runChunkedAnalystDefinition, c as nodeHttpPrimeBridgeTransport, ct as codeTraceBenchCase, d as publicBenchmarkDistributions, dt as agentRxPredictionsToFindings, et as analystBenchmarkImplementationDigest, f as publicBenchmarkSelectionReport, ft as normalizeAgentRxCategory, g as rlmEngineLimits, h as publicRlmAnalystDefinition, i as createPrimeBenchmarkRunner, it as ANALYST_BENCHMARK_OBSERVATIONS_FILE, j as analystInstructionsOverrideFromText, k as summarizeCodeTraceCalibration, l as loadPublicBenchmarkRows, lt as codeTracerPredictionsToFindings, m as createPublicBenchmarkRlmRunner, mt as normalizeBenchmarkLabel, n as runAnalystBenchmarkCommand, nt as ANALYST_BENCHMARK_LOCAL_RECEIPT_FILE, o as primeCodeTraceAnalystDefinition, ot as renderAgentRxCalibrationMarkdown, p as selectPublicBenchmarkRows, pt as roundAgentRxStep, q as ANALYST_BENCHMARK_EVIDENCE_DEPENDENCY_LOCK_SHA256, r as renderAnalystBenchmarkMarkdown, rt as ANALYST_BENCHMARK_MANIFEST_FILE, s as runInlineAnalystDefinition, st as summarizeAgentRxCalibration, t as ANALYST_BENCHMARK_HELP, tt as ANALYST_BENCHMARK_COST_LEDGER_FILE, u as preparePublicAnalystBenchmark, ut as agentRxBenchmarkCase, v as createPublicBenchmarkDirectRunner, w as adaptPublicBenchmarkFindings, x as AnalystExpressivenessError, y as publicDirectAnalystDefinition, z as publicBenchmarkSystemPrompt } from "../benchmark-command-RyFRoiYm.js";
10
+ import { $ as analystBenchmarkDependencyLockDigest, A as compareAnalystRunners, B as DEFAULT_MAX_VERIFICATION_ARTIFACT_BYTES, C as analystDefinitionProtocolSha256, D as readAnalystBenchmarkArtifact, E as expandCodeTraceFailureBlocks, F as MAX_INCORRECT_BLOCKS, G as ANALYST_BENCHMARK_DEPENDENCY_LOCK_FILES, H as loadCodeTraceVerificationArtifacts, I as MAX_INCORRECT_BLOCK_STEPS, J as ANALYST_BENCHMARK_EVIDENCE_IMPLEMENTATION_SHA256, K as ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256, L as publicBenchmarkProtocolSha256, M as effectiveAnalystProtocolSha256, N as readAnalystInstructionsOverride, O as renderCodeTraceCalibrationMarkdown, P as CODE_TRACE_BENCH_ANALYST_PROMPT, Q as ANALYST_BENCHMARK_IMPLEMENTATION_SHA256, R as publicBenchmarkRlmInstructions, S as analystDefinitionAsymmetries, T as emptyPublicBenchmarkRunner, U as parseVerificationOutcome, V as appendVerificationArtifactsToOtlp, W as ANALYST_BENCHMARK_DEPENDENCY_LOCK_DIGEST_ALGORITHM, X as ANALYST_BENCHMARK_IMPLEMENTATION_DIGEST_ALGORITHM, Y as ANALYST_BENCHMARK_EVIDENCE_PACKAGE_VERSION, Z as ANALYST_BENCHMARK_IMPLEMENTATION_FILES, _ as runReplVariableAnalystDefinition, a as primeAnalystProtocolSha256, at as AGENT_RX_UPSTREAM_REVISION, b as runChunkedAnalystDefinition, c as nodeHttpPrimeBridgeTransport, ct as codeTraceBenchCase, d as publicBenchmarkDistributions, dt as agentRxPredictionsToFindings, et as analystBenchmarkImplementationDigest, f as publicBenchmarkSelectionReport, ft as normalizeAgentRxCategory, g as rlmEngineLimits, h as publicRlmAnalystDefinition, i as createPrimeBenchmarkRunner, it as ANALYST_BENCHMARK_OBSERVATIONS_FILE, j as analystInstructionsOverrideFromText, k as summarizeCodeTraceCalibration, l as loadPublicBenchmarkRows, lt as codeTracerPredictionsToFindings, m as createPublicBenchmarkRlmRunner, mt as normalizeBenchmarkLabel, n as runAnalystBenchmarkCommand, nt as ANALYST_BENCHMARK_LOCAL_RECEIPT_FILE, o as primeCodeTraceAnalystDefinition, ot as renderAgentRxCalibrationMarkdown, p as selectPublicBenchmarkRows, pt as roundAgentRxStep, q as ANALYST_BENCHMARK_EVIDENCE_DEPENDENCY_LOCK_SHA256, r as renderAnalystBenchmarkMarkdown, rt as ANALYST_BENCHMARK_MANIFEST_FILE, s as runInlineAnalystDefinition, st as summarizeAgentRxCalibration, t as ANALYST_BENCHMARK_HELP, tt as ANALYST_BENCHMARK_COST_LEDGER_FILE, u as preparePublicAnalystBenchmark, ut as agentRxBenchmarkCase, v as createPublicBenchmarkDirectRunner, w as adaptPublicBenchmarkFindings, x as AnalystExpressivenessError, y as publicDirectAnalystDefinition, z as publicBenchmarkSystemPrompt } from "../benchmark-command-CIosBh1L.js";
11
11
  import { a as extractPrimeJsonObject, c as primeProtocolSha256, d as runPrimeExchange, f as decodeReplyRows, i as emptyPrimeRawUsage, l as primeReplyDefect, n as buildPrimePrompt, o as mergePrimeRawUsage, r as buildPrimeRepairPrompt, s as normalizePrimeUsage, t as analystUsageReceiptFromPrimeUsage, u as projectPrimeTrajectory } from "../prime-protocol-6tZTVsWm.js";
12
12
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
13
13
  import { join } from "node:path";
@@ -1209,7 +1209,7 @@ const ANALYST_BENCHMARK_DEPENDENCY_LOCK_FILES = Object.freeze([
1209
1209
  "package.json",
1210
1210
  "pnpm-lock.yaml"
1211
1211
  ]);
1212
- const ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256 = "ca56679a57495f6d4012ed2b242586da36c231195bd802507ec18cc541b89fe5";
1212
+ const ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256 = "ccd8fbc5b9517c5a0297020cf0d1ca09cfb5d84e393d5d461d5899b315baa2ab";
1213
1213
  /** The published benchmark evidence was produced at this package version, by
1214
1214
  * the retired one-shot direct runner, before trace analysts moved to the
1215
1215
  * recursive DSPy RLM engine. Both evidence digests below are historical facts
@@ -6369,4 +6369,4 @@ function shellQuote(value) {
6369
6369
  //#endregion
6370
6370
  export { analystBenchmarkDependencyLockDigest as $, compareAnalystRunners as A, DEFAULT_MAX_VERIFICATION_ARTIFACT_BYTES as B, analystDefinitionProtocolSha256 as C, readAnalystBenchmarkArtifact as D, expandCodeTraceFailureBlocks as E, MAX_INCORRECT_BLOCKS as F, ANALYST_BENCHMARK_DEPENDENCY_LOCK_FILES as G, loadCodeTraceVerificationArtifacts as H, MAX_INCORRECT_BLOCK_STEPS as I, ANALYST_BENCHMARK_EVIDENCE_IMPLEMENTATION_SHA256 as J, ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256 as K, publicBenchmarkProtocolSha256 as L, effectiveAnalystProtocolSha256 as M, readAnalystInstructionsOverride as N, renderCodeTraceCalibrationMarkdown as O, CODE_TRACE_BENCH_ANALYST_PROMPT as P, ANALYST_BENCHMARK_IMPLEMENTATION_SHA256 as Q, publicBenchmarkRlmInstructions as R, analystDefinitionAsymmetries as S, emptyPublicBenchmarkRunner as T, parseVerificationOutcome as U, appendVerificationArtifactsToOtlp as V, ANALYST_BENCHMARK_DEPENDENCY_LOCK_DIGEST_ALGORITHM as W, ANALYST_BENCHMARK_IMPLEMENTATION_DIGEST_ALGORITHM as X, ANALYST_BENCHMARK_EVIDENCE_PACKAGE_VERSION as Y, ANALYST_BENCHMARK_IMPLEMENTATION_FILES as Z, runReplVariableAnalystDefinition as _, primeAnalystProtocolSha256 as a, AGENT_RX_UPSTREAM_REVISION as at, runChunkedAnalystDefinition as b, nodeHttpPrimeBridgeTransport as c, codeTraceBenchCase as ct, publicBenchmarkDistributions as d, agentRxPredictionsToFindings as dt, analystBenchmarkImplementationDigest as et, publicBenchmarkSelectionReport as f, normalizeAgentRxCategory as ft, rlmEngineLimits as g, publicRlmAnalystDefinition as h, createPrimeBenchmarkRunner as i, ANALYST_BENCHMARK_OBSERVATIONS_FILE as it, analystInstructionsOverrideFromText as j, summarizeCodeTraceCalibration as k, loadPublicBenchmarkRows as l, codeTracerPredictionsToFindings as lt, createPublicBenchmarkRlmRunner as m, normalizeBenchmarkLabel as mt, runAnalystBenchmarkCommand as n, ANALYST_BENCHMARK_LOCAL_RECEIPT_FILE as nt, primeCodeTraceAnalystDefinition as o, renderAgentRxCalibrationMarkdown as ot, selectPublicBenchmarkRows as p, roundAgentRxStep as pt, ANALYST_BENCHMARK_EVIDENCE_DEPENDENCY_LOCK_SHA256 as q, renderAnalystBenchmarkMarkdown as r, ANALYST_BENCHMARK_MANIFEST_FILE as rt, runInlineAnalystDefinition as s, summarizeAgentRxCalibration as st, ANALYST_BENCHMARK_HELP as t, ANALYST_BENCHMARK_COST_LEDGER_FILE as tt, preparePublicAnalystBenchmark as u, agentRxBenchmarkCase as ut, createPublicBenchmarkDirectRunner as v, adaptPublicBenchmarkFindings as w, AnalystExpressivenessError as x, publicDirectAnalystDefinition as y, publicBenchmarkSystemPrompt as z };
6371
6371
 
6372
- //# sourceMappingURL=benchmark-command-RyFRoiYm.js.map
6372
+ //# sourceMappingURL=benchmark-command-CIosBh1L.js.map