textopt 0.0.0 → 0.2.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.
Files changed (65) hide show
  1. package/README.md +65 -25
  2. package/dist/bootstrap-search/index.cjs +159 -73
  3. package/dist/bootstrap-search/index.d.cts +32 -10
  4. package/dist/bootstrap-search/index.d.mts +32 -10
  5. package/dist/bootstrap-search/index.mjs +150 -66
  6. package/dist/demos-9v5ts7F3.cjs +244 -0
  7. package/dist/{demos-B0pVQjYC.d.mts → demos-ASsSXYXA.d.mts} +10 -3
  8. package/dist/demos-Brobjfuc.mjs +215 -0
  9. package/dist/{demos-BTuzFNsp.d.cts → demos-ByaLZy-Z.d.cts} +10 -3
  10. package/dist/file-cache.cjs +27 -8
  11. package/dist/file-cache.d.cts +13 -0
  12. package/dist/file-cache.d.mts +13 -0
  13. package/dist/file-cache.mjs +27 -8
  14. package/dist/gepa/index.cjs +128 -80
  15. package/dist/gepa/index.d.cts +15 -7
  16. package/dist/gepa/index.d.mts +15 -7
  17. package/dist/gepa/index.mjs +101 -55
  18. package/dist/index.cjs +157 -30
  19. package/dist/index.d.cts +177 -7
  20. package/dist/index.d.mts +177 -7
  21. package/dist/index.mjs +139 -18
  22. package/dist/{math-COOofUyv.cjs → math-BhlziRPc.cjs} +60 -9
  23. package/dist/math-Dqme4rYz.mjs +123 -0
  24. package/dist/mipro/index.cjs +104 -70
  25. package/dist/mipro/index.d.cts +17 -14
  26. package/dist/mipro/index.d.mts +17 -14
  27. package/dist/mipro/index.mjs +90 -58
  28. package/dist/opro/index.cjs +136 -51
  29. package/dist/opro/index.d.cts +17 -9
  30. package/dist/opro/index.d.mts +17 -9
  31. package/dist/opro/index.mjs +121 -38
  32. package/dist/{optimizer-B7SpRwl7.d.cts → optimizer-4Zv-Zt2t.d.cts} +90 -5
  33. package/dist/{optimizer-DqCoth_w.d.mts → optimizer-Ds5mzYjz.d.mts} +90 -5
  34. package/dist/random-search/index.cjs +99 -49
  35. package/dist/random-search/index.d.cts +15 -13
  36. package/dist/random-search/index.d.mts +15 -13
  37. package/dist/random-search/index.mjs +89 -41
  38. package/dist/{reflection-Cr_upzU0.d.mts → reflection-CMezGu6u.d.mts} +38 -14
  39. package/dist/{reflection-CQToe-5B.d.cts → reflection-D0A7eahD.d.cts} +38 -14
  40. package/dist/reporting-bq007_2z.d.cts +294 -0
  41. package/dist/reporting-bq007_2z.d.mts +294 -0
  42. package/dist/simba/index.cjs +216 -83
  43. package/dist/simba/index.d.cts +53 -13
  44. package/dist/simba/index.d.mts +53 -13
  45. package/dist/simba/index.mjs +206 -75
  46. package/dist/testing.cjs +1 -0
  47. package/dist/testing.d.cts +5 -3
  48. package/dist/testing.d.mts +5 -3
  49. package/dist/testing.mjs +1 -1
  50. package/dist/{evaluation-OZOp6TB7.cjs → warnings-CWRJF-jA.cjs} +228 -5
  51. package/dist/{evaluation-BV0nSZVx.mjs → warnings-OxvDi9kN.mjs} +175 -6
  52. package/docs/adapters.md +169 -0
  53. package/docs/benchmark.md +90 -0
  54. package/docs/data-prep.md +113 -0
  55. package/docs/distillation.md +128 -0
  56. package/docs/evaluation.md +87 -0
  57. package/docs/metric-preflight.md +132 -0
  58. package/docs/optimizers.md +293 -0
  59. package/docs/tuning.md +130 -0
  60. package/package.json +6 -4
  61. package/dist/demos-B9BJiNKz.cjs +0 -143
  62. package/dist/demos-Degx6UmP.mjs +0 -126
  63. package/dist/math-DhrDmpFS.mjs +0 -78
  64. package/dist/types-CWv4IQFF.d.cts +0 -129
  65. package/dist/types-CWv4IQFF.d.mts +0 -129
