/** * Demo injection (v0.10.0) — SIMBA-style "append a demo" challenger source. * * DSPy's SIMBA optimizer (Stochastic Introspective Mini-Batch Ascent) improves * programs through two complementary strategies: appending self-reflective * RULES (Darwin's reflector already covers that ground) and appending * successful past examples as DEMONSTRATIONS. This module is Darwin's * adaptation of the second strategy to the online evolution loop: * * 1. Harvest the agent's own highest-scoring past runs from memory * (score ≥ threshold, successful, non-trivial output). * 2. Prefer diversity: at most one demo per task type, best-scoring first. * 3. Render them as a clearly-delimited "Demonstrations" section and * append it to (or refresh it inside) the current prompt. * * The demo-augmented prompt is a CHALLENGER like any other — it goes through * the same alignment guard, the same A/B test, and the same safety gate as a * reflective or merged mutation. If demos don't actually help this agent, the * incumbent wins and nothing changes. * * Design notes: * - Zero LLM cost. Selection and rendering are pure string/array work on * data Darwin already persists (task, output, score, taskType). This makes * demos the cheapest challenger source in the loop. * - Idempotent via markers. The section is wrapped in * `` comments so a later demo cycle * REPLACES the previous section instead of stacking a second one, and * {@link stripDemoSection} can remove it cleanly. * - Demo text comes from the agent's OWN prior outputs (already produced * under this prompt lineage), not from an external input channel. Excerpts * are length-capped and fenced, but callers embedding third-party data in * tasks should be aware demos quote past tasks verbatim. * - Determinism. Given the same experiment list and options, selection and * rendering are fully deterministic (stable sort, no randomness) — the * loop's no-op check ("would this produce the same prompt?") stays cheap. */ import type { DarwinExperiment } from "../types.js"; /** One harvested demonstration, ready for rendering. */ export interface DemoCandidate { /** The task the agent was given. */ task: string; /** The agent's (high-scoring) output. */ output: string; /** Critic score (1-10) that qualified this run as a demo. */ score: number; /** Task category the run was classified under. */ taskType: string; } /** Options for {@link selectDemoCandidates}. */ export interface DemoSelectionOptions { /** * Maximum number of demos to keep (default {@link DEFAULT_MAX_DEMOS}). * SIMBA defaults to 4 per predictor; Darwin defaults lower (2) because the * online loop appends demos to a single system prompt and prompt length * correlates NEGATIVELY with reliability (documented v2-prompt incident). */ maxDemos?: number; /** * Minimum critic score for a run to qualify (default * {@link DEFAULT_DEMO_SCORE_THRESHOLD}). Mirrors the closed-loop feedback * convention where ≥ 8 marks a high-quality pattern. */ scoreThreshold?: number; /** * Minimum output length (chars) for a run to qualify (default * {@link DEFAULT_DEMO_MIN_OUTPUT_CHARS}). Filters out degenerate/truncated * outputs that scored well on a technicality. */ minOutputChars?: number; } /** Options for {@link buildDemoSection}. */ export interface DemoRenderOptions { /** Cap on the quoted task text, chars (default {@link DEFAULT_DEMO_TASK_CHARS}). */ maxTaskChars?: number; /** * Cap on each quoted output excerpt, chars (default * {@link DEFAULT_DEMO_OUTPUT_CHARS}). Truncation prefers a sentence/newline * boundary, same policy as the reflector's output cleaning. */ maxOutputChars?: number; } export declare const DEFAULT_MAX_DEMOS = 2; export declare const DEFAULT_DEMO_SCORE_THRESHOLD = 8; export declare const DEFAULT_DEMO_MIN_OUTPUT_CHARS = 200; export declare const DEFAULT_DEMO_TASK_CHARS = 240; export declare const DEFAULT_DEMO_OUTPUT_CHARS = 900; /** Start marker — everything between the markers is Darwin-managed. */ export declare const DEMO_SECTION_START = ""; /** End marker. */ export declare const DEMO_SECTION_END = ""; /** * Harvest demo candidates from an agent's experiment history. * * Filter: successful runs with a critic score ≥ `scoreThreshold` and an * output of at least `minOutputChars`. Diversity: at most ONE demo per task * type (the best-scoring run of that type, recency as tie-break) so two demos * never showcase the same narrow strength. Order: score descending, then * most-recent first — fully deterministic. */ export declare function selectDemoCandidates(experiments: ReadonlyArray, options?: DemoSelectionOptions): DemoCandidate[]; /** * Render demo candidates as a marker-delimited prompt section. * * Returns an empty string for an empty demo list so callers can treat * "nothing to inject" uniformly. */ export declare function buildDemoSection(demos: ReadonlyArray, options?: DemoRenderOptions): string; /** * Apply a rendered demo section to a prompt. * * If the prompt already contains a marker-delimited demo section it is * REPLACED in place (demos stay fresh, never stack); otherwise the section is * appended after a blank line. An empty `section` returns the prompt with any * existing demo section stripped — passing "no demos" acts as removal. * * The replacement uses a FUNCTION replacer: with a string replacer, * `$&` / `$'` / `` $` `` / `$$` inside the section (an agent output quoting * JS-regex or shell docs contains exactly these) would be interpreted as * replacement patterns and garble the prompt on every refresh cycle. */ export declare function applyDemoSection(prompt: string, section: string): string; /** * Remove the marker-delimited demo section (if any), collapsing the blank * line that {@link applyDemoSection} inserted. Prompts without a section are * returned unchanged. */ export declare function stripDemoSection(prompt: string): string; //# sourceMappingURL=demos.d.ts.map