@tangle-network/agent-eval 0.123.2 → 0.123.4
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/CHANGELOG.md +25 -0
- package/README.md +48 -4
- package/dist/analyst/index.d.ts +18 -3
- package/dist/analyst/index.js +5 -5
- package/dist/benchmarks/index.d.ts +10 -3
- package/dist/benchmarks/index.js +7 -7
- package/dist/campaign/index.d.ts +277 -250
- package/dist/campaign/index.js +20 -16
- package/dist/{chunk-EBDOTTZJ.js → chunk-4KO6D2BO.js} +3 -3
- package/dist/{chunk-3FCG7FBV.js → chunk-D5JZ7UDZ.js} +2 -2
- package/dist/{chunk-BGVTIE2C.js → chunk-GRCDRKII.js} +13 -2
- package/dist/chunk-GRCDRKII.js.map +1 -0
- package/dist/{chunk-FHFTYX2Q.js → chunk-JKDNAOF5.js} +2 -2
- package/dist/{chunk-RQP5UTK5.js → chunk-LT4J7ULK.js} +710 -359
- package/dist/chunk-LT4J7ULK.js.map +1 -0
- package/dist/{chunk-WXQTVEKM.js → chunk-MHPEGJHC.js} +3 -3
- package/dist/{chunk-J7S4YM27.js → chunk-MK3Q6GCL.js} +28 -14
- package/dist/chunk-MK3Q6GCL.js.map +1 -0
- package/dist/{chunk-DNVPOYUS.js → chunk-N7ZS6PEF.js} +2 -2
- package/dist/{chunk-4SOQ4ND2.js → chunk-QFQZ3U3X.js} +1 -1
- package/dist/chunk-QFQZ3U3X.js.map +1 -0
- package/dist/{chunk-WMJR67FX.js → chunk-QNVBALEX.js} +4 -4
- package/dist/{chunk-E3HAD4A3.js → chunk-SJT4OBVL.js} +2 -2
- package/dist/{chunk-HQY7LBV2.js → chunk-SUN7QLPB.js} +6 -6
- package/dist/{chunk-HQY7LBV2.js.map → chunk-SUN7QLPB.js.map} +1 -1
- package/dist/{chunk-5YMKIFYP.js → chunk-WP3GEXKI.js} +3 -3
- package/dist/cli.js +3 -3
- package/dist/contract/index.d.ts +18 -3
- package/dist/contract/index.js +7 -7
- package/dist/fuzz.d.ts +8 -1
- package/dist/fuzz.js +4 -4
- package/dist/index.d.ts +27 -9
- package/dist/index.js +14 -12
- package/dist/index.js.map +1 -1
- package/dist/multishot/index.d.ts +2 -2
- package/dist/openapi.json +1 -1
- package/dist/rl.d.ts +15 -2
- package/dist/rl.js +4 -2
- package/dist/rl.js.map +1 -1
- package/dist/{run-campaign-ZKR5MQMQ.js → run-campaign-I3JXKVAK.js} +3 -3
- package/dist/traces.d.ts +2 -2
- package/dist/traces.js +1 -1
- package/dist/wire/index.d.ts +16 -1
- package/dist/wire/index.js +3 -3
- package/docs/campaign-proposers.md +142 -131
- package/docs/concepts.md +30 -34
- package/docs/design/loop-taxonomy.md +2 -3
- package/docs/design.md +0 -1
- package/docs/multi-shot-optimization.md +41 -49
- package/package.json +1 -1
- package/dist/chunk-4SOQ4ND2.js.map +0 -1
- package/dist/chunk-BGVTIE2C.js.map +0 -1
- package/dist/chunk-J7S4YM27.js.map +0 -1
- package/dist/chunk-RQP5UTK5.js.map +0 -1
- package/docs/improvement-glossary.md +0 -204
- package/docs/self-improvement-map.md +0 -115
- /package/dist/{chunk-EBDOTTZJ.js.map → chunk-4KO6D2BO.js.map} +0 -0
- /package/dist/{chunk-3FCG7FBV.js.map → chunk-D5JZ7UDZ.js.map} +0 -0
- /package/dist/{chunk-FHFTYX2Q.js.map → chunk-JKDNAOF5.js.map} +0 -0
- /package/dist/{chunk-WXQTVEKM.js.map → chunk-MHPEGJHC.js.map} +0 -0
- /package/dist/{chunk-DNVPOYUS.js.map → chunk-N7ZS6PEF.js.map} +0 -0
- /package/dist/{chunk-WMJR67FX.js.map → chunk-QNVBALEX.js.map} +0 -0
- /package/dist/{chunk-E3HAD4A3.js.map → chunk-SJT4OBVL.js.map} +0 -0
- /package/dist/{chunk-5YMKIFYP.js.map → chunk-WP3GEXKI.js.map} +0 -0
- /package/dist/{run-campaign-ZKR5MQMQ.js.map → run-campaign-I3JXKVAK.js.map} +0 -0
|
@@ -15,12 +15,13 @@ import {
|
|
|
15
15
|
runImprovementLoop,
|
|
16
16
|
surfaceContentHash,
|
|
17
17
|
surfaceHash
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-SUN7QLPB.js";
|
|
19
19
|
import {
|
|
20
20
|
SearchLedgerConflictError,
|
|
21
21
|
SearchLedgerError,
|
|
22
22
|
SearchLedgerIntegrityError,
|
|
23
23
|
appendSearchLedgerLine,
|
|
24
|
+
assertCampaignDesign,
|
|
24
25
|
assertRealBackend,
|
|
25
26
|
canonicalJson,
|
|
26
27
|
contentHash,
|
|
@@ -33,13 +34,12 @@ import {
|
|
|
33
34
|
summarizeBackendIntegrity,
|
|
34
35
|
tryAcquireAtomicFileLock,
|
|
35
36
|
withSearchLedgerFileLock
|
|
36
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-D5JZ7UDZ.js";
|
|
37
38
|
import {
|
|
38
39
|
AnalystRegistry,
|
|
39
40
|
DEFAULT_TRACE_ANALYST_KINDS,
|
|
40
41
|
Mutex,
|
|
41
42
|
POLICY_EDIT_AXES,
|
|
42
|
-
POLICY_EDIT_TARGET_SURFACES,
|
|
43
43
|
admitPolicyEdit,
|
|
44
44
|
applyPolicyEditToSurface,
|
|
45
45
|
assertNoJudgeVerdict,
|
|
@@ -51,14 +51,14 @@ import {
|
|
|
51
51
|
mapConcurrent,
|
|
52
52
|
policyEditsFromFindings,
|
|
53
53
|
validatePolicyEditCandidateRecord
|
|
54
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-MHPEGJHC.js";
|
|
55
55
|
import {
|
|
56
56
|
callLlm,
|
|
57
57
|
callLlmJson,
|
|
58
58
|
costReceiptFromLlm,
|
|
59
59
|
costReceiptFromLlmError,
|
|
60
60
|
maximumChargeForLlmRequest
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-MK3Q6GCL.js";
|
|
62
62
|
import {
|
|
63
63
|
eProcess,
|
|
64
64
|
mcnemar,
|
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
import {
|
|
71
71
|
CostAccountingIncompleteError,
|
|
72
72
|
CostLedger
|
|
73
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-GRCDRKII.js";
|
|
74
74
|
import {
|
|
75
75
|
analyzeTraces
|
|
76
76
|
} from "./chunk-NUKSVU3W.js";
|
|
@@ -3404,56 +3404,509 @@ function snippet(s, max = 120) {
|
|
|
3404
3404
|
return t.length <= max ? t : `${t.slice(0, max)}\u2026`;
|
|
3405
3405
|
}
|
|
3406
3406
|
|
|
3407
|
+
// src/campaign/presets/compare-optimization-methods.ts
|
|
3408
|
+
import { randomUUID } from "crypto";
|
|
3409
|
+
async function compareOptimizationMethods(opts) {
|
|
3410
|
+
assertOptimizationMethods(opts.methods);
|
|
3411
|
+
assertComparisonPartitions(opts);
|
|
3412
|
+
const seed = opts.seed ?? 42;
|
|
3413
|
+
const confidence = opts.confidence ?? 0.95;
|
|
3414
|
+
assertConfidence(confidence);
|
|
3415
|
+
const optimizationConcurrency = opts.optimizationConcurrency ?? 1;
|
|
3416
|
+
const comparisonCount = opts.methods.length * (opts.methods.length + 1) / 2;
|
|
3417
|
+
const intervalConfidence = 1 - (1 - confidence) / comparisonCount;
|
|
3418
|
+
const minimumResamples = minimumBootstrapResamples(confidence, comparisonCount);
|
|
3419
|
+
const resamples = opts.resamples ?? Math.max(2e3, minimumResamples);
|
|
3420
|
+
assertComparisonControls(opts, seed, resamples, confidence);
|
|
3421
|
+
const storage = opts.storage ?? fsCampaignStorage();
|
|
3422
|
+
const resolvedRunDir = resolveRunDir(opts.runDir, opts.repo);
|
|
3423
|
+
const testCostPhase = `compareOptimizationMethods:test:${randomUUID()}`;
|
|
3424
|
+
const testCostLedger = opts.costLedger ?? createRunCostLedger({
|
|
3425
|
+
storage,
|
|
3426
|
+
runDir: `${resolvedRunDir}/test/cost`,
|
|
3427
|
+
costCeilingUsd: opts.costCeiling
|
|
3428
|
+
});
|
|
3429
|
+
const scoreOnTest = async (surface, tag) => {
|
|
3430
|
+
const campaign = await runCampaign({
|
|
3431
|
+
...opts,
|
|
3432
|
+
storage,
|
|
3433
|
+
costLedger: testCostLedger,
|
|
3434
|
+
costPhase: testCostPhase,
|
|
3435
|
+
scenarios: opts.testScenarios.map((scenario) => structuredClone(scenario)),
|
|
3436
|
+
dispatch: (scenario, ctx) => opts.dispatchWithSurface(surface, scenario, ctx),
|
|
3437
|
+
runDir: `${resolvedRunDir}/${tag}`
|
|
3438
|
+
});
|
|
3439
|
+
const byScenario = {};
|
|
3440
|
+
for (const { scenarioId, composite } of campaignBreakdown(campaign).scenarios) {
|
|
3441
|
+
byScenario[scenarioId] = composite;
|
|
3442
|
+
}
|
|
3443
|
+
return byScenario;
|
|
3444
|
+
};
|
|
3445
|
+
const scenarioIds = opts.testScenarios.map((s) => s.id).sort();
|
|
3446
|
+
const align = (byScenario, label) => {
|
|
3447
|
+
const missing = scenarioIds.filter((id) => !(id in byScenario));
|
|
3448
|
+
if (missing.length > 0) {
|
|
3449
|
+
throw new Error(
|
|
3450
|
+
`compareOptimizationMethods: ${label} produced no test score for scenario(s) [${missing.join(
|
|
3451
|
+
", "
|
|
3452
|
+
)}]. A cell failed or its judges returned nothing. Fix the dispatch or judge; the comparison will not replace missing scores with zero.`
|
|
3453
|
+
);
|
|
3454
|
+
}
|
|
3455
|
+
return scenarioIds.map((id) => byScenario[id]);
|
|
3456
|
+
};
|
|
3457
|
+
const optimized = await mapConcurrent(opts.methods, optimizationConcurrency, async (method) => {
|
|
3458
|
+
const out = await method.optimize(
|
|
3459
|
+
createOptimizationMethodInput(opts, method.name, resolvedRunDir, seed)
|
|
3460
|
+
);
|
|
3461
|
+
assertOptimizationResult(method.name, out);
|
|
3462
|
+
const winnerSurface = structuredClone(out.winnerSurface);
|
|
3463
|
+
return {
|
|
3464
|
+
name: method.name,
|
|
3465
|
+
winnerSurface,
|
|
3466
|
+
cost: out.cost,
|
|
3467
|
+
durationMs: out.durationMs
|
|
3468
|
+
};
|
|
3469
|
+
});
|
|
3470
|
+
const baselineArr = align(await scoreOnTest(opts.baselineSurface, "test/baseline"), "baseline");
|
|
3471
|
+
const testScoresBySurface = /* @__PURE__ */ new Map([[surfaceContentHash(opts.baselineSurface), baselineArr]]);
|
|
3472
|
+
const winners = [];
|
|
3473
|
+
for (const winner of optimized) {
|
|
3474
|
+
const surfaceKey = surfaceContentHash(winner.winnerSurface);
|
|
3475
|
+
let arr = testScoresBySurface.get(surfaceKey);
|
|
3476
|
+
if (!arr) {
|
|
3477
|
+
const byScenario = await scoreOnTest(
|
|
3478
|
+
winner.winnerSurface,
|
|
3479
|
+
`test/methods/${slug(winner.name)}`
|
|
3480
|
+
);
|
|
3481
|
+
arr = align(byScenario, `method "${winner.name}"`);
|
|
3482
|
+
testScoresBySurface.set(surfaceKey, arr);
|
|
3483
|
+
}
|
|
3484
|
+
winners.push({
|
|
3485
|
+
...winner,
|
|
3486
|
+
arr
|
|
3487
|
+
});
|
|
3488
|
+
}
|
|
3489
|
+
const scores = winners.map((w) => {
|
|
3490
|
+
const boot = pairedBootstrap(baselineArr, w.arr, {
|
|
3491
|
+
seed,
|
|
3492
|
+
resamples,
|
|
3493
|
+
confidence: intervalConfidence,
|
|
3494
|
+
statistic: "mean"
|
|
3495
|
+
});
|
|
3496
|
+
const score = {
|
|
3497
|
+
name: w.name,
|
|
3498
|
+
baselineComposite: mean2(baselineArr),
|
|
3499
|
+
winnerComposite: mean2(w.arr),
|
|
3500
|
+
lift: boot.mean,
|
|
3501
|
+
liftCi: { low: boot.low, high: boot.high },
|
|
3502
|
+
optimizationCost: w.cost,
|
|
3503
|
+
scenarioScores: scenarioIds.map((scenarioId, index) => ({
|
|
3504
|
+
scenarioId,
|
|
3505
|
+
baselineComposite: baselineArr[index],
|
|
3506
|
+
winnerComposite: w.arr[index],
|
|
3507
|
+
lift: w.arr[index] - baselineArr[index]
|
|
3508
|
+
})),
|
|
3509
|
+
winnerSurface: w.winnerSurface,
|
|
3510
|
+
rank: 0
|
|
3511
|
+
};
|
|
3512
|
+
if (w.durationMs !== void 0) score.durationMs = w.durationMs;
|
|
3513
|
+
return score;
|
|
3514
|
+
});
|
|
3515
|
+
scores.sort((a, b) => b.lift - a.lift);
|
|
3516
|
+
for (let start = 0; start < scores.length; ) {
|
|
3517
|
+
let end = start + 1;
|
|
3518
|
+
while (end < scores.length && scores[end].lift === scores[start].lift) end += 1;
|
|
3519
|
+
const tied = scores.slice(start, end);
|
|
3520
|
+
if (tied.every((score) => score.optimizationCost.accountingComplete)) {
|
|
3521
|
+
tied.sort((a, b) => a.optimizationCost.totalCostUsd - b.optimizationCost.totalCostUsd);
|
|
3522
|
+
scores.splice(start, tied.length, ...tied);
|
|
3523
|
+
}
|
|
3524
|
+
start = end;
|
|
3525
|
+
}
|
|
3526
|
+
scores.forEach((s, i) => {
|
|
3527
|
+
s.rank = i + 1;
|
|
3528
|
+
});
|
|
3529
|
+
const best = scores[0];
|
|
3530
|
+
const byName = new Map(winners.map((w) => [w.name, w]));
|
|
3531
|
+
const bestArr = byName.get(best.name).arr;
|
|
3532
|
+
const pairwise = scores.slice(1).map((other) => {
|
|
3533
|
+
const otherArr = byName.get(other.name).arr;
|
|
3534
|
+
const boot = pairedBootstrap(otherArr, bestArr, {
|
|
3535
|
+
seed,
|
|
3536
|
+
resamples,
|
|
3537
|
+
confidence: intervalConfidence,
|
|
3538
|
+
statistic: "mean"
|
|
3539
|
+
});
|
|
3540
|
+
const favored = boot.low > 0 ? best.name : boot.high < 0 ? other.name : "tie";
|
|
3541
|
+
return {
|
|
3542
|
+
a: best.name,
|
|
3543
|
+
b: other.name,
|
|
3544
|
+
deltaMean: boot.mean,
|
|
3545
|
+
low: boot.low,
|
|
3546
|
+
high: boot.high,
|
|
3547
|
+
favored
|
|
3548
|
+
};
|
|
3549
|
+
});
|
|
3550
|
+
const optimizationCost = combineCosts(
|
|
3551
|
+
scores.map((score) => ({ label: `method '${score.name}'`, cost: score.optimizationCost }))
|
|
3552
|
+
);
|
|
3553
|
+
const testCost = costFromLedgerSummary(testCostLedger.summary({ phase: testCostPhase }));
|
|
3554
|
+
const totalCost = combineCosts([
|
|
3555
|
+
{ label: "optimization", cost: optimizationCost },
|
|
3556
|
+
{ label: "final test", cost: testCost }
|
|
3557
|
+
]);
|
|
3558
|
+
return {
|
|
3559
|
+
scores,
|
|
3560
|
+
best,
|
|
3561
|
+
pairwise,
|
|
3562
|
+
testScenarioIds: scenarioIds,
|
|
3563
|
+
optimizationCost,
|
|
3564
|
+
testCost,
|
|
3565
|
+
totalCost,
|
|
3566
|
+
confidence,
|
|
3567
|
+
intervalConfidence,
|
|
3568
|
+
comparisonCount,
|
|
3569
|
+
seed,
|
|
3570
|
+
resamples,
|
|
3571
|
+
reps: opts.reps ?? 1
|
|
3572
|
+
};
|
|
3573
|
+
}
|
|
3574
|
+
function assertOptimizationMethods(methods) {
|
|
3575
|
+
if (!Array.isArray(methods) || methods.length === 0) {
|
|
3576
|
+
throw new Error("compareOptimizationMethods: no methods to compare");
|
|
3577
|
+
}
|
|
3578
|
+
const names = /* @__PURE__ */ new Set();
|
|
3579
|
+
const pathOwners = /* @__PURE__ */ new Map();
|
|
3580
|
+
for (const method of methods) {
|
|
3581
|
+
if (!method || typeof method !== "object" || typeof method.optimize !== "function") {
|
|
3582
|
+
throw new Error("compareOptimizationMethods: every method must provide optimize(input)");
|
|
3583
|
+
}
|
|
3584
|
+
if (!method.name || method.name.trim() !== method.name) {
|
|
3585
|
+
throw new Error("compareOptimizationMethods: method names must be trimmed and non-empty");
|
|
3586
|
+
}
|
|
3587
|
+
if (names.has(method.name)) {
|
|
3588
|
+
throw new Error(`compareOptimizationMethods: duplicate method name '${method.name}'`);
|
|
3589
|
+
}
|
|
3590
|
+
names.add(method.name);
|
|
3591
|
+
const pathKey = slug(method.name);
|
|
3592
|
+
const prior = pathOwners.get(pathKey);
|
|
3593
|
+
if (prior) {
|
|
3594
|
+
throw new Error(
|
|
3595
|
+
`compareOptimizationMethods: method names '${prior}' and '${method.name}' map to the same run path '${pathKey}'`
|
|
3596
|
+
);
|
|
3597
|
+
}
|
|
3598
|
+
pathOwners.set(pathKey, method.name);
|
|
3599
|
+
}
|
|
3600
|
+
}
|
|
3601
|
+
function assertOptimizationResult(name, result) {
|
|
3602
|
+
if (!result || typeof result !== "object") {
|
|
3603
|
+
throw new Error(`compareOptimizationMethods: method '${name}' returned no result`);
|
|
3604
|
+
}
|
|
3605
|
+
try {
|
|
3606
|
+
surfaceContentHash(result.winnerSurface);
|
|
3607
|
+
} catch (cause) {
|
|
3608
|
+
throw new Error(
|
|
3609
|
+
`compareOptimizationMethods: method '${name}' returned an invalid winnerSurface`,
|
|
3610
|
+
{ cause }
|
|
3611
|
+
);
|
|
3612
|
+
}
|
|
3613
|
+
assertComparisonCost(result.cost, `method '${name}'`);
|
|
3614
|
+
if (result.durationMs !== void 0 && (!Number.isFinite(result.durationMs) || result.durationMs < 0)) {
|
|
3615
|
+
throw new Error(`compareOptimizationMethods: method '${name}' returned an invalid durationMs`);
|
|
3616
|
+
}
|
|
3617
|
+
}
|
|
3618
|
+
function assertComparisonControls(opts, seed, resamples, confidence) {
|
|
3619
|
+
if (!opts.judges || opts.judges.length === 0) {
|
|
3620
|
+
throw new Error("compareOptimizationMethods: at least one judge is required");
|
|
3621
|
+
}
|
|
3622
|
+
if (typeof opts.dispatchWithSurface !== "function") {
|
|
3623
|
+
throw new Error("compareOptimizationMethods: dispatchWithSurface must be a function");
|
|
3624
|
+
}
|
|
3625
|
+
try {
|
|
3626
|
+
surfaceContentHash(opts.baselineSurface);
|
|
3627
|
+
} catch (cause) {
|
|
3628
|
+
throw new Error("compareOptimizationMethods: baselineSurface is invalid", { cause });
|
|
3629
|
+
}
|
|
3630
|
+
const judgeNames = /* @__PURE__ */ new Set();
|
|
3631
|
+
for (const judge of opts.judges) {
|
|
3632
|
+
if (!judge || typeof judge !== "object" || typeof judge.name !== "string" || judge.name.trim().length === 0 || judge.name.trim() !== judge.name || typeof judge.score !== "function" || !Array.isArray(judge.dimensions) || judge.dimensions.length === 0) {
|
|
3633
|
+
throw new Error(
|
|
3634
|
+
"compareOptimizationMethods: every judge needs a trimmed name, at least one dimension, and score(input)"
|
|
3635
|
+
);
|
|
3636
|
+
}
|
|
3637
|
+
if (judgeNames.has(judge.name)) {
|
|
3638
|
+
throw new Error(`compareOptimizationMethods: duplicate judge name '${judge.name}'`);
|
|
3639
|
+
}
|
|
3640
|
+
judgeNames.add(judge.name);
|
|
3641
|
+
const dimensionKeys = /* @__PURE__ */ new Set();
|
|
3642
|
+
for (const dimension of judge.dimensions) {
|
|
3643
|
+
if (!dimension || typeof dimension.key !== "string" || dimension.key.trim().length === 0 || dimension.key.trim() !== dimension.key || typeof dimension.description !== "string" || dimension.description.trim().length === 0) {
|
|
3644
|
+
throw new Error(
|
|
3645
|
+
`compareOptimizationMethods: judge '${judge.name}' has an invalid dimension`
|
|
3646
|
+
);
|
|
3647
|
+
}
|
|
3648
|
+
if (dimensionKeys.has(dimension.key)) {
|
|
3649
|
+
throw new Error(
|
|
3650
|
+
`compareOptimizationMethods: judge '${judge.name}' has duplicate dimension '${dimension.key}'`
|
|
3651
|
+
);
|
|
3652
|
+
}
|
|
3653
|
+
dimensionKeys.add(dimension.key);
|
|
3654
|
+
}
|
|
3655
|
+
}
|
|
3656
|
+
if (typeof opts.runDir !== "string" || opts.runDir.trim().length === 0) {
|
|
3657
|
+
throw new Error("compareOptimizationMethods: runDir must be a non-empty string");
|
|
3658
|
+
}
|
|
3659
|
+
if (!Number.isSafeInteger(seed)) {
|
|
3660
|
+
throw new Error(`compareOptimizationMethods: seed must be a safe integer, got ${String(seed)}`);
|
|
3661
|
+
}
|
|
3662
|
+
if (!Number.isSafeInteger(resamples) || resamples <= 0 || resamples > 1e6) {
|
|
3663
|
+
throw new Error(
|
|
3664
|
+
`compareOptimizationMethods: resamples must be a positive safe integer no greater than 1000000, got ${String(resamples)}`
|
|
3665
|
+
);
|
|
3666
|
+
}
|
|
3667
|
+
if (!Number.isFinite(confidence) || confidence <= 0 || confidence >= 1) {
|
|
3668
|
+
throw new Error(
|
|
3669
|
+
`compareOptimizationMethods: confidence must be a finite number in (0,1), got ${String(confidence)}`
|
|
3670
|
+
);
|
|
3671
|
+
}
|
|
3672
|
+
const minimumResamples = minimumBootstrapResamples(
|
|
3673
|
+
confidence,
|
|
3674
|
+
opts.methods.length * (opts.methods.length + 1) / 2
|
|
3675
|
+
);
|
|
3676
|
+
if (resamples < minimumResamples) {
|
|
3677
|
+
throw new Error(
|
|
3678
|
+
`compareOptimizationMethods: resamples must be at least ${minimumResamples} for simultaneous confidence ${confidence} across ${opts.methods.length} methods, got ${resamples}`
|
|
3679
|
+
);
|
|
3680
|
+
}
|
|
3681
|
+
if (opts.optimizationConcurrency !== void 0 && (!Number.isSafeInteger(opts.optimizationConcurrency) || opts.optimizationConcurrency <= 0)) {
|
|
3682
|
+
throw new Error(
|
|
3683
|
+
"compareOptimizationMethods: optimizationConcurrency must be a positive safe integer"
|
|
3684
|
+
);
|
|
3685
|
+
}
|
|
3686
|
+
if (opts.maxConcurrency !== void 0 && (!Number.isSafeInteger(opts.maxConcurrency) || opts.maxConcurrency <= 0)) {
|
|
3687
|
+
throw new Error("compareOptimizationMethods: maxConcurrency must be a positive safe integer");
|
|
3688
|
+
}
|
|
3689
|
+
if (opts.dispatchTimeoutMs !== void 0 && (!Number.isSafeInteger(opts.dispatchTimeoutMs) || opts.dispatchTimeoutMs < 0 || opts.dispatchTimeoutMs > 2147483647)) {
|
|
3690
|
+
throw new Error(
|
|
3691
|
+
"compareOptimizationMethods: dispatchTimeoutMs must be a non-negative safe integer no greater than 2147483647"
|
|
3692
|
+
);
|
|
3693
|
+
}
|
|
3694
|
+
if (opts.costCeiling !== void 0 && (!Number.isFinite(opts.costCeiling) || opts.costCeiling < 0)) {
|
|
3695
|
+
throw new Error(
|
|
3696
|
+
"compareOptimizationMethods: costCeiling must be a finite number greater than or equal to 0"
|
|
3697
|
+
);
|
|
3698
|
+
}
|
|
3699
|
+
if (opts.costCeiling !== void 0 && opts.costLedger !== void 0 && opts.costLedger.costCeilingUsd !== opts.costCeiling) {
|
|
3700
|
+
throw new Error(
|
|
3701
|
+
"compareOptimizationMethods: costCeiling must match the shared CostLedger ceiling"
|
|
3702
|
+
);
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
function assertComparisonPartitions(opts) {
|
|
3706
|
+
const legacy = opts;
|
|
3707
|
+
if (legacy.holdoutScenarios !== void 0) {
|
|
3708
|
+
throw new Error(
|
|
3709
|
+
"compareOptimizationMethods: holdoutScenarios is ambiguous and no longer accepted. Provide disjoint trainScenarios, selectionScenarios, and testScenarios; selection may be reused adaptively, test must remain untouched."
|
|
3710
|
+
);
|
|
3711
|
+
}
|
|
3712
|
+
const partitions = [
|
|
3713
|
+
{ name: "trainScenarios", scenarios: opts.trainScenarios },
|
|
3714
|
+
{ name: "selectionScenarios", scenarios: opts.selectionScenarios },
|
|
3715
|
+
{ name: "testScenarios", scenarios: opts.testScenarios }
|
|
3716
|
+
];
|
|
3717
|
+
const owner = /* @__PURE__ */ new Map();
|
|
3718
|
+
for (const partition of partitions) {
|
|
3719
|
+
if (!Array.isArray(partition.scenarios) || partition.scenarios.length === 0) {
|
|
3720
|
+
throw new Error(`compareOptimizationMethods: ${partition.name} is empty`);
|
|
3721
|
+
}
|
|
3722
|
+
if (partition.name === "testScenarios" && partition.scenarios.length < 2) {
|
|
3723
|
+
throw new Error(
|
|
3724
|
+
"compareOptimizationMethods: testScenarios requires at least 2 scenarios to estimate uncertainty"
|
|
3725
|
+
);
|
|
3726
|
+
}
|
|
3727
|
+
const local = /* @__PURE__ */ new Set();
|
|
3728
|
+
const duplicates = /* @__PURE__ */ new Set();
|
|
3729
|
+
const overlaps = /* @__PURE__ */ new Map();
|
|
3730
|
+
for (const scenario of partition.scenarios) {
|
|
3731
|
+
if (local.has(scenario.id)) duplicates.add(scenario.id);
|
|
3732
|
+
local.add(scenario.id);
|
|
3733
|
+
const prior = owner.get(scenario.id);
|
|
3734
|
+
if (prior !== void 0 && prior !== partition.name) overlaps.set(scenario.id, prior);
|
|
3735
|
+
}
|
|
3736
|
+
if (duplicates.size > 0) {
|
|
3737
|
+
throw new Error(
|
|
3738
|
+
`compareOptimizationMethods: ${partition.name} contains duplicate scenario id(s) [${[
|
|
3739
|
+
...duplicates
|
|
3740
|
+
].join(", ")}]`
|
|
3741
|
+
);
|
|
3742
|
+
}
|
|
3743
|
+
if (overlaps.size > 0) {
|
|
3744
|
+
const detail = [...overlaps].map(([id, prior]) => `${id} (${prior} \u2229 ${partition.name})`).join(", ");
|
|
3745
|
+
throw new Error(
|
|
3746
|
+
`compareOptimizationMethods: trainScenarios, selectionScenarios, and testScenarios must be pairwise disjoint; overlap: [${detail}]`
|
|
3747
|
+
);
|
|
3748
|
+
}
|
|
3749
|
+
assertCampaignDesign(partition.scenarios, opts.reps ?? 1);
|
|
3750
|
+
for (const id of local) owner.set(id, partition.name);
|
|
3751
|
+
}
|
|
3752
|
+
}
|
|
3753
|
+
function mean2(xs) {
|
|
3754
|
+
return xs.length === 0 ? 0 : xs.reduce((a, b) => a + b, 0) / xs.length;
|
|
3755
|
+
}
|
|
3756
|
+
function slug(name) {
|
|
3757
|
+
return name.replace(/[^a-z0-9]+/gi, "-").replace(/^-|-$/g, "").toLowerCase() || "method";
|
|
3758
|
+
}
|
|
3759
|
+
function assertConfidence(confidence) {
|
|
3760
|
+
if (!Number.isFinite(confidence) || confidence <= 0 || confidence >= 1) {
|
|
3761
|
+
throw new Error(
|
|
3762
|
+
`compareOptimizationMethods: confidence must be a finite number in (0,1), got ${String(confidence)}`
|
|
3763
|
+
);
|
|
3764
|
+
}
|
|
3765
|
+
}
|
|
3766
|
+
function minimumBootstrapResamples(confidence, comparisonCount) {
|
|
3767
|
+
const exact = 2 * comparisonCount / (1 - confidence);
|
|
3768
|
+
return Math.ceil(exact - Number.EPSILON * Math.max(1, exact) * 32);
|
|
3769
|
+
}
|
|
3770
|
+
function createOptimizationMethodInput(opts, methodName, resolvedRunDir, seed) {
|
|
3771
|
+
const cloneScenarios = (scenarios) => Object.freeze(scenarios.map((scenario) => structuredClone(scenario)));
|
|
3772
|
+
const judges = opts.judges.map(
|
|
3773
|
+
(judge) => Object.freeze({
|
|
3774
|
+
...judge,
|
|
3775
|
+
dimensions: Object.freeze(
|
|
3776
|
+
judge.dimensions.map((dimension) => Object.freeze({ ...dimension }))
|
|
3777
|
+
)
|
|
3778
|
+
})
|
|
3779
|
+
);
|
|
3780
|
+
return Object.freeze({
|
|
3781
|
+
baselineSurface: structuredClone(opts.baselineSurface),
|
|
3782
|
+
trainScenarios: cloneScenarios(opts.trainScenarios),
|
|
3783
|
+
selectionScenarios: cloneScenarios(opts.selectionScenarios),
|
|
3784
|
+
dispatchWithSurface: opts.dispatchWithSurface,
|
|
3785
|
+
judges: Object.freeze(judges),
|
|
3786
|
+
runDir: `${resolvedRunDir}/optimization/${slug(methodName)}`,
|
|
3787
|
+
seed,
|
|
3788
|
+
runOptions: Object.freeze({ ...opts.optimizationRunOptions ?? {} })
|
|
3789
|
+
});
|
|
3790
|
+
}
|
|
3791
|
+
function costFromLedgerSummary(summary) {
|
|
3792
|
+
const cost = {
|
|
3793
|
+
totalCostUsd: summary.totalCostUsd,
|
|
3794
|
+
accountingComplete: summary.accountingComplete,
|
|
3795
|
+
incompleteReasons: [...summary.incompleteReasons]
|
|
3796
|
+
};
|
|
3797
|
+
assertComparisonCost(cost, "cost ledger");
|
|
3798
|
+
return cost;
|
|
3799
|
+
}
|
|
3800
|
+
function combineCosts(entries) {
|
|
3801
|
+
return {
|
|
3802
|
+
totalCostUsd: entries.reduce((total, entry) => total + entry.cost.totalCostUsd, 0),
|
|
3803
|
+
accountingComplete: entries.every((entry) => entry.cost.accountingComplete),
|
|
3804
|
+
incompleteReasons: entries.flatMap(
|
|
3805
|
+
(entry) => entry.cost.incompleteReasons.map((reason) => `${entry.label}: ${reason}`)
|
|
3806
|
+
)
|
|
3807
|
+
};
|
|
3808
|
+
}
|
|
3809
|
+
function assertComparisonCost(cost, label) {
|
|
3810
|
+
if (!cost || typeof cost !== "object") {
|
|
3811
|
+
throw new Error(`compareOptimizationMethods: ${label} returned no cost`);
|
|
3812
|
+
}
|
|
3813
|
+
if (!Number.isFinite(cost.totalCostUsd) || cost.totalCostUsd < 0) {
|
|
3814
|
+
throw new Error(`compareOptimizationMethods: ${label} returned an invalid totalCostUsd`);
|
|
3815
|
+
}
|
|
3816
|
+
if (typeof cost.accountingComplete !== "boolean") {
|
|
3817
|
+
throw new Error(`compareOptimizationMethods: ${label} returned invalid accountingComplete`);
|
|
3818
|
+
}
|
|
3819
|
+
if (!Array.isArray(cost.incompleteReasons) || cost.incompleteReasons.some(
|
|
3820
|
+
(reason) => typeof reason !== "string" || reason.trim().length === 0
|
|
3821
|
+
)) {
|
|
3822
|
+
throw new Error(`compareOptimizationMethods: ${label} returned invalid incompleteReasons`);
|
|
3823
|
+
}
|
|
3824
|
+
if (cost.accountingComplete !== (cost.incompleteReasons.length === 0)) {
|
|
3825
|
+
throw new Error(
|
|
3826
|
+
`compareOptimizationMethods: ${label} returned inconsistent cost completeness and reasons`
|
|
3827
|
+
);
|
|
3828
|
+
}
|
|
3829
|
+
}
|
|
3830
|
+
|
|
3407
3831
|
// src/campaign/presets/run-skill-opt.ts
|
|
3408
3832
|
async function runSkillOpt(opts) {
|
|
3409
|
-
|
|
3410
|
-
if (
|
|
3833
|
+
const legacy = opts;
|
|
3834
|
+
if (legacy.holdoutScenarios !== void 0) {
|
|
3835
|
+
throw new Error(
|
|
3836
|
+
"runSkillOpt: holdoutScenarios was renamed to selectionScenarios because SkillOpt adaptively reuses it for edit acceptance. Provide selectionScenarios and score any final test outside runSkillOpt."
|
|
3837
|
+
);
|
|
3838
|
+
}
|
|
3839
|
+
if (!Array.isArray(opts.trainScenarios) || opts.trainScenarios.length === 0)
|
|
3840
|
+
throw new Error("runSkillOpt: trainScenarios is empty");
|
|
3841
|
+
if (!Array.isArray(opts.selectionScenarios) || opts.selectionScenarios.length === 0)
|
|
3842
|
+
throw new Error("runSkillOpt: selectionScenarios is empty");
|
|
3411
3843
|
if (!opts.judges || opts.judges.length === 0) {
|
|
3412
3844
|
throw new Error(
|
|
3413
3845
|
"runSkillOpt: at least one judge is required \u2014 scoring (and therefore acceptance) is meaningless without one, and would report a silent zero lift."
|
|
3414
3846
|
);
|
|
3415
3847
|
}
|
|
3416
|
-
const
|
|
3417
|
-
const overlap = opts.trainScenarios.filter((s) =>
|
|
3848
|
+
const selectionIds = new Set(opts.selectionScenarios.map((s) => s.id));
|
|
3849
|
+
const overlap = opts.trainScenarios.filter((s) => selectionIds.has(s.id)).map((s) => s.id);
|
|
3418
3850
|
if (overlap.length > 0) {
|
|
3419
3851
|
throw new Error(
|
|
3420
|
-
`runSkillOpt: trainScenarios and
|
|
3852
|
+
`runSkillOpt: trainScenarios and selectionScenarios must be disjoint (overlap: [${overlap.join(
|
|
3421
3853
|
", "
|
|
3422
|
-
)}]) \u2014 a shared scenario leaks the
|
|
3854
|
+
)}]) \u2014 a shared scenario leaks the selection axis into the proposal evidence.`
|
|
3423
3855
|
);
|
|
3424
3856
|
}
|
|
3857
|
+
const maxEpochs = opts.maxEpochs;
|
|
3425
3858
|
const patchesPerEpoch = opts.patchesPerEpoch ?? 2;
|
|
3426
3859
|
const initialBudget = opts.editBudget ?? 3;
|
|
3427
3860
|
const minImprovement = opts.minImprovement ?? 0;
|
|
3428
|
-
|
|
3429
|
-
throw new Error(
|
|
3430
|
-
"runSkillOpt: minImprovement must be >= 0 \u2014 a negative threshold would accept held-out regressions, breaking the monotonic-lift contract."
|
|
3431
|
-
);
|
|
3432
|
-
}
|
|
3433
|
-
const patience = opts.patience ?? opts.maxEpochs;
|
|
3861
|
+
const patience = opts.patience ?? maxEpochs;
|
|
3434
3862
|
const budgetAnneal = opts.budgetAnneal ?? true;
|
|
3435
3863
|
const rejectedBufferSize = opts.rejectedBufferSize ?? 12;
|
|
3436
3864
|
const slowMetaEvery = opts.slowMetaEvery ?? 2;
|
|
3437
|
-
|
|
3865
|
+
const evidenceK = opts.evidenceK ?? 3;
|
|
3866
|
+
assertPositiveSafeInteger("maxEpochs", maxEpochs);
|
|
3867
|
+
assertPositiveSafeInteger("patchesPerEpoch", patchesPerEpoch);
|
|
3868
|
+
assertPositiveSafeInteger("editBudget", initialBudget);
|
|
3869
|
+
assertFiniteNonNegative("minImprovement", minImprovement);
|
|
3870
|
+
assertPositiveSafeInteger("patience", patience);
|
|
3871
|
+
assertNonNegativeSafeInteger("rejectedBufferSize", rejectedBufferSize);
|
|
3872
|
+
assertNonNegativeSafeInteger("slowMetaEvery", slowMetaEvery);
|
|
3873
|
+
assertPositiveSafeInteger("evidenceK", evidenceK);
|
|
3874
|
+
if (typeof opts.runDir !== "string" || opts.runDir.trim().length === 0) {
|
|
3875
|
+
throw new Error("runSkillOpt: runDir must be a non-empty string");
|
|
3876
|
+
}
|
|
3877
|
+
const runDir = resolveRunDir(opts.runDir, opts.repo);
|
|
3438
3878
|
const storage = opts.storage ?? fsCampaignStorage();
|
|
3439
3879
|
const costLedger = opts.costLedger ?? createRunCostLedger({
|
|
3440
3880
|
storage,
|
|
3441
|
-
runDir
|
|
3881
|
+
runDir,
|
|
3442
3882
|
costCeilingUsd: opts.costCeiling
|
|
3443
3883
|
});
|
|
3444
|
-
const
|
|
3445
|
-
const campaign = await runScoringCampaign(
|
|
3884
|
+
const scoreSelection = async (surface, tag) => {
|
|
3885
|
+
const campaign = await runScoringCampaign(
|
|
3886
|
+
opts,
|
|
3887
|
+
opts.selectionScenarios,
|
|
3888
|
+
surface,
|
|
3889
|
+
tag,
|
|
3890
|
+
costLedger,
|
|
3891
|
+
runDir
|
|
3892
|
+
);
|
|
3446
3893
|
return campaignMeanComposite(campaign);
|
|
3447
3894
|
};
|
|
3448
|
-
const evidenceK = opts.evidenceK ?? 3;
|
|
3449
3895
|
const trainEvidence = async (surface, tag) => {
|
|
3450
|
-
const campaign = await runScoringCampaign(
|
|
3896
|
+
const campaign = await runScoringCampaign(
|
|
3897
|
+
opts,
|
|
3898
|
+
opts.trainScenarios,
|
|
3899
|
+
surface,
|
|
3900
|
+
tag,
|
|
3901
|
+
costLedger,
|
|
3902
|
+
runDir
|
|
3903
|
+
);
|
|
3451
3904
|
return toEvidence(campaign, evidenceK);
|
|
3452
3905
|
};
|
|
3453
3906
|
let current = opts.baselineSurface;
|
|
3454
3907
|
let currentEvidence = await trainEvidence(current, "baseline-train");
|
|
3455
|
-
const
|
|
3456
|
-
let
|
|
3908
|
+
const baselineSelection = await scoreSelection(current, "baseline-selection");
|
|
3909
|
+
let currentSelection = baselineSelection;
|
|
3457
3910
|
const buffer = [];
|
|
3458
3911
|
const acceptedEdits = [];
|
|
3459
3912
|
const rejectedAll = [];
|
|
@@ -3462,9 +3915,9 @@ async function runSkillOpt(opts) {
|
|
|
3462
3915
|
let sinceAccept = 0;
|
|
3463
3916
|
let metaNote;
|
|
3464
3917
|
let epochsRun = 0;
|
|
3465
|
-
for (let epoch = 0; epoch <
|
|
3918
|
+
for (let epoch = 0; epoch < maxEpochs; epoch++) {
|
|
3466
3919
|
epochsRun++;
|
|
3467
|
-
const
|
|
3920
|
+
const proposed = await opts.proposer.proposePatches({
|
|
3468
3921
|
surface: current,
|
|
3469
3922
|
evidence: currentEvidence,
|
|
3470
3923
|
editBudget: budget,
|
|
@@ -3475,6 +3928,10 @@ async function runSkillOpt(opts) {
|
|
|
3475
3928
|
costLedger,
|
|
3476
3929
|
costPhase: "skill-opt.proposal"
|
|
3477
3930
|
});
|
|
3931
|
+
if (!Array.isArray(proposed)) {
|
|
3932
|
+
throw new Error("runSkillOpt: proposer.proposePatches() must return an array");
|
|
3933
|
+
}
|
|
3934
|
+
const patches = proposed.slice(0, patchesPerEpoch);
|
|
3478
3935
|
let accepted = null;
|
|
3479
3936
|
const rejectedThisEpoch = [];
|
|
3480
3937
|
for (let i = 0; i < patches.length; i++) {
|
|
@@ -3488,23 +3945,26 @@ async function runSkillOpt(opts) {
|
|
|
3488
3945
|
});
|
|
3489
3946
|
continue;
|
|
3490
3947
|
}
|
|
3491
|
-
const
|
|
3492
|
-
|
|
3948
|
+
const candidateSelection = await scoreSelection(
|
|
3949
|
+
candidate,
|
|
3950
|
+
`epoch-${epoch}-cand-${i}-selection`
|
|
3951
|
+
);
|
|
3952
|
+
if (candidateSelection > currentSelection + minImprovement) {
|
|
3493
3953
|
accepted = {
|
|
3494
3954
|
epoch,
|
|
3495
3955
|
label: patch.label,
|
|
3496
3956
|
rationale: patch.rationale,
|
|
3497
|
-
|
|
3957
|
+
selectionDelta: candidateSelection - currentSelection
|
|
3498
3958
|
};
|
|
3499
3959
|
current = candidate;
|
|
3500
|
-
|
|
3960
|
+
currentSelection = candidateSelection;
|
|
3501
3961
|
currentEvidence = await trainEvidence(current, `epoch-${epoch}-train`);
|
|
3502
3962
|
break;
|
|
3503
3963
|
}
|
|
3504
3964
|
rejectedThisEpoch.push({
|
|
3505
3965
|
label: patch.label,
|
|
3506
3966
|
rationale: patch.rationale,
|
|
3507
|
-
reason: `
|
|
3967
|
+
reason: `selection ${candidateSelection.toFixed(3)} \u2264 current ${currentSelection.toFixed(3)}`
|
|
3508
3968
|
});
|
|
3509
3969
|
}
|
|
3510
3970
|
if (accepted) {
|
|
@@ -3528,16 +3988,16 @@ async function runSkillOpt(opts) {
|
|
|
3528
3988
|
proposed: patches.length,
|
|
3529
3989
|
accepted,
|
|
3530
3990
|
rejected: rejectedThisEpoch,
|
|
3531
|
-
|
|
3991
|
+
selectionComposite: currentSelection
|
|
3532
3992
|
});
|
|
3533
3993
|
if (sinceAccept >= patience) break;
|
|
3534
3994
|
}
|
|
3535
3995
|
const cost = costLedger.summary();
|
|
3536
3996
|
return {
|
|
3537
3997
|
winnerSurface: current,
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3998
|
+
baselineSelectionComposite: baselineSelection,
|
|
3999
|
+
winnerSelectionComposite: currentSelection,
|
|
4000
|
+
selectionLift: currentSelection - baselineSelection,
|
|
3541
4001
|
acceptedEdits,
|
|
3542
4002
|
rejectedEdits: rejectedAll,
|
|
3543
4003
|
epochsRun,
|
|
@@ -3546,15 +4006,30 @@ async function runSkillOpt(opts) {
|
|
|
3546
4006
|
cost
|
|
3547
4007
|
};
|
|
3548
4008
|
}
|
|
3549
|
-
function runScoringCampaign(opts, scenarios, surface, tag, costLedger) {
|
|
4009
|
+
function runScoringCampaign(opts, scenarios, surface, tag, costLedger, runDir) {
|
|
3550
4010
|
return runCampaign({
|
|
3551
4011
|
...opts,
|
|
3552
4012
|
costLedger,
|
|
3553
4013
|
scenarios,
|
|
3554
4014
|
dispatch: (scenario, ctx) => opts.dispatchWithSurface(surface, scenario, ctx),
|
|
3555
|
-
runDir: `${
|
|
4015
|
+
runDir: `${runDir}/${tag}`
|
|
3556
4016
|
});
|
|
3557
4017
|
}
|
|
4018
|
+
function assertPositiveSafeInteger(name, value) {
|
|
4019
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
4020
|
+
throw new Error(`runSkillOpt: ${name} must be a positive safe integer`);
|
|
4021
|
+
}
|
|
4022
|
+
}
|
|
4023
|
+
function assertNonNegativeSafeInteger(name, value) {
|
|
4024
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
4025
|
+
throw new Error(`runSkillOpt: ${name} must be a non-negative safe integer`);
|
|
4026
|
+
}
|
|
4027
|
+
}
|
|
4028
|
+
function assertFiniteNonNegative(name, value) {
|
|
4029
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
4030
|
+
throw new Error(`runSkillOpt: ${name} must be a finite number greater than or equal to 0`);
|
|
4031
|
+
}
|
|
4032
|
+
}
|
|
3558
4033
|
function toEvidence(campaign, k) {
|
|
3559
4034
|
const { dimensions, scenarios } = campaignBreakdown(campaign);
|
|
3560
4035
|
const weakScenarios = [...scenarios].sort((a, b) => a.composite - b.composite).slice(0, k);
|
|
@@ -3565,7 +4040,7 @@ function buildMetaNote(accepted, rejected) {
|
|
|
3565
4040
|
const parts = [];
|
|
3566
4041
|
if (accepted.length > 0) {
|
|
3567
4042
|
parts.push(
|
|
3568
|
-
`Edits that improved
|
|
4043
|
+
`Edits that improved selection so far: ${accepted.map((a) => `"${a.label}" (+${a.selectionDelta.toFixed(3)})`).join("; ")}. Build on these.`
|
|
3569
4044
|
);
|
|
3570
4045
|
}
|
|
3571
4046
|
if (rejected.length > 0) {
|
|
@@ -3576,231 +4051,108 @@ function buildMetaNote(accepted, rejected) {
|
|
|
3576
4051
|
return parts.join(" ");
|
|
3577
4052
|
}
|
|
3578
4053
|
|
|
3579
|
-
// src/campaign/presets/
|
|
3580
|
-
|
|
3581
|
-
return
|
|
4054
|
+
// src/campaign/presets/builtin-optimization-methods.ts
|
|
4055
|
+
function gepaReflectionMethod(config, name = "gepa-reflection") {
|
|
4056
|
+
return gepaMethod(config, false, name);
|
|
3582
4057
|
}
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
const seed = opts.seed ?? 42;
|
|
3586
|
-
const resamples = opts.resamples ?? 2e3;
|
|
3587
|
-
const confidence = opts.confidence ?? 0.95;
|
|
3588
|
-
const scoreOnHoldout = async (surface, tag) => {
|
|
3589
|
-
const campaign = await runCampaign({
|
|
3590
|
-
...opts,
|
|
3591
|
-
scenarios: opts.holdoutScenarios,
|
|
3592
|
-
dispatch: (scenario, ctx) => opts.dispatchWithSurface(surface, scenario, ctx),
|
|
3593
|
-
runDir: `${opts.runDir}/${tag}`
|
|
3594
|
-
});
|
|
3595
|
-
const byScenario = {};
|
|
3596
|
-
for (const { scenarioId, composite } of campaignBreakdown(campaign).scenarios) {
|
|
3597
|
-
byScenario[scenarioId] = composite;
|
|
3598
|
-
}
|
|
3599
|
-
return byScenario;
|
|
3600
|
-
};
|
|
3601
|
-
const scenarioIds = [...new Set(opts.holdoutScenarios.map((s) => s.id))].sort();
|
|
3602
|
-
if (scenarioIds.length === 0) throw new Error("compareProposers: holdoutScenarios is empty");
|
|
3603
|
-
const align = (byScenario, label) => {
|
|
3604
|
-
const missing = scenarioIds.filter((id) => !(id in byScenario));
|
|
3605
|
-
if (missing.length > 0) {
|
|
3606
|
-
throw new Error(
|
|
3607
|
-
`compareProposers: ${label} produced no held-out score for scenario(s) [${missing.join(
|
|
3608
|
-
", "
|
|
3609
|
-
)}] \u2014 a cell errored or its judges returned nothing. Refusing to fabricate a 0 (it would corrupt the lift comparison). Fix the dispatch/judge or drop the scenario.`
|
|
3610
|
-
);
|
|
3611
|
-
}
|
|
3612
|
-
return scenarioIds.map((id) => byScenario[id]);
|
|
3613
|
-
};
|
|
3614
|
-
const baselineArr = align(
|
|
3615
|
-
await scoreOnHoldout(opts.baselineSurface, "compare-baseline"),
|
|
3616
|
-
"baseline"
|
|
3617
|
-
);
|
|
3618
|
-
const winners = [];
|
|
3619
|
-
for (const proposer of opts.proposers) {
|
|
3620
|
-
const out = await proposer.optimize();
|
|
3621
|
-
const byScenario = await scoreOnHoldout(out.winnerSurface, `compare-${slug(proposer.name)}`);
|
|
3622
|
-
winners.push({
|
|
3623
|
-
name: proposer.name,
|
|
3624
|
-
winnerSurface: out.winnerSurface,
|
|
3625
|
-
costUsd: out.costUsd,
|
|
3626
|
-
durationMs: out.durationMs,
|
|
3627
|
-
arr: align(byScenario, `proposer "${proposer.name}"`)
|
|
3628
|
-
});
|
|
3629
|
-
}
|
|
3630
|
-
const scores = winners.map((w) => {
|
|
3631
|
-
const boot = pairedBootstrap(baselineArr, w.arr, {
|
|
3632
|
-
seed,
|
|
3633
|
-
resamples,
|
|
3634
|
-
confidence,
|
|
3635
|
-
statistic: "mean"
|
|
3636
|
-
});
|
|
3637
|
-
const score = {
|
|
3638
|
-
name: w.name,
|
|
3639
|
-
baselineComposite: mean2(baselineArr),
|
|
3640
|
-
winnerComposite: mean2(w.arr),
|
|
3641
|
-
lift: boot.mean,
|
|
3642
|
-
liftCi: { low: boot.low, high: boot.high },
|
|
3643
|
-
costUsd: w.costUsd,
|
|
3644
|
-
winnerSurface: w.winnerSurface,
|
|
3645
|
-
rank: 0
|
|
3646
|
-
};
|
|
3647
|
-
if (w.durationMs !== void 0) score.durationMs = w.durationMs;
|
|
3648
|
-
return score;
|
|
3649
|
-
});
|
|
3650
|
-
scores.sort((a, b) => b.lift - a.lift || a.costUsd - b.costUsd);
|
|
3651
|
-
scores.forEach((s, i) => {
|
|
3652
|
-
s.rank = i + 1;
|
|
3653
|
-
});
|
|
3654
|
-
const best = scores[0];
|
|
3655
|
-
const byName = new Map(winners.map((w) => [w.name, w]));
|
|
3656
|
-
const bestArr = byName.get(best.name).arr;
|
|
3657
|
-
const pairwise = scores.slice(1).map((other) => {
|
|
3658
|
-
const otherArr = byName.get(other.name).arr;
|
|
3659
|
-
const boot = pairedBootstrap(otherArr, bestArr, {
|
|
3660
|
-
seed,
|
|
3661
|
-
resamples,
|
|
3662
|
-
confidence,
|
|
3663
|
-
statistic: "mean"
|
|
3664
|
-
});
|
|
3665
|
-
const favored = boot.low > 0 ? best.name : boot.high < 0 ? other.name : "tie";
|
|
3666
|
-
return {
|
|
3667
|
-
a: best.name,
|
|
3668
|
-
b: other.name,
|
|
3669
|
-
deltaMean: boot.mean,
|
|
3670
|
-
low: boot.low,
|
|
3671
|
-
high: boot.high,
|
|
3672
|
-
favored
|
|
3673
|
-
};
|
|
3674
|
-
});
|
|
3675
|
-
return { scores, best, pairwise, holdoutScenarioIds: scenarioIds };
|
|
3676
|
-
}
|
|
3677
|
-
function mean2(xs) {
|
|
3678
|
-
return xs.length === 0 ? 0 : xs.reduce((a, b) => a + b, 0) / xs.length;
|
|
4058
|
+
function gepaParetoMethod(config, name = "gepa-pareto") {
|
|
4059
|
+
return gepaMethod(config, true, name);
|
|
3679
4060
|
}
|
|
3680
|
-
function
|
|
3681
|
-
return
|
|
3682
|
-
|
|
3683
|
-
function gepaReflectionEntry(config, name = "gepa-reflection") {
|
|
3684
|
-
return gepaEntry(config, false, name);
|
|
3685
|
-
}
|
|
3686
|
-
function gepaParetoEntry(config, name = "gepa-pareto") {
|
|
3687
|
-
return gepaEntry(config, true, name);
|
|
3688
|
-
}
|
|
3689
|
-
function gepaEntry(config, combineParents, name) {
|
|
3690
|
-
return {
|
|
4061
|
+
function gepaMethod(config, combineParents, name) {
|
|
4062
|
+
return improvementLoopMethod(
|
|
4063
|
+
config,
|
|
3691
4064
|
name,
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
});
|
|
3701
|
-
const result = await runImprovementLoop({
|
|
3702
|
-
scenarios: config.trainScenarios,
|
|
3703
|
-
holdoutScenarios: config.holdoutScenarios,
|
|
3704
|
-
baselineSurface: config.baselineSurface,
|
|
3705
|
-
dispatchWithSurface: config.dispatchWithSurface,
|
|
3706
|
-
judges: config.judges,
|
|
3707
|
-
proposer,
|
|
3708
|
-
populationSize: config.populationSize ?? 2,
|
|
3709
|
-
maxGenerations: config.maxGenerations ?? 3,
|
|
3710
|
-
gate: defaultProductionGate({
|
|
3711
|
-
holdoutScenarios: config.holdoutScenarios,
|
|
3712
|
-
deltaThreshold: 0
|
|
3713
|
-
}),
|
|
3714
|
-
autoOnPromote: "none",
|
|
3715
|
-
runDir: `${config.runDir}/${slug(name)}-loop`,
|
|
3716
|
-
...config.seed !== void 0 ? { seed: config.seed } : {},
|
|
3717
|
-
// Flow findings to the proposer's propose(). These reach runOptimization
|
|
3718
|
-
// unchanged (runImprovementLoop extends RunOptimizationOptions and
|
|
3719
|
-
// forwards {...opts}); ctx.findings/report/analyzeGeneration are consumed there.
|
|
3720
|
-
...config.findings !== void 0 ? { findings: config.findings } : {},
|
|
3721
|
-
...config.analyzeGeneration ? { analyzeGeneration: config.analyzeGeneration } : {},
|
|
3722
|
-
...config.report !== void 0 ? { report: config.report } : {}
|
|
3723
|
-
});
|
|
3724
|
-
return {
|
|
3725
|
-
winnerSurface: result.winnerSurface,
|
|
3726
|
-
costUsd: result.cost.totalCostUsd,
|
|
3727
|
-
durationMs: Date.now() - started
|
|
3728
|
-
};
|
|
3729
|
-
}
|
|
3730
|
-
};
|
|
4065
|
+
() => gepaProposer({
|
|
4066
|
+
llm: config.llm,
|
|
4067
|
+
model: config.model,
|
|
4068
|
+
target: config.target,
|
|
4069
|
+
combineParents,
|
|
4070
|
+
...config.mutationPrimitives ? { mutationPrimitives: config.mutationPrimitives } : {}
|
|
4071
|
+
})
|
|
4072
|
+
);
|
|
3731
4073
|
}
|
|
3732
|
-
function
|
|
4074
|
+
function skillOptMethod(config, name = "skill-opt") {
|
|
3733
4075
|
return {
|
|
3734
4076
|
name,
|
|
3735
|
-
async optimize() {
|
|
4077
|
+
async optimize(input) {
|
|
3736
4078
|
const started = Date.now();
|
|
4079
|
+
if (typeof input.baselineSurface !== "string") {
|
|
4080
|
+
throw new Error(`${name}: SkillOpt requires a string baselineSurface`);
|
|
4081
|
+
}
|
|
3737
4082
|
const proposer = skillOptProposer({
|
|
3738
4083
|
llm: config.llm,
|
|
3739
4084
|
model: config.model,
|
|
3740
4085
|
target: config.target
|
|
3741
4086
|
});
|
|
3742
4087
|
const result = await runSkillOpt({
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
4088
|
+
...input.runOptions,
|
|
4089
|
+
...config.runOptions ?? {},
|
|
4090
|
+
baselineSurface: input.baselineSurface,
|
|
4091
|
+
dispatchWithSurface: input.dispatchWithSurface,
|
|
4092
|
+
judges: [...input.judges],
|
|
3746
4093
|
proposer,
|
|
3747
|
-
trainScenarios:
|
|
3748
|
-
|
|
4094
|
+
trainScenarios: [...input.trainScenarios],
|
|
4095
|
+
selectionScenarios: [...input.selectionScenarios],
|
|
3749
4096
|
maxEpochs: config.maxEpochs ?? 6,
|
|
3750
|
-
runDir: `${
|
|
3751
|
-
|
|
4097
|
+
runDir: `${input.runDir}/loop`,
|
|
4098
|
+
seed: config.seed ?? input.seed
|
|
3752
4099
|
});
|
|
3753
4100
|
return {
|
|
3754
4101
|
winnerSurface: result.winnerSurface,
|
|
3755
|
-
|
|
4102
|
+
cost: costFromLedgerSummary(result.cost),
|
|
3756
4103
|
durationMs: Date.now() - started
|
|
3757
4104
|
};
|
|
3758
4105
|
}
|
|
3759
4106
|
};
|
|
3760
4107
|
}
|
|
3761
|
-
function
|
|
4108
|
+
function fapoEscalationMethod(config, name = "fapo-escalation") {
|
|
4109
|
+
return improvementLoopMethod(config, name, () => {
|
|
4110
|
+
const promptProposer = config.promptProposer ?? gepaProposer({
|
|
4111
|
+
llm: config.llm,
|
|
4112
|
+
model: config.model,
|
|
4113
|
+
target: config.target,
|
|
4114
|
+
combineParents: true,
|
|
4115
|
+
...config.mutationPrimitives ? { mutationPrimitives: config.mutationPrimitives } : {}
|
|
4116
|
+
});
|
|
4117
|
+
const parameterProposer = config.parameterProposer ?? (config.parameterCandidates ? parameterSweepProposer({ candidates: config.parameterCandidates }) : void 0);
|
|
4118
|
+
return fapoProposer({
|
|
4119
|
+
...config.fapo ?? {},
|
|
4120
|
+
promptProposer,
|
|
4121
|
+
...parameterProposer ? { parameterProposer } : {},
|
|
4122
|
+
...config.structuralProposer ? { structuralProposer: config.structuralProposer } : {}
|
|
4123
|
+
});
|
|
4124
|
+
});
|
|
4125
|
+
}
|
|
4126
|
+
function improvementLoopMethod(config, name, createProposer) {
|
|
3762
4127
|
return {
|
|
3763
4128
|
name,
|
|
3764
|
-
async optimize() {
|
|
4129
|
+
async optimize(input) {
|
|
3765
4130
|
const started = Date.now();
|
|
3766
|
-
const promptProposer = config.promptProposer ?? gepaProposer({
|
|
3767
|
-
llm: config.llm,
|
|
3768
|
-
model: config.model,
|
|
3769
|
-
target: config.target,
|
|
3770
|
-
combineParents: true,
|
|
3771
|
-
...config.mutationPrimitives ? { mutationPrimitives: config.mutationPrimitives } : {}
|
|
3772
|
-
});
|
|
3773
|
-
const parameterProposer = config.parameterProposer ?? (config.parameterCandidates ? parameterSweepProposer({ candidates: config.parameterCandidates }) : void 0);
|
|
3774
|
-
const structuralProposer = config.structuralProposer;
|
|
3775
|
-
const proposer = fapoProposer({
|
|
3776
|
-
...config.fapo ?? {},
|
|
3777
|
-
promptProposer,
|
|
3778
|
-
...parameterProposer ? { parameterProposer } : {},
|
|
3779
|
-
...structuralProposer ? { structuralProposer } : {}
|
|
3780
|
-
});
|
|
3781
4131
|
const result = await runImprovementLoop({
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
4132
|
+
...input.runOptions,
|
|
4133
|
+
...config.runOptions ?? {},
|
|
4134
|
+
scenarios: [...input.trainScenarios],
|
|
4135
|
+
holdoutScenarios: [...input.selectionScenarios],
|
|
4136
|
+
baselineSurface: input.baselineSurface,
|
|
4137
|
+
dispatchWithSurface: input.dispatchWithSurface,
|
|
4138
|
+
judges: [...input.judges],
|
|
4139
|
+
proposer: createProposer(),
|
|
3788
4140
|
populationSize: config.populationSize ?? 2,
|
|
3789
4141
|
maxGenerations: config.maxGenerations ?? 3,
|
|
3790
4142
|
gate: defaultProductionGate({
|
|
3791
|
-
holdoutScenarios:
|
|
4143
|
+
holdoutScenarios: [...input.selectionScenarios],
|
|
3792
4144
|
deltaThreshold: 0
|
|
3793
4145
|
}),
|
|
3794
4146
|
autoOnPromote: "none",
|
|
3795
|
-
runDir: `${
|
|
3796
|
-
|
|
4147
|
+
runDir: `${input.runDir}/loop`,
|
|
4148
|
+
seed: config.seed ?? input.seed,
|
|
3797
4149
|
...config.findings !== void 0 ? { findings: config.findings } : {},
|
|
3798
4150
|
...config.analyzeGeneration ? { analyzeGeneration: config.analyzeGeneration } : {},
|
|
3799
4151
|
...config.report !== void 0 ? { report: config.report } : {}
|
|
3800
4152
|
});
|
|
3801
4153
|
return {
|
|
3802
|
-
winnerSurface: result.winnerSurface,
|
|
3803
|
-
|
|
4154
|
+
winnerSurface: result.gateResult.decision === "ship" ? result.winnerSurface : input.baselineSurface,
|
|
4155
|
+
cost: costFromLedgerSummary(result.cost),
|
|
3804
4156
|
durationMs: Date.now() - started
|
|
3805
4157
|
};
|
|
3806
4158
|
}
|
|
@@ -3808,7 +4160,7 @@ function fapoEscalationEntry(config, name = "fapo-escalation") {
|
|
|
3808
4160
|
}
|
|
3809
4161
|
|
|
3810
4162
|
// src/completion-verifier.ts
|
|
3811
|
-
import { randomUUID } from "crypto";
|
|
4163
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
3812
4164
|
function completionVerdict(input) {
|
|
3813
4165
|
if (input.requirements.length === 0) {
|
|
3814
4166
|
throw new Error(
|
|
@@ -4068,7 +4420,7 @@ ${content.slice(0, maxContentChars)}`
|
|
|
4068
4420
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
4069
4421
|
const started = Date.now();
|
|
4070
4422
|
await record({
|
|
4071
|
-
eventId:
|
|
4423
|
+
eventId: randomUUID2(),
|
|
4072
4424
|
provider: "correctness-checker",
|
|
4073
4425
|
model,
|
|
4074
4426
|
endpoint: "/chat",
|
|
@@ -4100,7 +4452,7 @@ ${content.slice(0, maxContentChars)}`
|
|
|
4100
4452
|
const resp = paid.value;
|
|
4101
4453
|
const raw = resp.choices?.[0]?.message?.content ?? "";
|
|
4102
4454
|
await record({
|
|
4103
|
-
eventId:
|
|
4455
|
+
eventId: randomUUID2(),
|
|
4104
4456
|
provider: "correctness-checker",
|
|
4105
4457
|
model,
|
|
4106
4458
|
endpoint: "/chat",
|
|
@@ -4116,7 +4468,7 @@ ${content.slice(0, maxContentChars)}`
|
|
|
4116
4468
|
} catch (err) {
|
|
4117
4469
|
lastErr = err;
|
|
4118
4470
|
await record({
|
|
4119
|
-
eventId:
|
|
4471
|
+
eventId: randomUUID2(),
|
|
4120
4472
|
provider: "correctness-checker",
|
|
4121
4473
|
model,
|
|
4122
4474
|
endpoint: "/chat",
|
|
@@ -5284,7 +5636,11 @@ function coerceCandidateSurface(surface) {
|
|
|
5284
5636
|
|
|
5285
5637
|
// src/campaign/proposers/policy-edit-author-context.ts
|
|
5286
5638
|
function selectPolicyEditAuthorRows(rows, options) {
|
|
5287
|
-
|
|
5639
|
+
assertPositiveSafeInteger2(options.limit, "limit");
|
|
5640
|
+
const scenarioOrder = options.scenarioOrder ?? "ranked";
|
|
5641
|
+
if (scenarioOrder !== "ranked" && scenarioOrder !== "input") {
|
|
5642
|
+
throw new Error("selectPolicyEditAuthorRows: scenarioOrder must be 'ranked' or 'input'");
|
|
5643
|
+
}
|
|
5288
5644
|
const unique2 = /* @__PURE__ */ new Map();
|
|
5289
5645
|
for (const row of rows) {
|
|
5290
5646
|
if (!row.scenarioId || row.scenarioId.trim() !== row.scenarioId) {
|
|
@@ -5307,6 +5663,9 @@ function selectPolicyEditAuthorRows(rows, options) {
|
|
|
5307
5663
|
delta: reference === void 0 ? null : row.composite - reference
|
|
5308
5664
|
});
|
|
5309
5665
|
}
|
|
5666
|
+
if (scenarioOrder === "input") {
|
|
5667
|
+
return [...unique2.values()].slice(0, options.limit).map(({ row }) => row);
|
|
5668
|
+
}
|
|
5310
5669
|
const hardest = [...unique2.values()].sort(
|
|
5311
5670
|
(a, b) => a.row.composite - b.row.composite || compareScenarioId(a.row, b.row)
|
|
5312
5671
|
);
|
|
@@ -5328,7 +5687,7 @@ function selectPolicyEditAuthorRows(rows, options) {
|
|
|
5328
5687
|
return selected;
|
|
5329
5688
|
}
|
|
5330
5689
|
function assertPolicyEditAuthorContextBudget(value, maxChars) {
|
|
5331
|
-
|
|
5690
|
+
assertPositiveSafeInteger2(maxChars, "maxChars");
|
|
5332
5691
|
const json = JSON.stringify(value);
|
|
5333
5692
|
if (json === void 0) {
|
|
5334
5693
|
throw new Error("assertPolicyEditAuthorContextBudget: value must serialize to JSON");
|
|
@@ -5344,7 +5703,7 @@ function assertPolicyEditAuthorContextBudget(value, maxChars) {
|
|
|
5344
5703
|
function compareScenarioId(a, b) {
|
|
5345
5704
|
return a.scenarioId < b.scenarioId ? -1 : a.scenarioId > b.scenarioId ? 1 : 0;
|
|
5346
5705
|
}
|
|
5347
|
-
function
|
|
5706
|
+
function assertPositiveSafeInteger2(value, name) {
|
|
5348
5707
|
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
5349
5708
|
throw new Error(`${name} must be a positive safe integer (got ${value})`);
|
|
5350
5709
|
}
|
|
@@ -5372,37 +5731,27 @@ var JsonValueSchema = z.lazy(
|
|
|
5372
5731
|
);
|
|
5373
5732
|
var AuthoredJsonChangeSchema = z.discriminatedUnion("mode", [
|
|
5374
5733
|
z.object({
|
|
5375
|
-
kind: z.literal("json"),
|
|
5376
5734
|
mode: z.literal("set"),
|
|
5377
|
-
path: NonEmptyStringSchema,
|
|
5378
5735
|
value: JsonValueSchema
|
|
5379
5736
|
}).strict(),
|
|
5380
5737
|
z.object({
|
|
5381
|
-
kind: z.literal("json"),
|
|
5382
5738
|
mode: z.literal("merge"),
|
|
5383
|
-
path: NonEmptyStringSchema,
|
|
5384
5739
|
value: JsonValueSchema
|
|
5385
5740
|
}).strict(),
|
|
5386
5741
|
z.object({
|
|
5387
|
-
|
|
5388
|
-
mode: z.literal("remove"),
|
|
5389
|
-
path: NonEmptyStringSchema
|
|
5742
|
+
mode: z.literal("remove")
|
|
5390
5743
|
}).strict()
|
|
5391
5744
|
]);
|
|
5392
5745
|
var AuthoredPolicyEditSchema = z.object({
|
|
5393
5746
|
axis: z.enum(POLICY_EDIT_AXES),
|
|
5394
5747
|
target: z.object({
|
|
5395
|
-
surface: z.enum(POLICY_EDIT_TARGET_SURFACES),
|
|
5396
5748
|
path: NonEmptyStringSchema,
|
|
5397
5749
|
label: NonEmptyStringSchema.max(200).nullable()
|
|
5398
5750
|
}).strict(),
|
|
5399
5751
|
change: AuthoredJsonChangeSchema,
|
|
5400
5752
|
claim: NonEmptyStringSchema.max(2e3),
|
|
5401
5753
|
expectedGain: z.object({
|
|
5402
|
-
metric: NonEmptyStringSchema.max(400),
|
|
5403
|
-
direction: z.enum(["increase", "decrease"]),
|
|
5404
5754
|
amount: z.number().finite().positive(),
|
|
5405
|
-
unit: z.enum(["absolute", "relative", "percent", "score"]).nullable(),
|
|
5406
5755
|
rationale: NonEmptyStringSchema.max(2e3).nullable()
|
|
5407
5756
|
}).strict(),
|
|
5408
5757
|
confidence: z.number().finite().min(0).max(1),
|
|
@@ -5443,11 +5792,15 @@ var POLICY_EDIT_AUTHOR_JSON_SCHEMA = {
|
|
|
5443
5792
|
target: {
|
|
5444
5793
|
type: "object",
|
|
5445
5794
|
additionalProperties: false,
|
|
5446
|
-
required: ["
|
|
5795
|
+
required: ["path", "label"],
|
|
5447
5796
|
properties: {
|
|
5448
|
-
surface: { type: "string", enum: [...POLICY_EDIT_TARGET_SURFACES] },
|
|
5449
5797
|
path: { type: "string", minLength: 1 },
|
|
5450
|
-
label: {
|
|
5798
|
+
label: {
|
|
5799
|
+
type: ["string", "null"],
|
|
5800
|
+
minLength: 1,
|
|
5801
|
+
maxLength: 200,
|
|
5802
|
+
pattern: "\\S"
|
|
5803
|
+
}
|
|
5451
5804
|
}
|
|
5452
5805
|
},
|
|
5453
5806
|
change: {
|
|
@@ -5455,51 +5808,44 @@ var POLICY_EDIT_AUTHOR_JSON_SCHEMA = {
|
|
|
5455
5808
|
{
|
|
5456
5809
|
type: "object",
|
|
5457
5810
|
additionalProperties: false,
|
|
5458
|
-
required: ["
|
|
5811
|
+
required: ["mode", "value"],
|
|
5459
5812
|
properties: {
|
|
5460
|
-
kind: { const: "json" },
|
|
5461
5813
|
mode: { const: "set" },
|
|
5462
|
-
path: { type: "string", minLength: 1 },
|
|
5463
5814
|
value: {}
|
|
5464
5815
|
}
|
|
5465
5816
|
},
|
|
5466
5817
|
{
|
|
5467
5818
|
type: "object",
|
|
5468
5819
|
additionalProperties: false,
|
|
5469
|
-
required: ["
|
|
5820
|
+
required: ["mode", "value"],
|
|
5470
5821
|
properties: {
|
|
5471
|
-
kind: { const: "json" },
|
|
5472
5822
|
mode: { const: "merge" },
|
|
5473
|
-
path: { type: "string", minLength: 1 },
|
|
5474
5823
|
value: {}
|
|
5475
5824
|
}
|
|
5476
5825
|
},
|
|
5477
5826
|
{
|
|
5478
5827
|
type: "object",
|
|
5479
5828
|
additionalProperties: false,
|
|
5480
|
-
required: ["
|
|
5829
|
+
required: ["mode"],
|
|
5481
5830
|
properties: {
|
|
5482
|
-
|
|
5483
|
-
mode: { const: "remove" },
|
|
5484
|
-
path: { type: "string", minLength: 1 }
|
|
5831
|
+
mode: { const: "remove" }
|
|
5485
5832
|
}
|
|
5486
5833
|
}
|
|
5487
5834
|
]
|
|
5488
5835
|
},
|
|
5489
|
-
claim: { type: "string", minLength: 1, maxLength: 2e3 },
|
|
5836
|
+
claim: { type: "string", minLength: 1, maxLength: 2e3, pattern: "\\S" },
|
|
5490
5837
|
expectedGain: {
|
|
5491
5838
|
type: "object",
|
|
5492
5839
|
additionalProperties: false,
|
|
5493
|
-
required: ["
|
|
5840
|
+
required: ["amount", "rationale"],
|
|
5494
5841
|
properties: {
|
|
5495
|
-
metric: { type: "string", minLength: 1, maxLength: 400 },
|
|
5496
|
-
direction: { type: "string", enum: ["increase", "decrease"] },
|
|
5497
5842
|
amount: { type: "number", exclusiveMinimum: 0 },
|
|
5498
|
-
|
|
5843
|
+
rationale: {
|
|
5499
5844
|
type: ["string", "null"],
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5845
|
+
minLength: 1,
|
|
5846
|
+
maxLength: 2e3,
|
|
5847
|
+
pattern: "\\S"
|
|
5848
|
+
}
|
|
5503
5849
|
}
|
|
5504
5850
|
},
|
|
5505
5851
|
confidence: { type: "number", minimum: 0, maximum: 1 },
|
|
@@ -5513,18 +5859,28 @@ var POLICY_EDIT_AUTHOR_JSON_SCHEMA = {
|
|
|
5513
5859
|
type: "array",
|
|
5514
5860
|
minItems: 1,
|
|
5515
5861
|
uniqueItems: true,
|
|
5516
|
-
items: { type: "string", minLength: 1 }
|
|
5862
|
+
items: { type: "string", minLength: 1, pattern: "\\S" }
|
|
5517
5863
|
}
|
|
5518
5864
|
}
|
|
5519
5865
|
},
|
|
5520
|
-
rationale: {
|
|
5521
|
-
|
|
5866
|
+
rationale: {
|
|
5867
|
+
type: ["string", "null"],
|
|
5868
|
+
minLength: 1,
|
|
5869
|
+
maxLength: 4e3,
|
|
5870
|
+
pattern: "\\S"
|
|
5871
|
+
},
|
|
5872
|
+
validationPlan: {
|
|
5873
|
+
type: ["string", "null"],
|
|
5874
|
+
minLength: 1,
|
|
5875
|
+
maxLength: 2e3,
|
|
5876
|
+
pattern: "\\S"
|
|
5877
|
+
}
|
|
5522
5878
|
}
|
|
5523
5879
|
}
|
|
5524
5880
|
}
|
|
5525
5881
|
}
|
|
5526
5882
|
};
|
|
5527
|
-
function policyEditAuthorJsonSchema(maxItems,
|
|
5883
|
+
function policyEditAuthorJsonSchema(maxItems, allowedJsonPaths) {
|
|
5528
5884
|
const schema = JSON.parse(JSON.stringify(POLICY_EDIT_AUTHOR_JSON_SCHEMA));
|
|
5529
5885
|
const properties = schema.properties;
|
|
5530
5886
|
const edits = properties.edits;
|
|
@@ -5533,24 +5889,7 @@ function policyEditAuthorJsonSchema(maxItems, targetSurface, allowedJsonPaths, o
|
|
|
5533
5889
|
const itemProperties = item.properties;
|
|
5534
5890
|
const target = itemProperties.target;
|
|
5535
5891
|
const targetProperties = target.properties;
|
|
5536
|
-
targetProperties.surface = { type: "string", enum: [targetSurface] };
|
|
5537
5892
|
targetProperties.path = { type: "string", enum: [...allowedJsonPaths] };
|
|
5538
|
-
const change = itemProperties.change;
|
|
5539
|
-
for (const variant of change.anyOf) {
|
|
5540
|
-
const variantProperties = variant.properties;
|
|
5541
|
-
variantProperties.path = { type: "string", enum: [...allowedJsonPaths] };
|
|
5542
|
-
}
|
|
5543
|
-
const expectedGain = itemProperties.expectedGain;
|
|
5544
|
-
const gainProperties = expectedGain.properties;
|
|
5545
|
-
gainProperties.metric = { type: "string", enum: objectives.map((objective) => objective.key) };
|
|
5546
|
-
gainProperties.direction = {
|
|
5547
|
-
type: "string",
|
|
5548
|
-
enum: [...new Set(objectives.map((objective) => objective.direction))]
|
|
5549
|
-
};
|
|
5550
|
-
gainProperties.unit = {
|
|
5551
|
-
type: "string",
|
|
5552
|
-
enum: [...new Set(objectives.map((objective) => objective.unit))]
|
|
5553
|
-
};
|
|
5554
5893
|
return schema;
|
|
5555
5894
|
}
|
|
5556
5895
|
var DEFAULT_POLICY_EDIT_HISTORY_LIMITS = Object.freeze({
|
|
@@ -5564,9 +5903,9 @@ var POLICY_EDIT_AUTHOR_SYSTEM = [
|
|
|
5564
5903
|
"You author strictly typed PolicyEdit candidates over one JSON surface.",
|
|
5565
5904
|
'Return exactly one JSON object with shape {"edits":[...]}; emit an empty edits array when no evidence supports a change.',
|
|
5566
5905
|
`axis must be one of: ${POLICY_EDIT_AXES.join(", ")}.`,
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5906
|
+
"target.path must be one caller-allowed JSON path.",
|
|
5907
|
+
'change must be exactly one operation: {"mode":"set","value":json}, {"mode":"merge","value":json}, or {"mode":"remove"}.',
|
|
5908
|
+
"The caller binds target surface, JSON operation kind and path, and objective metric, direction, and unit; do not emit those fields.",
|
|
5570
5909
|
"Nullable fields required by the response schema must be null when they do not apply.",
|
|
5571
5910
|
"Every edit must cite one or more supplied finding keys in source.findingKeys. Do not emit persistent finding IDs, analyst IDs, or evidence references; the caller binds those from the cited findings.",
|
|
5572
5911
|
"Treat expectedGain and confidence as forecasts, never as measured evidence. Learn from baselineOutcome, incumbentOutcome, and observedDeltaFromParent.",
|
|
@@ -5605,6 +5944,7 @@ function llmPolicyEditProposer(opts) {
|
|
|
5605
5944
|
...opts.maxHistoryGenerations === void 0 ? {} : { maxGenerations: opts.maxHistoryGenerations },
|
|
5606
5945
|
...opts.maxHistoryCandidatesPerGeneration === void 0 ? {} : { maxCandidatesPerGeneration: opts.maxHistoryCandidatesPerGeneration },
|
|
5607
5946
|
...opts.maxScenariosPerCandidate === void 0 ? {} : { maxScenariosPerCandidate: opts.maxScenariosPerCandidate },
|
|
5947
|
+
...opts.scenarioOrder === void 0 ? {} : { scenarioOrder: opts.scenarioOrder },
|
|
5608
5948
|
...opts.scenarioIdTransform === void 0 ? {} : { scenarioIdTransform: opts.scenarioIdTransform }
|
|
5609
5949
|
});
|
|
5610
5950
|
const maxFindings = positiveLimit(
|
|
@@ -5658,12 +5998,14 @@ function llmPolicyEditProposer(opts) {
|
|
|
5658
5998
|
baselineOutcome: projectOutcome(
|
|
5659
5999
|
ctx.baselineOutcome,
|
|
5660
6000
|
scenarioIds,
|
|
5661
|
-
historyLimits.maxScenariosPerCandidate
|
|
6001
|
+
historyLimits.maxScenariosPerCandidate,
|
|
6002
|
+
historyLimits.scenarioOrder
|
|
5662
6003
|
),
|
|
5663
6004
|
incumbentOutcome: projectOutcome(
|
|
5664
6005
|
ctx.incumbentOutcome,
|
|
5665
6006
|
scenarioIds,
|
|
5666
6007
|
historyLimits.maxScenariosPerCandidate,
|
|
6008
|
+
historyLimits.scenarioOrder,
|
|
5667
6009
|
ctx.baselineOutcome
|
|
5668
6010
|
),
|
|
5669
6011
|
history: projectPolicyEditHistoryWithProjector(
|
|
@@ -5673,12 +6015,7 @@ function llmPolicyEditProposer(opts) {
|
|
|
5673
6015
|
objectiveByKey
|
|
5674
6016
|
)
|
|
5675
6017
|
};
|
|
5676
|
-
const responseSchema = policyEditAuthorJsonSchema(
|
|
5677
|
-
limit,
|
|
5678
|
-
opts.targetSurface,
|
|
5679
|
-
allowedJsonPaths,
|
|
5680
|
-
objectives
|
|
5681
|
-
);
|
|
6018
|
+
const responseSchema = policyEditAuthorJsonSchema(limit, allowedJsonPaths);
|
|
5682
6019
|
const system = policyEditAuthorSystem(responseSchema);
|
|
5683
6020
|
assertPolicyEditAuthorContextBudget(
|
|
5684
6021
|
{ system, authorContext, responseSchema },
|
|
@@ -5707,7 +6044,12 @@ function llmPolicyEditProposer(opts) {
|
|
|
5707
6044
|
maximumCharge: maximumChargeForLlmRequest(request, opts.llm),
|
|
5708
6045
|
tags: { generation: String(ctx.generation) },
|
|
5709
6046
|
signal: ctx.signal,
|
|
5710
|
-
execute: (signal, callId) => callLlmJson(request, {
|
|
6047
|
+
execute: (signal, callId) => callLlmJson(request, {
|
|
6048
|
+
...opts.llm,
|
|
6049
|
+
jsonPayloadMode: "exact",
|
|
6050
|
+
signal,
|
|
6051
|
+
idempotencyKey: callId
|
|
6052
|
+
}),
|
|
5711
6053
|
receipt: ({ result }) => costReceiptFromLlm(result),
|
|
5712
6054
|
receiptFromError: costReceiptFromLlmError
|
|
5713
6055
|
});
|
|
@@ -5725,7 +6067,7 @@ function llmPolicyEditProposer(opts) {
|
|
|
5725
6067
|
findingByKey,
|
|
5726
6068
|
opts.targetSurface,
|
|
5727
6069
|
allowedPathSet,
|
|
5728
|
-
|
|
6070
|
+
objectives[0],
|
|
5729
6071
|
ctx.incumbentOutcome?.composite ?? ctx.baselineOutcome?.composite
|
|
5730
6072
|
)
|
|
5731
6073
|
);
|
|
@@ -5773,6 +6115,7 @@ function projectPolicyEditHistoryWithProjector(history, limits, scenarioIds, obj
|
|
|
5773
6115
|
candidate,
|
|
5774
6116
|
scenarioIds,
|
|
5775
6117
|
limits.maxScenariosPerCandidate,
|
|
6118
|
+
limits.scenarioOrder,
|
|
5776
6119
|
candidate.parentSurfaceHash ? candidateByHash.get(candidate.parentSurfaceHash)?.scenarios : void 0,
|
|
5777
6120
|
objectiveByKey
|
|
5778
6121
|
)
|
|
@@ -5798,10 +6141,11 @@ function selectHistoryCandidates(record, limit) {
|
|
|
5798
6141
|
}
|
|
5799
6142
|
return selected;
|
|
5800
6143
|
}
|
|
5801
|
-
function projectHistoryCandidate(candidate, scenarioIds, maxScenarios, parentScenarios, objectiveByKey) {
|
|
6144
|
+
function projectHistoryCandidate(candidate, scenarioIds, maxScenarios, scenarioOrder, parentScenarios, objectiveByKey) {
|
|
5802
6145
|
const referenceByScenario = parentScenarios ? new Map(parentScenarios.map((scenario) => [scenario.scenarioId, scenario.composite])) : void 0;
|
|
5803
6146
|
const selectedScenarios = selectPolicyEditAuthorRows(candidate.scenarios, {
|
|
5804
6147
|
limit: maxScenarios,
|
|
6148
|
+
scenarioOrder,
|
|
5805
6149
|
...referenceByScenario ? { referenceByScenario } : {}
|
|
5806
6150
|
});
|
|
5807
6151
|
const validatedRecord = candidate.candidateRecord ? validatePolicyEditCandidateRecord(candidate.candidateRecord) : void 0;
|
|
@@ -5835,11 +6179,12 @@ function projectHistoryCandidate(candidate, scenarioIds, maxScenarios, parentSce
|
|
|
5835
6179
|
forecastCalibration: forecastCalibration(candidate, validatedRecord, objectiveByKey)
|
|
5836
6180
|
};
|
|
5837
6181
|
}
|
|
5838
|
-
function projectOutcome(outcome, scenarioIds, maxScenarios, reference = void 0) {
|
|
6182
|
+
function projectOutcome(outcome, scenarioIds, maxScenarios, scenarioOrder, reference = void 0) {
|
|
5839
6183
|
if (!outcome) return null;
|
|
5840
6184
|
const referenceByScenario = reference ? new Map(reference.scenarios.map((scenario) => [scenario.scenarioId, scenario.composite])) : void 0;
|
|
5841
6185
|
const selectedScenarios = selectPolicyEditAuthorRows(outcome.scenarios, {
|
|
5842
6186
|
limit: maxScenarios,
|
|
6187
|
+
scenarioOrder,
|
|
5843
6188
|
...referenceByScenario ? { referenceByScenario } : {}
|
|
5844
6189
|
});
|
|
5845
6190
|
return {
|
|
@@ -6092,6 +6437,7 @@ function validateHistoryLimits(options) {
|
|
|
6092
6437
|
const maxGenerations = options.maxGenerations ?? DEFAULT_POLICY_EDIT_HISTORY_LIMITS.generations;
|
|
6093
6438
|
const maxCandidatesPerGeneration = options.maxCandidatesPerGeneration ?? DEFAULT_POLICY_EDIT_HISTORY_LIMITS.candidatesPerGeneration;
|
|
6094
6439
|
const maxScenariosPerCandidate = options.maxScenariosPerCandidate ?? DEFAULT_POLICY_EDIT_HISTORY_LIMITS.scenariosPerCandidate;
|
|
6440
|
+
const scenarioOrder = options.scenarioOrder ?? "ranked";
|
|
6095
6441
|
if (!Number.isSafeInteger(maxGenerations) || maxGenerations <= 0) {
|
|
6096
6442
|
throw new Error("llmPolicyEditProposer: maxHistoryGenerations must be a positive safe integer");
|
|
6097
6443
|
}
|
|
@@ -6105,10 +6451,14 @@ function validateHistoryLimits(options) {
|
|
|
6105
6451
|
"llmPolicyEditProposer: maxScenariosPerCandidate must be a positive safe integer"
|
|
6106
6452
|
);
|
|
6107
6453
|
}
|
|
6454
|
+
if (scenarioOrder !== "ranked" && scenarioOrder !== "input") {
|
|
6455
|
+
throw new Error("llmPolicyEditProposer: scenarioOrder must be 'ranked' or 'input'");
|
|
6456
|
+
}
|
|
6108
6457
|
return {
|
|
6109
6458
|
maxGenerations,
|
|
6110
6459
|
maxCandidatesPerGeneration,
|
|
6111
6460
|
maxScenariosPerCandidate,
|
|
6461
|
+
scenarioOrder,
|
|
6112
6462
|
scenarioIdTransform: options.scenarioIdTransform ?? ((scenarioId) => scenarioId)
|
|
6113
6463
|
};
|
|
6114
6464
|
}
|
|
@@ -6163,18 +6513,10 @@ function parseAuthorResponse(value) {
|
|
|
6163
6513
|
const issues = parsed.error.issues.map((issue) => `${issue.path.join(".") || "<root>"}: ${issue.message}`).join("; ");
|
|
6164
6514
|
throw new Error(`llmPolicyEditProposer: invalid PolicyEdit response: ${issues}`);
|
|
6165
6515
|
}
|
|
6166
|
-
function bindAuthoredEdit(draft, findingByKey, targetSurface, allowedPaths,
|
|
6167
|
-
if (draft.target.
|
|
6516
|
+
function bindAuthoredEdit(draft, findingByKey, targetSurface, allowedPaths, objective, currentComposite) {
|
|
6517
|
+
if (!allowedPaths.has(draft.target.path)) {
|
|
6168
6518
|
throw new Error(
|
|
6169
|
-
`llmPolicyEditProposer:
|
|
6170
|
-
);
|
|
6171
|
-
}
|
|
6172
|
-
if (draft.target.path !== draft.change.path) {
|
|
6173
|
-
throw new Error("llmPolicyEditProposer: target.path must equal change.path");
|
|
6174
|
-
}
|
|
6175
|
-
if (!allowedPaths.has(draft.change.path)) {
|
|
6176
|
-
throw new Error(
|
|
6177
|
-
`llmPolicyEditProposer: JSON path '${draft.change.path}' is outside allowedJsonPaths`
|
|
6519
|
+
`llmPolicyEditProposer: JSON path '${draft.target.path}' is outside allowedJsonPaths`
|
|
6178
6520
|
);
|
|
6179
6521
|
}
|
|
6180
6522
|
const cited = draft.source.findingKeys.map((findingKey) => {
|
|
@@ -6190,22 +6532,6 @@ function bindAuthoredEdit(draft, findingByKey, targetSurface, allowedPaths, obje
|
|
|
6190
6532
|
if (evidenceRefs.length === 0) {
|
|
6191
6533
|
throw new Error("llmPolicyEditProposer: authored edit has no cited evidence");
|
|
6192
6534
|
}
|
|
6193
|
-
const objective = objectiveByKey.get(draft.expectedGain.metric);
|
|
6194
|
-
if (!objective) {
|
|
6195
|
-
throw new Error(
|
|
6196
|
-
`llmPolicyEditProposer: unknown forecast objective '${draft.expectedGain.metric}'`
|
|
6197
|
-
);
|
|
6198
|
-
}
|
|
6199
|
-
if (draft.expectedGain.direction !== objective.direction) {
|
|
6200
|
-
throw new Error(
|
|
6201
|
-
`llmPolicyEditProposer: forecast direction for '${objective.key}' must be '${objective.direction}'`
|
|
6202
|
-
);
|
|
6203
|
-
}
|
|
6204
|
-
if (draft.expectedGain.unit !== objective.unit) {
|
|
6205
|
-
throw new Error(
|
|
6206
|
-
`llmPolicyEditProposer: forecast unit for '${objective.key}' must be '${objective.unit}'`
|
|
6207
|
-
);
|
|
6208
|
-
}
|
|
6209
6535
|
const maxGain = currentComposite === void 0 ? objective.scale.max - objective.scale.min : objective.scale.max - currentComposite;
|
|
6210
6536
|
if (draft.expectedGain.amount > maxGain) {
|
|
6211
6537
|
throw new Error(
|
|
@@ -6213,20 +6539,26 @@ function bindAuthoredEdit(draft, findingByKey, targetSurface, allowedPaths, obje
|
|
|
6213
6539
|
);
|
|
6214
6540
|
}
|
|
6215
6541
|
const expectedGain = {
|
|
6216
|
-
metric:
|
|
6217
|
-
direction:
|
|
6542
|
+
metric: objective.key,
|
|
6543
|
+
direction: objective.direction,
|
|
6218
6544
|
amount: draft.expectedGain.amount,
|
|
6219
|
-
|
|
6545
|
+
unit: objective.unit,
|
|
6220
6546
|
...draft.expectedGain.rationale ? { rationale: draft.expectedGain.rationale } : {}
|
|
6221
6547
|
};
|
|
6548
|
+
const change = draft.change.mode === "remove" ? { kind: "json", mode: "remove", path: draft.target.path } : {
|
|
6549
|
+
kind: "json",
|
|
6550
|
+
mode: draft.change.mode,
|
|
6551
|
+
path: draft.target.path,
|
|
6552
|
+
value: draft.change.value
|
|
6553
|
+
};
|
|
6222
6554
|
const init = {
|
|
6223
6555
|
axis: draft.axis,
|
|
6224
6556
|
target: {
|
|
6225
|
-
surface:
|
|
6557
|
+
surface: targetSurface,
|
|
6226
6558
|
path: draft.target.path,
|
|
6227
6559
|
...draft.target.label ? { label: draft.target.label } : {}
|
|
6228
6560
|
},
|
|
6229
|
-
change
|
|
6561
|
+
change,
|
|
6230
6562
|
claim: draft.claim,
|
|
6231
6563
|
expectedGain,
|
|
6232
6564
|
confidence: draft.confidence,
|
|
@@ -6544,6 +6876,33 @@ ${block}
|
|
|
6544
6876
|
}
|
|
6545
6877
|
|
|
6546
6878
|
// src/campaign/proposers/trace-analyst.ts
|
|
6879
|
+
async function analyzeOtlpTraceFile(opts) {
|
|
6880
|
+
if (!opts.apiKey) throw new Error("analyzeOtlpTraceFile: apiKey is required");
|
|
6881
|
+
if (!opts.model) throw new Error("analyzeOtlpTraceFile: model is required");
|
|
6882
|
+
const aiService = createAnalystAi({
|
|
6883
|
+
provider: opts.provider ?? "openai",
|
|
6884
|
+
apiKey: opts.apiKey,
|
|
6885
|
+
baseUrl: opts.baseUrl,
|
|
6886
|
+
model: opts.model
|
|
6887
|
+
});
|
|
6888
|
+
const registry = new AnalystRegistry();
|
|
6889
|
+
for (const spec of opts.kinds ?? DEFAULT_TRACE_ANALYST_KINDS) {
|
|
6890
|
+
registry.register(createTraceAnalystKind(spec, { ai: aiService, model: opts.model }));
|
|
6891
|
+
}
|
|
6892
|
+
const result = await registry.run(
|
|
6893
|
+
opts.runId,
|
|
6894
|
+
{ traceStore: new OtlpFileTraceStore({ path: opts.tracePath }) },
|
|
6895
|
+
{
|
|
6896
|
+
signal: opts.signal ?? new AbortController().signal,
|
|
6897
|
+
chainFindings: true,
|
|
6898
|
+
...opts.costLedger ? { costLedger: opts.costLedger } : {},
|
|
6899
|
+
...opts.costPhase ? { costPhase: opts.costPhase } : {},
|
|
6900
|
+
...opts.priorFindings === void 0 ? {} : { priorFindings: opts.priorFindings }
|
|
6901
|
+
}
|
|
6902
|
+
);
|
|
6903
|
+
if (result.findings.length === 0) throw noFindingsError(result);
|
|
6904
|
+
return result.findings;
|
|
6905
|
+
}
|
|
6547
6906
|
function renderFindings(findings) {
|
|
6548
6907
|
return findings.map((f, i) => {
|
|
6549
6908
|
const action = f.recommended_action ? `
|
|
@@ -6562,30 +6921,20 @@ function traceAnalystProposer(opts) {
|
|
|
6562
6921
|
}
|
|
6563
6922
|
const kinds = opts.kinds ?? DEFAULT_TRACE_ANALYST_KINDS;
|
|
6564
6923
|
const produceFindings = opts.analyze ?? (async (path, c) => {
|
|
6565
|
-
const
|
|
6924
|
+
const priorFindings = await opts.resolvePriorFindings?.(c);
|
|
6925
|
+
return analyzeOtlpTraceFile({
|
|
6926
|
+
tracePath: path,
|
|
6927
|
+
runId: `trace-analyst-gen-${c.generation}`,
|
|
6566
6928
|
provider: opts.provider ?? "openai",
|
|
6567
6929
|
apiKey: opts.apiKey,
|
|
6568
6930
|
baseUrl: opts.baseUrl,
|
|
6569
|
-
model: opts.model
|
|
6931
|
+
model: opts.model,
|
|
6932
|
+
kinds,
|
|
6933
|
+
signal: c.signal,
|
|
6934
|
+
costLedger: c.costLedger,
|
|
6935
|
+
costPhase: c.costPhase,
|
|
6936
|
+
...priorFindings === void 0 ? {} : { priorFindings }
|
|
6570
6937
|
});
|
|
6571
|
-
const registry = new AnalystRegistry();
|
|
6572
|
-
for (const spec of kinds) {
|
|
6573
|
-
registry.register(createTraceAnalystKind(spec, { ai: aiService, model: opts.model }));
|
|
6574
|
-
}
|
|
6575
|
-
const priorFindings = await opts.resolvePriorFindings?.(c);
|
|
6576
|
-
const result = await registry.run(
|
|
6577
|
-
`trace-analyst-gen-${c.generation}`,
|
|
6578
|
-
{ traceStore: new OtlpFileTraceStore({ path }) },
|
|
6579
|
-
{
|
|
6580
|
-
signal: c.signal,
|
|
6581
|
-
chainFindings: true,
|
|
6582
|
-
costLedger: c.costLedger,
|
|
6583
|
-
costPhase: c.costPhase,
|
|
6584
|
-
...priorFindings === void 0 ? {} : { priorFindings }
|
|
6585
|
-
}
|
|
6586
|
-
);
|
|
6587
|
-
if (result.findings.length === 0) throw noFindingsError(result);
|
|
6588
|
-
return result.findings;
|
|
6589
6938
|
});
|
|
6590
6939
|
return analysisEditProposer({
|
|
6591
6940
|
kind: "trace-analyst",
|
|
@@ -8347,12 +8696,13 @@ export {
|
|
|
8347
8696
|
skillOptProposer,
|
|
8348
8697
|
SkillPatchParseError,
|
|
8349
8698
|
parseSkillPatchResponse,
|
|
8699
|
+
compareOptimizationMethods,
|
|
8700
|
+
costFromLedgerSummary,
|
|
8350
8701
|
runSkillOpt,
|
|
8351
|
-
|
|
8352
|
-
|
|
8353
|
-
|
|
8354
|
-
|
|
8355
|
-
fapoEscalationEntry,
|
|
8702
|
+
gepaReflectionMethod,
|
|
8703
|
+
gepaParetoMethod,
|
|
8704
|
+
skillOptMethod,
|
|
8705
|
+
fapoEscalationMethod,
|
|
8356
8706
|
makePlaybackDispatch,
|
|
8357
8707
|
scoreUserStory,
|
|
8358
8708
|
userStoryScoreboard,
|
|
@@ -8371,6 +8721,7 @@ export {
|
|
|
8371
8721
|
llmPolicyEditProposer,
|
|
8372
8722
|
projectPolicyEditHistory,
|
|
8373
8723
|
memoryCurationProposer,
|
|
8724
|
+
analyzeOtlpTraceFile,
|
|
8374
8725
|
traceAnalystProposer,
|
|
8375
8726
|
scoreDiscrimination,
|
|
8376
8727
|
selectDiscriminative,
|
|
@@ -8385,4 +8736,4 @@ export {
|
|
|
8385
8736
|
verifyCodeSurface,
|
|
8386
8737
|
resolveWorktreePath
|
|
8387
8738
|
};
|
|
8388
|
-
//# sourceMappingURL=chunk-
|
|
8739
|
+
//# sourceMappingURL=chunk-LT4J7ULK.js.map
|