@@ -0,0 +1,294 @@
1
+ //#region src/types.d.ts
2
+ /**
3
+ * A candidate is a map of named text components to their current text. This is
4
+ * the unit of optimization — prompts, instructions, code, tool descriptions,
5
+ * anything expressible as a named string.
6
+ *
7
+ * `K` is the union of component names, inferred from the seed candidate, so a
8
+ * misspelled component is a compile error rather than a silent no-op.
9
+ */
10
+ type Candidate<K extends string = string> = Record<K, string>;
11
+ /**
12
+ * What one rollout consumed. Every field is optional because providers report
13
+ * different subsets, and a partial reading is still worth more than none.
14
+ */
15
+ interface RolloutUsage {
16
+ inputTokens?: number;
17
+ outputTokens?: number;
18
+ /** Defaults to the sum of the two token counts when they are reported. */
19
+ totalTokens?: number;
20
+ costUsd?: number;
21
+ }
22
+ /** Usage summed over a run, alongside the rollouts that produced it. */
23
+ interface UsageTotals {
24
+ inputTokens: number;
25
+ outputTokens: number;
26
+ totalTokens: number;
27
+ costUsd: number;
28
+ /** Fresh rollouts counted here. Cached instances buy nothing. */
29
+ rollouts: number;
30
+ }
31
+ /**
32
+ * Result of running a candidate over a batch of data instances.
33
+ *
34
+ * `scores` is the load-bearing field: one number per instance, higher is
35
+ * better. `feedback` is a per-instance textual diagnosis of what went wrong,
36
+ * which a reflective optimizer reads to write a better candidate.
37
+ */
38
+ interface EvaluationBatch<Trajectory = unknown, Output = unknown> {
39
+ outputs: Output[];
40
+ scores: number[];
41
+ /**
42
+ * What each rollout consumed. Rollout counts are the budget, but they are a
43
+ * poor proxy for spend: reflective search grows the text it optimizes, so
44
+ * the same rollout costs more late in a run than early in it.
45
+ */
46
+ usage?: RolloutUsage[];
47
+ feedback?: string[];
48
+ trajectories?: Trajectory[];
49
+ objectiveScores?: Record<string, number>[];
50
+ /**
51
+ * Per-instance: true when the score reflects an infrastructure failure
52
+ * rather than the candidate's behaviour. Transient scores are never written
53
+ * to the evaluation cache.
54
+ */
55
+ transient?: boolean[];
56
+ }
57
+ /**
58
+ * What a per-instance scorer returns. Shared by every adapter so scorers are
59
+ * portable between them — a Braintrust scorer works in a LangChain run.
60
+ */
61
+ interface ScoreResult {
62
+ score: number;
63
+ feedback?: string;
64
+ objectiveScores?: Record<string, number>;
65
+ /** What this rollout consumed, when the caller can see it. */
66
+ usage?: RolloutUsage;
67
+ /**
68
+ * Marks a score produced by an infrastructure failure — a rate limit, a
69
+ * network blip, a provider 5xx — rather than by the candidate. Without this
70
+ * the engine cannot tell such a zero from a genuine one, and would cache it
71
+ * permanently against the candidate.
72
+ */
73
+ transient?: boolean;
74
+ }
75
+ interface EvaluateArgs<Datum, K extends string = string> {
76
+ batch: readonly Datum[];
77
+ candidate: Candidate<K>;
78
+ captureTraces: boolean;
79
+ /**
80
+ * Where this batch sits in the run. Forward it to whatever tracing the
81
+ * system under optimization already has — without it a run is thousands of
82
+ * indistinguishable rollouts, and no trace can be tied back to the iteration
83
+ * whose score moved.
84
+ */
85
+ run: EvaluationContext;
86
+ signal?: AbortSignal;
87
+ }
88
+ /**
89
+ * Identifies one evaluation within a run. `candidateId` is null while the
90
+ * candidate is still a proposal being screened on a minibatch: it has no
91
+ * record, and inventing an id for it would collide with the one it gets if it
92
+ * is accepted.
93
+ */
94
+ interface EvaluationContext {
95
+ iteration: number;
96
+ phase: EvaluationPhase;
97
+ split: EvaluationSplit;
98
+ candidateId: number | null;
99
+ }
100
+ type EvaluationPhase = "seed" | "minibatch" | "validation" | "test";
101
+ /**
102
+ * Which dataset an instance id was drawn from. Each split numbers its ids
103
+ * independently, so the same id can name three different instances; the cache
104
+ * key has to keep them apart.
105
+ */
106
+ type EvaluationSplit = "train" | "val" | "test";
107
+ /**
108
+ * The single integration seam between an optimizer and a system under
109
+ * optimization. Everything framework-specific — LangChain, the AI SDK,
110
+ * Braintrust — lives in an implementation of this interface.
111
+ */
112
+ interface Adapter<Datum, Trajectory = unknown, Output = unknown, K extends string = string> {
113
+ evaluate(args: EvaluateArgs<Datum, K>): Promise<EvaluationBatch<Trajectory, Output>> | EvaluationBatch<Trajectory, Output>;
114
+ }
115
+ /** Provider-agnostic text model: text in, text out. */
116
+ type TextModel = (args: {
117
+ prompt: string;
118
+ signal?: AbortSignal;
119
+ }) => Promise<string>;
120
+ /**
121
+ * The component names of a candidate, as the union they were inferred from.
122
+ *
123
+ * `Object.keys` widens a closed key union back to `string`. This is the one
124
+ * place that narrowing happens, so every other caller stays assertion-free.
125
+ * Accepts a partial so it also names the components of a component patch.
126
+ */
127
+ declare function componentNames<K extends string>(candidate: Partial<Candidate<K>>): K[];
128
+ //#endregion
129
+ //#region src/warnings.d.ts
130
+ /**
131
+ * Something about a run that its own numbers cannot say.
132
+ *
133
+ * A search reports a score, a stop reason and what it spent, and every one of
134
+ * those reads the same whether the run measured what the caller thinks it did
135
+ * or not. These are the conditions under which a normal-looking result means
136
+ * less than it appears to: they never stop a run, and they are carried on the
137
+ * result and the `finish` event so a report can say so next to the number.
138
+ */
139
+ interface RunWarning {
140
+ code: RunWarningCode;
141
+ message: string;
142
+ }
143
+ type RunWarningCode = "validationSetReusesTraining" | "seedScoreSaturated" | "seedScoreFloored";
144
+ /**
145
+ * The validation set a run will actually select against, and whatever the
146
+ * choice costs it.
147
+ *
148
+ * Defaulting to the training set is the right default for a first run and the
149
+ * wrong number to report from one. It is worse than ordinary overfitting under
150
+ * reflective search: the reflection prompt asks the model to mine domain facts
151
+ * out of the traces it is shown, so those facts come out of the very instances
152
+ * that then select the candidate carrying them. `"reuseTraining"` is the same
153
+ * behaviour with the caller's name on it, and silences the warning.
154
+ */
155
+ declare function resolveValidationSet<Datum>(args: {
156
+ validationSet: readonly Datum[] | "reuseTraining" | undefined;
157
+ trainingSet: readonly Datum[];
158
+ }): {
159
+ validationSet: readonly Datum[];
160
+ warnings: RunWarning[];
161
+ };
162
+ /**
163
+ * What the seed's own validation row says about whether the run could have
164
+ * learned anything.
165
+ *
166
+ * A search ranks candidates by how they differ across instances, so a seed row
167
+ * with no spread leaves nothing to rank: at the ceiling every proposal is a tie
168
+ * the acceptance test resolves by noise, and at the floor no proposal has a
169
+ * partial improvement to build on. Both produce a run that spends its whole
170
+ * budget and reports a stop reason that looks like any other.
171
+ */
172
+ declare function seedScoreWarnings(args: {
173
+ scores: readonly (number | undefined)[];
174
+ perfectScore: number;
175
+ }): RunWarning[];
176
+ //#endregion
177
+ //#region src/reporting.d.ts
178
+ /**
179
+ * Where a run's progress goes, for any optimizer. Observability only:
180
+ * persisting a run so it can be resumed is `onCheckpoint`, which is durability
181
+ * and a separate concern.
182
+ *
183
+ * Generic over the event union rather than one union covering every optimizer:
184
+ * a search emits what it actually has, and a reporter written against one
185
+ * optimizer still type-checks against the events it reads.
186
+ */
187
+ /**
188
+ * The least an optimizer's event satisfies. A reporter typed against this
189
+ * accepts every optimizer's union, because a literal tag is assignable to
190
+ * `string` and the parameter position is contravariant.
191
+ */
192
+ interface OptimizerEvent {
193
+ type: string;
194
+ }
195
+ interface Reporter<Event> {
196
+ /**
197
+ * Called on the search's hot path, synchronously. A reporter that ships
198
+ * anywhere over a network buffers here and uploads in `flush`, or it charges
199
+ * every iteration for its latency.
200
+ *
201
+ * A reporter that throws is warned about and skipped: observability never
202
+ * fails a run.
203
+ */
204
+ onEvent?: (event: Event) => void;
205
+ /** Awaited once as the run ends, including when it ends by throwing. */
206
+ flush?: () => Promise<void>;
207
+ }
208
+ /**
209
+ * The payload every optimizer's `candidateAccepted` carries, so one reporter
210
+ * can read an acceptance without knowing which search produced it. Each
211
+ * optimizer intersects its own fields onto this — GEPA its lineage, MIPRO its
212
+ * menu choices — the way the event unions already intersect `EvaluationEvent`.
213
+ *
214
+ * Emitted only when the incumbent moves and a full validation sweep measured
215
+ * it. An optimizer that accepts on a minibatch reports the acceptance in its
216
+ * own event and emits this one once the sweep that confirms it lands, so
217
+ * `instanceScores` never means "a subset, and you work out which".
218
+ */
219
+ interface CandidateAccepted<K extends string = string> {
220
+ /** Identifies the candidate within the run. */
221
+ candidateId: number;
222
+ /** The text that scored, so a move is readable next to the edit. */
223
+ candidate: Candidate<K>;
224
+ /** Mean over the validation set, which is what selection is decided on. */
225
+ aggregateScore: number;
226
+ /**
227
+ * Per-instance scores, aligned with the validation set. `undefined` marks an
228
+ * instance an infrastructure failure left unmeasured — unknown, not zero.
229
+ *
230
+ * Handed out by reference rather than copied: a run emits this once per
231
+ * accepted candidate, and copying a validation-set-sized array that often to
232
+ * guard against a listener that writes to it costs every run to protect a
233
+ * listener that should not exist.
234
+ */
235
+ instanceScores: readonly (number | undefined)[];
236
+ /** Aligned with `instanceScores`. Present only under `trackBestOutputs`. */
237
+ outputs?: readonly unknown[];
238
+ }
239
+ /**
240
+ * The payload every optimizer's `finish` carries. `reason` stays per-optimizer
241
+ * because the stop reasons genuinely differ — only GEPA can exhaust a
242
+ * reflection budget.
243
+ */
244
+ interface RunFinished {
245
+ /** The winner, named the way `CandidateAccepted.candidateId` names it. */
246
+ bestCandidateId: number;
247
+ bestScore: number;
248
+ metricCalls: number;
249
+ /** The winner's held-out score, when a testSet was given. */
250
+ testScore?: number;
251
+ /**
252
+ * The winner's per-instance held-out scores, aligned with the testSet and
253
+ * present whenever `testScore` is. `undefined` marks an instance an
254
+ * infrastructure failure left unmeasured, which is what `testScore` averages
255
+ * over too.
256
+ *
257
+ * The mean is the number selection never saw; this is where the gap below
258
+ * `bestScore` came from.
259
+ */
260
+ testInstanceScores?: readonly (number | undefined)[];
261
+ /** Aligned with `testInstanceScores`. Only under `trackBestOutputs`. */
262
+ testOutputs?: readonly unknown[];
263
+ /**
264
+ * What the run cannot say about itself from its own numbers. A reporter that
265
+ * writes the score somewhere permanent writes these beside it, or the record
266
+ * outlives the only place the caveat was ever stated.
267
+ */
268
+ warnings: readonly RunWarning[];
269
+ }
270
+ /**
271
+ * The two events every optimizer emits with a payload a reporter can read
272
+ * without knowing which search produced it. A cross-optimizer reporter takes
273
+ * this as its event type: it is a supertype of every optimizer's own union, so
274
+ * one reporter drops into any optimizer's `reporters` array.
275
+ */
276
+ type ReportableEvent<K extends string = string> = ({
277
+ type: "candidateAccepted";
278
+ } & CandidateAccepted<K>) | ({
279
+ type: "finish";
280
+ } & RunFinished);
281
+ /**
282
+ * Narrows an event off any optimizer's union to an acceptance. The tag is
283
+ * enough: every optimizer's `candidateAccepted` intersects `CandidateAccepted`,
284
+ * so carrying the payload is a compile-time obligation rather than a hope.
285
+ */
286
+ declare function isCandidateAccepted<K extends string = string>(event: OptimizerEvent): event is {
287
+ type: "candidateAccepted";
288
+ } & CandidateAccepted<K>;
289
+ /** Narrows an event off any optimizer's union to the end of the run. */
290
+ declare function isRunFinished(event: OptimizerEvent): event is {
291
+ type: "finish";
292
+ } & RunFinished;
293
+ //#endregion
294
+ export { componentNames as C, UsageTotals as S, EvaluationPhase as _, RunFinished as a, ScoreResult as b, RunWarning as c, seedScoreWarnings as d, Adapter as f, EvaluationContext as g, EvaluationBatch as h, Reporter as i, RunWarningCode as l, EvaluateArgs as m, OptimizerEvent as n, isCandidateAccepted as o, Candidate as p, ReportableEvent as r, isRunFinished as s, CandidateAccepted as t, resolveValidationSet as u, EvaluationSplit as v, TextModel as x, RolloutUsage as y };
@@ -0,0 +1,294 @@
1
+ //#region src/types.d.ts
2
+ /**
3
+ * A candidate is a map of named text components to their current text. This is
4
+ * the unit of optimization — prompts, instructions, code, tool descriptions,
5
+ * anything expressible as a named string.
6
+ *
7
+ * `K` is the union of component names, inferred from the seed candidate, so a
8
+ * misspelled component is a compile error rather than a silent no-op.
9
+ */
10
+ type Candidate<K extends string = string> = Record<K, string>;
11
+ /**
12
+ * What one rollout consumed. Every field is optional because providers report
13
+ * different subsets, and a partial reading is still worth more than none.
14
+ */
15
+ interface RolloutUsage {
16
+ inputTokens?: number;
17
+ outputTokens?: number;
18
+ /** Defaults to the sum of the two token counts when they are reported. */
19
+ totalTokens?: number;
20
+ costUsd?: number;
21
+ }
22
+ /** Usage summed over a run, alongside the rollouts that produced it. */
23
+ interface UsageTotals {
24
+ inputTokens: number;
25
+ outputTokens: number;
26
+ totalTokens: number;
27
+ costUsd: number;
28
+ /** Fresh rollouts counted here. Cached instances buy nothing. */
29
+ rollouts: number;
30
+ }
31
+ /**
32
+ * Result of running a candidate over a batch of data instances.
33
+ *
34
+ * `scores` is the load-bearing field: one number per instance, higher is
35
+ * better. `feedback` is a per-instance textual diagnosis of what went wrong,
36
+ * which a reflective optimizer reads to write a better candidate.
37
+ */
38
+ interface EvaluationBatch<Trajectory = unknown, Output = unknown> {
39
+ outputs: Output[];
40
+ scores: number[];
41
+ /**
42
+ * What each rollout consumed. Rollout counts are the budget, but they are a
43
+ * poor proxy for spend: reflective search grows the text it optimizes, so
44
+ * the same rollout costs more late in a run than early in it.
45
+ */
46
+ usage?: RolloutUsage[];
47
+ feedback?: string[];
48
+ trajectories?: Trajectory[];
49
+ objectiveScores?: Record<string, number>[];
50
+ /**
51
+ * Per-instance: true when the score reflects an infrastructure failure
52
+ * rather than the candidate's behaviour. Transient scores are never written
53
+ * to the evaluation cache.
54
+ */
55
+ transient?: boolean[];
56
+ }
57
+ /**
58
+ * What a per-instance scorer returns. Shared by every adapter so scorers are
59
+ * portable between them — a Braintrust scorer works in a LangChain run.
60
+ */
61
+ interface ScoreResult {
62
+ score: number;
63
+ feedback?: string;
64
+ objectiveScores?: Record<string, number>;
65
+ /** What this rollout consumed, when the caller can see it. */
66
+ usage?: RolloutUsage;
67
+ /**
68
+ * Marks a score produced by an infrastructure failure — a rate limit, a
69
+ * network blip, a provider 5xx — rather than by the candidate. Without this
70
+ * the engine cannot tell such a zero from a genuine one, and would cache it
71
+ * permanently against the candidate.
72
+ */
73
+ transient?: boolean;
74
+ }
75
+ interface EvaluateArgs<Datum, K extends string = string> {
76
+ batch: readonly Datum[];
77
+ candidate: Candidate<K>;
78
+ captureTraces: boolean;
79
+ /**
80
+ * Where this batch sits in the run. Forward it to whatever tracing the
81
+ * system under optimization already has — without it a run is thousands of
82
+ * indistinguishable rollouts, and no trace can be tied back to the iteration
83
+ * whose score moved.
84
+ */
85
+ run: EvaluationContext;
86
+ signal?: AbortSignal;
87
+ }
88
+ /**
89
+ * Identifies one evaluation within a run. `candidateId` is null while the
90
+ * candidate is still a proposal being screened on a minibatch: it has no
91
+ * record, and inventing an id for it would collide with the one it gets if it
92
+ * is accepted.
93
+ */
94
+ interface EvaluationContext {
95
+ iteration: number;
96
+ phase: EvaluationPhase;
97
+ split: EvaluationSplit;
98
+ candidateId: number | null;
99
+ }
100
+ type EvaluationPhase = "seed" | "minibatch" | "validation" | "test";
101
+ /**
102
+ * Which dataset an instance id was drawn from. Each split numbers its ids
103
+ * independently, so the same id can name three different instances; the cache
104
+ * key has to keep them apart.
105
+ */
106
+ type EvaluationSplit = "train" | "val" | "test";
107
+ /**
108
+ * The single integration seam between an optimizer and a system under
109
+ * optimization. Everything framework-specific — LangChain, the AI SDK,
110
+ * Braintrust — lives in an implementation of this interface.
111
+ */
112
+ interface Adapter<Datum, Trajectory = unknown, Output = unknown, K extends string = string> {
113
+ evaluate(args: EvaluateArgs<Datum, K>): Promise<EvaluationBatch<Trajectory, Output>> | EvaluationBatch<Trajectory, Output>;
114
+ }
115
+ /** Provider-agnostic text model: text in, text out. */
116
+ type TextModel = (args: {
117
+ prompt: string;
118
+ signal?: AbortSignal;
119
+ }) => Promise<string>;
120
+ /**
121
+ * The component names of a candidate, as the union they were inferred from.
122
+ *
123
+ * `Object.keys` widens a closed key union back to `string`. This is the one
124
+ * place that narrowing happens, so every other caller stays assertion-free.
125
+ * Accepts a partial so it also names the components of a component patch.
126
+ */
127
+ declare function componentNames<K extends string>(candidate: Partial<Candidate<K>>): K[];
128
+ //#endregion
129
+ //#region src/warnings.d.ts
130
+ /**
131
+ * Something about a run that its own numbers cannot say.
132
+ *
133
+ * A search reports a score, a stop reason and what it spent, and every one of
134
+ * those reads the same whether the run measured what the caller thinks it did
135
+ * or not. These are the conditions under which a normal-looking result means
136
+ * less than it appears to: they never stop a run, and they are carried on the
137
+ * result and the `finish` event so a report can say so next to the number.
138
+ */
139
+ interface RunWarning {
140
+ code: RunWarningCode;
141
+ message: string;
142
+ }
143
+ type RunWarningCode = "validationSetReusesTraining" | "seedScoreSaturated" | "seedScoreFloored";
144
+ /**
145
+ * The validation set a run will actually select against, and whatever the
146
+ * choice costs it.
147
+ *
148
+ * Defaulting to the training set is the right default for a first run and the
149
+ * wrong number to report from one. It is worse than ordinary overfitting under
150
+ * reflective search: the reflection prompt asks the model to mine domain facts
151
+ * out of the traces it is shown, so those facts come out of the very instances
152
+ * that then select the candidate carrying them. `"reuseTraining"` is the same
153
+ * behaviour with the caller's name on it, and silences the warning.
154
+ */
155
+ declare function resolveValidationSet<Datum>(args: {
156
+ validationSet: readonly Datum[] | "reuseTraining" | undefined;
157
+ trainingSet: readonly Datum[];
158
+ }): {
159
+ validationSet: readonly Datum[];
160
+ warnings: RunWarning[];
161
+ };
162
+ /**
163
+ * What the seed's own validation row says about whether the run could have
164
+ * learned anything.
165
+ *
166
+ * A search ranks candidates by how they differ across instances, so a seed row
167
+ * with no spread leaves nothing to rank: at the ceiling every proposal is a tie
168
+ * the acceptance test resolves by noise, and at the floor no proposal has a
169
+ * partial improvement to build on. Both produce a run that spends its whole
170
+ * budget and reports a stop reason that looks like any other.
171
+ */
172
+ declare function seedScoreWarnings(args: {
173
+ scores: readonly (number | undefined)[];
174
+ perfectScore: number;
175
+ }): RunWarning[];
176
+ //#endregion
177
+ //#region src/reporting.d.ts
178
+ /**
179
+ * Where a run's progress goes, for any optimizer. Observability only:
180
+ * persisting a run so it can be resumed is `onCheckpoint`, which is durability
181
+ * and a separate concern.
182
+ *
183
+ * Generic over the event union rather than one union covering every optimizer:
184
+ * a search emits what it actually has, and a reporter written against one
185
+ * optimizer still type-checks against the events it reads.
186
+ */
187
+ /**
188
+ * The least an optimizer's event satisfies. A reporter typed against this
189
+ * accepts every optimizer's union, because a literal tag is assignable to
190
+ * `string` and the parameter position is contravariant.
191
+ */
192
+ interface OptimizerEvent {
193
+ type: string;
194
+ }
195
+ interface Reporter<Event> {
196
+ /**
197
+ * Called on the search's hot path, synchronously. A reporter that ships
198
+ * anywhere over a network buffers here and uploads in `flush`, or it charges
199
+ * every iteration for its latency.
200
+ *
201
+ * A reporter that throws is warned about and skipped: observability never
202
+ * fails a run.
203
+ */
204
+ onEvent?: (event: Event) => void;
205
+ /** Awaited once as the run ends, including when it ends by throwing. */
206
+ flush?: () => Promise<void>;
207
+ }
208
+ /**
209
+ * The payload every optimizer's `candidateAccepted` carries, so one reporter
210
+ * can read an acceptance without knowing which search produced it. Each
211
+ * optimizer intersects its own fields onto this — GEPA its lineage, MIPRO its
212
+ * menu choices — the way the event unions already intersect `EvaluationEvent`.
213
+ *
214
+ * Emitted only when the incumbent moves and a full validation sweep measured
215
+ * it. An optimizer that accepts on a minibatch reports the acceptance in its
216
+ * own event and emits this one once the sweep that confirms it lands, so
217
+ * `instanceScores` never means "a subset, and you work out which".
218
+ */
219
+ interface CandidateAccepted<K extends string = string> {
220
+ /** Identifies the candidate within the run. */
221
+ candidateId: number;
222
+ /** The text that scored, so a move is readable next to the edit. */
223
+ candidate: Candidate<K>;
224
+ /** Mean over the validation set, which is what selection is decided on. */
225
+ aggregateScore: number;
226
+ /**
227
+ * Per-instance scores, aligned with the validation set. `undefined` marks an
228
+ * instance an infrastructure failure left unmeasured — unknown, not zero.
229
+ *
230
+ * Handed out by reference rather than copied: a run emits this once per
231
+ * accepted candidate, and copying a validation-set-sized array that often to
232
+ * guard against a listener that writes to it costs every run to protect a
233
+ * listener that should not exist.
234
+ */
235
+ instanceScores: readonly (number | undefined)[];
236
+ /** Aligned with `instanceScores`. Present only under `trackBestOutputs`. */
237
+ outputs?: readonly unknown[];
238
+ }
239
+ /**
240
+ * The payload every optimizer's `finish` carries. `reason` stays per-optimizer
241
+ * because the stop reasons genuinely differ — only GEPA can exhaust a
242
+ * reflection budget.
243
+ */
244
+ interface RunFinished {
245
+ /** The winner, named the way `CandidateAccepted.candidateId` names it. */
246
+ bestCandidateId: number;
247
+ bestScore: number;
248
+ metricCalls: number;
249
+ /** The winner's held-out score, when a testSet was given. */
250
+ testScore?: number;
251
+ /**
252
+ * The winner's per-instance held-out scores, aligned with the testSet and
253
+ * present whenever `testScore` is. `undefined` marks an instance an
254
+ * infrastructure failure left unmeasured, which is what `testScore` averages
255
+ * over too.
256
+ *
257
+ * The mean is the number selection never saw; this is where the gap below
258
+ * `bestScore` came from.
259
+ */
260
+ testInstanceScores?: readonly (number | undefined)[];
261
+ /** Aligned with `testInstanceScores`. Only under `trackBestOutputs`. */
262
+ testOutputs?: readonly unknown[];
263
+ /**
264
+ * What the run cannot say about itself from its own numbers. A reporter that
265
+ * writes the score somewhere permanent writes these beside it, or the record
266
+ * outlives the only place the caveat was ever stated.
267
+ */
268
+ warnings: readonly RunWarning[];
269
+ }
270
+ /**
271
+ * The two events every optimizer emits with a payload a reporter can read
272
+ * without knowing which search produced it. A cross-optimizer reporter takes
273
+ * this as its event type: it is a supertype of every optimizer's own union, so
274
+ * one reporter drops into any optimizer's `reporters` array.
275
+ */
276
+ type ReportableEvent<K extends string = string> = ({
277
+ type: "candidateAccepted";
278
+ } & CandidateAccepted<K>) | ({
279
+ type: "finish";
280
+ } & RunFinished);
281
+ /**
282
+ * Narrows an event off any optimizer's union to an acceptance. The tag is
283
+ * enough: every optimizer's `candidateAccepted` intersects `CandidateAccepted`,
284
+ * so carrying the payload is a compile-time obligation rather than a hope.
285
+ */
286
+ declare function isCandidateAccepted<K extends string = string>(event: OptimizerEvent): event is {
287
+ type: "candidateAccepted";
288
+ } & CandidateAccepted<K>;
289
+ /** Narrows an event off any optimizer's union to the end of the run. */
290
+ declare function isRunFinished(event: OptimizerEvent): event is {
291
+ type: "finish";
292
+ } & RunFinished;
293
+ //#endregion
294
+ export { componentNames as C, UsageTotals as S, EvaluationPhase as _, RunFinished as a, ScoreResult as b, RunWarning as c, seedScoreWarnings as d, Adapter as f, EvaluationContext as g, EvaluationBatch as h, Reporter as i, RunWarningCode as l, EvaluateArgs as m, OptimizerEvent as n, isCandidateAccepted as o, Candidate as p, ReportableEvent as r, isRunFinished as s, CandidateAccepted as t, resolveValidationSet as u, EvaluationSplit as v, TextModel as x, RolloutUsage as y };