@tangle-network/agent-eval 0.125.0 → 0.126.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +62 -35
- package/README.md +270 -189
- package/dist/analyst/index.d.ts +15 -145
- package/dist/analyst/index.js +33 -47
- package/dist/analyst/index.js.map +1 -1
- package/dist/benchmarks/index.d.ts +45 -162
- package/dist/benchmarks/index.js +8 -9
- package/dist/campaign/index.d.ts +3674 -5393
- package/dist/campaign/index.js +21 -95
- package/dist/{chunk-R226UZOI.js → chunk-474LBSOX.js} +2 -2
- package/dist/{chunk-HM6V7F3M.js → chunk-FO7HEH76.js} +3 -3
- package/dist/chunk-IILEIWGW.js +635 -0
- package/dist/chunk-IILEIWGW.js.map +1 -0
- package/dist/{chunk-EQUK3RFS.js → chunk-J5SQWP6Y.js} +8 -5
- package/dist/chunk-J5SQWP6Y.js.map +1 -0
- package/dist/{chunk-W5B3ZGP3.js → chunk-KE2VWPZX.js} +8 -6
- package/dist/{chunk-W5B3ZGP3.js.map → chunk-KE2VWPZX.js.map} +1 -1
- package/dist/{chunk-DT7OXY3C.js → chunk-LUNF2SEL.js} +538 -851
- package/dist/chunk-LUNF2SEL.js.map +1 -0
- package/dist/chunk-NGUYT5CI.js +4637 -0
- package/dist/chunk-NGUYT5CI.js.map +1 -0
- package/dist/{chunk-QFQZ3U3X.js → chunk-OCFJACJU.js} +2 -2
- package/dist/{chunk-GID26AN4.js → chunk-P22LJ3Y2.js} +4 -6
- package/dist/{chunk-GID26AN4.js.map → chunk-P22LJ3Y2.js.map} +1 -1
- package/dist/{chunk-SJT4OBVL.js → chunk-SDPM6554.js} +3 -3
- package/dist/{chunk-D5JZ7UDZ.js → chunk-UCLVDLCH.js} +136 -50
- package/dist/chunk-UCLVDLCH.js.map +1 -0
- package/dist/chunk-VMUENW6F.js +7274 -0
- package/dist/chunk-VMUENW6F.js.map +1 -0
- package/dist/{chunk-JKDNAOF5.js → chunk-W4L6C2XT.js} +2 -2
- package/dist/chunk-WGXIEX7P.js +116 -0
- package/dist/chunk-WGXIEX7P.js.map +1 -0
- package/dist/{chunk-GRCDRKII.js → chunk-WS3NZZQQ.js} +58 -20
- package/dist/chunk-WS3NZZQQ.js.map +1 -0
- package/dist/cli.js +3 -3
- package/dist/contract/index.d.ts +3220 -3094
- package/dist/contract/index.js +173 -42
- package/dist/contract/index.js.map +1 -1
- package/dist/control.js +2 -3
- package/dist/fuzz.d.ts +14 -1
- package/dist/fuzz.js +1 -1
- package/dist/hosted/index.d.ts +8 -1
- package/dist/index.d.ts +71 -687
- package/dist/index.js +178 -497
- package/dist/index.js.map +1 -1
- package/dist/openapi.json +1 -1
- package/dist/rl.d.ts +5 -100
- package/dist/rl.js +4 -5
- package/dist/rl.js.map +1 -1
- package/dist/{run-campaign-I3JXKVAK.js → run-campaign-LVFKZCEU.js} +3 -3
- package/dist/traces.js +2 -3
- package/dist/wire/index.d.ts +14 -1
- package/dist/wire/index.js +3 -3
- package/docs/campaign-proposers.md +363 -168
- package/docs/design/loop-taxonomy.md +142 -190
- package/docs/design.md +1 -1
- package/docs/distributed-driver.md +8 -11
- package/docs/feature-guide.md +20 -19
- package/docs/knowledge-readiness.md +2 -5
- package/docs/multi-shot-optimization.md +35 -27
- package/docs/rollout.md +5 -5
- package/package.json +4 -4
- package/dist/chunk-A62YMFWA.js +0 -9269
- package/dist/chunk-A62YMFWA.js.map +0 -1
- package/dist/chunk-A6GT67HT.js +0 -550
- package/dist/chunk-A6GT67HT.js.map +0 -1
- package/dist/chunk-D5JZ7UDZ.js.map +0 -1
- package/dist/chunk-DT7OXY3C.js.map +0 -1
- package/dist/chunk-EQUK3RFS.js.map +0 -1
- package/dist/chunk-GC4ATIKK.js +0 -317
- package/dist/chunk-GC4ATIKK.js.map +0 -1
- package/dist/chunk-GRCDRKII.js.map +0 -1
- package/dist/chunk-LOW3U7JZ.js +0 -328
- package/dist/chunk-LOW3U7JZ.js.map +0 -1
- package/dist/chunk-PMITBABE.js +0 -3841
- package/dist/chunk-PMITBABE.js.map +0 -1
- /package/dist/{chunk-R226UZOI.js.map → chunk-474LBSOX.js.map} +0 -0
- /package/dist/{chunk-HM6V7F3M.js.map → chunk-FO7HEH76.js.map} +0 -0
- /package/dist/{chunk-QFQZ3U3X.js.map → chunk-OCFJACJU.js.map} +0 -0
- /package/dist/{chunk-SJT4OBVL.js.map → chunk-SDPM6554.js.map} +0 -0
- /package/dist/{chunk-JKDNAOF5.js.map → chunk-W4L6C2XT.js.map} +0 -0
- /package/dist/{run-campaign-I3JXKVAK.js.map → run-campaign-LVFKZCEU.js.map} +0 -0
|
@@ -1,212 +1,164 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Evaluation And Improvement Model
|
|
2
2
|
|
|
3
|
-
This
|
|
4
|
-
|
|
5
|
-
layers, and the layers were getting conflated. Every role below has exactly
|
|
6
|
-
one meaning. Use these words and nothing else.
|
|
3
|
+
This document defines the package's internal terms and ownership boundaries.
|
|
4
|
+
Public examples should use concrete words such as prompt, skill, case, and agent whenever possible.
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
[`campaign-proposers.md`](../campaign-proposers.md) (proposer catalog), and
|
|
10
|
-
[`multi-shot-optimization.md`](../multi-shot-optimization.md) (GEPA).
|
|
6
|
+
## The Evaluation Unit
|
|
11
7
|
|
|
12
|
-
|
|
8
|
+
One evaluation cell contains:
|
|
13
9
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
10
|
+
```text
|
|
11
|
+
candidate surface
|
|
12
|
+
+ scenario
|
|
13
|
+
+ repetition
|
|
14
|
+
+ dispatch
|
|
15
|
+
+ judges
|
|
16
|
+
= artifact, scores, trace, usage, cost, and status
|
|
17
|
+
```
|
|
21
18
|
|
|
22
|
-
|
|
19
|
+
The dispatch runs the system under test.
|
|
20
|
+
A judge converts one artifact into dimension scores and a composite score.
|
|
21
|
+
A campaign repeats this process across cases and candidates.
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
can coordinate CC + Codex + OpenCode siblings sharing one workspace, or a
|
|
26
|
-
fleet spread across machines. `runLoop`'s placement encodes exactly this:
|
|
27
|
-
`{ sibling, sandboxId }` = co-located workers; `{ fleet, fleetId,
|
|
28
|
-
machineId, sandboxId }` = workers across machines.
|
|
23
|
+
## The Value Being Changed
|
|
29
24
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
surface for the measurement loop.
|
|
25
|
+
`MutableSurface` is the API type for the value under optimization.
|
|
26
|
+
It can be:
|
|
33
27
|
|
|
34
|
-
|
|
28
|
+
- a prompt string,
|
|
29
|
+
- a serialized configuration,
|
|
30
|
+
- a code surface owned by a runtime,
|
|
31
|
+
- a named component map for multi-part GEPA optimization.
|
|
35
32
|
|
|
36
|
-
|
|
33
|
+
A campaign measures surfaces but does not decide how a product stores or activates them.
|
|
37
34
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
└─ runLoop / runMultishot INNER loop: one conversation
|
|
54
|
-
├─ DRIVER = persona / user / planner chats with ↓
|
|
55
|
-
└─ WORKERS = 1..N agent harnesses in 1..M sandboxes
|
|
56
|
-
│
|
|
57
|
-
→ transcript / artifact
|
|
58
|
-
judge(artifact) → score
|
|
59
|
-
→ scorecard + CIs
|
|
60
|
-
gate(winner vs baseline) → PR
|
|
61
|
-
```
|
|
35
|
+
## Two Candidate Paths
|
|
36
|
+
|
|
37
|
+
### Complete Optimization Method
|
|
38
|
+
|
|
39
|
+
`OptimizationMethod` owns search, candidate history, selection, and stopping.
|
|
40
|
+
It receives train and selection cases and returns one selected surface.
|
|
41
|
+
|
|
42
|
+
Use this path for:
|
|
43
|
+
|
|
44
|
+
- `gepaOptimizationMethod()`, which calls official GEPA engines and composition functions,
|
|
45
|
+
- `skillOptOptimizationMethod()`, which calls Microsoft's official `ReflACTTrainer`,
|
|
46
|
+
- another optimizer that already owns its search behavior.
|
|
47
|
+
|
|
48
|
+
Complete methods run through `compareOptimizationMethods()`.
|
|
49
|
+
The comparison function scores selected surfaces on final cases after all optimization finishes.
|
|
62
50
|
|
|
63
|
-
###
|
|
51
|
+
### Caller-Owned Candidate Generator
|
|
64
52
|
|
|
65
|
-
`
|
|
66
|
-
|
|
67
|
-
artifact was produced. Behind the seam can be:
|
|
53
|
+
`SurfaceProposer` suggests candidates inside Agent Eval's `runImprovementLoop()`.
|
|
54
|
+
It receives the current surface, prior campaign history, findings, generation number, requested population size, and cancellation signal.
|
|
68
55
|
|
|
69
|
-
|
|
70
|
-
- one worker (CC) in one sandbox,
|
|
71
|
-
- a conversation driver coordinating 10 workers (CC + Codex + OpenCode)
|
|
72
|
-
sharing a workspace in one sandbox,
|
|
73
|
-
- a fleet across machines.
|
|
56
|
+
Use this path when:
|
|
74
57
|
|
|
75
|
-
|
|
76
|
-
|
|
58
|
+
- product rules generate candidates,
|
|
59
|
+
- agent-runtime delegates candidate creation to a worker,
|
|
60
|
+
- a human-authored list defines possible edits.
|
|
77
61
|
|
|
78
|
-
|
|
62
|
+
Do not reproduce an upstream optimizer behind this interface.
|
|
63
|
+
Use its complete method adapter so the upstream package retains control of its own search state.
|
|
79
64
|
|
|
80
|
-
|
|
81
|
-
- `runCampaign` is a **measurement**, not a worker. It *runs the worker* (via
|
|
82
|
-
`dispatch`); the worker does not "run the eval".
|
|
83
|
-
- The outer improvement loop has **no single worker**: its proposer proposes a
|
|
84
|
-
*surface*, and each surface is scored by a *measurement* that drives the
|
|
85
|
-
inner workers.
|
|
65
|
+
## Three Data Partitions
|
|
86
66
|
|
|
87
|
-
|
|
67
|
+
| Partition | May author candidates | May select candidates | May rank final methods |
|
|
68
|
+
|---|---:|---:|---:|
|
|
69
|
+
| Train | yes | yes | no |
|
|
70
|
+
| Selection | yes | yes | no |
|
|
71
|
+
| Final test | no | no | yes |
|
|
88
72
|
|
|
89
|
-
|
|
90
|
-
|
|
73
|
+
An `OptimizationMethodInput` has no final-test field.
|
|
74
|
+
This structural omission prevents an optimizer from receiving final cases through the normal API.
|
|
75
|
+
Official methods receive serialized train and selection cases, so both partitions are optimizer-visible.
|
|
91
76
|
|
|
92
|
-
|
|
93
|
-
`(scenario, artifact, judgeScore, source)` into the `LabeledScenarioStore`.
|
|
94
|
-
The `source` discriminates *why* the run happened: but the captured tuple is
|
|
95
|
-
identical in shape:
|
|
77
|
+
Change authors must still avoid indirect leaks through files, environment variables, cached artifacts, or custom scenario descriptions.
|
|
96
78
|
|
|
97
|
-
|
|
79
|
+
## Main APIs
|
|
80
|
+
|
|
81
|
+
| API | Responsibility |
|
|
98
82
|
|---|---|
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
83
|
+
| `runCampaign()` | Execute and score a fixed set of candidate cells. |
|
|
84
|
+
| `runImprovementLoop()` | Search with a caller-owned `SurfaceProposer` and apply a release rule. |
|
|
85
|
+
| `compareOptimizationMethods()` | Run complete methods and compare selected surfaces on shared final cases. |
|
|
86
|
+
| `gepaOptimizationMethod()` | Adapt official GEPA recipes to Agent Eval execution and scoring. |
|
|
87
|
+
| `skillOptOptimizationMethod()` | Adapt official SkillOpt training to Agent Eval execution and scoring. |
|
|
88
|
+
|
|
89
|
+
## Runtime Ownership
|
|
90
|
+
|
|
91
|
+
Agent Eval owns measurement:
|
|
92
|
+
|
|
93
|
+
- scenarios,
|
|
94
|
+
- dispatch contracts,
|
|
95
|
+
- judges,
|
|
96
|
+
- run records,
|
|
97
|
+
- cost receipts,
|
|
98
|
+
- statistics,
|
|
99
|
+
- method comparison.
|
|
100
|
+
|
|
101
|
+
Agent Runtime owns execution policy:
|
|
102
|
+
|
|
103
|
+
- agent sessions,
|
|
104
|
+
- worker creation,
|
|
105
|
+
- steering,
|
|
106
|
+
- code edits,
|
|
107
|
+
- process placement,
|
|
108
|
+
- activation in a running product.
|
|
109
|
+
|
|
110
|
+
Agent Knowledge owns knowledge state:
|
|
111
|
+
|
|
112
|
+
- sources,
|
|
113
|
+
- retrieval,
|
|
114
|
+
- memory adapters,
|
|
115
|
+
- knowledge writes,
|
|
116
|
+
- freshness and provenance.
|
|
117
|
+
|
|
118
|
+
Runtime and knowledge packages can expose their values as candidate surfaces and use Agent Eval to measure them.
|
|
119
|
+
Agent Eval must not import either consumer package.
|
|
120
|
+
|
|
121
|
+
## Resume And Parallel Work
|
|
122
|
+
|
|
123
|
+
Campaign storage keeps cell-level results and cost receipts.
|
|
124
|
+
Official optimizer adapters add their own compatible-run identity and process lock.
|
|
125
|
+
|
|
126
|
+
A compatible official run includes:
|
|
127
|
+
|
|
128
|
+
- upstream package revision,
|
|
129
|
+
- optimizer recipe or trainer settings,
|
|
130
|
+
- starting surface,
|
|
131
|
+
- train and selection descriptions,
|
|
132
|
+
- evaluation ID for execution and scoring behavior,
|
|
133
|
+
- seed,
|
|
134
|
+
- work limits.
|
|
135
|
+
|
|
136
|
+
SkillOpt and a direct GEPA engine can restore official state.
|
|
137
|
+
Composed GEPA recipes restart and report `resumed: false`.
|
|
138
|
+
Method-level concurrency and candidate-level concurrency are separate controls.
|
|
139
|
+
Each method receives its own run directory and optimization spend account.
|
|
140
|
+
|
|
141
|
+
## Cost Accounting
|
|
142
|
+
|
|
143
|
+
Agent and judge calls must report receipts through `DispatchContext.cost`.
|
|
144
|
+
Unknown spend remains unknown.
|
|
145
|
+
|
|
146
|
+
Standard GEPA and SkillOpt model calls pass through Agent Eval's local proxy.
|
|
147
|
+
The proxy enforces limits and records provider usage at caller-supplied rates.
|
|
148
|
+
Other GEPA engines can report their own spend, but that amount remains incomplete because Agent Eval did not observe those model calls.
|
|
149
|
+
Missing usage remains unknown instead of being treated as zero.
|
|
150
|
+
|
|
151
|
+
## Promotion
|
|
152
|
+
|
|
153
|
+
Optimization returns a candidate.
|
|
154
|
+
Product activation remains a separate caller decision.
|
|
155
|
+
|
|
156
|
+
The caller should require:
|
|
157
|
+
|
|
158
|
+
- a calibrated score,
|
|
159
|
+
- improvement on cases not used to author candidates,
|
|
160
|
+
- acceptable regressions by dimension,
|
|
161
|
+
- complete enough cost data for the decision,
|
|
162
|
+
- an inspectable exact change.
|
|
144
163
|
|
|
145
|
-
|
|
146
|
-
|---|---|---|---|
|
|
147
|
-
| `evolutionaryProposer` | Evolutionary (GEPA / AxGEPA) | Standalone `SurfaceProposer`. Mutates the current best surface into N candidates, blind to history beyond the current best. Optimizes against the dataset's rewards. | **agent-eval** (pure: dataset → surface, no sandbox) |
|
|
148
|
-
| Runtime reflective proposer | Reflective | Cheap generator: drafts patches from the report and applies them into a worktree (shots=1, no sandbox). | **agent-runtime**: implements agent-eval's proposer contract |
|
|
149
|
-
| Runtime agentic proposer | Agentic | Full generator: runs a coding harness in the worktree (≤ `maxImprovementShots`) to edit in place. | **agent-runtime** |
|
|
150
|
-
|
|
151
|
-
This resolves the prior duplication where `runImprovementLoop` (evolutionary,
|
|
152
|
-
agent-eval) and `runAnalystLoop` (reflective, agent-runtime) were two parallel
|
|
153
|
-
loops doing "propose change → measure → gate → PR". There is **one loop** and
|
|
154
|
-
one proposer contract. The reflective and agentic paths are two settings of the
|
|
155
|
-
same cost dial, not separate outer loops. The dependency direction permits this
|
|
156
|
-
cleanly: agent-eval is the leaf and owns the proposer contract; agent-runtime
|
|
157
|
-
imports agent-eval and implements it.
|
|
158
|
-
|
|
159
|
-
## What "the surface" is: improvement tiers
|
|
160
|
-
|
|
161
|
-
`MutableSurface` is the thing the proposer changes. It has tiers, least → most
|
|
162
|
-
invasive. `MutableSurface = string | CodeSurface` spans all of them: `string`
|
|
163
|
-
for tiers 1–2, and a finalized `CodeSurface` for tier 4. A code surface's
|
|
164
|
-
worktree path is only its locator; exact base/candidate commits, final tree,
|
|
165
|
-
and binary-patch digest are its portable identity. Call `verifyCodeSurface`
|
|
166
|
-
before executing the checkout so a moved ref or post-finalization mutation
|
|
167
|
-
fails before measurement. Verification hashes raw files and executable modes
|
|
168
|
-
without Git filters and rejects external symlinks or submodules whose bytes are
|
|
169
|
-
not represented by the candidate tree.
|
|
170
|
-
|
|
171
|
-
| Tier | Surface | Generator that changes it | Blast radius |
|
|
172
|
-
|---|---|---|---|
|
|
173
|
-
| 1 | System prompt / prompt-signature addendum | `evolutionaryProposer` (GEPA), `reflectiveGenerator` | prompt only |
|
|
174
|
-
| 2 | Tool config / tool signatures | `reflectiveGenerator` | which tools, their schemas |
|
|
175
|
-
| 3 | Knowledge (wiki / knowledge graph) | agent-knowledge's knowledge adapter | what the agent *knows* |
|
|
176
|
-
| 4 | Code / scaffolding | `agenticGenerator` (coding harness reads codebase + report) → worktree / PR | the implementation itself |
|
|
177
|
-
|
|
178
|
-
The cost/capability distinction:
|
|
179
|
-
|
|
180
|
-
- **`reflectiveGenerator`** updates the *signatures*: prompt + tool surface
|
|
181
|
-
(tiers 1–2). Cheap (drafts patches, no sandbox), reversible, measured
|
|
182
|
-
directly against the dataset.
|
|
183
|
-
- **`agenticGenerator`** updates the *code* (tier 4). A coding harness reads
|
|
184
|
-
the repository + the report, edits in a worktree, iterates up to
|
|
185
|
-
`maxImprovementShots`: measured by re-running the inner loop against the
|
|
186
|
-
changed code.
|
|
187
|
-
|
|
188
|
-
Both are implementations of the one proposer contract (propose → measure → gate
|
|
189
|
-
→ PR). They differ only in *what* they edit and *how invasive* it is: and both
|
|
190
|
-
consume the **same dataset** the flywheel builds.
|
|
191
|
-
|
|
192
|
-
## Vocabulary quick reference
|
|
193
|
-
|
|
194
|
-
- **shot**: one conversational turn (driver says X, worker responds Y). Used
|
|
195
|
-
in `runMultishot`. Never used to mean a whole eval run.
|
|
196
|
-
- **runMultishot**: many shots in one conversation; persona-driver ↔ one
|
|
197
|
-
router-agent. agent-eval.
|
|
198
|
-
- **runLoop**: driver ↔ workers in sandboxes; topology-agnostic execution.
|
|
199
|
-
agent-runtime.
|
|
200
|
-
- **runCampaign**: a measurement: a surface scored over N scenarios × M reps.
|
|
201
|
-
agent-eval. (A "campaign" = a coordinated batch of measurements.)
|
|
202
|
-
- **runOptimization**: the improvement loop body: proposer suggests surfaces, each is measured, and only a candidate that beats the global incumbent is promoted. agent-eval.
|
|
203
|
-
- **runImprovementLoop**: `runOptimization` + holdout re-score + release gate
|
|
204
|
-
+ optional PR. agent-eval.
|
|
205
|
-
- **runAnalystLoop**: reflective autoresearch: findings + knowledge updates +
|
|
206
|
-
improvement proposals. agent-runtime.
|
|
207
|
-
- **SurfaceProposer**: the contract a surface proposer implements.
|
|
208
|
-
`evolutionaryProposer` (agent-eval) is one; agent-runtime can provide
|
|
209
|
-
reflective or agentic implementations.
|
|
210
|
-
- **CandidateGenerator**: the byte-producing seam inside a runtime proposer;
|
|
211
|
-
`reflectiveGenerator` (cheap, no sandbox) and `agenticGenerator` (coding
|
|
212
|
-
harness in the worktree) are the two cost settings. agent-runtime.
|
|
164
|
+
The package records the decision inputs but does not deploy a prompt, skill, model, code change, memory, or knowledge base.
|
package/docs/design.md
CHANGED
|
@@ -14,7 +14,7 @@ agent-runtime Runs agents (chat turns, one-shot tasks, multi-attempt loops),
|
|
|
14
14
|
run as a trace, and exposes improve(), which composes agent-eval's improvement
|
|
15
15
|
loop. Produces the RunRecords + traces agent-eval scores. Depends on agent-eval.
|
|
16
16
|
|
|
17
|
-
agent-eval selfImprove, analyzeRuns, runCampaign
|
|
17
|
+
agent-eval selfImprove, analyzeRuns, runCampaign, official optimizer adapters,
|
|
18
18
|
(this repo) the gates (heldOutGate, defaultProductionGate, paretoSignificanceGate), the
|
|
19
19
|
InsightReport, the RL bridge, the wire protocol. Depends on neither consumer.
|
|
20
20
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Distributed campaign execution: coordinator-on-A, workers-on-B
|
|
2
2
|
|
|
3
|
-
The coordinator process
|
|
4
|
-
|
|
5
|
-
same process, machine, region, or cloud
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
The coordinator process runs `runCampaign()`, `runImprovementLoop()`, or `compareOptimizationMethods()`.
|
|
4
|
+
The worker runs your actual agent.
|
|
5
|
+
They do not have to live in the same process, machine, region, or cloud.
|
|
6
|
+
`Dispatch` is a function from scenario to artifact.
|
|
7
|
+
The implementation can be local, remote, sandboxed, or spread across a worker fleet.
|
|
8
8
|
|
|
9
9
|
## Why you'd want this
|
|
10
10
|
|
|
@@ -161,12 +161,9 @@ and using `cellPlacement` to fan across many of them.
|
|
|
161
161
|
stay on the worker. We need to forward them in the response body so
|
|
162
162
|
`defaultProductionGate`'s `budgetUsd` ceiling reflects total spend, not
|
|
163
163
|
coordinator-side spend. Tracked as a 0.45.x follow-up.
|
|
164
|
-
- **Per-cell artifact streaming**: when the worker writes intermediate
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
(S3/GCS) reachable from both sides; today consumers wire that as a
|
|
168
|
-
`CampaignStorage` impl. A reference S3-backed storage is on the
|
|
169
|
-
roadmap.
|
|
164
|
+
- **Per-cell artifact streaming**: when the worker writes intermediate artifacts through `ctx.artifacts.write`, those files remain in worker storage.
|
|
165
|
+
Multi-worker campaigns need a shared `CampaignStorage` implementation reachable from both sides.
|
|
166
|
+
This package does not include an S3 or GCS implementation.
|
|
170
167
|
- **gRPC / NATS / Temporal transports**: the wire is HTTP today by
|
|
171
168
|
default because everything speaks HTTP. Other transports can ship as
|
|
172
169
|
additional adapters; the `Dispatch` interface itself is
|
package/docs/feature-guide.md
CHANGED
|
@@ -5,9 +5,8 @@ then shows when to use each one.
|
|
|
5
5
|
|
|
6
6
|
## Overview
|
|
7
7
|
|
|
8
|
-
LLM agents can write code, drafts, research, plans, and actions.
|
|
9
|
-
|
|
10
|
-
trying, and whether a change made them better or worse.
|
|
8
|
+
LLM agents can write code, drafts, research, plans, and actions.
|
|
9
|
+
Evaluation measures whether the result met its requirements, whether another attempt is warranted, and whether a change improved outcomes.
|
|
11
10
|
|
|
12
11
|
`agent-eval` gives you reusable tools for that:
|
|
13
12
|
|
|
@@ -18,8 +17,7 @@ trying, and whether a change made them better or worse.
|
|
|
18
17
|
- **Feedback trajectories** turn normal user approvals/rejections into training
|
|
19
18
|
and eval data.
|
|
20
19
|
- **Datasets and holdouts** keep examples organized so you do not overfit.
|
|
21
|
-
- **Optimizers and mutation loops** try prompt
|
|
22
|
-
the ones that really improve.
|
|
20
|
+
- **Optimizers and mutation loops** try prompt, signature, or code variants and retain measured improvements.
|
|
23
21
|
- **Traces and telemetry** show what happened, step by step.
|
|
24
22
|
|
|
25
23
|
## Which Primitive Should I Use?
|
|
@@ -27,15 +25,15 @@ trying, and whether a change made them better or worse.
|
|
|
27
25
|
| Problem | Use | Why |
|
|
28
26
|
| --- | --- | --- |
|
|
29
27
|
| “Did this single answer/draft pass?” | Judge or rubric | Fast quality signal for one artifact. |
|
|
30
|
-
| “Does generated code
|
|
28
|
+
| “Does generated code work?” | `BuilderSession`, `MultiLayerVerifier` | Build, test, and runtime checks catch failures judges miss. |
|
|
31
29
|
| “Should the agent keep trying?” | `runAgentControlLoop` | Budgeted `observe -> validate -> decide -> act` runtime. |
|
|
32
30
|
| “The agent should propose, verify, review, and revise.” | `runProposeReviewAsControlLoop` | Reusable preset over the generic control loop. |
|
|
33
31
|
| “Human feedback should become reusable eval data.” | `FeedbackTrajectory` | Captures approvals, rejections, edits, choices, metrics, and policy blocks. |
|
|
34
32
|
| “I want Vercel-style eval folders agents can add quickly.” | `loadEvalFixtureScenarios`, `planEvalFixtureRun`, `runCampaign` | Folder-per-eval DX with campaign scoring and cache-safe dry runs. |
|
|
35
33
|
| “Can this action run, or does it need approval?” | `evaluateActionPolicy` | Generic preflight for side effects, budgets, and required evidence. |
|
|
36
34
|
| “I need train/dev/test/holdout examples.” | `Dataset` plus feedback trajectory conversion | Stable splits and contamination control. |
|
|
37
|
-
| “Which
|
|
38
|
-
| “Improve a multi-turn agent
|
|
35
|
+
| “Which optimization procedure wins?” | `compareOptimizationMethods` | Runs complete methods on shared train and selection cases, then compares them on separate final cases. |
|
|
36
|
+
| “Improve a multi-turn agent with candidates from my runtime.” | `runImprovementLoop` | Evaluates caller-generated candidates and applies a separate release rule. |
|
|
39
37
|
| “Improve prompts, then code if prompts plateau.” | `runPromptEvolution`, composite mutator, code mutator | Bounded evolution with telemetry and lineage. |
|
|
40
38
|
| “Find why a regression happened.” | bisector, traces, run records | Narrows changes and preserves evidence. |
|
|
41
39
|
| “Expose evals to another language.” | Wire protocol and Python client | HTTP/RPC boundary for non-TypeScript apps. |
|
|
@@ -102,21 +100,24 @@ Result:
|
|
|
102
100
|
generated code -> build/test/runtime gates -> score -> ship or revise
|
|
103
101
|
```
|
|
104
102
|
|
|
105
|
-
### Prompt
|
|
103
|
+
### Prompt And Skill Optimization
|
|
106
104
|
|
|
107
|
-
Use
|
|
105
|
+
Use `gepaOptimizationMethod()` for official GEPA recipes.
|
|
106
|
+
Use `skillOptOptimizationMethod()` for Microsoft's official SkillOpt trainer.
|
|
107
|
+
For DSPy programs, use official DSPy optimizers with Python's `DspyJudgeMetric`.
|
|
108
|
+
Run complete methods through `compareOptimizationMethods()`.
|
|
109
|
+
Use `runImprovementLoop()` only when your application or runtime owns candidate generation through `SurfaceProposer`.
|
|
108
110
|
|
|
109
|
-
1.
|
|
110
|
-
2.
|
|
111
|
-
3.
|
|
112
|
-
4.
|
|
113
|
-
5.
|
|
114
|
-
6. Keep run records with prompt hash, model, config, cost, and commit.
|
|
111
|
+
1. Build train, selection, and final splits from the real product path.
|
|
112
|
+
2. Score complete trajectories rather than final text alone.
|
|
113
|
+
3. Give optimizers actionable evidence from train and selection failures.
|
|
114
|
+
4. Keep final cases out of candidate generation and method selection.
|
|
115
|
+
5. Record prompt hash, model, configuration, cost status, and source revision.
|
|
115
116
|
|
|
116
117
|
Result:
|
|
117
118
|
|
|
118
119
|
```text
|
|
119
|
-
candidate variant -> repeated
|
|
120
|
+
candidate variant -> repeated evaluations -> statistical comparison -> release decision
|
|
120
121
|
```
|
|
121
122
|
|
|
122
123
|
Do not optimize a toy harness if users run a different product loop. Build
|
|
@@ -158,9 +159,9 @@ Store as `FeedbackTrajectory`, then derive:
|
|
|
158
159
|
| Action policy | `evaluateActionPolicy` | Approval/budget preflight | Blocks or labels actions before `act()`. |
|
|
159
160
|
| Datasets | `Dataset`, holdout tools, canaries | Train/dev/test/holdout corpora | Keeps optimization honest. |
|
|
160
161
|
| Eval fixtures | `discoverEvalFixtures`, `loadEvalFixtureScenarios`, `planEvalFixtureRun` | Coding-agent eval folders | Vercel-style input shape; still executes through `runCampaign`. |
|
|
161
|
-
| Optimization | `
|
|
162
|
+
| Optimization | `compareOptimizationMethods`, official optimizer adapters, `runImprovementLoop` | Prompt and skill comparison | Reserve separate final cases for method ranking. |
|
|
162
163
|
| Evolution | prompt/code mutators, sandbox pool, telemetry | Autoresearch and mutation loops | Use budgets and lineage; do not run unbounded. |
|
|
163
|
-
| Telemetry | `TraceStore`, OTLP, file sinks |
|
|
164
|
+
| Telemetry | `TraceStore`, OTLP, file sinks | Evidence and replay | Store traces as inspectable run evidence. |
|
|
164
165
|
| Reporting | summaries, pareto, cost tracker | Decision support | Useful for PRs, launch gates, research notes. |
|
|
165
166
|
|
|
166
167
|
## Guardrails
|
|
@@ -77,8 +77,5 @@ Knowledge-related failures use the normal failure taxonomy:
|
|
|
77
77
|
- `contradictory_evidence`
|
|
78
78
|
- `ambiguous_user_intent`
|
|
79
79
|
|
|
80
|
-
For optimization, scorers should
|
|
81
|
-
|
|
82
|
-
`user-question-policy` in actionable side information. That lets GEPA-style
|
|
83
|
-
loops improve data acquisition and retrieval policy instead of blaming every
|
|
84
|
-
failure on the prompt.
|
|
80
|
+
For optimization, scorers should identify responsible surfaces such as `knowledge-requirements`, `data-acquisition`, `retrieval-policy`, and `user-question-policy`.
|
|
81
|
+
That evidence lets an official optimization method or caller-owned `SurfaceProposer` improve acquisition and retrieval policy instead of blaming every failure on the prompt.
|
|
@@ -1,32 +1,45 @@
|
|
|
1
1
|
# Improve One Surface
|
|
2
2
|
|
|
3
|
-
`runImprovementLoop`
|
|
3
|
+
`runImprovementLoop()` evaluates candidates from a `SurfaceProposer`, selects one on training data, and compares it with the baseline on separate holdout cases.
|
|
4
4
|
|
|
5
|
-
Use it when
|
|
6
|
-
Use [`compareOptimizationMethods`](./campaign-proposers.md
|
|
5
|
+
Use it when your application or runtime owns candidate generation.
|
|
6
|
+
Use [`compareOptimizationMethods()`](./campaign-proposers.md) when GEPA, SkillOpt, or another external system owns the complete search procedure.
|
|
7
7
|
|
|
8
8
|
## Inputs
|
|
9
9
|
|
|
10
10
|
| Input | Meaning |
|
|
11
11
|
|---|---|
|
|
12
|
-
| `baselineSurface` | Current prompt or
|
|
13
|
-
| `scenarios` | Training
|
|
14
|
-
| `holdoutScenarios` | Separate
|
|
15
|
-
| `dispatchWithSurface` | Runs one
|
|
12
|
+
| `baselineSurface` | Current prompt or serialized configuration. |
|
|
13
|
+
| `scenarios` | Training cases used to generate and score candidates. |
|
|
14
|
+
| `holdoutScenarios` | Separate cases used for the release decision after search. |
|
|
15
|
+
| `dispatchWithSurface` | Runs one case with one candidate surface. |
|
|
16
16
|
| `judges` | Scores the returned artifact. |
|
|
17
|
-
| `proposer` |
|
|
18
|
-
| `gate` |
|
|
19
|
-
| `runDir` |
|
|
17
|
+
| `proposer` | Caller-owned candidate generator. |
|
|
18
|
+
| `gate` | Caller-owned release rule for the baseline and selected candidate. |
|
|
19
|
+
| `runDir` | Directory for run artifacts, traces, and resumable state. |
|
|
20
20
|
|
|
21
21
|
## Example
|
|
22
22
|
|
|
23
23
|
```ts
|
|
24
24
|
import {
|
|
25
25
|
defaultProductionGate,
|
|
26
|
-
gepaProposer,
|
|
27
26
|
runImprovementLoop,
|
|
27
|
+
type SurfaceProposer,
|
|
28
28
|
} from '@tangle-network/agent-eval/campaign'
|
|
29
29
|
|
|
30
|
+
const proposer: SurfaceProposer = {
|
|
31
|
+
kind: 'product-rules',
|
|
32
|
+
async propose({ currentSurface, populationSize }) {
|
|
33
|
+
return [
|
|
34
|
+
{
|
|
35
|
+
surface: `${String(currentSurface)}\nReturn JSON only.`,
|
|
36
|
+
label: 'json-only',
|
|
37
|
+
rationale: 'Training failures contained prose around the JSON object.',
|
|
38
|
+
},
|
|
39
|
+
].slice(0, populationSize)
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
|
|
30
43
|
const result = await runImprovementLoop({
|
|
31
44
|
baselineSurface: currentSystemPrompt,
|
|
32
45
|
scenarios: trainScenarios,
|
|
@@ -34,13 +47,9 @@ const result = await runImprovementLoop({
|
|
|
34
47
|
dispatchWithSurface: async (surface, scenario, ctx) =>
|
|
35
48
|
runYourAgent({ prompt: String(surface), scenario, signal: ctx.signal }),
|
|
36
49
|
judges: [qualityJudge],
|
|
37
|
-
proposer
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
target: 'the complete system prompt',
|
|
41
|
-
}),
|
|
42
|
-
populationSize: 4,
|
|
43
|
-
maxGenerations: 4,
|
|
50
|
+
proposer,
|
|
51
|
+
populationSize: 1,
|
|
52
|
+
maxGenerations: 1,
|
|
44
53
|
gate: defaultProductionGate({
|
|
45
54
|
holdoutScenarios,
|
|
46
55
|
deltaThreshold: 0,
|
|
@@ -54,14 +63,13 @@ if (result.gateResult.decision === 'ship') {
|
|
|
54
63
|
}
|
|
55
64
|
```
|
|
56
65
|
|
|
57
|
-
##
|
|
66
|
+
## Rules
|
|
58
67
|
|
|
59
|
-
- Training and holdout
|
|
60
|
-
- Candidate generation cannot read holdout
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
- `result.
|
|
64
|
-
- `result.promotedDiff` describes the exact selected surface change.
|
|
68
|
+
- Training and holdout case IDs must be disjoint.
|
|
69
|
+
- Candidate generation cannot read holdout scores through `SurfaceProposer`.
|
|
70
|
+
- An unchanged selected surface does not receive credit for model variance.
|
|
71
|
+
- `result.cost` includes calls recorded through the shared cost ledger.
|
|
72
|
+
- `result.promotedDiff` identifies the exact selected change.
|
|
65
73
|
|
|
66
|
-
|
|
67
|
-
|
|
74
|
+
Calibrate the judge on known strong and weak artifacts before using its decision in production.
|
|
75
|
+
The runnable offline example is [`examples/multi-shot-optimization`](../examples/multi-shot-optimization/).
|