/**
 * IntentScorer — the pluggable PORT that judges a new user message against the
 * graph's declared intents (SG-C tier 2).
 *
 * Custody split, deliberately: a scorer produces NUMBERS for EVERY candidate —
 * never a bare winner — and the FRAMEWORK (`routingPolicy.decideTier2`)
 * applies the floor and the near-tie margin, decides the verdict, and records
 * it. That is what keeps scorers a tier and never a correctness dependency: a
 * scorer cannot route by itself, and its near-ties fall through to the model.
 *
 * Three built-ins share this port:
 *   • `keywordScorer()`        — widened in `entryScorer.ts` (no dependency;
 *     set-cosine over intent + example tokens; `floor: 0` — zero overlap IS
 *     honestly "did not match at all");
 *   • `embeddingScorer(e)`     — widened in `entryScorer.ts` (semantic cosine;
 *     NO floor unless the consumer declares one — an absolute embedding
 *     threshold is a lie by default);
 *   • `llmClassifier(provider)` — `llmClassifier.ts` (one constrained-enum
 *     model call per turn, off the hot loop; `categorical`).
 *
 * `when` predicates remain the opaque escape hatch — tier 1, never scored.
 */
/** One candidate the classifier judges — a declared intent, or the incumbent
 *  skill (its `intent` = its description; examples may be empty). Ids are
 *  never fabricated — every candidate comes from the graph. */
export interface IntentCandidate {
    readonly id: string;
    /** One sentence naming the intent ("customer wants a refund"). */
    readonly intent: string;
    /** Real user phrasings. May be empty only for the incumbent. */
    readonly examples: readonly string[];
}
/** What a scorer receives. `recentTurns` is present ONLY when the scorer
 *  declared a `window` — newest last, the current message excluded. */
export interface IntentScorerInput {
    /** The NEW user message that started this turn. */
    readonly message: string;
    readonly recentTurns?: ReadonlyArray<{
        readonly role: 'user' | 'assistant';
        readonly content: string;
    }>;
}
/** One candidate's raw, strategy-specific score — same contract as
 *  `EntryScore.score`: higher = more relevant, not normalized across
 *  strategies. The framework softmaxes for the recorded relevance shares. */
export interface IntentScore {
    readonly id: string;
    readonly score: number;
}
/**
 * The port. Score EVERY candidate — the framework refuses a result that omits
 * a candidate or names an id it wasn't given (see {@link validateIntentScores}).
 * Runs ONCE per turn, off the hot loop, in the RouteTurn stage.
 */
export interface IntentScorer {
    /** Short stable name — lands on the record (`turn_routed.scorer`). */
    readonly name: string;
    /** Declared floor: a raw score at/below it means "did not match at all".
     *  Absent = this scorer cannot honestly claim non-match (embeddings). */
    readonly floor?: number;
    /** Declared recent-turns window (count of prior conversational turns the
     *  scorer wants to see). Absent = current message only. */
    readonly window?: number;
    /** One id or none (the LLM classifier): a pick is decisive by construction
     *  and is never diluted by the near-tie margin. */
    readonly categorical?: boolean;
    score(input: IntentScorerInput, candidates: readonly IntentCandidate[], signal?: AbortSignal): Promise<readonly IntentScore[]> | readonly IntentScore[];
}
/**
 * The framework's half of the scorer contract: every candidate scored exactly
 * once, no foreign ids. Returns the scores in CANDIDATE order (so a scorer
 * that reordered them cannot smuggle a different ranking past the caller's
 * declaration order). Throws a teaching error naming the scorer, what it
 * omitted or invented, and the contract — the RouteTurn stage treats that
 * throw exactly like a scorer failure (fall through to the recorded fallback),
 * because a misbehaving scorer must never abort a run.
 */
export declare function validateIntentScores(scorerName: string, candidates: readonly IntentCandidate[], result: readonly IntentScore[]): readonly IntentScore[];
