/**
 * Surprise helper — D-MEM-style novelty score for a turn against recent memories.
 *
 * Used (eventually, in a follow-up PR) by the smart buffer as an additive flush
 * trigger: a turn that is semantically far from everything already in memory is
 * "surprising" and worth extracting immediately, even if turn-count and signal
 * heuristics would otherwise keep buffering.
 *
 * This module intentionally contains ONLY the pure scoring function. Wiring
 * into the buffer, configuration flags, telemetry, and benchmark work live in
 * later PRs (see issue #563). Keeping the helper in a sibling file instead of
 * inside `buffer.ts` keeps the buffer module focused and makes the eventual
 * integration a small, reviewable change.
 *
 * # Formula
 *
 * Given an input `turn` and a list of `recentMemories`:
 *
 * 1. Embed the turn and every candidate memory via the caller-provided
 *    `embedFn`.
 * 2. For each candidate, compute cosine similarity `cos(turn, candidate)` in
 *    `[0, 1]` (negative cosines are clamped to 0 — "opposite directions"
 *    is treated as maximally diverse, consistent with `recall-mmr.ts`).
 * 3. Keep the top-`k` *highest* similarities (the turn's nearest neighbors).
 * 4. Average those top-`k` similarities → `nearestSim ∈ [0, 1]`.
 * 5. Return `1 − nearestSim` as the surprise score.
 *
 * Intuition: a turn that is close to at least one recent memory has a high
 * `nearestSim` and therefore a *low* surprise (near 0 = redundant). A turn
 * that is far from all of its k nearest neighbors has a low `nearestSim` and
 * therefore a *high* surprise (near 1 = novel).
 *
 * Using the top-k average instead of a single nearest neighbor makes the
 * score less sensitive to one outlier duplicate (e.g. an exact restatement of
 * a stale fact). `k=1` reduces to pure nearest-neighbor distance.
 *
 * # Edge cases
 *
 * - `recentMemories` empty → returns `1.0` (maximally surprising). There is
 *   nothing to compare against, so the turn cannot be redundant.
 * - `k` default is `5`. It is clamped to `[1, recentMemories.length]` so that
 *   small corpora still produce a meaningful score (e.g. 3 memories with
 *   `k=5` behaves the same as `k=3`).
 * - Zero-norm embeddings (all zeros) contribute similarity `0` (they cannot
 *   be "close" to anything), which is treated as maximally surprising for
 *   that pair. The rest of the corpus is scored normally.
 * - Embedding-length mismatches between the turn and a candidate are treated
 *   as similarity `0` for that pair. We do not silently truncate to the
 *   shorter vector because that would hide a real configuration bug.
 * - `embedFn` rejection is allowed to propagate. The caller decides whether
 *   to catch, fall back, or fail the flush decision — this helper has no
 *   opinion beyond the pure score.
 *
 * # Purity
 *
 * No I/O, no hidden globals. Given the same inputs and the same `embedFn`,
 * the output is deterministic.
 */
/** Minimal shape of a recent memory passed to `computeSurprise`. */
interface RecentMemoryLike {
    /** Stable identifier. Only used for debug/logging; not part of the score. */
    readonly id: string;
    /** Text to embed and compare against the incoming turn. */
    readonly content: string;
}
/** Options accepted by `computeSurprise`. */
interface ComputeSurpriseOptions {
    /**
     * Embedding function. Called once for the turn and once per candidate
     * memory. Callers may wrap a provider client, a local model, or a
     * deterministic hash for tests.
     */
    readonly embedFn: (text: string) => Promise<readonly number[]>;
    /**
     * Number of nearest neighbors to average over. Defaults to 5. Clamped to
     * `[1, recentMemories.length]`.
     */
    readonly k?: number;
}
/** Default k (top nearest neighbors to average). */
declare const DEFAULT_SURPRISE_K = 5;
/**
 * Compute a surprise score in `[0, 1]` for `turn` against `recentMemories`.
 *
 * See the module-level docstring for the exact formula, edge cases, and
 * purity guarantees.
 *
 * @param turn           The incoming turn text (caller is responsible for
 *                       stringifying structured turn content — this helper
 *                       only needs the text to embed).
 * @param recentMemories Candidate memories to compare against.
 * @param options        `embedFn` (required) and optional `k` (defaults to 5).
 * @returns A scalar in `[0, 1]`. `1.0` = maximally surprising / novel;
 *          `0.0` = redundant with at least one recent memory.
 */
declare function computeSurprise(turn: string, recentMemories: readonly RecentMemoryLike[], options: ComputeSurpriseOptions): Promise<number>;

export { type ComputeSurpriseOptions, DEFAULT_SURPRISE_K, type RecentMemoryLike, computeSurprise };
