import { UIMessage } from '@tanstack/ai';
import { AIPersistence, ChatTranscriptStores } from './types.js';
/**
 * The JSON body `reconstructChat` returns and a server-authoritative client
 * hydrates from on mount.
 *
 * `messages` is the stored transcript as UI messages (ready to paint).
 * `activeRun` is a cursor to a run still generating for the thread, or `null` —
 * resolved from the STABLE thread id via `stores.runs.findActiveRun`, so the
 * client learns "there is a live run to tail" without ever handling a run id.
 * `interrupts` is the thread's pending human-in-the-loop interrupts (tool
 * approvals, client-tool/generic waits) and the run they paused, or `null` —
 * so a reload (or another device) re-prompts the approval from the SERVER, not
 * from client storage. Resolved via `stores.interrupts.listPending`.
 */
export interface ReconstructedChat {
    messages: Array<UIMessage>;
    activeRun: {
        runId: string;
    } | null;
    interrupts: {
        runId: string;
        pending: Array<Record<string, unknown>>;
    } | null;
}
export interface ReconstructChatOptions {
    /** Query parameter carrying the thread id. Defaults to `threadId`. */
    param?: string;
    /**
     * Authorize access to the requested thread before loading history.
     *
     * ⚠️ Without this, any caller who knows or guesses `?threadId=` receives the
     * full transcript. Multi-user / multi-tenant deployments **must** supply
     * an authorization check (session → owned threads) or resolve a validated
     * thread id in the route and pass it via a custom `param` that only your
     * server sets.
     *
     * Return:
     * - `true` to allow the load
     * - `false` for a default `403` response
     * - a `Response` to return as-is (e.g. `401` with a body)
     */
    authorize?: (threadId: string, request: Request) => boolean | Response | Promise<boolean | Response>;
}
/**
 * Build the JSON `Response` a server-authoritative client hydrates from on load
 * (see the client-persistence guide). Reads the thread id from the request query
 * (`?threadId=` by default) and returns `{ messages, activeRun, interrupts }`
 * ({@link ReconstructedChat}):
 *
 * - `messages` — the stored transcript as UI messages.
 * - `activeRun` — `{ runId }` if a run is still generating for the thread (so the
 *   client tails it via the durability stream), else `null`. Resolved via the
 *   required `stores.runs.findActiveRun`; `null` when the `runs` store is absent.
 * - `interrupts` — `{ runId, pending }` if the thread has pending human-in-the-loop
 *   interrupts (a paused approval / wait) and the run they paused, else `null`, so
 *   a reload re-prompts the decision from the server. Resolved via the optional
 *   `stores.interrupts.listPending`; `null` when that store is absent.
 *
 * Requires `stores.messages`. Returns an empty transcript with no active run
 * and no interrupts when the thread id is missing or the thread is unknown, so
 * the caller never has to special-case a first load.
 *
 * This helper does **not** enforce tenancy by itself. Pass
 * {@link ReconstructChatOptions.authorize} (or wrap the call in your own
 * session gate) before exposing it on a public route.
 *
 * ```ts
 * export async function GET(request: Request) {
 *   return reconstructChat(persistence, request, {
 *     authorize: async (threadId, req) => {
 *       const userId = await getSessionUserId(req)
 *       return userId != null && (await userOwnsThread(userId, threadId))
 *     },
 *   })
 * }
 * ```
 */
export declare function reconstructChat(persistence: AIPersistence<ChatTranscriptStores>, request: Request, options?: ReconstructChatOptions): Promise<Response>;
