/**
 * `runDistillation` — the teacher→student distillation loop. COMPOSES existing
 * substrate primitives; reimplements none of them:
 *
 *   - DRIVER       = `gepaProposer` (reflective prompt optimizer)
 *   - LOOP         = `runImprovementLoop` (outer: optimize → holdout re-score → gate)
 *   - MEASUREMENT  = `runCampaign` (inside the loop) scoring the student
 *   - JUDGE        = `buildAgreementJudge` — student label vs gold teacher label
 *   - GATE         = caller-supplied (`heldOutGate` / `defaultProductionGate`)
 *   - STUDENT      = a cheap single-shot analyst whose system prompt is the
 *                    `MutableSurface` GEPA mutates; it calls the LLM through
 *                    `createChatClient` and emits a JSON label.
 *
 * The surface IS the student's system prompt. Each generation GEPA rewrites it;
 * `dispatchWithSurface` renders {surface + scenario.input} into a chat request,
 * calls the (cheap) model, parses the produced JSON label, and returns it as
 * the artifact. The agreement judge scores that label against the gold label.
 *
 * `autoOnPromote: 'none'` is FORCED — the loop never opens a PR; the caller
 * (the `distill` CLI) decides what to do with the winning prompt.
 */
import { type ChatRequest, type CreateChatClientOpts } from '../../analyst/chat-client';
import type { LlmClientOptions } from '../../llm-client';
import { type RunImprovementLoopResult } from '../presets/run-improvement-loop';
import { type GepaProposerConstraints } from '../proposers/gepa';
import type { CampaignResult, Gate, JudgeConfig } from '../types';
import type { GoldScenario } from './gold-scenarios';
/** Render the student's prompt from {current surface, scenario input}. The
 *  surface is the system prompt; the scenario input is the user turn. Override
 *  to inject few-shot framing or a JSON-schema reminder. */
export type RenderStudentPrompt<TInput> = (args: {
    surface: string;
    input: TInput;
    scenarioId: string;
}) => ChatRequest['messages'];
/** Parse the model's raw text into a typed produced label. Throws on
 *  unparseable output — a thrown dispatch is recorded as a failed cell (never
 *  silently scored 0), which is the honest signal that the prompt isn't
 *  emitting valid JSON yet. */
export type ParseStudentLabel<TProduced> = (rawContent: string, scenarioId: string) => TProduced;
export interface RunDistillationOptions<TProduced, TInput, TLabel> {
    /** The student analyst's INITIAL system prompt — the baseline surface GEPA
     *  searches from. */
    baselinePrompt: string;
    /** Training scenarios (the optimization pool). */
    train: GoldScenario<TInput, TLabel>[];
    /** Held-out scenarios — kept OUT of training; scored only at the gate. */
    holdout: GoldScenario<TInput, TLabel>[];
    /** Transport for BOTH the student (cheap model) and the GEPA reflection
     *  (the optimizer model). The student calls it via `createChatClient`. */
    llm: CreateChatClientOpts;
    /** Router transport the GEPA proposer reflects through. `gepaProposer` uses the
     *  package `LlmClient` directly (`LlmClientOptions`), not the ChatClient —
     *  pass the router creds here. A test may inject `fetch` to stub the
     *  reflection HTTP and exercise the wiring without real tokens. */
    reflectionLlm: LlmClientOptions;
    /** Cheap model the student runs (e.g. a small/fast model). */
    studentModel: string;
    /** Model GEPA uses to propose prompt rewrites (typically a stronger model). */
    optimizerModel: string;
    /** Agreement judge — produced student label vs gold teacher label. */
    judge: JudgeConfig<TProduced, GoldScenario<TInput, TLabel>>;
    /** Promotion gate. Default: `heldOutGate` over the holdout. Pass
     *  `defaultProductionGate({ holdoutScenarios: holdout, ... })` for the full
     *  red-team / reward-hacking / canary stack. */
    gate?: Gate<TProduced, GoldScenario<TInput, TLabel>>;
    /** GEPA population size (candidates per generation). Default 4. */
    populationSize?: number;
    /** GEPA generations. Default 3. */
    maxGenerations?: number;
    /** Campaign reps per scenario. Default 1 — raise for CI bands on a flaky
     *  student. */
    reps?: number;
    /** Where campaign artifacts + traces land. Default a temp dir under cwd. */
    runDir?: string;
    /** Levers offered to the GEPA reflection prompt. */
    mutationPrimitives?: string[];
    /** GEPA structured-doc constraints (preserve sections, edit budget). */
    constraints?: GepaProposerConstraints;
    /** Gate's minimum holdout-agreement delta to ship. Default 0.0 — a
     *  distillation run reports the lift; the caller decides the bar. Only used
     *  when `gate` is omitted (the default `heldOutGate`). */
    deltaThreshold?: number;
    /** Render the student prompt. Default: surface as system, JSON-stringified
     *  input as the user turn with a JSON-only instruction. */
    renderStudentPrompt?: RenderStudentPrompt<TInput>;
    /** Parse the model's text into a produced label. Default: strict JSON parse
     *  with fenced-block stripping. */
    parseStudentLabel?: ParseStudentLabel<TProduced>;
    /** Per-student-call sampling temperature. Default 0 (deterministic student;
     *  the optimization signal must come from the PROMPT, not sampling noise). */
    studentTemperature?: number;
    /** Per-student-call max tokens. Default 1024. */
    studentMaxTokens?: number;
}
export interface RunDistillationResult<TProduced, TInput, TLabel> extends RunImprovementLoopResult<TProduced, GoldScenario<TInput, TLabel>> {
    /** The winning student prompt (a string surface). */
    winnerPrompt: string;
    /** Mean agreement on the HOLDOUT — baseline vs winner. The headline number:
     *  did distillation move the student closer to the teacher on UNSEEN gold? */
    holdoutAgreement: {
        baseline: number;
        winner: number;
        delta: number;
    };
}
export declare function runDistillation<TProduced, TInput, TLabel>(opts: RunDistillationOptions<TProduced, TInput, TLabel>): Promise<RunDistillationResult<TProduced, TInput, TLabel>>;
/** Default student prompt render: surface as system, JSON input as the user
 *  turn, with a JSON-only output instruction. */
export declare function defaultRenderStudentPrompt<TInput>(args: {
    surface: string;
    input: TInput;
    scenarioId: string;
}): ChatRequest['messages'];
/** Default label parse: strip a ```json fence if present, then `JSON.parse`.
 *  Throws on failure so the cell is recorded as failed, not silently zeroed. */
export declare function defaultParseStudentLabel<TProduced>(rawContent: string, scenarioId: string): TProduced;
export type { CampaignResult };
//# sourceMappingURL=run-distillation.d.ts.map