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.
- package/LICENSE +21 -0
- package/README.md +509 -0
- package/dist/bootstrap-search/index.cjs +308 -0
- package/dist/bootstrap-search/index.d.cts +162 -0
- package/dist/bootstrap-search/index.d.mts +162 -0
- package/dist/bootstrap-search/index.mjs +307 -0
- package/dist/cache-CuSo0NJ8.d.cts +24 -0
- package/dist/cache-CuSo0NJ8.d.mts +24 -0
- package/dist/concurrency-C-cFzWW2.cjs +44 -0
- package/dist/concurrency-D58PWeSk.mjs +39 -0
- package/dist/demos-B0pVQjYC.d.mts +88 -0
- package/dist/demos-B9BJiNKz.cjs +143 -0
- package/dist/demos-BTuzFNsp.d.cts +88 -0
- package/dist/demos-Degx6UmP.mjs +126 -0
- package/dist/evaluation-BV0nSZVx.mjs +521 -0
- package/dist/evaluation-OZOp6TB7.cjs +598 -0
- package/dist/file-cache.cjs +70 -0
- package/dist/file-cache.d.cts +21 -0
- package/dist/file-cache.d.mts +21 -0
- package/dist/file-cache.mjs +69 -0
- package/dist/gepa/index.cjs +1671 -0
- package/dist/gepa/index.d.cts +385 -0
- package/dist/gepa/index.d.mts +385 -0
- package/dist/gepa/index.mjs +1652 -0
- package/dist/index.cjs +266 -0
- package/dist/index.d.cts +221 -0
- package/dist/index.d.mts +221 -0
- package/dist/index.mjs +245 -0
- package/dist/math-COOofUyv.cjs +101 -0
- package/dist/math-DhrDmpFS.mjs +78 -0
- package/dist/mipro/index.cjs +739 -0
- package/dist/mipro/index.d.cts +372 -0
- package/dist/mipro/index.d.mts +372 -0
- package/dist/mipro/index.mjs +736 -0
- package/dist/opro/index.cjs +487 -0
- package/dist/opro/index.d.cts +230 -0
- package/dist/opro/index.d.mts +230 -0
- package/dist/opro/index.mjs +485 -0
- package/dist/optimizer-B7SpRwl7.d.cts +288 -0
- package/dist/optimizer-DqCoth_w.d.mts +288 -0
- package/dist/random-search/index.cjs +321 -0
- package/dist/random-search/index.d.cts +156 -0
- package/dist/random-search/index.d.mts +156 -0
- package/dist/random-search/index.mjs +319 -0
- package/dist/reflection-CQToe-5B.d.cts +283 -0
- package/dist/reflection-Cr_upzU0.d.mts +283 -0
- package/dist/reflection-DRfbk6hu.cjs +249 -0
- package/dist/reflection-mwMhrjs_.mjs +214 -0
- package/dist/rng-BR5MOedA.d.cts +22 -0
- package/dist/rng-BR5MOedA.d.mts +22 -0
- package/dist/rng-DbA_rPIo.cjs +67 -0
- package/dist/rng-Dtc5eZ_W.mjs +62 -0
- package/dist/sampling-CfHt7Gue.mjs +59 -0
- package/dist/sampling-DFo_7RNJ.d.mts +23 -0
- package/dist/sampling-Dars7ctR.cjs +64 -0
- package/dist/sampling-axOwfZf5.d.cts +23 -0
- package/dist/simba/index.cjs +709 -0
- package/dist/simba/index.d.cts +289 -0
- package/dist/simba/index.d.mts +289 -0
- package/dist/simba/index.mjs +700 -0
- package/dist/testing.cjs +155 -0
- package/dist/testing.d.cts +53 -0
- package/dist/testing.d.mts +53 -0
- package/dist/testing.mjs +148 -0
- package/dist/text--v4Ffbus.mjs +21 -0
- package/dist/text-CK_HB3su.cjs +26 -0
- package/dist/types-CWv4IQFF.d.cts +129 -0
- package/dist/types-CWv4IQFF.d.mts +129 -0
- package/package.json +135 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { d as UsageTotals, i as EvaluationBatch, n as Candidate, o as EvaluationPhase, s as EvaluationSplit, t as Adapter } from "./types-CWv4IQFF.cjs";
|
|
2
|
+
import { n as EvaluationCache, t as CachedScore } from "./cache-CuSo0NJ8.cjs";
|
|
3
|
+
//#region src/budget.d.ts
|
|
4
|
+
interface Budget {
|
|
5
|
+
readonly maxMetricCalls: number;
|
|
6
|
+
spent(): number;
|
|
7
|
+
remaining(): number;
|
|
8
|
+
canAfford(calls: number): boolean;
|
|
9
|
+
/** Debits `calls` atomically. False when the allowance cannot cover them. */
|
|
10
|
+
reserve(calls: number): boolean;
|
|
11
|
+
/** Credits back calls a reservation did not end up spending. */
|
|
12
|
+
refund(calls: number): void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Rollouts are the currency of prompt optimization: an optimizer's cost is
|
|
16
|
+
* measured in metric calls, not iterations. The engine debits this budget
|
|
17
|
+
* before every evaluation and stops when it can no longer afford the next one.
|
|
18
|
+
*
|
|
19
|
+
* Debiting happens up front, as an atomic reserve-then-refund rather than a
|
|
20
|
+
* check followed by a charge: proposals evaluated concurrently would otherwise
|
|
21
|
+
* each see the same remaining allowance and all spend it.
|
|
22
|
+
*/
|
|
23
|
+
declare function createBudget(args: {
|
|
24
|
+
maxMetricCalls: number;
|
|
25
|
+
/** Rollouts a resumed run already paid for before the checkpoint. */
|
|
26
|
+
spent?: number;
|
|
27
|
+
}): Budget;
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/evaluation.d.ts
|
|
30
|
+
/**
|
|
31
|
+
* One evaluation, reported as it happens. Optimizer-agnostic: every search
|
|
32
|
+
* pays for rollouts the same way, and a caller watching cost should not have
|
|
33
|
+
* to know which algorithm is spending it.
|
|
34
|
+
*/
|
|
35
|
+
interface EvaluationEvent {
|
|
36
|
+
iteration: number;
|
|
37
|
+
phase: EvaluationPhase;
|
|
38
|
+
split: EvaluationSplit;
|
|
39
|
+
candidateId: number | null;
|
|
40
|
+
/** Rollouts this evaluation actually bought. Cached instances are not here. */
|
|
41
|
+
metricCalls: number;
|
|
42
|
+
cacheHits: number;
|
|
43
|
+
meanScore: number;
|
|
44
|
+
}
|
|
45
|
+
/** Scores plus, when the adapter reports them, their per-objective breakdown. */
|
|
46
|
+
interface ScoredBatch<Output> {
|
|
47
|
+
scores: number[];
|
|
48
|
+
objectiveScores: (Record<string, number> | undefined)[];
|
|
49
|
+
/** Populated only under `trackOutputs`, and only for fresh rollouts. */
|
|
50
|
+
outputs: (Output | undefined)[];
|
|
51
|
+
/** Per instance: the score came from an infrastructure failure, not the candidate. */
|
|
52
|
+
transient: boolean[];
|
|
53
|
+
}
|
|
54
|
+
interface EvaluateBatchArgs<Datum, K extends string> {
|
|
55
|
+
candidate: Candidate<K>;
|
|
56
|
+
batch: readonly Datum[];
|
|
57
|
+
/** Instance ids, aligned with `batch`, naming rows in the cache. */
|
|
58
|
+
ids: readonly string[];
|
|
59
|
+
split: EvaluationSplit;
|
|
60
|
+
phase: EvaluationPhase;
|
|
61
|
+
candidateId: number | null;
|
|
62
|
+
iteration: number;
|
|
63
|
+
/**
|
|
64
|
+
* Whether these rollouts come out of the search budget. Measurement taken
|
|
65
|
+
* after the search has chosen a winner passes false: charging it would let
|
|
66
|
+
* the size of a held-out set change which candidate wins.
|
|
67
|
+
*/
|
|
68
|
+
charge?: boolean;
|
|
69
|
+
}
|
|
70
|
+
interface EvaluateTracedArgs<Datum, K extends string> {
|
|
71
|
+
candidate: Candidate<K>;
|
|
72
|
+
batch: readonly Datum[];
|
|
73
|
+
split: EvaluationSplit;
|
|
74
|
+
phase: EvaluationPhase;
|
|
75
|
+
candidateId: number | null;
|
|
76
|
+
iteration: number;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The part of an optimizer that spends money. Every search built on this
|
|
80
|
+
* package shares it, so caching, budgeting, transient-failure handling and
|
|
81
|
+
* cost reporting behave identically whichever algorithm is running.
|
|
82
|
+
*/
|
|
83
|
+
interface Evaluator<Datum, Trajectory, Output, K extends string> {
|
|
84
|
+
evaluate(args: EvaluateBatchArgs<Datum, K>): Promise<ScoredBatch<Output>>;
|
|
85
|
+
/**
|
|
86
|
+
* A rollout with traces captured, always fresh. Reflection reads the traces,
|
|
87
|
+
* and the cache stores scores rather than trajectories, so a cached instance
|
|
88
|
+
* has nothing to reflect on — serving one here would silently hand the
|
|
89
|
+
* reflection model an empty dataset.
|
|
90
|
+
*
|
|
91
|
+
* Returns null when the budget cannot cover the batch, rather than throwing:
|
|
92
|
+
* a run that cannot afford to reflect is finished, not broken.
|
|
93
|
+
*/
|
|
94
|
+
evaluateTraced(args: EvaluateTracedArgs<Datum, K>): Promise<EvaluationBatch<Trajectory, Output> | null>;
|
|
95
|
+
/**
|
|
96
|
+
* How many of `ids` this candidate has not been scored on yet — what a sweep
|
|
97
|
+
* would actually cost. Lets a caller price an evaluation before committing
|
|
98
|
+
* to it, instead of discovering the shortfall halfway through.
|
|
99
|
+
*/
|
|
100
|
+
countUncached(args: {
|
|
101
|
+
candidate: Candidate<K>;
|
|
102
|
+
ids: readonly string[];
|
|
103
|
+
split: EvaluationSplit;
|
|
104
|
+
}): number;
|
|
105
|
+
/** Instances served from the cache, which no budget was charged for. */
|
|
106
|
+
cacheHits(): number;
|
|
107
|
+
/** Rollouts made with `charge: false`, tracked apart from the budget. */
|
|
108
|
+
unchargedCalls(): number;
|
|
109
|
+
/** Tokens and money the run has spent, as far as adapters have reported it. */
|
|
110
|
+
usage(): UsageTotals;
|
|
111
|
+
/** Cache contents for checkpointing, when the cache can enumerate them. */
|
|
112
|
+
entries(): [string, CachedScore][] | undefined;
|
|
113
|
+
restore(entries: Iterable<readonly [string, CachedScore]>): void;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* How often a rollout the adapter reported as infrastructure failure is tried
|
|
117
|
+
* again before its instance is left unmeasured.
|
|
118
|
+
*/
|
|
119
|
+
interface RetryPolicy {
|
|
120
|
+
/** Extra attempts per instance, beyond the first. Zero disables retrying. */
|
|
121
|
+
attempts?: number;
|
|
122
|
+
/** Wait before the first retry. Doubled for each attempt after it. */
|
|
123
|
+
delayMs?: number;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Raised when a reservation cannot be met mid-flight. A concurrent evaluation
|
|
127
|
+
* cannot check the budget and then spend it — another may take the remainder
|
|
128
|
+
* in between — so running out is reported where it happens and turned into a
|
|
129
|
+
* stop reason by whichever loop is driving.
|
|
130
|
+
*/
|
|
131
|
+
declare class BudgetExhausted extends Error {}
|
|
132
|
+
declare function createEvaluator<Datum, Trajectory, Output, K extends string>(args: {
|
|
133
|
+
adapter: Adapter<Datum, Trajectory, Output, K>;
|
|
134
|
+
budget: Budget;
|
|
135
|
+
/** Omit to run uncached; every instance is then a fresh rollout. */
|
|
136
|
+
cache?: EvaluationCache;
|
|
137
|
+
/** Keep what each rollout produced. Costs memory proportional to outputs. */
|
|
138
|
+
trackOutputs?: boolean;
|
|
139
|
+
onEvaluation?: (event: EvaluationEvent) => void;
|
|
140
|
+
signal?: AbortSignal;
|
|
141
|
+
/** Resumed counters, so a continued run reports totals rather than deltas. */
|
|
142
|
+
cacheHits?: number;
|
|
143
|
+
/**
|
|
144
|
+
* Rate limits and 5xx responses are the common case in a long run, and a
|
|
145
|
+
* transient row costs the instance whichever optimizer is driving: it is
|
|
146
|
+
* either an unexplained zero or a hole in the candidate's coverage. Retrying
|
|
147
|
+
* here fixes it once for every optimizer rather than in each search loop.
|
|
148
|
+
*/
|
|
149
|
+
retry?: RetryPolicy;
|
|
150
|
+
/** Scopes every cache key to the system these rollouts were measured under. */
|
|
151
|
+
cacheNamespace?: string;
|
|
152
|
+
}): Evaluator<Datum, Trajectory, Output, K>;
|
|
153
|
+
/**
|
|
154
|
+
* Mean over the rows that measured the candidate. Transient rows measured the
|
|
155
|
+
* infrastructure instead, so averaging their zeros in would reject a candidate
|
|
156
|
+
* for an outage; undefined when no row measured anything at all, which is a
|
|
157
|
+
* batch that says nothing rather than a batch that says zero.
|
|
158
|
+
*/
|
|
159
|
+
declare function measuredMean(batch: {
|
|
160
|
+
scores: readonly number[];
|
|
161
|
+
transient?: readonly boolean[];
|
|
162
|
+
}): number | undefined;
|
|
163
|
+
/**
|
|
164
|
+
* Whether a run has spent what it was allowed to. Checked between evaluations,
|
|
165
|
+
* because usage is only known once a rollout has been paid for.
|
|
166
|
+
*/
|
|
167
|
+
declare function costExhausted(args: {
|
|
168
|
+
usage: UsageTotals;
|
|
169
|
+
maxCostUsd?: number;
|
|
170
|
+
}): boolean;
|
|
171
|
+
/**
|
|
172
|
+
* The measured mean of an evaluation a run cannot continue without — its seed
|
|
173
|
+
* baseline, and the sweeps it compares everything against.
|
|
174
|
+
*
|
|
175
|
+
* Reporting zero for a batch in which nothing ran would set the search a
|
|
176
|
+
* baseline no rollout produced, and every later comparison would be made
|
|
177
|
+
* against it. Failing here names the provider outage instead.
|
|
178
|
+
*/
|
|
179
|
+
declare function requireMeasuredMean(args: {
|
|
180
|
+
batch: {
|
|
181
|
+
scores: readonly number[];
|
|
182
|
+
transient?: readonly boolean[];
|
|
183
|
+
};
|
|
184
|
+
phase: string;
|
|
185
|
+
}): number;
|
|
186
|
+
//#endregion
|
|
187
|
+
//#region src/optimizer.d.ts
|
|
188
|
+
/**
|
|
189
|
+
* The run-level inputs every optimizer needs, whatever search it runs. An
|
|
190
|
+
* optimizer's own task type is a superset of this; the shared members are what
|
|
191
|
+
* a caller can rely on without knowing which optimizer it holds.
|
|
192
|
+
*/
|
|
193
|
+
interface OptimizerTask<Datum, Trajectory = unknown, Output = unknown, K extends string = string> {
|
|
194
|
+
seedCandidate: Candidate<K>;
|
|
195
|
+
trainingSet: readonly Datum[];
|
|
196
|
+
validationSet?: readonly Datum[];
|
|
197
|
+
/**
|
|
198
|
+
* `NoInfer` keeps the adapter out of `K`'s inference: an adapter built by a
|
|
199
|
+
* factory knows nothing about component names, and one inference candidate of
|
|
200
|
+
* `string` widens `K` back to `string` everywhere.
|
|
201
|
+
*/
|
|
202
|
+
adapter: Adapter<Datum, Trajectory, Output, NoInfer<K>>;
|
|
203
|
+
/**
|
|
204
|
+
* Instances held back from the search entirely, used once at the end to
|
|
205
|
+
* score the winner. Selection pressure is applied to the validation set for the
|
|
206
|
+
* whole run, so `bestScore` is partly fitted to it; `testScore` is the only
|
|
207
|
+
* number in a result that no candidate was ever selected against.
|
|
208
|
+
*/
|
|
209
|
+
testSet?: readonly Datum[];
|
|
210
|
+
maxMetricCalls: number;
|
|
211
|
+
/**
|
|
212
|
+
* Dollars the run may spend, as reported by the adapter's usage. Checked
|
|
213
|
+
* between evaluations rather than during one, so a run stops at the first
|
|
214
|
+
* decision point past the ceiling rather than exactly on it.
|
|
215
|
+
*
|
|
216
|
+
* A rollout ceiling cannot bound spend on its own: reflective search grows
|
|
217
|
+
* the text it optimizes, so late rollouts cost more than early ones.
|
|
218
|
+
*/
|
|
219
|
+
maxCostUsd?: number;
|
|
220
|
+
/**
|
|
221
|
+
* Wall-clock milliseconds the run may take. Checked between evaluations, so
|
|
222
|
+
* a run overruns by at most the length of one.
|
|
223
|
+
*
|
|
224
|
+
* Neither a rollout ceiling nor a cost ceiling bounds duration: a run behind
|
|
225
|
+
* a rate limit spends almost nothing and takes as long as the provider
|
|
226
|
+
* makes it take. This is what makes an optimizer safe to put behind a
|
|
227
|
+
* request timeout or a nightly job.
|
|
228
|
+
*/
|
|
229
|
+
maxWallClockMs?: number;
|
|
230
|
+
/**
|
|
231
|
+
* Names the system under optimization — model id, decoding settings, scorer
|
|
232
|
+
* version — so cached scores measured under one are never served to another.
|
|
233
|
+
* Change it whenever anything outside the candidate text changes.
|
|
234
|
+
*/
|
|
235
|
+
cacheNamespace?: string;
|
|
236
|
+
/**
|
|
237
|
+
* How a rollout the adapter reported as an infrastructure failure is retried.
|
|
238
|
+
* Optimizer-agnostic, because a rate limit costs every search the same thing:
|
|
239
|
+
* an instance that measured the provider rather than the candidate.
|
|
240
|
+
*/
|
|
241
|
+
retry?: RetryPolicy;
|
|
242
|
+
signal?: AbortSignal;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* What every optimizer reports. `Stop` has no default: an optimizer that cannot
|
|
246
|
+
* enumerate the reasons it stops has not finished being designed, and a default
|
|
247
|
+
* here would put `string` back.
|
|
248
|
+
*/
|
|
249
|
+
interface OptimizerResult<K extends string, Stop extends string, Output = unknown> {
|
|
250
|
+
bestCandidate: Candidate<K>;
|
|
251
|
+
bestScore: number;
|
|
252
|
+
bestOutputs?: (Output | undefined)[];
|
|
253
|
+
metricCalls: number;
|
|
254
|
+
/**
|
|
255
|
+
* Tokens and dollars the run spent, summed from what the adapter reported.
|
|
256
|
+
* Zero throughout when the adapter reports no usage.
|
|
257
|
+
*/
|
|
258
|
+
usage: UsageTotals;
|
|
259
|
+
/**
|
|
260
|
+
* `bestCandidate`'s mean score over the held-out testSet. Absent when no
|
|
261
|
+
* testSet was given. A large gap below `bestScore` is the search having
|
|
262
|
+
* fitted the validation instances rather than the task.
|
|
263
|
+
*/
|
|
264
|
+
testScore?: number;
|
|
265
|
+
/**
|
|
266
|
+
* Rollouts the held-out sweep cost. Reported separately because it is
|
|
267
|
+
* measurement rather than search, and so is not charged to `maxMetricCalls`.
|
|
268
|
+
*/
|
|
269
|
+
testMetricCalls?: number;
|
|
270
|
+
stopReason: Stop;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* An optimizer: a task in, the best candidate it found out. Exactly one method.
|
|
274
|
+
*
|
|
275
|
+
* `Datum` and `K` are inferred per call, so they live on the method rather than
|
|
276
|
+
* on the interface — a class parameter could only be fixed at `new`, where no
|
|
277
|
+
* seed candidate exists yet.
|
|
278
|
+
*
|
|
279
|
+
* The interface names the contract; it is not a type to hold instances in.
|
|
280
|
+
* Method parameters are bivariant, which is what lets an optimizer with a
|
|
281
|
+
* richer task type implement it at all, and equally what lets a task missing
|
|
282
|
+
* that optimizer's own inputs typecheck against this signature.
|
|
283
|
+
*/
|
|
284
|
+
interface Optimizer<Stop extends string> {
|
|
285
|
+
optimize<Datum, Trajectory = unknown, Output = unknown, const K extends string = string>(task: OptimizerTask<Datum, Trajectory, Output, K>): Promise<OptimizerResult<K, Stop, Output>>;
|
|
286
|
+
}
|
|
287
|
+
//#endregion
|
|
288
|
+
export { EvaluateBatchArgs as a, Evaluator as c, costExhausted as d, createEvaluator as f, createBudget as g, Budget as h, BudgetExhausted as i, RetryPolicy as l, requireMeasuredMean as m, OptimizerResult as n, EvaluateTracedArgs as o, measuredMean as p, OptimizerTask as r, EvaluationEvent as s, Optimizer as t, ScoredBatch as u };
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { d as UsageTotals, i as EvaluationBatch, n as Candidate, o as EvaluationPhase, s as EvaluationSplit, t as Adapter } from "./types-CWv4IQFF.mjs";
|
|
2
|
+
import { n as EvaluationCache, t as CachedScore } from "./cache-CuSo0NJ8.mjs";
|
|
3
|
+
//#region src/budget.d.ts
|
|
4
|
+
interface Budget {
|
|
5
|
+
readonly maxMetricCalls: number;
|
|
6
|
+
spent(): number;
|
|
7
|
+
remaining(): number;
|
|
8
|
+
canAfford(calls: number): boolean;
|
|
9
|
+
/** Debits `calls` atomically. False when the allowance cannot cover them. */
|
|
10
|
+
reserve(calls: number): boolean;
|
|
11
|
+
/** Credits back calls a reservation did not end up spending. */
|
|
12
|
+
refund(calls: number): void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Rollouts are the currency of prompt optimization: an optimizer's cost is
|
|
16
|
+
* measured in metric calls, not iterations. The engine debits this budget
|
|
17
|
+
* before every evaluation and stops when it can no longer afford the next one.
|
|
18
|
+
*
|
|
19
|
+
* Debiting happens up front, as an atomic reserve-then-refund rather than a
|
|
20
|
+
* check followed by a charge: proposals evaluated concurrently would otherwise
|
|
21
|
+
* each see the same remaining allowance and all spend it.
|
|
22
|
+
*/
|
|
23
|
+
declare function createBudget(args: {
|
|
24
|
+
maxMetricCalls: number;
|
|
25
|
+
/** Rollouts a resumed run already paid for before the checkpoint. */
|
|
26
|
+
spent?: number;
|
|
27
|
+
}): Budget;
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/evaluation.d.ts
|
|
30
|
+
/**
|
|
31
|
+
* One evaluation, reported as it happens. Optimizer-agnostic: every search
|
|
32
|
+
* pays for rollouts the same way, and a caller watching cost should not have
|
|
33
|
+
* to know which algorithm is spending it.
|
|
34
|
+
*/
|
|
35
|
+
interface EvaluationEvent {
|
|
36
|
+
iteration: number;
|
|
37
|
+
phase: EvaluationPhase;
|
|
38
|
+
split: EvaluationSplit;
|
|
39
|
+
candidateId: number | null;
|
|
40
|
+
/** Rollouts this evaluation actually bought. Cached instances are not here. */
|
|
41
|
+
metricCalls: number;
|
|
42
|
+
cacheHits: number;
|
|
43
|
+
meanScore: number;
|
|
44
|
+
}
|
|
45
|
+
/** Scores plus, when the adapter reports them, their per-objective breakdown. */
|
|
46
|
+
interface ScoredBatch<Output> {
|
|
47
|
+
scores: number[];
|
|
48
|
+
objectiveScores: (Record<string, number> | undefined)[];
|
|
49
|
+
/** Populated only under `trackOutputs`, and only for fresh rollouts. */
|
|
50
|
+
outputs: (Output | undefined)[];
|
|
51
|
+
/** Per instance: the score came from an infrastructure failure, not the candidate. */
|
|
52
|
+
transient: boolean[];
|
|
53
|
+
}
|
|
54
|
+
interface EvaluateBatchArgs<Datum, K extends string> {
|
|
55
|
+
candidate: Candidate<K>;
|
|
56
|
+
batch: readonly Datum[];
|
|
57
|
+
/** Instance ids, aligned with `batch`, naming rows in the cache. */
|
|
58
|
+
ids: readonly string[];
|
|
59
|
+
split: EvaluationSplit;
|
|
60
|
+
phase: EvaluationPhase;
|
|
61
|
+
candidateId: number | null;
|
|
62
|
+
iteration: number;
|
|
63
|
+
/**
|
|
64
|
+
* Whether these rollouts come out of the search budget. Measurement taken
|
|
65
|
+
* after the search has chosen a winner passes false: charging it would let
|
|
66
|
+
* the size of a held-out set change which candidate wins.
|
|
67
|
+
*/
|
|
68
|
+
charge?: boolean;
|
|
69
|
+
}
|
|
70
|
+
interface EvaluateTracedArgs<Datum, K extends string> {
|
|
71
|
+
candidate: Candidate<K>;
|
|
72
|
+
batch: readonly Datum[];
|
|
73
|
+
split: EvaluationSplit;
|
|
74
|
+
phase: EvaluationPhase;
|
|
75
|
+
candidateId: number | null;
|
|
76
|
+
iteration: number;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The part of an optimizer that spends money. Every search built on this
|
|
80
|
+
* package shares it, so caching, budgeting, transient-failure handling and
|
|
81
|
+
* cost reporting behave identically whichever algorithm is running.
|
|
82
|
+
*/
|
|
83
|
+
interface Evaluator<Datum, Trajectory, Output, K extends string> {
|
|
84
|
+
evaluate(args: EvaluateBatchArgs<Datum, K>): Promise<ScoredBatch<Output>>;
|
|
85
|
+
/**
|
|
86
|
+
* A rollout with traces captured, always fresh. Reflection reads the traces,
|
|
87
|
+
* and the cache stores scores rather than trajectories, so a cached instance
|
|
88
|
+
* has nothing to reflect on — serving one here would silently hand the
|
|
89
|
+
* reflection model an empty dataset.
|
|
90
|
+
*
|
|
91
|
+
* Returns null when the budget cannot cover the batch, rather than throwing:
|
|
92
|
+
* a run that cannot afford to reflect is finished, not broken.
|
|
93
|
+
*/
|
|
94
|
+
evaluateTraced(args: EvaluateTracedArgs<Datum, K>): Promise<EvaluationBatch<Trajectory, Output> | null>;
|
|
95
|
+
/**
|
|
96
|
+
* How many of `ids` this candidate has not been scored on yet — what a sweep
|
|
97
|
+
* would actually cost. Lets a caller price an evaluation before committing
|
|
98
|
+
* to it, instead of discovering the shortfall halfway through.
|
|
99
|
+
*/
|
|
100
|
+
countUncached(args: {
|
|
101
|
+
candidate: Candidate<K>;
|
|
102
|
+
ids: readonly string[];
|
|
103
|
+
split: EvaluationSplit;
|
|
104
|
+
}): number;
|
|
105
|
+
/** Instances served from the cache, which no budget was charged for. */
|
|
106
|
+
cacheHits(): number;
|
|
107
|
+
/** Rollouts made with `charge: false`, tracked apart from the budget. */
|
|
108
|
+
unchargedCalls(): number;
|
|
109
|
+
/** Tokens and money the run has spent, as far as adapters have reported it. */
|
|
110
|
+
usage(): UsageTotals;
|
|
111
|
+
/** Cache contents for checkpointing, when the cache can enumerate them. */
|
|
112
|
+
entries(): [string, CachedScore][] | undefined;
|
|
113
|
+
restore(entries: Iterable<readonly [string, CachedScore]>): void;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* How often a rollout the adapter reported as infrastructure failure is tried
|
|
117
|
+
* again before its instance is left unmeasured.
|
|
118
|
+
*/
|
|
119
|
+
interface RetryPolicy {
|
|
120
|
+
/** Extra attempts per instance, beyond the first. Zero disables retrying. */
|
|
121
|
+
attempts?: number;
|
|
122
|
+
/** Wait before the first retry. Doubled for each attempt after it. */
|
|
123
|
+
delayMs?: number;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Raised when a reservation cannot be met mid-flight. A concurrent evaluation
|
|
127
|
+
* cannot check the budget and then spend it — another may take the remainder
|
|
128
|
+
* in between — so running out is reported where it happens and turned into a
|
|
129
|
+
* stop reason by whichever loop is driving.
|
|
130
|
+
*/
|
|
131
|
+
declare class BudgetExhausted extends Error {}
|
|
132
|
+
declare function createEvaluator<Datum, Trajectory, Output, K extends string>(args: {
|
|
133
|
+
adapter: Adapter<Datum, Trajectory, Output, K>;
|
|
134
|
+
budget: Budget;
|
|
135
|
+
/** Omit to run uncached; every instance is then a fresh rollout. */
|
|
136
|
+
cache?: EvaluationCache;
|
|
137
|
+
/** Keep what each rollout produced. Costs memory proportional to outputs. */
|
|
138
|
+
trackOutputs?: boolean;
|
|
139
|
+
onEvaluation?: (event: EvaluationEvent) => void;
|
|
140
|
+
signal?: AbortSignal;
|
|
141
|
+
/** Resumed counters, so a continued run reports totals rather than deltas. */
|
|
142
|
+
cacheHits?: number;
|
|
143
|
+
/**
|
|
144
|
+
* Rate limits and 5xx responses are the common case in a long run, and a
|
|
145
|
+
* transient row costs the instance whichever optimizer is driving: it is
|
|
146
|
+
* either an unexplained zero or a hole in the candidate's coverage. Retrying
|
|
147
|
+
* here fixes it once for every optimizer rather than in each search loop.
|
|
148
|
+
*/
|
|
149
|
+
retry?: RetryPolicy;
|
|
150
|
+
/** Scopes every cache key to the system these rollouts were measured under. */
|
|
151
|
+
cacheNamespace?: string;
|
|
152
|
+
}): Evaluator<Datum, Trajectory, Output, K>;
|
|
153
|
+
/**
|
|
154
|
+
* Mean over the rows that measured the candidate. Transient rows measured the
|
|
155
|
+
* infrastructure instead, so averaging their zeros in would reject a candidate
|
|
156
|
+
* for an outage; undefined when no row measured anything at all, which is a
|
|
157
|
+
* batch that says nothing rather than a batch that says zero.
|
|
158
|
+
*/
|
|
159
|
+
declare function measuredMean(batch: {
|
|
160
|
+
scores: readonly number[];
|
|
161
|
+
transient?: readonly boolean[];
|
|
162
|
+
}): number | undefined;
|
|
163
|
+
/**
|
|
164
|
+
* Whether a run has spent what it was allowed to. Checked between evaluations,
|
|
165
|
+
* because usage is only known once a rollout has been paid for.
|
|
166
|
+
*/
|
|
167
|
+
declare function costExhausted(args: {
|
|
168
|
+
usage: UsageTotals;
|
|
169
|
+
maxCostUsd?: number;
|
|
170
|
+
}): boolean;
|
|
171
|
+
/**
|
|
172
|
+
* The measured mean of an evaluation a run cannot continue without — its seed
|
|
173
|
+
* baseline, and the sweeps it compares everything against.
|
|
174
|
+
*
|
|
175
|
+
* Reporting zero for a batch in which nothing ran would set the search a
|
|
176
|
+
* baseline no rollout produced, and every later comparison would be made
|
|
177
|
+
* against it. Failing here names the provider outage instead.
|
|
178
|
+
*/
|
|
179
|
+
declare function requireMeasuredMean(args: {
|
|
180
|
+
batch: {
|
|
181
|
+
scores: readonly number[];
|
|
182
|
+
transient?: readonly boolean[];
|
|
183
|
+
};
|
|
184
|
+
phase: string;
|
|
185
|
+
}): number;
|
|
186
|
+
//#endregion
|
|
187
|
+
//#region src/optimizer.d.ts
|
|
188
|
+
/**
|
|
189
|
+
* The run-level inputs every optimizer needs, whatever search it runs. An
|
|
190
|
+
* optimizer's own task type is a superset of this; the shared members are what
|
|
191
|
+
* a caller can rely on without knowing which optimizer it holds.
|
|
192
|
+
*/
|
|
193
|
+
interface OptimizerTask<Datum, Trajectory = unknown, Output = unknown, K extends string = string> {
|
|
194
|
+
seedCandidate: Candidate<K>;
|
|
195
|
+
trainingSet: readonly Datum[];
|
|
196
|
+
validationSet?: readonly Datum[];
|
|
197
|
+
/**
|
|
198
|
+
* `NoInfer` keeps the adapter out of `K`'s inference: an adapter built by a
|
|
199
|
+
* factory knows nothing about component names, and one inference candidate of
|
|
200
|
+
* `string` widens `K` back to `string` everywhere.
|
|
201
|
+
*/
|
|
202
|
+
adapter: Adapter<Datum, Trajectory, Output, NoInfer<K>>;
|
|
203
|
+
/**
|
|
204
|
+
* Instances held back from the search entirely, used once at the end to
|
|
205
|
+
* score the winner. Selection pressure is applied to the validation set for the
|
|
206
|
+
* whole run, so `bestScore` is partly fitted to it; `testScore` is the only
|
|
207
|
+
* number in a result that no candidate was ever selected against.
|
|
208
|
+
*/
|
|
209
|
+
testSet?: readonly Datum[];
|
|
210
|
+
maxMetricCalls: number;
|
|
211
|
+
/**
|
|
212
|
+
* Dollars the run may spend, as reported by the adapter's usage. Checked
|
|
213
|
+
* between evaluations rather than during one, so a run stops at the first
|
|
214
|
+
* decision point past the ceiling rather than exactly on it.
|
|
215
|
+
*
|
|
216
|
+
* A rollout ceiling cannot bound spend on its own: reflective search grows
|
|
217
|
+
* the text it optimizes, so late rollouts cost more than early ones.
|
|
218
|
+
*/
|
|
219
|
+
maxCostUsd?: number;
|
|
220
|
+
/**
|
|
221
|
+
* Wall-clock milliseconds the run may take. Checked between evaluations, so
|
|
222
|
+
* a run overruns by at most the length of one.
|
|
223
|
+
*
|
|
224
|
+
* Neither a rollout ceiling nor a cost ceiling bounds duration: a run behind
|
|
225
|
+
* a rate limit spends almost nothing and takes as long as the provider
|
|
226
|
+
* makes it take. This is what makes an optimizer safe to put behind a
|
|
227
|
+
* request timeout or a nightly job.
|
|
228
|
+
*/
|
|
229
|
+
maxWallClockMs?: number;
|
|
230
|
+
/**
|
|
231
|
+
* Names the system under optimization — model id, decoding settings, scorer
|
|
232
|
+
* version — so cached scores measured under one are never served to another.
|
|
233
|
+
* Change it whenever anything outside the candidate text changes.
|
|
234
|
+
*/
|
|
235
|
+
cacheNamespace?: string;
|
|
236
|
+
/**
|
|
237
|
+
* How a rollout the adapter reported as an infrastructure failure is retried.
|
|
238
|
+
* Optimizer-agnostic, because a rate limit costs every search the same thing:
|
|
239
|
+
* an instance that measured the provider rather than the candidate.
|
|
240
|
+
*/
|
|
241
|
+
retry?: RetryPolicy;
|
|
242
|
+
signal?: AbortSignal;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* What every optimizer reports. `Stop` has no default: an optimizer that cannot
|
|
246
|
+
* enumerate the reasons it stops has not finished being designed, and a default
|
|
247
|
+
* here would put `string` back.
|
|
248
|
+
*/
|
|
249
|
+
interface OptimizerResult<K extends string, Stop extends string, Output = unknown> {
|
|
250
|
+
bestCandidate: Candidate<K>;
|
|
251
|
+
bestScore: number;
|
|
252
|
+
bestOutputs?: (Output | undefined)[];
|
|
253
|
+
metricCalls: number;
|
|
254
|
+
/**
|
|
255
|
+
* Tokens and dollars the run spent, summed from what the adapter reported.
|
|
256
|
+
* Zero throughout when the adapter reports no usage.
|
|
257
|
+
*/
|
|
258
|
+
usage: UsageTotals;
|
|
259
|
+
/**
|
|
260
|
+
* `bestCandidate`'s mean score over the held-out testSet. Absent when no
|
|
261
|
+
* testSet was given. A large gap below `bestScore` is the search having
|
|
262
|
+
* fitted the validation instances rather than the task.
|
|
263
|
+
*/
|
|
264
|
+
testScore?: number;
|
|
265
|
+
/**
|
|
266
|
+
* Rollouts the held-out sweep cost. Reported separately because it is
|
|
267
|
+
* measurement rather than search, and so is not charged to `maxMetricCalls`.
|
|
268
|
+
*/
|
|
269
|
+
testMetricCalls?: number;
|
|
270
|
+
stopReason: Stop;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* An optimizer: a task in, the best candidate it found out. Exactly one method.
|
|
274
|
+
*
|
|
275
|
+
* `Datum` and `K` are inferred per call, so they live on the method rather than
|
|
276
|
+
* on the interface — a class parameter could only be fixed at `new`, where no
|
|
277
|
+
* seed candidate exists yet.
|
|
278
|
+
*
|
|
279
|
+
* The interface names the contract; it is not a type to hold instances in.
|
|
280
|
+
* Method parameters are bivariant, which is what lets an optimizer with a
|
|
281
|
+
* richer task type implement it at all, and equally what lets a task missing
|
|
282
|
+
* that optimizer's own inputs typecheck against this signature.
|
|
283
|
+
*/
|
|
284
|
+
interface Optimizer<Stop extends string> {
|
|
285
|
+
optimize<Datum, Trajectory = unknown, Output = unknown, const K extends string = string>(task: OptimizerTask<Datum, Trajectory, Output, K>): Promise<OptimizerResult<K, Stop, Output>>;
|
|
286
|
+
}
|
|
287
|
+
//#endregion
|
|
288
|
+
export { EvaluateBatchArgs as a, Evaluator as c, costExhausted as d, createEvaluator as f, createBudget as g, Budget as h, BudgetExhausted as i, RetryPolicy as l, requireMeasuredMean as m, OptimizerResult as n, EvaluateTracedArgs as o, measuredMean as p, OptimizerTask as r, EvaluationEvent as s, Optimizer as t, ScoredBatch as u };
|