import type { ActionProposal, ActionProposalMutationResult } from '../spi/action-proposal-store.js';
import type { UiCapabilities } from '../ui-capabilities.js';
import { type ChatFrame, type ChatPart } from './sse.js';
/**
 * Body of `POST /agent/chat` (shape accepted by the provider → `AgentService.chat`). `message` is
 * required; everything else is optional context. `pageContext` reaches the tools' ctx (not the model
 * prompt) and is rebuilt from each turn's input, so send it on every message, not just the first.
 */
export interface AgentChatRequestBody {
    message: string;
    threadId?: string;
    agent?: string;
    persona?: string;
    pageContext?: {
        kind?: string;
        [key: string]: unknown;
    };
    uiCapabilities?: UiCapabilities;
    /** Uploads named by id alone (`POST <base>/attachments` answered them). */
    attachments?: unknown[];
    /** Run THIS turn on a catalog model (`GET <base>/models`). Never pins it on the thread. */
    model?: string;
    /**
     * Answer the thread's last user message again (needs `threadId`; `message` is ignored): the
     * server drops the old answer and streams a new one under a new run.
     */
    regenerate?: true;
    /**
     * What to do when the thread already has a turn running: `'auto'` (default — run now, else wait
     * in the thread's queue), `'queue'` (always queue), `'interrupt'` (cancel the running turn and run
     * this next). A queued send answers `202` — see {@link AgentChatQueued}.
     */
    mode?: 'auto' | 'queue' | 'interrupt';
}
/**
 * What `POST {basePath}/chat` answers (`202`) when the message waits in its thread's queue instead
 * of running: nothing streams. `runId` is present when it started straight away (attach with
 * {@link AgentChatClient.resume}); otherwise it runs — under `messageId` as its run id — once the
 * turn ahead of it settles, announced by a `queue` event with `started` in that turn's stream.
 */
export interface AgentChatQueued {
    queued: true;
    threadId: string;
    messageId: string;
    /** 0-based place in the queue (`0` → runs next). */
    position: number;
    queue: {
        items: {
            id: string;
            content: string;
            [key: string]: unknown;
        }[];
        paused: unknown;
    };
    runId?: string;
    /** The run an interrupt cancelled to make room for it. */
    interrupting?: string;
}
/** Options for {@link createAgentChatClient}. */
export interface AgentChatClientOptions {
    /**
     * Base path the provider mounted its routes under (`POST {basePath}/chat`,
     * `GET {basePath}/chat/:runId/stream`). Defaults to `/agent`.
     */
    basePath?: string;
    /** `fetch` implementation to use. Defaults to `globalThis.fetch`. */
    fetch?: typeof fetch;
    /**
     * Extra headers merged into every request — e.g. an anti-CSRF token (`{ 'X-XSRF-TOKEN': ... }`).
     * Called per request so a rotating token is always read fresh.
     */
    getHeaders?: () => Record<string, string>;
    /** Reconnection policy for a dropped stream, or `false` to disable and fail on the first drop. */
    resume?: AgentChatResumeOptions | false;
}
/** Reconnection policy: how many times to re-attach, and the backoff before each attempt. */
export interface AgentChatResumeOptions {
    /** Max consecutive re-attach attempts before giving up. Defaults to 6. */
    maxAttempts?: number;
    /** Backoff before attempt `n` (1-based), in ms. Defaults to `min(400 * n, 3000)`. */
    backoffMs?: (attempt: number) => number;
}
/** Callbacks fired while a stream is consumed. All optional. */
export interface AgentChatHandlers {
    /** The assistant message's parts so far, rebuilt on every frame (safe to render directly). */
    onParts?: (parts: ChatPart[]) => void;
    /** Each decoded renderable/control frame, in wire order. */
    onFrame?: (frame: ChatFrame) => void;
    /** The run id, as soon as it is known (response header, then the `meta` frame). */
    onRunId?: (runId: string) => void;
    /** The thread id, as soon as it is known. */
    onThreadId?: (threadId: string) => void;
}
/** Arguments to {@link AgentChatClient.send}. */
export interface AgentChatSendOptions extends AgentChatHandlers {
    body: AgentChatRequestBody;
    signal?: AbortSignal;
}
/** The settled result of a completed chat turn. */
export interface AgentChatResult {
    runId?: string;
    threadId?: string;
    parts: ChatPart[];
    /** Present when the server queued the message instead of streaming a reply (`202`). */
    queued?: AgentChatQueued;
    proposalDecision?: ActionProposalMutationResult | {
        status: 'ambiguous';
        proposalIds: string[];
    };
}
/**
 * Thrown when a run's stream dropped and could not be resumed within the retry budget. Carries the
 * partial parts received so far (and the ids) so a consumer can keep what streamed and surface a
 * "couldn't finish, try again" state instead of losing the message.
 */
export declare class AgentChatDisconnectedError extends Error {
    readonly runId: string | undefined;
    readonly threadId: string | undefined;
    readonly parts: ChatPart[];
    constructor(runId: string | undefined, threadId: string | undefined, parts: ChatPart[]);
}
/**
 * The server refused the request before any stream started — a non-2xx answer. `message` is the
 * server's own words (`{ message, code? }`, the body every refusal answers), `code` its
 * machine-readable reason (`quota_exceeded`, `model_not_allowed`, `thread_required`, …) and `body`
 * the parsed answer, or `undefined` when it was not JSON.
 */
export declare class AgentChatHttpError extends Error {
    readonly status: number;
    readonly code: string | undefined;
    readonly body: unknown;
    constructor(status: number, message: string, code: string | undefined, body: unknown);
}
/**
 * The server ended the run with `event: error` (agent protocol). Not a dropped connection: the run
 * is over, so it is surfaced rather than re-attached. `code` is the server's (`quota_exceeded`,
 * `output_rejected`, `structured_output_invalid`, `run_failed`).
 */
export declare class AgentChatStreamError extends Error {
    readonly code: string;
    constructor(code: string, message: string);
}
/**
 * A framework-agnostic client for the agent chat SSE endpoints. `send` posts a turn and streams the
 * reply; if the connection drops before the run finishes, it re-attaches to
 * `GET {basePath}/chat/:runId/stream` — which replays the whole stream from the start and follows live
 * — with backoff, until the run emits `done` or the retry budget is exhausted. The run itself is
 * durable and keeps executing server-side across the drop, so no tokens are lost.
 */
export interface AgentChatClient {
    send(options: AgentChatSendOptions): Promise<AgentChatResult>;
    listActionProposals(threadId: string, signal?: AbortSignal): Promise<ActionProposal[]>;
    decideActionProposal(threadId: string, proposalId: string, decision: 'approved' | 'rejected', command?: {
        remember?: boolean;
        reason?: string;
    }, signal?: AbortSignal): Promise<ActionProposalMutationResult>;
    /** Re-attach to an already-started run (e.g. after a fresh page load) and stream it to completion. */
    resume(runId: string, options?: AgentChatHandlers & {
        signal?: AbortSignal;
    }): Promise<AgentChatResult>;
}
export declare function createAgentChatClient(options?: AgentChatClientOptions): AgentChatClient;
//# sourceMappingURL=chat-client.d.ts.map