/** * Darwin — Alignment Preservation Guard (shared, v0.6.0). * * Single source of truth for the safety-keyword preservation check. BOTH * the legacy single-shot {@link PromptOptimizer} AND the GEPA reflective * loop path (v0.6) run this guard on every mutated prompt — a mutation * that drops safety constraints ("never", "do not", "must not", …) is * rejected so self-evolution cannot silently erode alignment. * * Why this module exists (v0.6.0): before the GEPA optimizer was wired * into {@link DarwinLoop}, this check lived ONLY as a private method on * `PromptOptimizer`. The Reflector / `GepaOptimizer.merge` paths had no * alignment guard. Wiring GEPA into the loop without extracting the check * to a shared layer would have opened a safety-regression hole — the new * mutation path could quietly strip "never reveal secrets" and ship it. * Extracting it here means every mutation path, old and new, runs the * exact same guard. * * The check is intentionally conservative: it counts occurrences of each * safety pattern in the original and rejects the mutation if any pattern's * count drops. It cannot understand semantics (a reworded-but-equivalent * constraint is also rejected) — that false-positive is deliberate. A * rejected mutation costs one evolution cycle; a silently weakened safety * instruction shipped to production is unbounded. Fail closed. */ /** * Safety / alignment keyword patterns whose occurrence count must not * decrease across a mutation. Each pattern's `.source` is re-compiled with * the `gi` flag in {@link checkAlignmentPreservation} and matched against the * lower-cased original + mutated prompts, so the per-entry `/i` flag is * informational only. Kept as an explicit, auditable list. * * v0.6.0: the three case-variant duplicates the legacy optimizer carried * (`/\bdo NOT\b/`, `/\bNEVER\b/`, `/\bMUST NOT\b/`) were dropped — under the * `gi` recompile they were exact duplicates of the `/i` entries above and * only produced doubled keyword names in the rejection message. The * accept/reject decision is unchanged. */ export declare const SAFETY_PATTERNS: RegExp[]; /** * Check that a mutated prompt preserves the safety-related keywords from * the original. * * @returns `null` if the mutation is safe (no safety keyword count dropped), * or a human-readable rejection reason naming the eroded keywords. */ export declare function checkAlignmentPreservation(original: string, mutated: string): string | null; /** * Batch embedding function. Returns one vector per input text (same order). * INJECTED — Darwin keeps zero hard deps, so the caller supplies the embedder * (OpenAI `text-embedding-3-small`, a local model, Anthropic, whatever). Pure * keyword checking needs none of this; semantic checking is strictly opt-in. * * NEW v0.7.0. */ export type EmbedFn = (texts: string[]) => Promise; export interface SemanticAlignmentOptions { /** Injected batch embedder. When omitted, the check is keyword-only (fail-closed). */ embed?: EmbedFn; /** * Cosine-similarity threshold above which an eroded safety keyword is judged * to have been REWORDED (not removed) and the mutation is accepted. Default * 0.82 — high enough that only a genuinely equivalent restatement passes. */ minSafetySimilarity?: number; } /** * Semantic alignment guard (v0.7.0) — the embedding-distance upgrade to the * keyword-count {@link checkAlignmentPreservation}. The keyword check is * conservative BY DESIGN: it rejects a reworded-but-equivalent constraint * ("never reveal secrets" → "you must keep secrets confidential") as if the * safety instruction were removed. That false-positive costs a wasted * evolution cycle every time the optimizer legitimately rephrases. * * This function keeps the keyword check as the first, cheap gate, and ONLY * when it trips does it spend embeddings to ask: "is the safety statement * still semantically present, just worded differently?" For every safety * sentence in the original that contained an eroded keyword, it checks whether * the mutated prompt still contains a sentence above `minSafetySimilarity`. If * EVERY eroded safety sentence has a close semantic match, the rewording is * accepted (returns null). Otherwise the keyword rejection stands. * * Fail-closed contract preserved: * - keyword check passes ⇒ null (no embedding spent) * - keyword check fails AND no `embed` supplied ⇒ keyword rejection (== sync) * - keyword check fails, embed supplied, embedding errors ⇒ keyword rejection * * So a missing/broken embedder NEVER weakens the guard — it just falls back to * the strict keyword behaviour. */ export declare function checkAlignmentPreservationSemantic(original: string, mutated: string, opts?: SemanticAlignmentOptions): Promise; //# sourceMappingURL=alignment.d.ts.map