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.
- package/README.md +65 -25
- package/dist/bootstrap-search/index.cjs +159 -73
- package/dist/bootstrap-search/index.d.cts +32 -10
- package/dist/bootstrap-search/index.d.mts +32 -10
- package/dist/bootstrap-search/index.mjs +150 -66
- package/dist/demos-9v5ts7F3.cjs +244 -0
- package/dist/{demos-B0pVQjYC.d.mts → demos-ASsSXYXA.d.mts} +10 -3
- package/dist/demos-Brobjfuc.mjs +215 -0
- package/dist/{demos-BTuzFNsp.d.cts → demos-ByaLZy-Z.d.cts} +10 -3
- package/dist/file-cache.cjs +27 -8
- package/dist/file-cache.d.cts +13 -0
- package/dist/file-cache.d.mts +13 -0
- package/dist/file-cache.mjs +27 -8
- package/dist/gepa/index.cjs +128 -80
- package/dist/gepa/index.d.cts +15 -7
- package/dist/gepa/index.d.mts +15 -7
- package/dist/gepa/index.mjs +101 -55
- package/dist/index.cjs +157 -30
- package/dist/index.d.cts +177 -7
- package/dist/index.d.mts +177 -7
- package/dist/index.mjs +139 -18
- package/dist/{math-COOofUyv.cjs → math-BhlziRPc.cjs} +60 -9
- package/dist/math-Dqme4rYz.mjs +123 -0
- package/dist/mipro/index.cjs +104 -70
- package/dist/mipro/index.d.cts +17 -14
- package/dist/mipro/index.d.mts +17 -14
- package/dist/mipro/index.mjs +90 -58
- package/dist/opro/index.cjs +136 -51
- package/dist/opro/index.d.cts +17 -9
- package/dist/opro/index.d.mts +17 -9
- package/dist/opro/index.mjs +121 -38
- package/dist/{optimizer-B7SpRwl7.d.cts → optimizer-4Zv-Zt2t.d.cts} +90 -5
- package/dist/{optimizer-DqCoth_w.d.mts → optimizer-Ds5mzYjz.d.mts} +90 -5
- package/dist/random-search/index.cjs +99 -49
- package/dist/random-search/index.d.cts +15 -13
- package/dist/random-search/index.d.mts +15 -13
- package/dist/random-search/index.mjs +89 -41
- package/dist/{reflection-Cr_upzU0.d.mts → reflection-CMezGu6u.d.mts} +38 -14
- package/dist/{reflection-CQToe-5B.d.cts → reflection-D0A7eahD.d.cts} +38 -14
- package/dist/reporting-bq007_2z.d.cts +294 -0
- package/dist/reporting-bq007_2z.d.mts +294 -0
- package/dist/simba/index.cjs +216 -83
- package/dist/simba/index.d.cts +53 -13
- package/dist/simba/index.d.mts +53 -13
- package/dist/simba/index.mjs +206 -75
- package/dist/testing.cjs +1 -0
- package/dist/testing.d.cts +5 -3
- package/dist/testing.d.mts +5 -3
- package/dist/testing.mjs +1 -1
- package/dist/{evaluation-OZOp6TB7.cjs → warnings-CWRJF-jA.cjs} +228 -5
- package/dist/{evaluation-BV0nSZVx.mjs → warnings-OxvDi9kN.mjs} +175 -6
- package/docs/adapters.md +169 -0
- package/docs/benchmark.md +90 -0
- package/docs/data-prep.md +113 -0
- package/docs/distillation.md +128 -0
- package/docs/evaluation.md +87 -0
- package/docs/metric-preflight.md +132 -0
- package/docs/optimizers.md +293 -0
- package/docs/tuning.md +130 -0
- package/package.json +6 -4
- package/dist/demos-B9BJiNKz.cjs +0 -143
- package/dist/demos-Degx6UmP.mjs +0 -126
- package/dist/math-DhrDmpFS.mjs +0 -78
- package/dist/types-CWv4IQFF.d.cts +0 -129
- package/dist/types-CWv4IQFF.d.mts +0 -129
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { n as Candidate, t as
|
|
1
|
+
import { S as UsageTotals, a as RunFinished, f as Adapter, i as Reporter, n as OptimizerEvent, o as isCandidateAccepted, p as Candidate, r as ReportableEvent, s as isRunFinished, t as CandidateAccepted } from "../reporting-bq007_2z.cjs";
|
|
2
2
|
import { n as EvaluationCache, t as CachedScore } from "../cache-CuSo0NJ8.cjs";
|
|
3
|
-
import { r as DemoRenderer } from "../demos-
|
|
4
|
-
import { n as OptimizerResult, r as OptimizerTask, s as EvaluationEvent, t as Optimizer } from "../optimizer-
|
|
3
|
+
import { r as DemoRenderer } from "../demos-ByaLZy-Z.cjs";
|
|
4
|
+
import { n as OptimizerResult, r as OptimizerTask, s as EvaluationEvent, t as Optimizer } from "../optimizer-4Zv-Zt2t.cjs";
|
|
5
5
|
//#region src/bootstrap-search/optimize.d.ts
|
|
6
6
|
/**
|
|
7
7
|
* Where a candidate's demo block came from. `zeroShot` holds no demos at all,
|
|
@@ -35,6 +35,18 @@ interface BootstrapSearchConfig {
|
|
|
35
35
|
* every candidate, which is the reliable reading and the expensive one.
|
|
36
36
|
*/
|
|
37
37
|
stopAtScore?: number;
|
|
38
|
+
/**
|
|
39
|
+
* How many candidates may be swept at once. Default 1.
|
|
40
|
+
*
|
|
41
|
+
* Harvesting stays in plan order however this is set — every harvest draws
|
|
42
|
+
* from the same random stream, and reordering them would make a seeded run
|
|
43
|
+
* unreproducible — so what overlaps is a sweep with the harvest of the
|
|
44
|
+
* candidates behind it. Two costs come with raising it: a checkpoint is
|
|
45
|
+
* taken per wave rather than per candidate, so a killed run loses up to this
|
|
46
|
+
* many candidates instead of one, and `stopAtScore` is honoured by sweeping
|
|
47
|
+
* one at a time, since a wave cannot know it has already passed the target.
|
|
48
|
+
*/
|
|
49
|
+
concurrency?: number;
|
|
38
50
|
seed?: number;
|
|
39
51
|
trackBestOutputs?: boolean;
|
|
40
52
|
/**
|
|
@@ -61,6 +73,13 @@ interface BootstrapSearchSnapshot {
|
|
|
61
73
|
metricCalls: number;
|
|
62
74
|
bootstrapMetricCalls: number;
|
|
63
75
|
cacheHits: number;
|
|
76
|
+
/** Usage already spent, so a resumed run reports totals and honours ceilings. */
|
|
77
|
+
usage?: UsageTotals;
|
|
78
|
+
/**
|
|
79
|
+
* Candidates accepted so far. Reporters key rows by this id, so restarting it
|
|
80
|
+
* at zero makes a resumed run collide with the run it continues.
|
|
81
|
+
*/
|
|
82
|
+
acceptedCandidates?: number;
|
|
64
83
|
rngState: number;
|
|
65
84
|
cache?: [string, CachedScore][];
|
|
66
85
|
}
|
|
@@ -92,7 +111,8 @@ interface BootstrapSearchTask<Datum, Trajectory = unknown, Output = unknown, K e
|
|
|
92
111
|
}) => string;
|
|
93
112
|
/** Pass `false` to disable caching entirely. */
|
|
94
113
|
cache?: EvaluationCache | false;
|
|
95
|
-
|
|
114
|
+
/** Observers of the run. Every one sees every event; none can fail it. */
|
|
115
|
+
reporters?: readonly Reporter<BootstrapSearchEvent<NoInfer<K>>>[];
|
|
96
116
|
/** Called with a resumable snapshot after every candidate is scored. */
|
|
97
117
|
onCheckpoint?: (snapshot: BootstrapSearchSnapshot) => void | Promise<void>;
|
|
98
118
|
/** Snapshot to continue from. */
|
|
@@ -112,13 +132,15 @@ type BootstrapSearchEvent<K extends string = string> = {
|
|
|
112
132
|
demos: number;
|
|
113
133
|
score: number;
|
|
114
134
|
accepted: boolean;
|
|
115
|
-
} | {
|
|
135
|
+
} | ({
|
|
136
|
+
type: "candidateAccepted";
|
|
137
|
+
/** Which construction produced the demo block that won. */
|
|
138
|
+
source: DemoSource;
|
|
139
|
+
demos: number;
|
|
140
|
+
} & CandidateAccepted<K>) | ({
|
|
116
141
|
type: "finish";
|
|
117
142
|
reason: BootstrapSearchStopReason;
|
|
118
|
-
|
|
119
|
-
metricCalls: number;
|
|
120
|
-
testScore?: number;
|
|
121
|
-
};
|
|
143
|
+
} & RunFinished);
|
|
122
144
|
interface BootstrapSearchResult<K extends string = string, Output = unknown> extends OptimizerResult<K, BootstrapSearchStopReason, Output> {
|
|
123
145
|
/** The seed's score, so the lift the demos bought is readable directly. */
|
|
124
146
|
seedScore: number;
|
|
@@ -159,4 +181,4 @@ declare class BootstrapSearchOptimizer implements Optimizer<BootstrapSearchStopR
|
|
|
159
181
|
optimize<Datum, Trajectory = unknown, Output = unknown, const K extends string = string>(task: BootstrapSearchTask<Datum, Trajectory, Output, K>): Promise<BootstrapSearchResult<K, Output>>;
|
|
160
182
|
}
|
|
161
183
|
//#endregion
|
|
162
|
-
export { type BootstrapCandidate, type BootstrapSearchConfig, type BootstrapSearchEvent, BootstrapSearchOptimizer, type BootstrapSearchResult, type BootstrapSearchSnapshot, type BootstrapSearchStopReason, type BootstrapSearchTask, type DemoSource };
|
|
184
|
+
export { type BootstrapCandidate, type BootstrapSearchConfig, type BootstrapSearchEvent, BootstrapSearchOptimizer, type BootstrapSearchResult, type BootstrapSearchSnapshot, type BootstrapSearchStopReason, type BootstrapSearchTask, type CandidateAccepted, type DemoSource, type OptimizerEvent, type ReportableEvent, type Reporter, type RunFinished, isCandidateAccepted, isRunFinished };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { n as Candidate, t as
|
|
1
|
+
import { S as UsageTotals, a as RunFinished, f as Adapter, i as Reporter, n as OptimizerEvent, o as isCandidateAccepted, p as Candidate, r as ReportableEvent, s as isRunFinished, t as CandidateAccepted } from "../reporting-bq007_2z.mjs";
|
|
2
2
|
import { n as EvaluationCache, t as CachedScore } from "../cache-CuSo0NJ8.mjs";
|
|
3
|
-
import { r as DemoRenderer } from "../demos-
|
|
4
|
-
import { n as OptimizerResult, r as OptimizerTask, s as EvaluationEvent, t as Optimizer } from "../optimizer-
|
|
3
|
+
import { r as DemoRenderer } from "../demos-ASsSXYXA.mjs";
|
|
4
|
+
import { n as OptimizerResult, r as OptimizerTask, s as EvaluationEvent, t as Optimizer } from "../optimizer-Ds5mzYjz.mjs";
|
|
5
5
|
//#region src/bootstrap-search/optimize.d.ts
|
|
6
6
|
/**
|
|
7
7
|
* Where a candidate's demo block came from. `zeroShot` holds no demos at all,
|
|
@@ -35,6 +35,18 @@ interface BootstrapSearchConfig {
|
|
|
35
35
|
* every candidate, which is the reliable reading and the expensive one.
|
|
36
36
|
*/
|
|
37
37
|
stopAtScore?: number;
|
|
38
|
+
/**
|
|
39
|
+
* How many candidates may be swept at once. Default 1.
|
|
40
|
+
*
|
|
41
|
+
* Harvesting stays in plan order however this is set — every harvest draws
|
|
42
|
+
* from the same random stream, and reordering them would make a seeded run
|
|
43
|
+
* unreproducible — so what overlaps is a sweep with the harvest of the
|
|
44
|
+
* candidates behind it. Two costs come with raising it: a checkpoint is
|
|
45
|
+
* taken per wave rather than per candidate, so a killed run loses up to this
|
|
46
|
+
* many candidates instead of one, and `stopAtScore` is honoured by sweeping
|
|
47
|
+
* one at a time, since a wave cannot know it has already passed the target.
|
|
48
|
+
*/
|
|
49
|
+
concurrency?: number;
|
|
38
50
|
seed?: number;
|
|
39
51
|
trackBestOutputs?: boolean;
|
|
40
52
|
/**
|
|
@@ -61,6 +73,13 @@ interface BootstrapSearchSnapshot {
|
|
|
61
73
|
metricCalls: number;
|
|
62
74
|
bootstrapMetricCalls: number;
|
|
63
75
|
cacheHits: number;
|
|
76
|
+
/** Usage already spent, so a resumed run reports totals and honours ceilings. */
|
|
77
|
+
usage?: UsageTotals;
|
|
78
|
+
/**
|
|
79
|
+
* Candidates accepted so far. Reporters key rows by this id, so restarting it
|
|
80
|
+
* at zero makes a resumed run collide with the run it continues.
|
|
81
|
+
*/
|
|
82
|
+
acceptedCandidates?: number;
|
|
64
83
|
rngState: number;
|
|
65
84
|
cache?: [string, CachedScore][];
|
|
66
85
|
}
|
|
@@ -92,7 +111,8 @@ interface BootstrapSearchTask<Datum, Trajectory = unknown, Output = unknown, K e
|
|
|
92
111
|
}) => string;
|
|
93
112
|
/** Pass `false` to disable caching entirely. */
|
|
94
113
|
cache?: EvaluationCache | false;
|
|
95
|
-
|
|
114
|
+
/** Observers of the run. Every one sees every event; none can fail it. */
|
|
115
|
+
reporters?: readonly Reporter<BootstrapSearchEvent<NoInfer<K>>>[];
|
|
96
116
|
/** Called with a resumable snapshot after every candidate is scored. */
|
|
97
117
|
onCheckpoint?: (snapshot: BootstrapSearchSnapshot) => void | Promise<void>;
|
|
98
118
|
/** Snapshot to continue from. */
|
|
@@ -112,13 +132,15 @@ type BootstrapSearchEvent<K extends string = string> = {
|
|
|
112
132
|
demos: number;
|
|
113
133
|
score: number;
|
|
114
134
|
accepted: boolean;
|
|
115
|
-
} | {
|
|
135
|
+
} | ({
|
|
136
|
+
type: "candidateAccepted";
|
|
137
|
+
/** Which construction produced the demo block that won. */
|
|
138
|
+
source: DemoSource;
|
|
139
|
+
demos: number;
|
|
140
|
+
} & CandidateAccepted<K>) | ({
|
|
116
141
|
type: "finish";
|
|
117
142
|
reason: BootstrapSearchStopReason;
|
|
118
|
-
|
|
119
|
-
metricCalls: number;
|
|
120
|
-
testScore?: number;
|
|
121
|
-
};
|
|
143
|
+
} & RunFinished);
|
|
122
144
|
interface BootstrapSearchResult<K extends string = string, Output = unknown> extends OptimizerResult<K, BootstrapSearchStopReason, Output> {
|
|
123
145
|
/** The seed's score, so the lift the demos bought is readable directly. */
|
|
124
146
|
seedScore: number;
|
|
@@ -159,4 +181,4 @@ declare class BootstrapSearchOptimizer implements Optimizer<BootstrapSearchStopR
|
|
|
159
181
|
optimize<Datum, Trajectory = unknown, Output = unknown, const K extends string = string>(task: BootstrapSearchTask<Datum, Trajectory, Output, K>): Promise<BootstrapSearchResult<K, Output>>;
|
|
160
182
|
}
|
|
161
183
|
//#endregion
|
|
162
|
-
export { type BootstrapCandidate, type BootstrapSearchConfig, type BootstrapSearchEvent, BootstrapSearchOptimizer, type BootstrapSearchResult, type BootstrapSearchSnapshot, type BootstrapSearchStopReason, type BootstrapSearchTask, type DemoSource };
|
|
184
|
+
export { type BootstrapCandidate, type BootstrapSearchConfig, type BootstrapSearchEvent, BootstrapSearchOptimizer, type BootstrapSearchResult, type BootstrapSearchSnapshot, type BootstrapSearchStopReason, type BootstrapSearchTask, type CandidateAccepted, type DemoSource, type OptimizerEvent, type ReportableEvent, type Reporter, type RunFinished, isCandidateAccepted, isRunFinished };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import { n as
|
|
1
|
+
import { S as createBudget, _ as componentNames, a as instanceRow, b as defaultInstanceId, c as BudgetExhausted, d as measuredMean, f as requireMeasuredMean, g as runFingerprint, i as flushReporters, l as costExhausted, m as assertResumable, o as isCandidateAccepted, p as createDeadline, r as createEmitter, s as isRunFinished, t as resolveValidationSet, u as createEvaluator, v as candidateHash, y as createMemoryCache } from "../warnings-OxvDi9kN.mjs";
|
|
2
|
+
import { n as harvestFewShotExamples, t as formatDemos } from "../demos-Brobjfuc.mjs";
|
|
3
3
|
import { t as createSeededRng } from "../rng-Dtc5eZ_W.mjs";
|
|
4
4
|
//#region src/bootstrap-search/optimize.ts
|
|
5
5
|
const DEFAULT_CANDIDATES = 16;
|
|
@@ -33,19 +33,29 @@ const DEFAULT_MAX_LABELED_DEMOS = 16;
|
|
|
33
33
|
var BootstrapSearchOptimizer = class {
|
|
34
34
|
#config;
|
|
35
35
|
constructor(config = {}) {
|
|
36
|
+
assertBootstrapSearchConfig(config);
|
|
36
37
|
this.#config = config;
|
|
37
38
|
}
|
|
38
|
-
optimize(task) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
async optimize(task) {
|
|
40
|
+
try {
|
|
41
|
+
return await run({
|
|
42
|
+
config: this.#config,
|
|
43
|
+
task
|
|
44
|
+
});
|
|
45
|
+
} finally {
|
|
46
|
+
await flushReporters(task.reporters ?? []);
|
|
47
|
+
}
|
|
43
48
|
}
|
|
44
49
|
};
|
|
45
50
|
async function run(args) {
|
|
46
51
|
const { config, task } = args;
|
|
47
|
-
const { candidates: shuffledHarvests = DEFAULT_CANDIDATES, maxDemos = DEFAULT_MAX_DEMOS, minDemos = DEFAULT_MIN_DEMOS, maxLabeledDemos = DEFAULT_MAX_LABELED_DEMOS, demoMinScore, stopAtScore, seed = 0, trackBestOutputs = false, checkpointCache = true } = config;
|
|
48
|
-
const { seedCandidate, trainingSet, validationSet
|
|
52
|
+
const { candidates: shuffledHarvests = DEFAULT_CANDIDATES, maxDemos = DEFAULT_MAX_DEMOS, minDemos = DEFAULT_MIN_DEMOS, maxLabeledDemos = DEFAULT_MAX_LABELED_DEMOS, demoMinScore, stopAtScore, concurrency = 1, seed = 0, trackBestOutputs = false, checkpointCache = true } = config;
|
|
53
|
+
const { seedCandidate, trainingSet, validationSet: requestedValidationSet, testSet, adapter, demoComponents, renderDemo, goldOutput, maxMetricCalls, cache, cacheNamespace, retry, maxCostUsd, maxWallClockMs, instanceId = defaultInstanceId, reporters = [], onCheckpoint, resumeFrom, signal } = task;
|
|
54
|
+
const { validationSet, warnings } = resolveValidationSet({
|
|
55
|
+
validationSet: requestedValidationSet,
|
|
56
|
+
trainingSet
|
|
57
|
+
});
|
|
58
|
+
const emit = createEmitter(reporters);
|
|
49
59
|
const deadline = createDeadline({ maxWallClockMs });
|
|
50
60
|
const components = componentNames(seedCandidate);
|
|
51
61
|
if (trainingSet.length === 0) throw new Error("optimize requires a non-empty trainingSet");
|
|
@@ -88,8 +98,9 @@ async function run(args) {
|
|
|
88
98
|
...evaluationCache === void 0 ? {} : { cache: evaluationCache },
|
|
89
99
|
trackOutputs: trackBestOutputs,
|
|
90
100
|
cacheHits: resumeFrom?.cacheHits ?? 0,
|
|
101
|
+
...resumeFrom?.usage === void 0 ? {} : { usage: resumeFrom.usage },
|
|
91
102
|
...signal === void 0 ? {} : { signal },
|
|
92
|
-
onEvaluation: (event) =>
|
|
103
|
+
onEvaluation: (event) => emit({
|
|
93
104
|
type: "evaluation",
|
|
94
105
|
...event
|
|
95
106
|
})
|
|
@@ -99,7 +110,7 @@ async function run(args) {
|
|
|
99
110
|
let drawn = resumeFrom?.drawn ?? 0;
|
|
100
111
|
let bootstrapMetricCalls = resumeFrom?.bootstrapMetricCalls ?? 0;
|
|
101
112
|
let stopReason = "candidatesExhausted";
|
|
102
|
-
|
|
113
|
+
emit({
|
|
103
114
|
type: "start",
|
|
104
115
|
components,
|
|
105
116
|
validationSetSize: validationSet.length
|
|
@@ -115,13 +126,25 @@ async function run(args) {
|
|
|
115
126
|
iteration: evaluated.length
|
|
116
127
|
});
|
|
117
128
|
}
|
|
118
|
-
const
|
|
119
|
-
|
|
129
|
+
const seedEvaluation = resumeFrom === void 0 ? await sweep(seedCandidate, "seed") : void 0;
|
|
130
|
+
const seedScore = seedEvaluation === void 0 ? resumeFrom.seedScore : requireMeasuredMean({
|
|
131
|
+
batch: seedEvaluation,
|
|
120
132
|
phase: "seed"
|
|
121
133
|
});
|
|
122
134
|
let best = resumeFrom?.best ?? seedCandidate;
|
|
123
135
|
let bestScore = resumeFrom?.bestScore ?? seedScore;
|
|
124
136
|
let bestOutputs;
|
|
137
|
+
let acceptedCandidates = resumeFrom?.acceptedCandidates ?? 0;
|
|
138
|
+
if (seedEvaluation !== void 0) emit({
|
|
139
|
+
type: "candidateAccepted",
|
|
140
|
+
source: "zeroShot",
|
|
141
|
+
demos: 0,
|
|
142
|
+
candidateId: 0,
|
|
143
|
+
candidate: seedCandidate,
|
|
144
|
+
aggregateScore: seedScore,
|
|
145
|
+
instanceScores: instanceRow(seedEvaluation),
|
|
146
|
+
...trackBestOutputs ? { outputs: seedEvaluation.outputs } : {}
|
|
147
|
+
});
|
|
125
148
|
function takeSnapshot() {
|
|
126
149
|
const cached = checkpointCache ? evaluationCache?.entries?.() : void 0;
|
|
127
150
|
return {
|
|
@@ -135,6 +158,8 @@ async function run(args) {
|
|
|
135
158
|
metricCalls: budget.spent(),
|
|
136
159
|
bootstrapMetricCalls,
|
|
137
160
|
cacheHits: evaluator.cacheHits(),
|
|
161
|
+
usage: evaluator.usage(),
|
|
162
|
+
acceptedCandidates,
|
|
138
163
|
rngState: rng.state(),
|
|
139
164
|
...cached === void 0 ? {} : { cache: cached }
|
|
140
165
|
};
|
|
@@ -147,7 +172,8 @@ async function run(args) {
|
|
|
147
172
|
shuffledHarvests,
|
|
148
173
|
labeled: goldOutput !== void 0
|
|
149
174
|
});
|
|
150
|
-
|
|
175
|
+
const waveSize = stopAtScore === void 0 ? concurrency : 1;
|
|
176
|
+
while (drawn < plan.length) {
|
|
151
177
|
if (signal?.aborted) {
|
|
152
178
|
stopReason = "aborted";
|
|
153
179
|
break;
|
|
@@ -163,58 +189,95 @@ async function run(args) {
|
|
|
163
189
|
stopReason = "deadlineReached";
|
|
164
190
|
break;
|
|
165
191
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const candidate = withDemos(block);
|
|
173
|
-
let evaluation;
|
|
174
|
-
try {
|
|
175
|
-
evaluation = await sweep(candidate, "validation");
|
|
176
|
-
} catch (err) {
|
|
177
|
-
if (err instanceof BudgetExhausted) {
|
|
178
|
-
stopReason = "budgetExhausted";
|
|
179
|
-
break;
|
|
180
|
-
}
|
|
181
|
-
if (signal?.aborted) {
|
|
182
|
-
stopReason = "aborted";
|
|
192
|
+
const wave = [];
|
|
193
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
194
|
+
let waveStop;
|
|
195
|
+
while (wave.length < waveSize && drawn + wave.length < plan.length) {
|
|
196
|
+
if (!budget.canAfford(validationSet.length + 1)) {
|
|
197
|
+
waveStop = "budgetExhausted";
|
|
183
198
|
break;
|
|
184
199
|
}
|
|
185
|
-
|
|
200
|
+
const source = plan[drawn + wave.length];
|
|
201
|
+
const block = await buildBlock(source);
|
|
202
|
+
const candidate = withDemos(block);
|
|
203
|
+
const key = candidateHash(candidate);
|
|
204
|
+
const prior = inFlight.get(key);
|
|
205
|
+
const sweeping = prior === void 0 ? settled(sweep(candidate, "validation")) : prior.then(() => settled(sweep(candidate, "validation")));
|
|
206
|
+
inFlight.set(key, sweeping);
|
|
207
|
+
wave.push({
|
|
208
|
+
source,
|
|
209
|
+
candidate,
|
|
210
|
+
block,
|
|
211
|
+
sweep: sweeping
|
|
212
|
+
});
|
|
186
213
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
214
|
+
let waveError;
|
|
215
|
+
let draining = false;
|
|
216
|
+
for (const entry of wave) {
|
|
217
|
+
const outcome = await entry.sweep;
|
|
218
|
+
if (draining) continue;
|
|
219
|
+
drawn += 1;
|
|
220
|
+
if (outcome.failed === true) {
|
|
221
|
+
draining = true;
|
|
222
|
+
if (outcome.err instanceof BudgetExhausted) {
|
|
223
|
+
waveStop = "budgetExhausted";
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (signal?.aborted) {
|
|
227
|
+
waveStop = "aborted";
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
waveError = outcome.err;
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
const evaluation = outcome.evaluation;
|
|
234
|
+
const score = measuredMean(evaluation);
|
|
235
|
+
if (score === void 0) continue;
|
|
236
|
+
const accepted = score > bestScore;
|
|
237
|
+
evaluated.push({
|
|
238
|
+
candidate: entry.candidate,
|
|
239
|
+
source: entry.source,
|
|
240
|
+
demos: countDemos(entry.block),
|
|
241
|
+
score
|
|
242
|
+
});
|
|
243
|
+
emit({
|
|
244
|
+
type: "candidate",
|
|
245
|
+
index: evaluated.length - 1,
|
|
246
|
+
source: entry.source,
|
|
247
|
+
demos: countDemos(entry.block),
|
|
248
|
+
score,
|
|
249
|
+
accepted
|
|
250
|
+
});
|
|
251
|
+
if (accepted) {
|
|
252
|
+
acceptedCandidates += 1;
|
|
253
|
+
emit({
|
|
254
|
+
type: "candidateAccepted",
|
|
255
|
+
source: entry.source,
|
|
256
|
+
demos: countDemos(entry.block),
|
|
257
|
+
candidateId: acceptedCandidates,
|
|
258
|
+
candidate: entry.candidate,
|
|
259
|
+
aggregateScore: score,
|
|
260
|
+
instanceScores: instanceRow(evaluation),
|
|
261
|
+
...trackBestOutputs ? { outputs: evaluation.outputs } : {}
|
|
262
|
+
});
|
|
263
|
+
best = entry.candidate;
|
|
264
|
+
bestScore = score;
|
|
265
|
+
bestOutputs = evaluation.outputs;
|
|
266
|
+
}
|
|
267
|
+
if (stopAtScore !== void 0 && score >= stopAtScore) {
|
|
268
|
+
waveStop = "scoreReached";
|
|
269
|
+
draining = true;
|
|
270
|
+
}
|
|
208
271
|
}
|
|
272
|
+
if (waveError !== void 0) throw waveError;
|
|
209
273
|
await checkpoint();
|
|
210
|
-
if (
|
|
211
|
-
stopReason =
|
|
212
|
-
drawn += 1;
|
|
274
|
+
if (waveStop !== void 0) {
|
|
275
|
+
stopReason = waveStop;
|
|
213
276
|
break;
|
|
214
277
|
}
|
|
215
278
|
}
|
|
216
279
|
if (signal?.aborted) stopReason = "aborted";
|
|
217
|
-
const
|
|
280
|
+
const heldOut = testSet === void 0 ? void 0 : await evaluator.evaluate({
|
|
218
281
|
candidate: best,
|
|
219
282
|
batch: testSet,
|
|
220
283
|
ids: testIds,
|
|
@@ -223,13 +286,18 @@ async function run(args) {
|
|
|
223
286
|
candidateId: null,
|
|
224
287
|
iteration: evaluated.length,
|
|
225
288
|
charge: false
|
|
226
|
-
})
|
|
227
|
-
|
|
289
|
+
});
|
|
290
|
+
const testScore = heldOut === void 0 ? void 0 : measuredMean(heldOut);
|
|
291
|
+
emit({
|
|
228
292
|
type: "finish",
|
|
229
293
|
reason: stopReason,
|
|
294
|
+
warnings,
|
|
295
|
+
bestCandidateId: acceptedCandidates,
|
|
230
296
|
bestScore,
|
|
231
297
|
metricCalls: budget.spent(),
|
|
232
|
-
...testScore === void 0 ? {} : { testScore }
|
|
298
|
+
...testScore === void 0 ? {} : { testScore },
|
|
299
|
+
...heldOut === void 0 ? {} : { testInstanceScores: instanceRow(heldOut) },
|
|
300
|
+
...heldOut === void 0 || !trackBestOutputs ? {} : { testOutputs: heldOut.outputs }
|
|
233
301
|
});
|
|
234
302
|
return {
|
|
235
303
|
bestCandidate: best,
|
|
@@ -244,8 +312,10 @@ async function run(args) {
|
|
|
244
312
|
...trackBestOutputs && bestOutputs !== void 0 ? { bestOutputs } : {},
|
|
245
313
|
...testScore === void 0 ? {} : {
|
|
246
314
|
testScore,
|
|
247
|
-
testMetricCalls:
|
|
315
|
+
testMetricCalls: evaluator.unchargedCalls(),
|
|
316
|
+
testUsage: evaluator.unchargedUsage()
|
|
248
317
|
},
|
|
318
|
+
warnings,
|
|
249
319
|
stopReason
|
|
250
320
|
};
|
|
251
321
|
function withDemos(block) {
|
|
@@ -259,19 +329,21 @@ async function run(args) {
|
|
|
259
329
|
const requested = source === "unshuffled" ? maxDemos : minDemos + rng.nextInt(Math.max(1, maxDemos - minDemos + 1));
|
|
260
330
|
const affordable = Math.min(trainingSet.length, budget.remaining() - validationSet.length);
|
|
261
331
|
if (affordable < 1) return "";
|
|
262
|
-
const harvest = await
|
|
332
|
+
const harvest = await harvestFewShotExamples({
|
|
263
333
|
adapter,
|
|
264
334
|
candidate: seedCandidate,
|
|
265
335
|
trainingSet,
|
|
266
336
|
...demoMinScore === void 0 ? {} : { minScore: demoMinScore },
|
|
267
337
|
maxDemos: requested,
|
|
268
338
|
maxMetricCalls: affordable,
|
|
339
|
+
...maxCostUsd === void 0 ? {} : { maxCostUsd: maxCostUsd - evaluator.usage().costUsd },
|
|
269
340
|
...source === "unshuffled" ? {} : { rng },
|
|
270
341
|
...renderDemo === void 0 ? {} : { renderDemo },
|
|
271
342
|
...signal === void 0 ? {} : { signal }
|
|
272
343
|
});
|
|
273
344
|
bootstrapMetricCalls += harvest.metricCalls;
|
|
274
345
|
budget.reserve(harvest.metricCalls);
|
|
346
|
+
evaluator.absorbUsage(harvest.usage);
|
|
275
347
|
return harvest.block;
|
|
276
348
|
}
|
|
277
349
|
function labeledBlock() {
|
|
@@ -297,11 +369,23 @@ function candidatePlan(args) {
|
|
|
297
369
|
...Array.from({ length: shuffledHarvests }, () => "bootstrapped")
|
|
298
370
|
];
|
|
299
371
|
}
|
|
372
|
+
/** Turns a sweep into a value, so a dispatched one never rejects unobserved. */
|
|
373
|
+
function settled(sweeping) {
|
|
374
|
+
return sweeping.then((evaluation) => ({ evaluation }), (err) => ({
|
|
375
|
+
failed: true,
|
|
376
|
+
err
|
|
377
|
+
}));
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Range checks on the search knobs, run at construction so a configuration
|
|
381
|
+
* that could never terminate is refused before a task is ever handed to it.
|
|
382
|
+
*/
|
|
383
|
+
function assertBootstrapSearchConfig(config) {
|
|
384
|
+
const { concurrency = 1 } = config;
|
|
385
|
+
if (!Number.isInteger(concurrency) || concurrency < 1) throw new Error(`concurrency must be a positive integer, received ${concurrency}`);
|
|
386
|
+
}
|
|
300
387
|
function countDemos(block) {
|
|
301
388
|
return block.split("<demo>").length - 1;
|
|
302
389
|
}
|
|
303
|
-
function defaultInstanceId(args) {
|
|
304
|
-
return String(args.index);
|
|
305
|
-
}
|
|
306
390
|
//#endregion
|
|
307
|
-
export { BootstrapSearchOptimizer };
|
|
391
|
+
export { BootstrapSearchOptimizer, isCandidateAccepted, isRunFinished };
|