import type { CitationSource } from './CitationChip/index.js'; /** Author of a chat message. */ export type ChatRole = 'user' | 'assistant' | 'system'; /** * Lifecycle of a message. `streaming` drives the live-rendering affordances * (markdown tail repair, cursor, deferred screen-reader announcement); * `error` / `aborted` switch the message to its failure presentation. * A message without a status counts as `complete`. */ export type ChatMessageStatus = 'streaming' | 'complete' | 'error' | 'aborted'; /** * One renderable segment of a message. Mirrors the shape of modern * model/tool transcripts: interleaved text, reasoning, tool calls, sources * and attachments — rendered in order by the ChatMessage component. */ export type ChatMessagePart = /** Markdown text, rendered through StreamingMarkdown. */ { type: 'text'; text: string; } /** Model reasoning. Collapsed, tertiary presentation; `durationMs` feeds the "Thought for Xs" label. */ | { type: 'reasoning'; text: string; durationMs?: number; } /** A tool invocation with its lifecycle state. Rendered as a ToolCallCard by default; override via `partRenderers`. */ | { type: 'tool-call'; id: string; name: string; state: 'pending' | 'running' | 'complete' | 'error'; input?: unknown; output?: unknown; errorMessage?: string; } /** A cited source. Same shape as CitationSource — also feeds StreamingMarkdown's `sources` for `[id]` markers. */ | ({ type: 'source'; } & CitationSource) /** * A file attached to the message. `url` is only ever rendered as a * policy-checked download link (never as an inline image/iframe) — LLM- or * server-supplied URLs are untrusted input. */ | { type: 'attachment'; name: string; mimeType: string; size?: number; url?: string; } /** Declarative A2UI payload (P4). Validated fail-loud by A2UIView; ignored by default renderers until then. */ | { type: 'a2ui'; payload: unknown; }; /** The `tool-call` member of {@link ChatMessagePart} — the prop shape of ToolCallCard. */ export type ChatToolCallPart = Extract; /** The `reasoning` member of {@link ChatMessagePart} — the prop shape of ReasoningDisclosure. */ export type ChatReasoningPart = Extract; /** * One message in a conversation. Named `ChatMessageData` because the value * export `ChatMessage` is the component that renders it. */ export interface ChatMessageData { /** Stable unique id — keyed `{#each}` identity, never an array index. */ id: string; role: ChatRole; /** Ordered renderable segments. A plain text answer is `[{ type: 'text', text }]`. */ parts: ChatMessagePart[]; createdAt?: Date; /** Omitted counts as `complete`. */ status?: ChatMessageStatus; /** Consumer-defined extras (model name, token counts, …). Not rendered by defaults. */ metadata?: Record; }