/**
 * In-memory harness for the `ask_user_choices` tool.
 *
 * The tool extension POSTs to `/api/internal/user-question` and blocks.
 * The server calls `register()` to park a Promise keyed by (sessionId, toolUseId).
 * The UI widget POSTs answers to `/api/internal/user-question/submit`, which
 * calls `submit()` to resolve the parked Promise — the HTTP response to the
 * tool extension then carries the answers back to the agent.
 *
 * Not persisted across restarts: if the server restarts while a question is
 * pending, the extension's HTTP call is severed and the tool returns an error.
 */
export interface UserQuestion {
    question: string;
    options: string[];
    allow_other?: boolean;
    /** When true, the UI renders checkboxes and `selected` is an array. */
    multi?: boolean;
    /** Minimum number of selections when `multi`. Defaults to 1. */
    min?: number;
    /** Maximum number of selections when `multi`. Defaults to options.length (+1 if allow_other). */
    max?: number;
}
export interface UserQuestionAnswer {
    question: string;
    /**
     * Single-select: option text the user picked; "Other" when free-text.
     * Multi-select: array of option texts (may include "Other").
     */
    selected: string | string[];
    /** Free-text content when "Other" was picked, otherwise null. */
    other_text: string | null;
}
export interface PendingUserQuestion {
    sessionId: string;
    toolUseId: string;
    questions: UserQuestion[];
    createdAt: number;
    resolve: (answers: UserQuestionAnswer[]) => void;
    reject: (err: Error) => void;
}
/**
 * Validate the shape of `questions`. Returns null on success, or a human-readable
 * error message on failure.
 */
export declare function validateQuestions(questions: unknown): string | null;
/**
 * Validate the raw shape of `answers` submitted by the UI (no cross-check
 * against questions — that happens inside submit()).
 */
export declare function validateAnswers(answers: unknown): string | null;
export type SubmitResult = {
    ok: true;
} | {
    ok: false;
    code: "not_found" | "invalid";
    error: string;
};
export declare class UserQuestionHarness {
    /** keyed by `${sessionId}:${toolUseId}` — allows concurrent questions per session */
    private pending;
    private key;
    /**
     * Register a pending question and return a Promise that resolves when the
     * user submits, or rejects if the session is terminated.
     *
     * Idempotent: if the same (sessionId, toolUseId) registers twice (e.g. agent
     * replay), the second call receives the same resolution as the first.
     */
    register(sessionId: string, toolUseId: string, questions: UserQuestion[]): Promise<UserQuestionAnswer[]>;
    /**
     * Resolve a pending question with the user's answers.
     * Cross-validates the answers against the registered question shape.
     */
    submit(sessionId: string, toolUseId: string, answers: UserQuestionAnswer[]): SubmitResult;
    /**
     * Reject all pending questions for a given session — called on session
     * termination or abort.
     */
    rejectAllForSession(sessionId: string, reason?: string): void;
    /** Inspection helper — list pending questions for a session (UI rehydrate). */
    listForSession(sessionId: string): PendingUserQuestion[];
    /** Test-only: clear all pending. */
    clear(): void;
    /** Total number of pending questions (for diagnostics). */
    size(): number;
}
//# sourceMappingURL=user-question-harness.d.ts.map