textopt 0.0.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 (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +509 -0
  3. package/dist/bootstrap-search/index.cjs +308 -0
  4. package/dist/bootstrap-search/index.d.cts +162 -0
  5. package/dist/bootstrap-search/index.d.mts +162 -0
  6. package/dist/bootstrap-search/index.mjs +307 -0
  7. package/dist/cache-CuSo0NJ8.d.cts +24 -0
  8. package/dist/cache-CuSo0NJ8.d.mts +24 -0
  9. package/dist/concurrency-C-cFzWW2.cjs +44 -0
  10. package/dist/concurrency-D58PWeSk.mjs +39 -0
  11. package/dist/demos-B0pVQjYC.d.mts +88 -0
  12. package/dist/demos-B9BJiNKz.cjs +143 -0
  13. package/dist/demos-BTuzFNsp.d.cts +88 -0
  14. package/dist/demos-Degx6UmP.mjs +126 -0
  15. package/dist/evaluation-BV0nSZVx.mjs +521 -0
  16. package/dist/evaluation-OZOp6TB7.cjs +598 -0
  17. package/dist/file-cache.cjs +70 -0
  18. package/dist/file-cache.d.cts +21 -0
  19. package/dist/file-cache.d.mts +21 -0
  20. package/dist/file-cache.mjs +69 -0
  21. package/dist/gepa/index.cjs +1671 -0
  22. package/dist/gepa/index.d.cts +385 -0
  23. package/dist/gepa/index.d.mts +385 -0
  24. package/dist/gepa/index.mjs +1652 -0
  25. package/dist/index.cjs +266 -0
  26. package/dist/index.d.cts +221 -0
  27. package/dist/index.d.mts +221 -0
  28. package/dist/index.mjs +245 -0
  29. package/dist/math-COOofUyv.cjs +101 -0
  30. package/dist/math-DhrDmpFS.mjs +78 -0
  31. package/dist/mipro/index.cjs +739 -0
  32. package/dist/mipro/index.d.cts +372 -0
  33. package/dist/mipro/index.d.mts +372 -0
  34. package/dist/mipro/index.mjs +736 -0
  35. package/dist/opro/index.cjs +487 -0
  36. package/dist/opro/index.d.cts +230 -0
  37. package/dist/opro/index.d.mts +230 -0
  38. package/dist/opro/index.mjs +485 -0
  39. package/dist/optimizer-B7SpRwl7.d.cts +288 -0
  40. package/dist/optimizer-DqCoth_w.d.mts +288 -0
  41. package/dist/random-search/index.cjs +321 -0
  42. package/dist/random-search/index.d.cts +156 -0
  43. package/dist/random-search/index.d.mts +156 -0
  44. package/dist/random-search/index.mjs +319 -0
  45. package/dist/reflection-CQToe-5B.d.cts +283 -0
  46. package/dist/reflection-Cr_upzU0.d.mts +283 -0
  47. package/dist/reflection-DRfbk6hu.cjs +249 -0
  48. package/dist/reflection-mwMhrjs_.mjs +214 -0
  49. package/dist/rng-BR5MOedA.d.cts +22 -0
  50. package/dist/rng-BR5MOedA.d.mts +22 -0
  51. package/dist/rng-DbA_rPIo.cjs +67 -0
  52. package/dist/rng-Dtc5eZ_W.mjs +62 -0
  53. package/dist/sampling-CfHt7Gue.mjs +59 -0
  54. package/dist/sampling-DFo_7RNJ.d.mts +23 -0
  55. package/dist/sampling-Dars7ctR.cjs +64 -0
  56. package/dist/sampling-axOwfZf5.d.cts +23 -0
  57. package/dist/simba/index.cjs +709 -0
  58. package/dist/simba/index.d.cts +289 -0
  59. package/dist/simba/index.d.mts +289 -0
  60. package/dist/simba/index.mjs +700 -0
  61. package/dist/testing.cjs +155 -0
  62. package/dist/testing.d.cts +53 -0
  63. package/dist/testing.d.mts +53 -0
  64. package/dist/testing.mjs +148 -0
  65. package/dist/text--v4Ffbus.mjs +21 -0
  66. package/dist/text-CK_HB3su.cjs +26 -0
  67. package/dist/types-CWv4IQFF.d.cts +129 -0
  68. package/dist/types-CWv4IQFF.d.mts +129 -0
  69. package/package.json +135 -0
@@ -0,0 +1,289 @@
1
+ import { n as Candidate, t as Adapter, u as TextModel } from "../types-CWv4IQFF.cjs";
2
+ import { n as EvaluationCache, t as CachedScore } from "../cache-CuSo0NJ8.cjs";
3
+ import { t as Rng } from "../rng-BR5MOedA.cjs";
4
+ import { r as DemoRenderer } from "../demos-BTuzFNsp.cjs";
5
+ import { n as OptimizerResult, r as OptimizerTask, s as EvaluationEvent, t as Optimizer } from "../optimizer-B7SpRwl7.cjs";
6
+ import { t as BatchSampler } from "../sampling-axOwfZf5.cjs";
7
+ //#region src/simba/advice.d.ts
8
+ interface AdviceTrajectory<Output = unknown> {
9
+ output: Output;
10
+ score: number;
11
+ feedback?: string;
12
+ }
13
+ interface AdvicePromptArgs<Datum = unknown, Output = unknown> {
14
+ /** Components the advice is wanted for, named so each can be addressed. */
15
+ components: readonly string[];
16
+ input: Datum;
17
+ /** The higher scoring run of this instance, when there is one to contrast. */
18
+ better?: AdviceTrajectory<Output>;
19
+ /** The lower scoring run of this instance, when there is one to contrast. */
20
+ worse?: AdviceTrajectory<Output>;
21
+ }
22
+ type AdvicePromptBuilder<Datum = unknown, Output = unknown> = (args: AdvicePromptArgs<Datum, Output>) => string;
23
+ /**
24
+ * Adapted from SIMBA's `OfferFeedback` signature (Opsahl-Ong et al.'s DSPy).
25
+ *
26
+ * The framing that matters is "build up experience": the component will not
27
+ * see this instance again, so advice that only fixes this one input is wasted.
28
+ * Contrasting two runs of the *same* input is what makes that possible — the
29
+ * inputs are held constant, so the difference in reward is attributable to the
30
+ * behaviour rather than to the instance being easier.
31
+ */
32
+ declare function buildAdvicePrompt<Datum, Output>(args: AdvicePromptArgs<Datum, Output>): string;
33
+ /**
34
+ * Read the per-component advice out of the model's response, ignoring anything
35
+ * written around it. A component the model had nothing to say about is absent
36
+ * rather than empty, so the caller appends nothing instead of appending noise.
37
+ */
38
+ declare function parseAdvice(response: string): Record<string, string>;
39
+ //#endregion
40
+ //#region src/simba/optimize.d.ts
41
+ /**
42
+ * How a candidate is mutated. `appendDemo` adds a rollout the metric already
43
+ * rewarded; `appendRule` asks a model to say what the winning run did
44
+ * differently and writes that into the instruction.
45
+ */
46
+ type SimbaStrategy = "appendDemo" | "appendRule";
47
+ interface SimbaFinalist<K extends string = string> {
48
+ candidate: Candidate<K>;
49
+ /** Mean over the full validation set, which is what selection is decided on. */
50
+ score: number;
51
+ /** Which step produced it; 0 is the seed. */
52
+ step: number;
53
+ }
54
+ interface SimbaConfig {
55
+ /** Instances per step. Default 32. */
56
+ minibatchSize?: number;
57
+ /** Programs sampled per step, and candidates built from them. Default 6. */
58
+ candidates?: number;
59
+ /** Steps to run. Default 8. */
60
+ maxSteps?: number;
61
+ /** Demos a candidate may hold before the loop starts dropping them. Default 4. */
62
+ maxDemos?: number;
63
+ /** Sharpness of the pick between programs when sampling trajectories. */
64
+ samplingTemperature?: number;
65
+ /** Sharpness of the pick between programs when choosing what to mutate. */
66
+ candidateTemperature?: number;
67
+ /** Mutations to draw from. Defaults to both, or to rules alone with no demo component. */
68
+ strategies?: readonly SimbaStrategy[];
69
+ /**
70
+ * Advice calls the run may make. Unset lets the rollout budget bound them,
71
+ * which it does only loosely: a step spends a bounded number of rollouts and
72
+ * up to one advice call per instance in its minibatch, and the advice model
73
+ * is usually the expensive one. Once spent, `appendDemo` carries the run on
74
+ * alone, or the run stops if it was the only mutation enabled.
75
+ */
76
+ maxReflectionCalls?: number;
77
+ seed?: number;
78
+ trackBestOutputs?: boolean;
79
+ checkpointCache?: boolean;
80
+ }
81
+ /**
82
+ * Everything needed to continue a run: the program pool with its observed
83
+ * scores, the step winners, and the budget already spent. Plain JSON — persist
84
+ * it and hand it back as `resumeFrom`.
85
+ */
86
+ interface SimbaSnapshot {
87
+ version: 1;
88
+ fingerprint: string;
89
+ programs: Candidate[];
90
+ /** Every minibatch mean observed for each program, in the order observed. */
91
+ programScores: number[][];
92
+ winners: {
93
+ candidate: Candidate;
94
+ step: number;
95
+ }[];
96
+ step: number;
97
+ metricCalls: number;
98
+ reflectionCalls: number;
99
+ cacheHits: number;
100
+ rngState: number;
101
+ sampler?: unknown;
102
+ cache?: [string, CachedScore][];
103
+ }
104
+ interface SimbaTask<Datum, Trajectory = unknown, Output = unknown, K extends string = string> extends OptimizerTask<Datum, Trajectory, Output, K> {
105
+ /**
106
+ * The base adapter. SIMBA reads outputs, scores and feedback and builds its
107
+ * own evidence, so unlike GEPA it needs no `makeReflectiveDataset`.
108
+ */
109
+ adapter: Adapter<Datum, Trajectory, Output, NoInfer<K>>;
110
+ /** Writes the advice `appendRule` appends. Unused when only demos are appended. */
111
+ reflect?: TextModel;
112
+ /** Components holding few-shot demo blocks. Empty disables `appendDemo`. */
113
+ demoComponents?: readonly NoInfer<K>[];
114
+ /** Components advice is appended to. Defaults to every non-demo component. */
115
+ instructionComponents?: readonly NoInfer<K>[];
116
+ renderDemo?: DemoRenderer<NoInfer<Datum>, NoInfer<Output>>;
117
+ buildAdvicePrompt?: AdvicePromptBuilder<NoInfer<Datum>, NoInfer<Output>>;
118
+ sampler?: BatchSampler<NoInfer<Datum>>;
119
+ instanceId?: (args: {
120
+ datum: NoInfer<Datum>;
121
+ index: number;
122
+ }) => string;
123
+ cache?: EvaluationCache | false;
124
+ onEvent?: (event: SimbaEvent<NoInfer<K>>) => void;
125
+ onCheckpoint?: (snapshot: SimbaSnapshot) => void | Promise<void>;
126
+ resumeFrom?: SimbaSnapshot;
127
+ }
128
+ type SimbaStopReason = "budgetExhausted" | "costExhausted" | "deadlineReached" | "reflectionBudgetExhausted" | "maxSteps" | "aborted";
129
+ type SimbaEvent<K extends string = string> = {
130
+ type: "start";
131
+ components: K[];
132
+ validationSetSize: number;
133
+ } | ({
134
+ type: "evaluation";
135
+ } & EvaluationEvent) | {
136
+ type: "stepStart";
137
+ step: number;
138
+ poolSize: number;
139
+ } | {
140
+ type: "candidate";
141
+ step: number;
142
+ strategy: SimbaStrategy;
143
+ /** The program it was mutated from; 0 is the seed. */
144
+ sourceProgram: number;
145
+ minibatchScore: number;
146
+ } | {
147
+ type: "error";
148
+ step: number;
149
+ err: unknown;
150
+ } | {
151
+ type: "finish";
152
+ reason: SimbaStopReason;
153
+ bestScore: number;
154
+ metricCalls: number;
155
+ testScore?: number;
156
+ };
157
+ interface SimbaResult<K extends string = string, Output = unknown> extends OptimizerResult<K, SimbaStopReason, Output> {
158
+ /** The seed's own validation score, so the lift the run bought is readable. */
159
+ seedScore: number;
160
+ steps: number;
161
+ /** The step winners scored on the full validation set, best first. */
162
+ finalists: SimbaFinalist<K>[];
163
+ reflectionCalls: number;
164
+ cacheHits: number;
165
+ snapshot: SimbaSnapshot;
166
+ }
167
+ /**
168
+ * SIMBA — stochastic introspective mini-batch ascent.
169
+ *
170
+ * Run several programs over the same minibatch, find the instances they
171
+ * disagree about most, and mutate toward whatever the winning run did. The
172
+ * disagreement is the point: an instance one program solved and another failed
173
+ * is a controlled experiment with the input held fixed, so the difference in
174
+ * reward is attributable to behaviour rather than to difficulty. GEPA reflects
175
+ * on failures; SIMBA reflects on the *contrast* between a success and a failure
176
+ * of the same input, which is a strictly stronger signal when it exists — and
177
+ * costs a pool of programs to produce.
178
+ *
179
+ * Two mutations, drawn at random per instance: append a demonstration the
180
+ * metric already rewarded, or ask a model what the better run did differently
181
+ * and append that as a rule. Neither replaces text, so a candidate accumulates;
182
+ * demos are dropped at a Poisson rate to keep the block from crowding out
183
+ * everything else.
184
+ *
185
+ * Ported from DSPy's SIMBA, with two deliberate changes. First, a trajectory
186
+ * sample runs one program across the whole minibatch rather than resampling a
187
+ * program per instance: the adapter here owns decoding, so there is no
188
+ * temperature knob to vary, and the variability comes from the program pool
189
+ * instead. Second, the percentile guards are strict rather than inclusive — on
190
+ * a step where every rollout ties, an inclusive guard blocks every mutation and
191
+ * the run does nothing at all, which is the one case where the guard's own
192
+ * premise does not hold.
193
+ */
194
+ declare class SimbaOptimizer implements Optimizer<SimbaStopReason> {
195
+ #private;
196
+ constructor(config?: SimbaConfig);
197
+ optimize<Datum, Trajectory = unknown, Output = unknown, const K extends string = string>(task: SimbaTask<Datum, Trajectory, Output, K>): Promise<SimbaResult<K, Output>>;
198
+ }
199
+ //#endregion
200
+ //#region src/simba/strategies.d.ts
201
+ /** One sample of one instance: which program produced it, and how it scored. */
202
+ interface SimbaRollout<Output = unknown> {
203
+ programIndex: number;
204
+ score: number;
205
+ output?: Output;
206
+ feedback?: string;
207
+ }
208
+ /**
209
+ * Every sample of one training instance, sorted best first, with the spread
210
+ * that decides whether the instance is worth learning from.
211
+ */
212
+ interface SimbaBucket<Datum = unknown, Output = unknown> {
213
+ index: number;
214
+ datum: Datum;
215
+ rollouts: SimbaRollout<Output>[];
216
+ maxToMinGap: number;
217
+ maxScore: number;
218
+ maxToAvgGap: number;
219
+ }
220
+ interface SimbaSample<Output = unknown> {
221
+ programIndex: number;
222
+ scores: readonly number[];
223
+ outputs?: readonly (Output | undefined)[];
224
+ feedback?: readonly string[];
225
+ }
226
+ /**
227
+ * Group the step's samples by instance and rank the instances by how much the
228
+ * programs disagreed about them.
229
+ *
230
+ * Disagreement is the signal SIMBA runs on. An instance every program gets
231
+ * right teaches nothing, and one every program gets wrong is usually beyond
232
+ * the reach of a prompt edit; the instructive ones are where one program
233
+ * succeeded and another failed, because the pair is a controlled experiment
234
+ * the reflection model can read directly.
235
+ *
236
+ * Ranked on the max-to-min gap first, then the best score, then the max-to-avg
237
+ * gap: widest disagreement first, ties broken toward instances where something
238
+ * actually worked, since a bucket whose best rollout is bad has no success to
239
+ * generalize from.
240
+ */
241
+ declare function buildBuckets<Datum, Output>(args: {
242
+ batch: readonly Datum[];
243
+ samples: readonly SimbaSample<Output>[];
244
+ }): SimbaBucket<Datum, Output>[];
245
+ /**
246
+ * Linear-interpolated percentile, matching numpy's default so the thresholds
247
+ * behave the way the reference implementation's do.
248
+ */
249
+ declare function percentile(values: readonly number[], p: number): number;
250
+ /**
251
+ * Softmax weights over program scores, for picking which program to mutate
252
+ * next. Shifted by the maximum before exponentiating — the same distribution,
253
+ * but a score scale the caller chose freely cannot overflow it.
254
+ */
255
+ declare function softmaxWeights(scores: readonly number[], temperature: number): number[];
256
+ /**
257
+ * The `k` highest scoring programs, with the baseline forced into the pool.
258
+ *
259
+ * Keeping the baseline is what makes the search recoverable: every candidate
260
+ * descends from a program already in the pool, so a pool that has drifted into
261
+ * a bad region has nothing left to climb back from.
262
+ */
263
+ declare function topKPlusBaseline(args: {
264
+ scores: readonly number[];
265
+ k: number;
266
+ }): number[];
267
+ /**
268
+ * A Poisson draw by Knuth's method, used to decide how many demonstrations to
269
+ * drop before a mutation. Random rather than fixed so a candidate can shed a
270
+ * demo that is no longer earning its place — nothing else in the loop ever
271
+ * removes one, and a block that only grows eventually crowds out the
272
+ * instruction it was meant to support.
273
+ */
274
+ declare function samplePoisson(rng: Rng, lambda: number): number;
275
+ /**
276
+ * Positions spread evenly across a sequence, first and last included.
277
+ *
278
+ * The step winners are held back and only a sample of them is scored on the
279
+ * full validation set at the end, because scoring every one of them costs more
280
+ * than the search did. Sampling evenly rather than taking the last few keeps
281
+ * early winners in the running: minibatch scores are noisy, and the run's
282
+ * genuine best is often not its most recent.
283
+ */
284
+ declare function evenlySpacedIndices(args: {
285
+ length: number;
286
+ count: number;
287
+ }): number[];
288
+ //#endregion
289
+ export { type AdvicePromptArgs, type AdvicePromptBuilder, type AdviceTrajectory, type SimbaBucket, type SimbaConfig, type SimbaEvent, type SimbaFinalist, SimbaOptimizer, type SimbaResult, type SimbaRollout, type SimbaSample, type SimbaSnapshot, type SimbaStopReason, type SimbaStrategy, type SimbaTask, buildAdvicePrompt, buildBuckets, evenlySpacedIndices, parseAdvice, percentile, samplePoisson, softmaxWeights, topKPlusBaseline };
@@ -0,0 +1,289 @@
1
+ import { n as Candidate, t as Adapter, u as TextModel } from "../types-CWv4IQFF.mjs";
2
+ import { n as EvaluationCache, t as CachedScore } from "../cache-CuSo0NJ8.mjs";
3
+ import { t as Rng } from "../rng-BR5MOedA.mjs";
4
+ import { r as DemoRenderer } from "../demos-B0pVQjYC.mjs";
5
+ import { n as OptimizerResult, r as OptimizerTask, s as EvaluationEvent, t as Optimizer } from "../optimizer-DqCoth_w.mjs";
6
+ import { t as BatchSampler } from "../sampling-DFo_7RNJ.mjs";
7
+ //#region src/simba/advice.d.ts
8
+ interface AdviceTrajectory<Output = unknown> {
9
+ output: Output;
10
+ score: number;
11
+ feedback?: string;
12
+ }
13
+ interface AdvicePromptArgs<Datum = unknown, Output = unknown> {
14
+ /** Components the advice is wanted for, named so each can be addressed. */
15
+ components: readonly string[];
16
+ input: Datum;
17
+ /** The higher scoring run of this instance, when there is one to contrast. */
18
+ better?: AdviceTrajectory<Output>;
19
+ /** The lower scoring run of this instance, when there is one to contrast. */
20
+ worse?: AdviceTrajectory<Output>;
21
+ }
22
+ type AdvicePromptBuilder<Datum = unknown, Output = unknown> = (args: AdvicePromptArgs<Datum, Output>) => string;
23
+ /**
24
+ * Adapted from SIMBA's `OfferFeedback` signature (Opsahl-Ong et al.'s DSPy).
25
+ *
26
+ * The framing that matters is "build up experience": the component will not
27
+ * see this instance again, so advice that only fixes this one input is wasted.
28
+ * Contrasting two runs of the *same* input is what makes that possible — the
29
+ * inputs are held constant, so the difference in reward is attributable to the
30
+ * behaviour rather than to the instance being easier.
31
+ */
32
+ declare function buildAdvicePrompt<Datum, Output>(args: AdvicePromptArgs<Datum, Output>): string;
33
+ /**
34
+ * Read the per-component advice out of the model's response, ignoring anything
35
+ * written around it. A component the model had nothing to say about is absent
36
+ * rather than empty, so the caller appends nothing instead of appending noise.
37
+ */
38
+ declare function parseAdvice(response: string): Record<string, string>;
39
+ //#endregion
40
+ //#region src/simba/optimize.d.ts
41
+ /**
42
+ * How a candidate is mutated. `appendDemo` adds a rollout the metric already
43
+ * rewarded; `appendRule` asks a model to say what the winning run did
44
+ * differently and writes that into the instruction.
45
+ */
46
+ type SimbaStrategy = "appendDemo" | "appendRule";
47
+ interface SimbaFinalist<K extends string = string> {
48
+ candidate: Candidate<K>;
49
+ /** Mean over the full validation set, which is what selection is decided on. */
50
+ score: number;
51
+ /** Which step produced it; 0 is the seed. */
52
+ step: number;
53
+ }
54
+ interface SimbaConfig {
55
+ /** Instances per step. Default 32. */
56
+ minibatchSize?: number;
57
+ /** Programs sampled per step, and candidates built from them. Default 6. */
58
+ candidates?: number;
59
+ /** Steps to run. Default 8. */
60
+ maxSteps?: number;
61
+ /** Demos a candidate may hold before the loop starts dropping them. Default 4. */
62
+ maxDemos?: number;
63
+ /** Sharpness of the pick between programs when sampling trajectories. */
64
+ samplingTemperature?: number;
65
+ /** Sharpness of the pick between programs when choosing what to mutate. */
66
+ candidateTemperature?: number;
67
+ /** Mutations to draw from. Defaults to both, or to rules alone with no demo component. */
68
+ strategies?: readonly SimbaStrategy[];
69
+ /**
70
+ * Advice calls the run may make. Unset lets the rollout budget bound them,
71
+ * which it does only loosely: a step spends a bounded number of rollouts and
72
+ * up to one advice call per instance in its minibatch, and the advice model
73
+ * is usually the expensive one. Once spent, `appendDemo` carries the run on
74
+ * alone, or the run stops if it was the only mutation enabled.
75
+ */
76
+ maxReflectionCalls?: number;
77
+ seed?: number;
78
+ trackBestOutputs?: boolean;
79
+ checkpointCache?: boolean;
80
+ }
81
+ /**
82
+ * Everything needed to continue a run: the program pool with its observed
83
+ * scores, the step winners, and the budget already spent. Plain JSON — persist
84
+ * it and hand it back as `resumeFrom`.
85
+ */
86
+ interface SimbaSnapshot {
87
+ version: 1;
88
+ fingerprint: string;
89
+ programs: Candidate[];
90
+ /** Every minibatch mean observed for each program, in the order observed. */
91
+ programScores: number[][];
92
+ winners: {
93
+ candidate: Candidate;
94
+ step: number;
95
+ }[];
96
+ step: number;
97
+ metricCalls: number;
98
+ reflectionCalls: number;
99
+ cacheHits: number;
100
+ rngState: number;
101
+ sampler?: unknown;
102
+ cache?: [string, CachedScore][];
103
+ }
104
+ interface SimbaTask<Datum, Trajectory = unknown, Output = unknown, K extends string = string> extends OptimizerTask<Datum, Trajectory, Output, K> {
105
+ /**
106
+ * The base adapter. SIMBA reads outputs, scores and feedback and builds its
107
+ * own evidence, so unlike GEPA it needs no `makeReflectiveDataset`.
108
+ */
109
+ adapter: Adapter<Datum, Trajectory, Output, NoInfer<K>>;
110
+ /** Writes the advice `appendRule` appends. Unused when only demos are appended. */
111
+ reflect?: TextModel;
112
+ /** Components holding few-shot demo blocks. Empty disables `appendDemo`. */
113
+ demoComponents?: readonly NoInfer<K>[];
114
+ /** Components advice is appended to. Defaults to every non-demo component. */
115
+ instructionComponents?: readonly NoInfer<K>[];
116
+ renderDemo?: DemoRenderer<NoInfer<Datum>, NoInfer<Output>>;
117
+ buildAdvicePrompt?: AdvicePromptBuilder<NoInfer<Datum>, NoInfer<Output>>;
118
+ sampler?: BatchSampler<NoInfer<Datum>>;
119
+ instanceId?: (args: {
120
+ datum: NoInfer<Datum>;
121
+ index: number;
122
+ }) => string;
123
+ cache?: EvaluationCache | false;
124
+ onEvent?: (event: SimbaEvent<NoInfer<K>>) => void;
125
+ onCheckpoint?: (snapshot: SimbaSnapshot) => void | Promise<void>;
126
+ resumeFrom?: SimbaSnapshot;
127
+ }
128
+ type SimbaStopReason = "budgetExhausted" | "costExhausted" | "deadlineReached" | "reflectionBudgetExhausted" | "maxSteps" | "aborted";
129
+ type SimbaEvent<K extends string = string> = {
130
+ type: "start";
131
+ components: K[];
132
+ validationSetSize: number;
133
+ } | ({
134
+ type: "evaluation";
135
+ } & EvaluationEvent) | {
136
+ type: "stepStart";
137
+ step: number;
138
+ poolSize: number;
139
+ } | {
140
+ type: "candidate";
141
+ step: number;
142
+ strategy: SimbaStrategy;
143
+ /** The program it was mutated from; 0 is the seed. */
144
+ sourceProgram: number;
145
+ minibatchScore: number;
146
+ } | {
147
+ type: "error";
148
+ step: number;
149
+ err: unknown;
150
+ } | {
151
+ type: "finish";
152
+ reason: SimbaStopReason;
153
+ bestScore: number;
154
+ metricCalls: number;
155
+ testScore?: number;
156
+ };
157
+ interface SimbaResult<K extends string = string, Output = unknown> extends OptimizerResult<K, SimbaStopReason, Output> {
158
+ /** The seed's own validation score, so the lift the run bought is readable. */
159
+ seedScore: number;
160
+ steps: number;
161
+ /** The step winners scored on the full validation set, best first. */
162
+ finalists: SimbaFinalist<K>[];
163
+ reflectionCalls: number;
164
+ cacheHits: number;
165
+ snapshot: SimbaSnapshot;
166
+ }
167
+ /**
168
+ * SIMBA — stochastic introspective mini-batch ascent.
169
+ *
170
+ * Run several programs over the same minibatch, find the instances they
171
+ * disagree about most, and mutate toward whatever the winning run did. The
172
+ * disagreement is the point: an instance one program solved and another failed
173
+ * is a controlled experiment with the input held fixed, so the difference in
174
+ * reward is attributable to behaviour rather than to difficulty. GEPA reflects
175
+ * on failures; SIMBA reflects on the *contrast* between a success and a failure
176
+ * of the same input, which is a strictly stronger signal when it exists — and
177
+ * costs a pool of programs to produce.
178
+ *
179
+ * Two mutations, drawn at random per instance: append a demonstration the
180
+ * metric already rewarded, or ask a model what the better run did differently
181
+ * and append that as a rule. Neither replaces text, so a candidate accumulates;
182
+ * demos are dropped at a Poisson rate to keep the block from crowding out
183
+ * everything else.
184
+ *
185
+ * Ported from DSPy's SIMBA, with two deliberate changes. First, a trajectory
186
+ * sample runs one program across the whole minibatch rather than resampling a
187
+ * program per instance: the adapter here owns decoding, so there is no
188
+ * temperature knob to vary, and the variability comes from the program pool
189
+ * instead. Second, the percentile guards are strict rather than inclusive — on
190
+ * a step where every rollout ties, an inclusive guard blocks every mutation and
191
+ * the run does nothing at all, which is the one case where the guard's own
192
+ * premise does not hold.
193
+ */
194
+ declare class SimbaOptimizer implements Optimizer<SimbaStopReason> {
195
+ #private;
196
+ constructor(config?: SimbaConfig);
197
+ optimize<Datum, Trajectory = unknown, Output = unknown, const K extends string = string>(task: SimbaTask<Datum, Trajectory, Output, K>): Promise<SimbaResult<K, Output>>;
198
+ }
199
+ //#endregion
200
+ //#region src/simba/strategies.d.ts
201
+ /** One sample of one instance: which program produced it, and how it scored. */
202
+ interface SimbaRollout<Output = unknown> {
203
+ programIndex: number;
204
+ score: number;
205
+ output?: Output;
206
+ feedback?: string;
207
+ }
208
+ /**
209
+ * Every sample of one training instance, sorted best first, with the spread
210
+ * that decides whether the instance is worth learning from.
211
+ */
212
+ interface SimbaBucket<Datum = unknown, Output = unknown> {
213
+ index: number;
214
+ datum: Datum;
215
+ rollouts: SimbaRollout<Output>[];
216
+ maxToMinGap: number;
217
+ maxScore: number;
218
+ maxToAvgGap: number;
219
+ }
220
+ interface SimbaSample<Output = unknown> {
221
+ programIndex: number;
222
+ scores: readonly number[];
223
+ outputs?: readonly (Output | undefined)[];
224
+ feedback?: readonly string[];
225
+ }
226
+ /**
227
+ * Group the step's samples by instance and rank the instances by how much the
228
+ * programs disagreed about them.
229
+ *
230
+ * Disagreement is the signal SIMBA runs on. An instance every program gets
231
+ * right teaches nothing, and one every program gets wrong is usually beyond
232
+ * the reach of a prompt edit; the instructive ones are where one program
233
+ * succeeded and another failed, because the pair is a controlled experiment
234
+ * the reflection model can read directly.
235
+ *
236
+ * Ranked on the max-to-min gap first, then the best score, then the max-to-avg
237
+ * gap: widest disagreement first, ties broken toward instances where something
238
+ * actually worked, since a bucket whose best rollout is bad has no success to
239
+ * generalize from.
240
+ */
241
+ declare function buildBuckets<Datum, Output>(args: {
242
+ batch: readonly Datum[];
243
+ samples: readonly SimbaSample<Output>[];
244
+ }): SimbaBucket<Datum, Output>[];
245
+ /**
246
+ * Linear-interpolated percentile, matching numpy's default so the thresholds
247
+ * behave the way the reference implementation's do.
248
+ */
249
+ declare function percentile(values: readonly number[], p: number): number;
250
+ /**
251
+ * Softmax weights over program scores, for picking which program to mutate
252
+ * next. Shifted by the maximum before exponentiating — the same distribution,
253
+ * but a score scale the caller chose freely cannot overflow it.
254
+ */
255
+ declare function softmaxWeights(scores: readonly number[], temperature: number): number[];
256
+ /**
257
+ * The `k` highest scoring programs, with the baseline forced into the pool.
258
+ *
259
+ * Keeping the baseline is what makes the search recoverable: every candidate
260
+ * descends from a program already in the pool, so a pool that has drifted into
261
+ * a bad region has nothing left to climb back from.
262
+ */
263
+ declare function topKPlusBaseline(args: {
264
+ scores: readonly number[];
265
+ k: number;
266
+ }): number[];
267
+ /**
268
+ * A Poisson draw by Knuth's method, used to decide how many demonstrations to
269
+ * drop before a mutation. Random rather than fixed so a candidate can shed a
270
+ * demo that is no longer earning its place — nothing else in the loop ever
271
+ * removes one, and a block that only grows eventually crowds out the
272
+ * instruction it was meant to support.
273
+ */
274
+ declare function samplePoisson(rng: Rng, lambda: number): number;
275
+ /**
276
+ * Positions spread evenly across a sequence, first and last included.
277
+ *
278
+ * The step winners are held back and only a sample of them is scored on the
279
+ * full validation set at the end, because scoring every one of them costs more
280
+ * than the search did. Sampling evenly rather than taking the last few keeps
281
+ * early winners in the running: minibatch scores are noisy, and the run's
282
+ * genuine best is often not its most recent.
283
+ */
284
+ declare function evenlySpacedIndices(args: {
285
+ length: number;
286
+ count: number;
287
+ }): number[];
288
+ //#endregion
289
+ export { type AdvicePromptArgs, type AdvicePromptBuilder, type AdviceTrajectory, type SimbaBucket, type SimbaConfig, type SimbaEvent, type SimbaFinalist, SimbaOptimizer, type SimbaResult, type SimbaRollout, type SimbaSample, type SimbaSnapshot, type SimbaStopReason, type SimbaStrategy, type SimbaTask, buildAdvicePrompt, buildBuckets, evenlySpacedIndices, parseAdvice, percentile, samplePoisson, softmaxWeights, topKPlusBaseline };