import type { RunContext } from './approval-bus.js';
/** Hard caps on user-facing prompt + choice count + per-choice label. */
export declare const MAX_QUESTION_CHARS = 1000;
export declare const MAX_CHOICE_LABEL_CHARS = 80;
export declare const MIN_CHOICES = 2;
export declare const MAX_CHOICES = 9;
export interface AskPayload {
    question?: unknown;
    choices?: unknown;
    timeoutSec?: unknown;
    /** When true (default), text replies like "1" / "a" / the choice
     *  label substring match the corresponding option. Disable for
     *  strict button-only flows (the user must click a button or wait
     *  for the timeout). */
    allowTextReply?: unknown;
}
export interface AskChoice {
    /** 1-indexed for human readability (1 / 2 / 3 …) */
    index: number;
    /** Display label as shown to the user. */
    label: string;
}
export type AskResult = {
    ok: true;
    result: {
        /** 1-indexed choice the user picked. */
        index: number;
        /** The label that was shown for that choice. */
        label: string;
        /** 'button' | 'text' | 'timeout'. timeout never has a chosen
         *  index either — see ok=false for that. */
        via: 'button' | 'text';
        /** Raw user-typed text or button data; lets the agent diff
         *  against what was shown if needed. */
        raw: string;
    };
} | {
    ok: false;
    error: string;
    reason?: 'timeout' | 'cancelled' | 'invalid' | 'no-messenger';
};
/**
 * Handle one `ask_user` RPC. Returns the AskResult to be wired back to
 * the sidecar. ALL exceptions caught + converted; the bus never sees
 * a thrown error from here.
 */
export declare function handleAskOp(payload: AskPayload, ctx: RunContext): Promise<AskResult>;
/**
 * Router-side: try to resolve a pending ask for this thread with the
 * inbound text. Returns true iff the text was consumed (router should
 * skip normal routing).
 */
export declare function tryResolvePendingAsk(platform: string, channelId: string, threadId: string, rawText: string): boolean;
/**
 * Messenger-side: button callback handler. The data field is the
 * card's `data` we stored as `ask:<reqId>:<index>`. Returns true iff
 * resolved (caller can ack the tap).
 */
export declare function tryResolvePendingAskByButton(data: string): boolean;
/** Diagnostic: pending count per thread. Used by /ask status / future
 *  /tasks#ask web tile. */
export declare function listPendingAsks(): Array<{
    reqId: string;
    platform: string;
    threadId: string;
    question: string;
    choices: number;
    ageMs: number;
}>;
/**
 * Cancel a single pending ask by reqId. Returns true iff something
 * was cancelled. Used by the admin panel's per-row Cancel button —
 * the agent waiting on it gets { ok: false, reason: 'cancelled' }
 * back exactly as if the user had let it time out, which the agent
 * already knows how to handle.
 */
export declare function cancelPendingAsk(reqId: string, reason?: string): boolean;
/** Test hook: cancel everything. Useful between bun-test cases. */
export declare function _resetAskBusForTests(): void;
//# sourceMappingURL=ask-user-rpc.d.ts.map