import type { JudgeConfig, ProgressCallback, Report, Sample } from '../types/index.js'; interface WeakSample { sample_id: string; compositeScore: number; llmReason: string | null; failedAssertions: string[]; dimensions: Record | null; diagnostic?: { summary?: string; expected?: string; actual?: string; rootCause?: string[]; skillSuggestion?: string; sampleSuggestion?: string; none?: string; }; } export declare function singleVariantReport(report: Report, variantKey: string): Report; export declare function extractWeakSamples(report: Report, variantKey: string, count?: number, sampleIdFilter?: Set): WeakSample[]; /** A train / val / test partition. `val` drives the accept decision; `test` is * locked — never seen during the loop, read once at the end for an unbiased * generalization score. Two-way holdout (`splitHoldout`), the stride picker * (`pickByStride`), `MIN_HOLDOUT_SUBSET`, and `subsetCompositeScore` live in * `src/eval-core/holdout.ts` so `omk eval --holdout-ratio` reuses them. */ interface TrainValTestSplit { trainIds: Set; valIds: Set; testIds: Set; } /** Below this many decision (val) samples the bootstrap diff CI almost never * excludes 0 for realistic effect sizes, so the significance gate would reject * every candidate. Under that floor evolve degrades to the point-estimate accept * and flags `gate.underpowered`. */ export declare const MIN_GATE_SAMPLES = 8; /** * Deterministically split sample ids into train / val / test. `val` is carved * first at an even stride; `test` is carved at an even stride over what remains, * so the three sets are disjoint and stable across rounds/runs (no RNG). Returns * null when either ratio ≤ 0 or any of the three sides would drop below * MIN_HOLDOUT_SUBSET — the caller then degrades to a 2-way (or full-set) split. */ export declare function splitTrainValTest(sampleIds: string[], valRatio: number, testRatio: number): TrainValTestSplit | null; export interface AcceptDecision { accepted: boolean; /** Diff CI (candidate − best) when the gate ran; absent when it degraded. */ diffCI?: { low: number; high: number; estimate: number; significant: boolean; }; /** True when the gate was requested but the decision set was below MIN_GATE_SAMPLES, * so the decision degraded to the point-estimate comparison. */ underpowered: boolean; } /** * The accept decision for one round. With the significance gate on and enough * decision samples, a candidate is accepted only when it is **significantly** above * the current best's fresh re-eval (`bootstrapDiffCI(...).significant && estimate > 0`) * AND its decision score actually beats the recorded best (`pointCand > pointBest`). * The second clause preserves evolve's monotonic invariant: `bestScore` never * decreases. Without it, an unlucky (noise-low) re-eval of the current best could let * a candidate that is significantly above that re-eval — yet still below the recorded * best — win and overwrite the best downward. Off, or under-powered, the gate degrades * to the legacy point-estimate comparison alone. Pure (modulo the seeded bootstrap) so * the core behavior is unit-testable. */ export declare function decideAccept(bestScores: number[], candScores: number[], pointBest: number, pointCand: number, opts: { significanceGate: boolean; alpha: number; seed: number; }): AcceptDecision; /** * A view of `report` whose results are restricted to `sampleIds`. Used to keep the * holdout split out of the sample-fixer: under an active holdout, only training-split * samples may enter the --auto-fix-samples prompt or be rewritten — otherwise the * skill's samples get tuned to the very samples that decide acceptance, reintroducing * the leak holdout exists to prevent. */ export declare function restrictReportToSamples(report: Report, sampleIds: Set): Report; export declare function allNonTripwireAssertionsPass(report: Report, variantKey: string): boolean; export declare function agentSampleEditWithinScope(previous: Sample, next: Sample): boolean; interface EditDelta { /** Symmetric line difference (added + removed unique lines) over original line count. */ ratio: number; /** Absolute count of added + removed unique lines. */ changedLines: number; /** Compact `+`/`-` summary of the changed lines, truncated. */ summary: string; } /** * How a candidate differs from the current best, by trimmed non-empty line sets. * `ratio` drives the edit budget; `summary` feeds the rejected-edit memory so the * improver doesn't re-propose changes that already failed. Order-insensitive and * O(n) over small skill files. */ export declare function computeEditDelta(before: string, after: string, maxSummaryLines?: number): EditDelta; export declare function buildImprovementPrompt(skillContent: string, score: number, weakSamples: WeakSample[], rejectedEdits?: string[]): string; /** @deprecated Use ProgressCallback from evaluation-core.ts */ export type EvolveProgressInfo = Parameters[0]; export interface EvolveRoundProgressInfo { round: number; totalRounds: number; phase: string; score?: number; delta?: number; accepted?: boolean; costUSD?: number; /** False = exec 或 judge executor 不报 cost(如 codex)→ costUSD 是占位 0。 * CLI 输出据此把 "$0.0000" 改成「—」。 */ costReported?: boolean; error?: string; reused?: boolean; /** When the significance gate ran: whether the candidate's gain was significant. * False on a rejected round means "score rose but within noise" — lets the CLI * explain an otherwise-confusing `(+0.0x) ✗ REJECT`. Undefined = gate didn't run. */ significant?: boolean; } export interface EvolveOptions { skillPath: string; samplesPath: string; rounds?: number; target?: number | null; stopOnAssertionsPass?: boolean; autoFixSamples?: boolean; sampleFixMaxAttempts?: number; reuseLatestEval?: boolean; /** Explicit measured runtime. Provider defaults belong to the CLI boundary. */ model: string; /** Single-judge config. evolve 不支持 ensemble — CLI 在 length>=2 时 exit 2, * programmatic API 在 evolveSkill 入口同样 throw,二者一致。缺省时复用 * 被测 executor/model;CLI 会在调用前解析 provider-specific 默认值。 */ judgeModels?: JudgeConfig[]; improveModel?: string; /** 改写策略。'agent' 用 agent 工具增量 Edit;'rewrite' 用单次 LLM 输出全文。默认 'agent'。 */ improveMode?: 'agent' | 'rewrite'; /** Explicit measured executor. Provider defaults belong to the CLI boundary. */ executorName: string; concurrency?: number; timeoutMs?: number; skipConnectivity?: boolean; /** 控被评测 LLM 的扩展思考预算。默认 'low' 跟 omk eval 一致。 */ effort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max'; /** 关闭 diagnostic LLM 调用。默认 false。 */ noDiagnostic?: boolean; /** 跳过 doctor 健康检查门禁。默认 false。 */ skipDoctor?: boolean; /** Fraction of samples held out for the accept decision (0..1). Default 0 = off. * When > 0, a candidate is accepted on its **holdout** composite rather than the * training composite, and weak-sample extraction only sees the training split — * so the skill is never tuned to the samples that judge it. Too small a split * (either side < MIN_HOLDOUT_SUBSET) falls back to full-set scoring + a warning. */ holdoutRatio?: number; /** Statistically gate acceptance: a candidate is accepted only when its * per-sample composite is **significantly** above the current best on the * decision (val) set — `bootstrapDiffCI(...).significant && estimate > 0` — * not merely numerically higher. Default true (rejecting improvements * indistinguishable from judge noise is the point). Below MIN_GATE_SAMPLES * decision samples the gate is underpowered and degrades to the point-estimate * comparison + a warning. Set false to force the legacy point-estimate accept. */ significanceGate?: boolean; /** Significance level for the accept gate's diff CI. Default 0.05 (95% CI). */ significanceAlpha?: number; /** Fraction of samples locked away as a **test** set (0..1). Default 0 = off. * Only honored alongside `holdoutRatio` > 0 (test needs a separate val set to * decide on). The test split is never seen during the loop — not by weak-sample * extraction, not by the accept gate — and is read exactly once at the end for an * unbiased `generalizationScore`. Too small a 3-way split degrades to 2-way. */ testRatio?: number; /** Max fraction of skill lines a single round may change before the candidate is * rejected **without paying for evaluation**. Default 0.2 (matches the "≤20%" * the improvement prompt already asks for — this enforces it). A small floor * always permits a handful of lines so tiny skills aren't frozen. Set 0 to disable. */ editBudget?: number; /** Feed rejected candidate edits back into the next round's improvement prompt * ("these were tried and did not help — don't repeat them"). Default true. */ rejectMemory?: boolean; /** 是否把胜出版本写回原 source 文件。默认 true(保「一键化」:evolve 跑完源即更新)。 * `--snapshot-only` 置 false → 不写 source,候选仍落在 `evolve/.r{N}.md` 供人工挑选 / promote。 */ writeBackToSource?: boolean; onProgress?: ProgressCallback | null; onRoundProgress?: ((progress: EvolveRoundProgressInfo) => void) | null; } interface TrajectoryEntry { round: number; /** Accept-decision score: val composite when a holdout split is active, else full-set. */ score: number; delta: number; accepted: boolean; costUSD: number; /** Present when a holdout split is active: the training-split composite (improvement signal). */ trainScore?: number; /** Present when a holdout split is active: the val-split composite (== score). */ holdoutScore?: number; /** Significance-gate diff CI (candidate − current best) on the decision set, when * the gate was powered enough to run. `significant` 决定接受。 */ diffCI?: { low: number; high: number; estimate: number; significant: boolean; }; /** Fraction of skill lines this candidate changed vs the current best. */ editRatio?: number; /** True when the candidate was rejected by the edit budget before evaluation. */ rejectedPreEval?: boolean; } export interface EvolveResult { startScore: number; finalScore: number; bestRound: number; totalRounds: number; totalCostUSD: number; stopReason?: 'target' | 'assertions-pass' | 'consecutive-rejects' | 'rounds'; sampleFixes?: Array<{ round: number; fixedCount: number; costUSD: number; }>; reusedBaselineReportId?: string; /** False = 任一轮的 exec / judge 不报 cost → totalCostUSD 是 lower-bound 而非真值。 */ costReported?: boolean; /** Holdout split summary when `--holdout-ratio` > 0. `disabled` is true when the * split was too small and evolve fell back to full-set scoring (CLI formats the * user-facing message bilingually). */ holdout?: { ratio: number; trainCount: number; holdoutCount: number; disabled?: boolean; }; /** Locked-test split summary. `disabled` is true when `--test-ratio` was requested * but the 3-way split was too small, so evolve fell back to a 2-way holdout and * produced no generalization score. */ test?: { ratio: number; count: number; disabled?: boolean; }; /** Unbiased composite of the best skill on the locked test set — the headline honest * number. Present only when a 3-way split was active. The test set never influenced * selection or weak-sample extraction, so this is an out-of-sample estimate. */ generalizationScore?: number; /** Accept-gate summary. `underpowered` = the decision set was below MIN_GATE_SAMPLES * at least once, so the gate degraded to the point-estimate comparison + warned. */ gate?: { enabled: boolean; alpha: number; underpowered?: boolean; }; trajectory: TrajectoryEntry[]; bestSkillPath: string; allVersions: string[]; reportId?: string; } export interface RoundReport { round: number; accepted: boolean; report: Report; } export declare function mergeEvolveReports(roundReports: RoundReport[], skillName: string, processCostUSD: number, samples?: Sample[], skillPath?: string, processCostReported?: boolean): Report; export declare function evolveSkill({ skillPath, samplesPath, rounds, target, stopOnAssertionsPass, autoFixSamples, sampleFixMaxAttempts, reuseLatestEval, model, judgeModels, improveModel, improveMode, executorName, concurrency, timeoutMs, skipConnectivity, effort, noDiagnostic, skipDoctor, holdoutRatio, significanceGate, significanceAlpha, testRatio, editBudget, rejectMemory, writeBackToSource, onProgress, onRoundProgress, }: EvolveOptions): Promise; export {};