import type { UIMessage } from 'ai';
import type { MessageFeedback } from '../../index.js';
import type { StoredMessage } from './client-wire.js';
/**
 * Summed usage/cost across the stored-message rows merged into one turn (see
 * {@link storedThreadToUiMessages}). Mirrors `MessageUsage`, but `costUsd` is always present
 * (never omitted) since it's a computed aggregate, not a single provider report.
 */
export interface AggregatedTurnUsage {
    inputTokens: number;
    outputTokens: number;
    /**
     * `null` only when EVERY merged row reports a null/absent cost (no pricing store bound, or an
     * unpriced model) — same "unknown, not a real $0" distinction `MessageUsage.costUsd` makes for a
     * single row. A null cost on SOME rows (mixed with priced ones) contributes `0` to the sum
     * instead of poisoning the whole turn's total to `null` — the tokens are still real and summed
     * either way, so only the cost figure would be understated, never wrong in a "$0 turn" sense.
     */
    costUsd: number | null;
}
/** Metadata the grouped `UIMessage` carries on `.metadata.usage` — see {@link AggregatedTurnUsage}. */
export interface StoredTurnMetadata {
    usage: AggregatedTurnUsage;
}
/**
 * Everything a message's `metadata` may carry from this library: `usage` on a merged replayed turn,
 * `feedback` on a replayed message that was rated (a merged turn is rated through its last row,
 * whose id it carries), `runId` on a live-streamed one, `costUsd` from the stream's step ends.
 */
export interface AgentMessageMetadata extends Partial<StoredTurnMetadata> {
    feedback?: MessageFeedback;
    runId?: string;
    costUsd?: number | null;
    /** ISO timestamp: the stored row's `createdAt` (a merged turn: its first row's), or when a live turn started streaming. */
    createdAt?: string;
    /** The agent that wrote a replayed message, when the row names one (`StoredMessage.agentName`). */
    agentName?: string;
    /** The persona the turn that wrote a replayed message ran under (`StoredMessage.persona`). */
    persona?: string;
    /** Host-defined keys: `StoredMessage.metadata` and the stream's `message-metadata` frames. */
    [key: string]: unknown;
}
/**
 * Convert a thread's full `StoredMessage[]` history into `UIMessage[]`, merging consecutive
 * assistant rows (no user message between them) into ONE `UIMessage` per turn.
 *
 * Why: the agent loop persists one row per model iteration (see `agent-loop.ts`'s per-step
 * `persist:assistant:${i}`) — a turn with tool calls appends "I'll check that..." + tool calls,
 * then a separate final-answer row. `storedMessageToUiMessage` maps 1:1, so a reloaded thread
 * renders 2-3 assistant bubbles (each with its own cost/tokens footer) for what the LIVE stream
 * renders as one continuous response (one `UIMessage`, stepped internally — see
 * `AgentChatTransport.toChunkStream`'s `start-step`/`finish-step` bracketing). This closes that gap
 * for replayed history.
 *
 * Merge shape: each row is mapped via `storedMessageToUiMessage` (unchanged — same text-then-tool
 * part ordering per row) and the parts are concatenated in row order, so the grouped message's parts
 * read as `[row1 text?, row1 tools?, row2 text?, row2 tools?, ...]` — exactly the sequence the live
 * transport streams for the same turn. The group's `id` is the LAST row's id (the final-answer row —
 * it's the one carrying `followUps`, and what a host keys turn-level actions like "fork" or
 * "regenerate" on). Non-assistant rows (user/system) pass through `storedMessageToUiMessage`
 * unchanged, one row → one message, same as today.
 *
 * A lone assistant row between two user rows (the common case: no tool calls, or already a single
 * iteration) has nothing to merge with, so it comes back byte-for-byte identical to calling
 * `storedMessageToUiMessage` directly — no `metadata` is added for that case either, preserving
 * exact backward compatibility for hosts that read stored usage some other way.
 *
 * Only an ACTUAL merge (2+ rows) attaches `metadata.usage` — the {@link AggregatedTurnUsage} summed
 * across the merged rows' `usage` (rows without a `usage` at all, e.g. an older/test fixture, are
 * skipped rather than treated as zero-and-priced).
 *
 * Deliberately NOT reproduced: the live transport's `{type: 'step-start'}` UI parts (one per model
 * call, emitted by the AI SDK for every `start-step` chunk — see `repro-real-frames.spec.ts` for a
 * captured wire dump). Those are structural brackets `MessageItem`'s `renderBlocks` never renders
 * (it draws only text, reasoning, files and tool blocks), and `storedMessageToUiMessage` has never
 * emitted them for a single row either — inventing them here would make a merged turn diverge from
 * a same-shaped unmerged one instead of converging on it. "Indistinguishable from the live stream"
 * is scoped to what actually renders: the text/tool-call content in step order, not the step
 * brackets around it.
 */
export declare function storedThreadToUiMessages(messages: StoredMessage[]): UIMessage[];
//# sourceMappingURL=stored-thread-to-ui-messages.d.ts.map