textopt 0.0.0 → 0.1.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 +44 -22
- package/dist/bootstrap-search/index.cjs +153 -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 +144 -66
- package/dist/{demos-B0pVQjYC.d.mts → demos-1b7JiUue.d.mts} +10 -3
- package/dist/{demos-BTuzFNsp.d.cts → demos-CU9dy2oT.d.cts} +10 -3
- package/dist/demos-D2o0qSSo.cjs +244 -0
- package/dist/demos-DE2oxNWX.mjs +215 -0
- package/dist/file-cache.cjs +11 -3
- package/dist/file-cache.mjs +11 -3
- package/dist/gepa/index.cjs +76 -71
- package/dist/gepa/index.d.cts +12 -6
- package/dist/gepa/index.d.mts +12 -6
- package/dist/gepa/index.mjs +49 -46
- package/dist/index.cjs +129 -27
- package/dist/index.d.cts +145 -7
- package/dist/index.d.mts +145 -7
- package/dist/index.mjs +113 -15
- package/dist/{math-COOofUyv.cjs → math-BhlziRPc.cjs} +60 -9
- package/dist/math-Dqme4rYz.mjs +123 -0
- package/dist/mipro/index.cjs +98 -70
- package/dist/mipro/index.d.cts +17 -14
- package/dist/mipro/index.d.mts +17 -14
- package/dist/mipro/index.mjs +84 -58
- package/dist/opro/index.cjs +130 -51
- package/dist/opro/index.d.cts +17 -9
- package/dist/opro/index.d.mts +17 -9
- package/dist/opro/index.mjs +115 -38
- package/dist/{optimizer-B7SpRwl7.d.cts → optimizer-Bh5DPRMH.d.cts} +50 -4
- package/dist/{optimizer-DqCoth_w.d.mts → optimizer-Ck6-e_8o.d.mts} +50 -4
- package/dist/random-search/index.cjs +93 -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 +83 -41
- package/dist/{reflection-CQToe-5B.d.cts → reflection-Dt3QrXhM.d.cts} +7 -11
- package/dist/{reflection-Cr_upzU0.d.mts → reflection-LRaAZP4e.d.mts} +7 -11
- package/dist/{evaluation-OZOp6TB7.cjs → reporting-CNHzbJC-.cjs} +165 -5
- package/dist/reporting-DQbAohc9.d.cts +240 -0
- package/dist/reporting-DQbAohc9.d.mts +240 -0
- package/dist/{evaluation-BV0nSZVx.mjs → reporting-DY-DC4HG.mjs} +124 -6
- package/dist/simba/index.cjs +210 -83
- package/dist/simba/index.d.cts +32 -11
- package/dist/simba/index.d.mts +32 -11
- package/dist/simba/index.mjs +200 -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/package.json +4 -3
- 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
package/dist/simba/index.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const
|
|
3
|
-
const
|
|
2
|
+
const require_reporting = require("../reporting-CNHzbJC-.cjs");
|
|
3
|
+
const require_concurrency = require("../concurrency-C-cFzWW2.cjs");
|
|
4
|
+
const require_demos = require("../demos-D2o0qSSo.cjs");
|
|
4
5
|
const require_rng = require("../rng-DbA_rPIo.cjs");
|
|
5
6
|
const require_sampling = require("../sampling-Dars7ctR.cjs");
|
|
6
7
|
//#region src/simba/advice.ts
|
|
@@ -15,7 +16,7 @@ const ADVICE_BLOCK = /<advice\s+component="([^"]+)"\s*>([\s\S]*?)<\/advice>/g;
|
|
|
15
16
|
* behaviour rather than to the instance being easier.
|
|
16
17
|
*/
|
|
17
18
|
function buildAdvicePrompt(args) {
|
|
18
|
-
const { components, input, better, worse } = args;
|
|
19
|
+
const { components, current, input, better, worse } = args;
|
|
19
20
|
return [
|
|
20
21
|
"Two runs of the same system on the same input are shown below, with the reward each earned.",
|
|
21
22
|
"Your job is to write advice that would make the system behave like the higher scoring run the next time it sees a similar input.",
|
|
@@ -26,12 +27,18 @@ function buildAdvicePrompt(args) {
|
|
|
26
27
|
...worse === void 0 ? [] : trajectoryBlock("worse", worse),
|
|
27
28
|
...better === void 0 ? [] : trajectoryBlock("better", better),
|
|
28
29
|
"",
|
|
29
|
-
"Write advice for each of these components:",
|
|
30
|
+
"Write advice for each of these components, shown with what it says now:",
|
|
30
31
|
"",
|
|
31
32
|
"<components>",
|
|
32
|
-
components.
|
|
33
|
+
components.map((component) => [
|
|
34
|
+
`<component name="${component}">`,
|
|
35
|
+
current[component] ?? "",
|
|
36
|
+
"</component>"
|
|
37
|
+
].join("\n")).join("\n"),
|
|
33
38
|
"</components>",
|
|
34
39
|
"",
|
|
40
|
+
"Your advice is appended to what the component already says. Do not restate advice it already carries; add what is missing or correct what is wrong.",
|
|
41
|
+
"",
|
|
35
42
|
"The component will not have access to this example, so advice that only covers this input is wasted. State the general behaviour it should adopt, and be concrete about when it applies.",
|
|
36
43
|
"Address each component's own sub-task rather than the system as a whole.",
|
|
37
44
|
"Base the advice on what actually differed between the two runs. If nothing useful can be said for a component, leave it out.",
|
|
@@ -229,21 +236,28 @@ const DEMO_DROP_SCALE = 3;
|
|
|
229
236
|
var SimbaOptimizer = class {
|
|
230
237
|
#config;
|
|
231
238
|
constructor(config = {}) {
|
|
239
|
+
assertSimbaConfig(config);
|
|
232
240
|
this.#config = config;
|
|
233
241
|
}
|
|
234
|
-
optimize(task) {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
242
|
+
async optimize(task) {
|
|
243
|
+
try {
|
|
244
|
+
return await run({
|
|
245
|
+
config: this.#config,
|
|
246
|
+
task
|
|
247
|
+
});
|
|
248
|
+
} finally {
|
|
249
|
+
await require_reporting.flushReporters(task.reporters ?? []);
|
|
250
|
+
}
|
|
239
251
|
}
|
|
240
252
|
};
|
|
241
253
|
async function run(args) {
|
|
242
254
|
const { config, task } = args;
|
|
243
|
-
const { minibatchSize = DEFAULT_MINIBATCH_SIZE, candidates: candidateCount = DEFAULT_CANDIDATES, maxSteps = DEFAULT_MAX_STEPS, maxDemos = DEFAULT_MAX_DEMOS, samplingTemperature = DEFAULT_TEMPERATURE, candidateTemperature = DEFAULT_TEMPERATURE, strategies, maxReflectionCalls, seed = 0, trackBestOutputs = false, checkpointCache = true } = config;
|
|
244
|
-
const { seedCandidate, trainingSet, validationSet = trainingSet, testSet, adapter, reflect, demoComponents = [], instructionComponents, renderDemo, buildAdvicePrompt: buildPrompt = buildAdvicePrompt, sampler = require_sampling.createEpochShuffledSampler({ minibatchSize }), maxMetricCalls, cache, cacheNamespace, retry, maxCostUsd, maxWallClockMs, instanceId = defaultInstanceId,
|
|
245
|
-
const
|
|
246
|
-
const
|
|
255
|
+
const { minibatchSize = DEFAULT_MINIBATCH_SIZE, candidates: candidateCount = DEFAULT_CANDIDATES, concurrency = 1, maxSteps = DEFAULT_MAX_STEPS, maxDemos = DEFAULT_MAX_DEMOS, samplingTemperature = DEFAULT_TEMPERATURE, candidateTemperature = DEFAULT_TEMPERATURE, strategies, maxReflectionCalls, seed = 0, trackBestOutputs = false, checkpointCache = true } = config;
|
|
256
|
+
const { seedCandidate, trainingSet, validationSet = trainingSet, testSet, adapter, reflect, demoComponents = [], instructionComponents, renderDemo, buildAdvicePrompt: buildPrompt = buildAdvicePrompt, sampler = require_sampling.createEpochShuffledSampler({ minibatchSize }), maxMetricCalls, cache, cacheNamespace, retry, maxCostUsd, maxWallClockMs, instanceId = require_reporting.defaultInstanceId, reporters = [], onCheckpoint, resumeFrom, signal } = task;
|
|
257
|
+
const emit = require_reporting.createEmitter(reporters);
|
|
258
|
+
const components = require_reporting.componentNames(seedCandidate);
|
|
259
|
+
const nonDemo = components.filter((name) => !demoComponents.includes(name));
|
|
260
|
+
const ruleComponents = instructionComponents ?? (nonDemo.length > 0 ? nonDemo : components);
|
|
247
261
|
const enabled = strategies ?? (demoComponents.length > 0 ? ["appendDemo", "appendRule"] : ["appendRule"]);
|
|
248
262
|
if (trainingSet.length === 0) throw new Error("optimize requires a non-empty trainingSet");
|
|
249
263
|
if (validationSet.length === 0) throw new Error("optimize requires a non-empty validationSet");
|
|
@@ -252,6 +266,10 @@ async function run(args) {
|
|
|
252
266
|
if (enabled.includes("appendDemo") && demoComponents.length === 0) throw new Error("the appendDemo strategy requires at least one entry in demoComponents");
|
|
253
267
|
if (enabled.includes("appendRule") && ruleComponents.length === 0) throw new Error("the appendRule strategy requires at least one instruction component to write into");
|
|
254
268
|
if (testSet !== void 0 && testSet.length === 0) throw new Error("optimize requires a non-empty testSet when one is given; omit it to skip held-out evaluation");
|
|
269
|
+
const trainingIds = trainingSet.map((datum, index) => instanceId({
|
|
270
|
+
datum,
|
|
271
|
+
index
|
|
272
|
+
}));
|
|
255
273
|
const validationIds = validationSet.map((datum, index) => instanceId({
|
|
256
274
|
datum,
|
|
257
275
|
index
|
|
@@ -260,28 +278,25 @@ async function run(args) {
|
|
|
260
278
|
datum,
|
|
261
279
|
index
|
|
262
280
|
})) ?? [];
|
|
263
|
-
const fingerprint =
|
|
281
|
+
const fingerprint = require_reporting.runFingerprint({
|
|
264
282
|
seedCandidate,
|
|
265
|
-
trainingIds
|
|
266
|
-
datum,
|
|
267
|
-
index
|
|
268
|
-
})),
|
|
283
|
+
trainingIds,
|
|
269
284
|
validationIds,
|
|
270
285
|
seed,
|
|
271
286
|
...cacheNamespace === void 0 ? {} : { cacheNamespace }
|
|
272
287
|
});
|
|
273
|
-
|
|
288
|
+
require_reporting.assertResumable({
|
|
274
289
|
fingerprint,
|
|
275
290
|
...resumeFrom === void 0 ? {} : { snapshot: resumeFrom }
|
|
276
291
|
});
|
|
277
|
-
const deadline =
|
|
292
|
+
const deadline = require_reporting.createDeadline({ maxWallClockMs });
|
|
278
293
|
const rng = require_rng.createSeededRng(seed, resumeFrom?.rngState);
|
|
279
|
-
const budget =
|
|
294
|
+
const budget = require_reporting.createBudget({
|
|
280
295
|
maxMetricCalls,
|
|
281
296
|
spent: resumeFrom?.metricCalls ?? 0
|
|
282
297
|
});
|
|
283
|
-
const evaluationCache = cache === false ? void 0 : cache ??
|
|
284
|
-
const evaluator =
|
|
298
|
+
const evaluationCache = cache === false ? void 0 : cache ?? require_reporting.createMemoryCache();
|
|
299
|
+
const evaluator = require_reporting.createEvaluator({
|
|
285
300
|
adapter,
|
|
286
301
|
budget,
|
|
287
302
|
...retry === void 0 ? {} : { retry },
|
|
@@ -289,8 +304,9 @@ async function run(args) {
|
|
|
289
304
|
...evaluationCache === void 0 ? {} : { cache: evaluationCache },
|
|
290
305
|
trackOutputs: true,
|
|
291
306
|
cacheHits: resumeFrom?.cacheHits ?? 0,
|
|
307
|
+
...resumeFrom?.usage === void 0 ? {} : { usage: resumeFrom.usage },
|
|
292
308
|
...signal === void 0 ? {} : { signal },
|
|
293
|
-
onEvaluation: (event) =>
|
|
309
|
+
onEvaluation: (event) => emit({
|
|
294
310
|
type: "evaluation",
|
|
295
311
|
...event
|
|
296
312
|
})
|
|
@@ -306,7 +322,7 @@ async function run(args) {
|
|
|
306
322
|
let step = resumeFrom?.step ?? 0;
|
|
307
323
|
let reflectionCalls = resumeFrom?.reflectionCalls ?? 0;
|
|
308
324
|
let stopReason = "maxSteps";
|
|
309
|
-
|
|
325
|
+
emit({
|
|
310
326
|
type: "start",
|
|
311
327
|
components,
|
|
312
328
|
validationSetSize: validationSet.length
|
|
@@ -318,7 +334,7 @@ async function run(args) {
|
|
|
318
334
|
stopReason = "aborted";
|
|
319
335
|
break;
|
|
320
336
|
}
|
|
321
|
-
if (
|
|
337
|
+
if (require_reporting.costExhausted({
|
|
322
338
|
usage: evaluator.usage(),
|
|
323
339
|
maxCostUsd
|
|
324
340
|
})) {
|
|
@@ -341,16 +357,17 @@ async function run(args) {
|
|
|
341
357
|
scores: programs.map((_, index) => averageScore(index)),
|
|
342
358
|
k: candidateCount
|
|
343
359
|
});
|
|
344
|
-
|
|
360
|
+
emit({
|
|
345
361
|
type: "stepStart",
|
|
346
362
|
step,
|
|
347
363
|
poolSize: pool.length
|
|
348
364
|
});
|
|
349
|
-
const
|
|
365
|
+
const batchIndices = sampler({
|
|
350
366
|
trainingSet,
|
|
351
367
|
iteration: step,
|
|
352
368
|
rng
|
|
353
|
-
})
|
|
369
|
+
});
|
|
370
|
+
const batch = batchIndices.map((index) => trainingSet[index]);
|
|
354
371
|
const samples = [];
|
|
355
372
|
for (let slot = 0; slot < candidateCount; slot += 1) {
|
|
356
373
|
const programIndex = softmaxSample({
|
|
@@ -372,7 +389,7 @@ async function run(args) {
|
|
|
372
389
|
outputs: evaluation.outputs,
|
|
373
390
|
...evaluation.feedback === void 0 ? {} : { feedback: evaluation.feedback }
|
|
374
391
|
});
|
|
375
|
-
programScores[programIndex].push(
|
|
392
|
+
programScores[programIndex].push(require_reporting.measuredMean(evaluation) ?? 0);
|
|
376
393
|
}
|
|
377
394
|
if (samples.length === 0) {
|
|
378
395
|
stopReason = "budgetExhausted";
|
|
@@ -412,7 +429,7 @@ async function run(args) {
|
|
|
412
429
|
high
|
|
413
430
|
});
|
|
414
431
|
} catch (err) {
|
|
415
|
-
|
|
432
|
+
emit({
|
|
416
433
|
type: "error",
|
|
417
434
|
step,
|
|
418
435
|
err
|
|
@@ -427,36 +444,54 @@ async function run(args) {
|
|
|
427
444
|
});
|
|
428
445
|
}
|
|
429
446
|
let stepBest;
|
|
447
|
+
const batchIds = batchIndices.map((index) => trainingIds[index]);
|
|
448
|
+
const scheduled = [];
|
|
449
|
+
let owed = 0;
|
|
430
450
|
for (const entry of built) {
|
|
431
|
-
if (!budget.canAfford(batch.length)) {
|
|
451
|
+
if (!budget.canAfford(owed + batch.length)) {
|
|
432
452
|
stopReason = "budgetExhausted";
|
|
433
453
|
break;
|
|
434
454
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
455
|
+
owed += evaluator.countUncached({
|
|
456
|
+
candidate: entry.candidate,
|
|
457
|
+
ids: batchIds,
|
|
458
|
+
split: "train"
|
|
459
|
+
});
|
|
460
|
+
scheduled.push(entry);
|
|
461
|
+
}
|
|
462
|
+
const poolBase = programs.length;
|
|
463
|
+
const scored = await mapDistinct({
|
|
464
|
+
items: scheduled,
|
|
465
|
+
limit: concurrency,
|
|
466
|
+
key: (entry) => require_reporting.candidateHash(entry.candidate),
|
|
467
|
+
task: async (entry, index) => {
|
|
468
|
+
try {
|
|
469
|
+
return { score: require_reporting.measuredMean(await evaluator.evaluate({
|
|
470
|
+
candidate: entry.candidate,
|
|
471
|
+
batch,
|
|
472
|
+
ids: batchIds,
|
|
473
|
+
split: "train",
|
|
474
|
+
phase: "minibatch",
|
|
475
|
+
candidateId: poolBase + index,
|
|
476
|
+
iteration: step
|
|
477
|
+
})) };
|
|
478
|
+
} catch (err) {
|
|
479
|
+
if (err instanceof require_reporting.BudgetExhausted) return { stop: true };
|
|
480
|
+
throw err;
|
|
453
481
|
}
|
|
454
|
-
throw err;
|
|
455
482
|
}
|
|
483
|
+
});
|
|
484
|
+
for (const [index, outcome] of scored.entries()) {
|
|
485
|
+
if (outcome.stop === true) {
|
|
486
|
+
stopReason = "budgetExhausted";
|
|
487
|
+
break;
|
|
488
|
+
}
|
|
489
|
+
const { score } = outcome;
|
|
456
490
|
if (score === void 0) continue;
|
|
491
|
+
const entry = scheduled[index];
|
|
457
492
|
programs.push(entry.candidate);
|
|
458
493
|
programScores.push([score]);
|
|
459
|
-
|
|
494
|
+
emit({
|
|
460
495
|
type: "candidate",
|
|
461
496
|
step,
|
|
462
497
|
strategy: entry.strategy,
|
|
@@ -479,38 +514,78 @@ async function run(args) {
|
|
|
479
514
|
}
|
|
480
515
|
}
|
|
481
516
|
if (signal?.aborted) stopReason = "aborted";
|
|
482
|
-
const
|
|
517
|
+
const contenders = [];
|
|
518
|
+
let owedForFinalists = 0;
|
|
483
519
|
for (const index of evenlySpacedIndices({
|
|
484
520
|
length: winners.length,
|
|
485
521
|
count: candidateCount + 1
|
|
486
522
|
})) {
|
|
487
523
|
const winner = winners[index];
|
|
488
|
-
|
|
524
|
+
const uncached = evaluator.countUncached({
|
|
489
525
|
candidate: winner.candidate,
|
|
490
526
|
ids: validationIds,
|
|
491
527
|
split: "val"
|
|
492
|
-
})
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
batch: validationSet,
|
|
498
|
-
ids: validationIds,
|
|
499
|
-
split: "val",
|
|
500
|
-
phase: index === 0 ? "seed" : "validation",
|
|
501
|
-
candidateId: index,
|
|
502
|
-
iteration: step
|
|
503
|
-
}));
|
|
504
|
-
} catch (err) {
|
|
505
|
-
if (err instanceof require_evaluation.BudgetExhausted || signal?.aborted) break;
|
|
506
|
-
throw err;
|
|
507
|
-
}
|
|
508
|
-
if (score !== void 0) finalists.push({
|
|
528
|
+
});
|
|
529
|
+
if (!budget.canAfford(owedForFinalists + uncached)) break;
|
|
530
|
+
owedForFinalists += uncached;
|
|
531
|
+
contenders.push({
|
|
532
|
+
index,
|
|
509
533
|
candidate: winner.candidate,
|
|
510
|
-
score,
|
|
511
534
|
step: winner.step
|
|
512
535
|
});
|
|
513
536
|
}
|
|
537
|
+
const sweeps = await mapDistinct({
|
|
538
|
+
items: contenders,
|
|
539
|
+
limit: concurrency,
|
|
540
|
+
key: (contender) => require_reporting.candidateHash(contender.candidate),
|
|
541
|
+
task: async (contender) => {
|
|
542
|
+
if (signal?.aborted) return { stop: true };
|
|
543
|
+
try {
|
|
544
|
+
const evaluation = await evaluator.evaluate({
|
|
545
|
+
candidate: contender.candidate,
|
|
546
|
+
batch: validationSet,
|
|
547
|
+
ids: validationIds,
|
|
548
|
+
split: "val",
|
|
549
|
+
phase: contender.index === 0 ? "seed" : "validation",
|
|
550
|
+
candidateId: contender.index,
|
|
551
|
+
iteration: step
|
|
552
|
+
});
|
|
553
|
+
return {
|
|
554
|
+
score: require_reporting.measuredMean(evaluation),
|
|
555
|
+
evaluation
|
|
556
|
+
};
|
|
557
|
+
} catch (err) {
|
|
558
|
+
if (err instanceof require_reporting.BudgetExhausted || signal?.aborted) return { stop: true };
|
|
559
|
+
throw err;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
const finalists = [];
|
|
564
|
+
let acceptedCandidates = -1;
|
|
565
|
+
let acceptedScore = Number.NEGATIVE_INFINITY;
|
|
566
|
+
for (const [position, outcome] of sweeps.entries()) {
|
|
567
|
+
if (outcome.stop === true) break;
|
|
568
|
+
if (outcome.score === void 0) continue;
|
|
569
|
+
const contender = contenders[position];
|
|
570
|
+
finalists.push({
|
|
571
|
+
candidate: contender.candidate,
|
|
572
|
+
score: outcome.score,
|
|
573
|
+
step: contender.step
|
|
574
|
+
});
|
|
575
|
+
if (outcome.score > acceptedScore) {
|
|
576
|
+
acceptedScore = outcome.score;
|
|
577
|
+
acceptedCandidates += 1;
|
|
578
|
+
emit({
|
|
579
|
+
type: "candidateAccepted",
|
|
580
|
+
step: contender.step,
|
|
581
|
+
candidateId: acceptedCandidates,
|
|
582
|
+
candidate: contender.candidate,
|
|
583
|
+
aggregateScore: outcome.score,
|
|
584
|
+
instanceScores: require_reporting.instanceRow(outcome.evaluation),
|
|
585
|
+
...trackBestOutputs ? { outputs: outcome.evaluation.outputs } : {}
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
}
|
|
514
589
|
const seedScore = finalists[0]?.score ?? 0;
|
|
515
590
|
finalists.sort((a, b) => b.score - a.score);
|
|
516
591
|
const best = finalists[0] ?? {
|
|
@@ -526,7 +601,7 @@ async function run(args) {
|
|
|
526
601
|
candidateId: null,
|
|
527
602
|
iteration: step
|
|
528
603
|
}))?.outputs;
|
|
529
|
-
const
|
|
604
|
+
const heldOut = testSet === void 0 ? void 0 : await evaluator.evaluate({
|
|
530
605
|
candidate: best.candidate,
|
|
531
606
|
batch: testSet,
|
|
532
607
|
ids: testIds,
|
|
@@ -535,13 +610,17 @@ async function run(args) {
|
|
|
535
610
|
candidateId: null,
|
|
536
611
|
iteration: step,
|
|
537
612
|
charge: false
|
|
538
|
-
})
|
|
539
|
-
|
|
613
|
+
});
|
|
614
|
+
const testScore = heldOut === void 0 ? void 0 : require_reporting.measuredMean(heldOut);
|
|
615
|
+
emit({
|
|
540
616
|
type: "finish",
|
|
541
617
|
reason: stopReason,
|
|
618
|
+
bestCandidateId: acceptedCandidates,
|
|
542
619
|
bestScore: best.score,
|
|
543
620
|
metricCalls: budget.spent(),
|
|
544
|
-
...testScore === void 0 ? {} : { testScore }
|
|
621
|
+
...testScore === void 0 ? {} : { testScore },
|
|
622
|
+
...heldOut === void 0 ? {} : { testInstanceScores: require_reporting.instanceRow(heldOut) },
|
|
623
|
+
...heldOut === void 0 || !trackBestOutputs ? {} : { testOutputs: heldOut.outputs }
|
|
545
624
|
});
|
|
546
625
|
return {
|
|
547
626
|
bestCandidate: best.candidate,
|
|
@@ -557,7 +636,8 @@ async function run(args) {
|
|
|
557
636
|
...bestOutputs === void 0 ? {} : { bestOutputs },
|
|
558
637
|
...testScore === void 0 ? {} : {
|
|
559
638
|
testScore,
|
|
560
|
-
testMetricCalls:
|
|
639
|
+
testMetricCalls: evaluator.unchargedCalls(),
|
|
640
|
+
testUsage: evaluator.unchargedUsage()
|
|
561
641
|
},
|
|
562
642
|
stopReason
|
|
563
643
|
};
|
|
@@ -594,7 +674,11 @@ async function run(args) {
|
|
|
594
674
|
const drops = /* @__PURE__ */ new Set();
|
|
595
675
|
for (let draw = 0; draw < Math.min(wanted, held); draw += 1) drops.add(rng.nextInt(held));
|
|
596
676
|
const next = { ...candidate };
|
|
597
|
-
for (const [name, demos] of blocks) next[name] = require_demos.
|
|
677
|
+
for (const [name, demos] of blocks) next[name] = require_demos.replaceDemos({
|
|
678
|
+
text: next[name] ?? "",
|
|
679
|
+
demos: demos.filter((_, index) => !drops.has(index)),
|
|
680
|
+
...renderDemo === void 0 ? {} : { render: renderDemo }
|
|
681
|
+
});
|
|
598
682
|
return next;
|
|
599
683
|
}
|
|
600
684
|
/**
|
|
@@ -615,8 +699,12 @@ async function run(args) {
|
|
|
615
699
|
};
|
|
616
700
|
const next = { ...candidate };
|
|
617
701
|
for (const name of demoComponents) {
|
|
618
|
-
const
|
|
619
|
-
next[name] = require_demos.
|
|
702
|
+
const text = next[name] ?? "";
|
|
703
|
+
next[name] = require_demos.replaceDemos({
|
|
704
|
+
text,
|
|
705
|
+
demos: [...require_demos.parseDemos(text), demo],
|
|
706
|
+
...renderDemo === void 0 ? {} : { render: renderDemo }
|
|
707
|
+
});
|
|
620
708
|
}
|
|
621
709
|
return next;
|
|
622
710
|
}
|
|
@@ -644,6 +732,7 @@ async function run(args) {
|
|
|
644
732
|
const response = await reflect({
|
|
645
733
|
prompt: buildPrompt({
|
|
646
734
|
components: ruleComponents,
|
|
735
|
+
current: Object.fromEntries(ruleComponents.map((name) => [name, candidate[name] ?? ""])),
|
|
647
736
|
input: bucket.datum,
|
|
648
737
|
...better === void 0 ? {} : { better },
|
|
649
738
|
...worse === void 0 ? {} : { worse }
|
|
@@ -684,6 +773,7 @@ async function run(args) {
|
|
|
684
773
|
metricCalls: budget.spent(),
|
|
685
774
|
reflectionCalls,
|
|
686
775
|
cacheHits: evaluator.cacheHits(),
|
|
776
|
+
usage: evaluator.usage(),
|
|
687
777
|
rngState: rng.state(),
|
|
688
778
|
...sampler.state === void 0 ? {} : { sampler: sampler.state() },
|
|
689
779
|
...cached === void 0 ? {} : { cache: cached }
|
|
@@ -694,14 +784,51 @@ async function run(args) {
|
|
|
694
784
|
await onCheckpoint(takeSnapshot(completed));
|
|
695
785
|
}
|
|
696
786
|
}
|
|
697
|
-
|
|
698
|
-
|
|
787
|
+
/**
|
|
788
|
+
* Runs `items` concurrently, except that items sharing a key run one after the
|
|
789
|
+
* other.
|
|
790
|
+
*
|
|
791
|
+
* Two identical candidates cost one evaluation and one cache hit when they are
|
|
792
|
+
* scored in sequence, and two evaluations when they overlap: the cache is only
|
|
793
|
+
* written once a rollout returns. Serializing the duplicates is what keeps a
|
|
794
|
+
* fan-out from buying a second copy of a score the run has already paid for.
|
|
795
|
+
*/
|
|
796
|
+
async function mapDistinct(args) {
|
|
797
|
+
const { items, limit, key, task } = args;
|
|
798
|
+
const groups = /* @__PURE__ */ new Map();
|
|
799
|
+
items.forEach((item, index) => {
|
|
800
|
+
const group = groups.get(key(item));
|
|
801
|
+
if (group === void 0) {
|
|
802
|
+
groups.set(key(item), [index]);
|
|
803
|
+
return;
|
|
804
|
+
}
|
|
805
|
+
group.push(index);
|
|
806
|
+
});
|
|
807
|
+
const results = new Array(items.length);
|
|
808
|
+
await require_concurrency.mapWithConcurrency({
|
|
809
|
+
items: [...groups.values()],
|
|
810
|
+
limit,
|
|
811
|
+
task: async (indices) => {
|
|
812
|
+
for (const index of indices) results[index] = await task(items[index], index);
|
|
813
|
+
}
|
|
814
|
+
});
|
|
815
|
+
return results;
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Range checks on the search knobs, run at construction so a configuration
|
|
819
|
+
* that could never terminate is refused before a task is ever handed to it.
|
|
820
|
+
*/
|
|
821
|
+
function assertSimbaConfig(config) {
|
|
822
|
+
const { concurrency = 1 } = config;
|
|
823
|
+
if (!Number.isInteger(concurrency) || concurrency < 1) throw new Error(`concurrency must be a positive integer, received ${concurrency}`);
|
|
699
824
|
}
|
|
700
825
|
//#endregion
|
|
701
826
|
exports.SimbaOptimizer = SimbaOptimizer;
|
|
702
827
|
exports.buildAdvicePrompt = buildAdvicePrompt;
|
|
703
828
|
exports.buildBuckets = buildBuckets;
|
|
704
829
|
exports.evenlySpacedIndices = evenlySpacedIndices;
|
|
830
|
+
exports.isCandidateAccepted = require_reporting.isCandidateAccepted;
|
|
831
|
+
exports.isRunFinished = require_reporting.isRunFinished;
|
|
705
832
|
exports.parseAdvice = parseAdvice;
|
|
706
833
|
exports.percentile = percentile;
|
|
707
834
|
exports.samplePoisson = samplePoisson;
|
package/dist/simba/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as TextModel, a as RunFinished, c as Adapter, i as Reporter, l as Candidate, n as OptimizerEvent, o as isCandidateAccepted, r as ReportableEvent, s as isRunFinished, t as CandidateAccepted, v as UsageTotals } from "../reporting-DQbAohc9.cjs";
|
|
2
2
|
import { n as EvaluationCache, t as CachedScore } from "../cache-CuSo0NJ8.cjs";
|
|
3
3
|
import { t as Rng } from "../rng-BR5MOedA.cjs";
|
|
4
|
-
import { r as DemoRenderer } from "../demos-
|
|
5
|
-
import { n as OptimizerResult, r as OptimizerTask, s as EvaluationEvent, t as Optimizer } from "../optimizer-
|
|
4
|
+
import { r as DemoRenderer } from "../demos-CU9dy2oT.cjs";
|
|
5
|
+
import { n as OptimizerResult, r as OptimizerTask, s as EvaluationEvent, t as Optimizer } from "../optimizer-Bh5DPRMH.cjs";
|
|
6
6
|
import { t as BatchSampler } from "../sampling-axOwfZf5.cjs";
|
|
7
7
|
//#region src/simba/advice.d.ts
|
|
8
8
|
interface AdviceTrajectory<Output = unknown> {
|
|
@@ -13,6 +13,12 @@ interface AdviceTrajectory<Output = unknown> {
|
|
|
13
13
|
interface AdvicePromptArgs<Datum = unknown, Output = unknown> {
|
|
14
14
|
/** Components the advice is wanted for, named so each can be addressed. */
|
|
15
15
|
components: readonly string[];
|
|
16
|
+
/**
|
|
17
|
+
* What each of those components currently says. Advice is appended to this
|
|
18
|
+
* text rather than replacing it, so a proposer that cannot see it writes
|
|
19
|
+
* blind: it restates what is already there, and cannot correct it.
|
|
20
|
+
*/
|
|
21
|
+
current: Record<string, string>;
|
|
16
22
|
input: Datum;
|
|
17
23
|
/** The higher scoring run of this instance, when there is one to contrast. */
|
|
18
24
|
better?: AdviceTrajectory<Output>;
|
|
@@ -56,6 +62,17 @@ interface SimbaConfig {
|
|
|
56
62
|
minibatchSize?: number;
|
|
57
63
|
/** Programs sampled per step, and candidates built from them. Default 6. */
|
|
58
64
|
candidates?: number;
|
|
65
|
+
/**
|
|
66
|
+
* How many evaluations may be in flight at once. Default 1.
|
|
67
|
+
*
|
|
68
|
+
* Covers the two places a step's work is independent — scoring the
|
|
69
|
+
* candidates a step built, and sweeping the finalists at the end of the run
|
|
70
|
+
* — and nothing else. The trajectory samples and the mutations that read
|
|
71
|
+
* them are deliberately left in sequence: each of those reads state the one
|
|
72
|
+
* before it wrote, so overlapping them would make a seeded run depend on
|
|
73
|
+
* which call returned first.
|
|
74
|
+
*/
|
|
75
|
+
concurrency?: number;
|
|
59
76
|
/** Steps to run. Default 8. */
|
|
60
77
|
maxSteps?: number;
|
|
61
78
|
/** Demos a candidate may hold before the loop starts dropping them. Default 4. */
|
|
@@ -97,6 +114,8 @@ interface SimbaSnapshot {
|
|
|
97
114
|
metricCalls: number;
|
|
98
115
|
reflectionCalls: number;
|
|
99
116
|
cacheHits: number;
|
|
117
|
+
/** Usage already spent, so a resumed run reports totals and honours ceilings. */
|
|
118
|
+
usage?: UsageTotals;
|
|
100
119
|
rngState: number;
|
|
101
120
|
sampler?: unknown;
|
|
102
121
|
cache?: [string, CachedScore][];
|
|
@@ -121,7 +140,8 @@ interface SimbaTask<Datum, Trajectory = unknown, Output = unknown, K extends str
|
|
|
121
140
|
index: number;
|
|
122
141
|
}) => string;
|
|
123
142
|
cache?: EvaluationCache | false;
|
|
124
|
-
|
|
143
|
+
/** Observers of the run. Every one sees every event; none can fail it. */
|
|
144
|
+
reporters?: readonly Reporter<SimbaEvent<NoInfer<K>>>[];
|
|
125
145
|
onCheckpoint?: (snapshot: SimbaSnapshot) => void | Promise<void>;
|
|
126
146
|
resumeFrom?: SimbaSnapshot;
|
|
127
147
|
}
|
|
@@ -143,17 +163,18 @@ type SimbaEvent<K extends string = string> = {
|
|
|
143
163
|
/** The program it was mutated from; 0 is the seed. */
|
|
144
164
|
sourceProgram: number;
|
|
145
165
|
minibatchScore: number;
|
|
146
|
-
} | {
|
|
166
|
+
} | ({
|
|
167
|
+
type: "candidateAccepted";
|
|
168
|
+
/** The step whose winner this was. */
|
|
169
|
+
step: number;
|
|
170
|
+
} & CandidateAccepted<K>) | {
|
|
147
171
|
type: "error";
|
|
148
172
|
step: number;
|
|
149
173
|
err: unknown;
|
|
150
|
-
} | {
|
|
174
|
+
} | ({
|
|
151
175
|
type: "finish";
|
|
152
176
|
reason: SimbaStopReason;
|
|
153
|
-
|
|
154
|
-
metricCalls: number;
|
|
155
|
-
testScore?: number;
|
|
156
|
-
};
|
|
177
|
+
} & RunFinished);
|
|
157
178
|
interface SimbaResult<K extends string = string, Output = unknown> extends OptimizerResult<K, SimbaStopReason, Output> {
|
|
158
179
|
/** The seed's own validation score, so the lift the run bought is readable. */
|
|
159
180
|
seedScore: number;
|
|
@@ -286,4 +307,4 @@ declare function evenlySpacedIndices(args: {
|
|
|
286
307
|
count: number;
|
|
287
308
|
}): number[];
|
|
288
309
|
//#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 };
|
|
310
|
+
export { type AdvicePromptArgs, type AdvicePromptBuilder, type AdviceTrajectory, type CandidateAccepted, type OptimizerEvent, type ReportableEvent, type Reporter, type RunFinished, 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, isCandidateAccepted, isRunFinished, parseAdvice, percentile, samplePoisson, softmaxWeights, topKPlusBaseline };
|