/**
 * Client-side counterpart to {@link import('../sse.js').AgentSseEncoder}: parses the provider's SSE
 * back into typed frames the browser can render. Kept framework-agnostic (no React, no Adonis) so
 * any consumer — a React hook, a Vue composable, a plain fetch loop — decodes the wire format the
 * same way, and so the envelope stays owned by the package that emits it.
 *
 * Wire format — the agent stream protocol shared with `@dudousxd/nestjs-agent`:
 * - `event: meta\ndata: {runId,threadId}`   — sent once, first, before any token
 * - `id: <seq>\ndata: <AgentStreamEvent>`    — one event per frame (`{"kind":"text","text":…}`,
 *   `ui`, `elicitation`, `approval-requested`, reasoning, tool calls, steps, title, …)
 * - `event: error\ndata: {code,message}`     — the run failed (terminal)
 * - `event: done\ndata: {}`                  — the run's stream finished
 */
import type { ElicitationRequest } from '../elicitation.js';
import type { ToolConfirmation } from '../tool-presentation.js';
/** A rendered part of an assistant message: streamed text, or a named component with its props. */
export type ChatPart = {
    type: 'text';
    text: string;
} | {
    type: 'component';
    name: string;
    data: unknown;
    id?: string;
    version?: number;
    fallbackText?: string;
    componentVersions?: Record<string, number>;
    /**
     * A preview of a layout the model is still writing (genui `streaming: 'partial'`): unvalidated,
     * replaced in place by the final component under the same `id`.
     */
    partial?: true;
};
/** A decoded stream frame — the typed form of one SSE event. */
export type ChatFrame = {
    type: 'text';
    delta: string;
} | {
    type: 'component';
    name: string;
    data: unknown;
    id?: string;
    version?: number;
    fallbackText?: string;
    componentVersions?: Record<string, number>;
    /**
     * A preview of a layout the model is still writing (genui `streaming: 'partial'`): unvalidated,
     * replaced in place by the final component under the same `id`.
     */
    partial?: true;
} | {
    type: 'meta';
    runId?: string;
    threadId?: string;
}
/** A failed run (`event: error` under the agent protocol). Terminal, like `done`. */
 | {
    type: 'error';
    code: string;
    message: string;
}
/** Any other agent-protocol event — reasoning, tool calls, steps, title, … */
 | {
    type: 'event';
    event: Record<string, unknown> & {
        kind: string;
    };
}
/**
 * A question set the run is parked on, with everything needed to answer it: `runId` and
 * `toolCallId` are the body `POST /agent/tool-call/answer` takes, and `request` is the form.
 *
 * `runId` is NOT necessarily the run this stream was opened for. A delegated sub-agent forwards
 * its frames into its top-level ancestor's stream — that is the only stream a human is watching —
 * so the run to answer is the child's, and reading it off `meta` would address the wrong one.
 */
 | {
    type: 'elicitation';
    runId: string;
    toolCallId: string;
    request: ElicitationRequest;
}
/**
 * An action tool awaiting an approve/reject, with what it means to run. `runId`/`toolCallId` are
 * the body `POST /agent/tool-call/approve` (or `/reject`) takes — and `runId` is the parked run,
 * which for a delegated sub-agent is not the run this stream was opened for.
 */
 | {
    type: 'approval';
    target?: {
        kind: 'proposal';
        proposalId: string;
    };
    runId: string;
    toolCallId: string;
    toolName: string;
    input: unknown;
    confirmation?: ToolConfirmation;
    approver?: string;
    expiresAt?: string;
    reason?: string;
} | {
    type: 'done';
};
/** One raw SSE event: the `event:` name (default `message`) and the joined `data:` payload. */
export interface SseEvent {
    event: string;
    data: string;
    /**
     * The frame's `id:` — its sequence number in the run. Strictly increasing within a run, gaps
     * allowed; `meta`, `done` and `error` carry none.
     */
    id?: string;
}
/**
 * Parses one raw SSE frame (the text between `\n\n` separators, without them) into `{event, data}`.
 * A frame with no `data:` line (e.g. a `:` keep-alive comment) returns `null`.
 */
export declare function parseSseEvent(frame: string): SseEvent | null;
/**
 * Decodes a parsed {@link SseEvent} into a typed {@link ChatFrame}, or `null` when the payload is
 * malformed (non-JSON, or missing required fields) so callers can skip it without crashing.
 */
export declare function decodeFrame(event: SseEvent): ChatFrame | null;
/**
 * Folds a renderable {@link ChatFrame} (text or component) into the message's parts, concatenating
 * consecutive text deltas into the trailing text part and appending components in order. A
 * `step-start` closes the text before it with a paragraph break ({@link STEP_SEPARATOR}), so two
 * model steps never run into each other.
 * `meta`/`elicitation`/`approval`/`done` are control frames and are ignored here — a form to put to
 * the user is not a part of the assistant's message. Returns a new array (never mutates the input).
 */
export declare function foldPart(parts: ChatPart[], frame: ChatFrame): ChatPart[];
/** What separates the text of two consecutive model steps in one message: a paragraph break. */
export declare const STEP_SEPARATOR = "\n\n";
/**
 * Reads a byte {@link ReadableStream} (a `fetch` `response.body`) as a sequence of raw SSE events,
 * splitting on the `\n\n` frame separator and buffering partial frames across chunks. Yields only
 * frames that carry a `data:` payload (keep-alives are dropped).
 */
export declare function readSseStream(body: ReadableStream<Uint8Array>): AsyncGenerator<SseEvent>;
/** The parts with every preview left standing removed — what a finished stream keeps. */
export declare function settleParts(parts: ChatPart[]): ChatPart[];
//# sourceMappingURL=sse.d.ts.map