/**
 * constrainedEnumPick — ONE model call that can only answer from a fixed
 * list (9.19.0). The machinery extracted from `llmClassifier` so the tier-3
 * decider (RouteTurn's out-of-band menu resolver) and the classifier share
 * one enum discipline instead of two drifting copies:
 *
 *   • When `forcedToolChoiceFor(provider, model)` permits it, the pick rides
 *     a forced synthetic tool whose single argument is `enum: allowed` —
 *     the same mechanism the `'tool-forced'` output strategy uses. The
 *     provider constrains generation; an answer outside the enum cannot be
 *     emitted at all.
 *   • On any other provider it is a strict single-line parse validated
 *     against the enum, ONE structured re-ask, then the caller's fallback.
 *
 * An off-enum answer is a PARSE FAILURE, never a pick — this function can
 * never return an id it was not given (the `allowed` list plus `fallback`).
 * Callers put their own "none" sentinel INTO `allowed` (and as `fallback`)
 * so the model can decline explicitly; the sentinel is a first-class enum
 * member on the wire, exactly as `llmClassifier` has always sent it.
 */
import type { LLMProvider } from '../provider-contract/types.js';
/** The synthetic pick tool, named by the caller (the wire shows this name). */
export interface EnumPickTool {
    readonly name: string;
    readonly description: string;
    /** The single argument's name (`'intent'` for the classifier, `'skill'`
     *  for the decider) — a reader of the raw request sees the domain word. */
    readonly argName: string;
    readonly argDescription: string;
}
export interface ConstrainedEnumPickRequest {
    readonly provider: LLMProvider;
    /** Model id for the call. Left unset, the request carries an empty model
     *  id, which only the mock tolerates — name it for any real provider. */
    readonly model?: string;
    /** The catalog/context prompt — WITHOUT the parse instruction; the parse
     *  path appends its own, so both paths read one catalog. */
    readonly systemPrompt: string;
    readonly messages: ReadonlyArray<{
        readonly role: 'user' | 'assistant';
        readonly content: string;
    }>;
    /** The complete enum, the caller's decline-sentinel included. */
    readonly allowed: readonly string[];
    /** Returned on parse failure / off-enum after the one re-ask (callers pass
     *  their decline-sentinel, conventionally `'none'`). */
    readonly fallback: string;
    readonly pickTool: EnumPickTool;
    readonly signal?: AbortSignal;
}
/** Run the pick. Resolves to a member of `allowed`, else `fallback`. */
export declare function constrainedEnumPick(req: ConstrainedEnumPickRequest): Promise<string>;
/**
 * A trimmed single-token answer that IS one of the allowed ids, else undefined.
 * The decoration is walked off each end, not matched with `/[…]+$/`: the
 * reply is model output, and that regex retries from every position of a long
 * run of quotes (`lib/linearText.ts` · "Why these exist").
 */
export declare function parseEnumLine(content: string, allowed: readonly string[]): string | undefined;
