import { type ChatMessageReasoningClassNames, type ChatMessageReasoningTranslations } from './ChatMessageReasoning'; import type { ChatComponentPropsWithContext, ChatMessageBase, ChatStatus, ClientSideTools, ReasoningUIPart, TextUIPart } from './types'; import type { ComponentProps, Renderer, VNode } from '../../types'; export type ChatMessageSide = 'left' | 'right'; export type ChatMessageVariant = 'neutral' | 'subtle'; export type ChatMessageTranslations = { /** * The label for the message */ messageLabel: string; /** * The label for message actions */ actionsLabel: string; /** * The retry button text for failed tools */ toolErrorRetryText?: string; } & Partial; export type ChatMessageClassNames = { /** * Class names to apply to the root element */ root: string | string[]; /** * Class names to apply to the container element */ container: string | string[]; /** * Class names to apply to the leading element (avatar area) */ leading: string | string[]; /** * Class names to apply to the content wrapper */ content: string | string[]; /** * Class names to apply to the message element */ message: string | string[]; /** * Class names to apply to the actions container */ actions: string | string[]; /** * Class names to apply to the footer element */ footer: string | string[]; } & Partial; export type ChatMessageActionProps = { /** * The icon to display in the action button */ icon?: () => JSX.Element; /** * The title/tooltip for the action */ title?: string; /** * Whether the action is disabled */ disabled?: boolean; /** * Click handler for the action */ onClick?: (message: ChatMessageBase) => void; }; export type ChatMessageTextComponentProps = { /** * The text part to render */ part: TextUIPart; /** * The message containing the text part */ message: TMessage; /** * The full conversation, when available */ messages?: TMessage[]; /** * The current chat status */ status: ChatStatus; /** * The text part's index in the full `message.parts` array */ partIndex: number; }; export type { ChatMessageReasoningPart } from './ChatMessageReasoning'; export type ChatMessageReasoningComponentProps = ChatComponentPropsWithContext<{ /** * The reasoning part to render */ part: ReasoningUIPart; /** * The reasoning part's index in the full `message.parts` array */ partIndex: number; /** * Whether this reasoning part is currently being produced */ isStreaming: boolean; /** * The message containing the reasoning part */ message: TMessage; }, TMessage>; export type ChatMessageProps = ComponentProps<'article'> & { /** * The message object associated with this chat message */ message: TMessage; /** * The side of the message */ side?: ChatMessageSide; /** * The variant of the message */ variant?: ChatMessageVariant; /** * Array of action buttons */ actions?: ChatMessageActionProps[]; /** * Whether to auto-hide actions until hover */ autoHideActions?: boolean; /** * Leading content */ leadingComponent?: () => JSX.Element; /** * Custom actions renderer */ actionsComponent?: (props: ChatComponentPropsWithContext<{ actions: ChatMessageActionProps[]; message: ChatMessageBase; }>) => JSX.Element | null; /** * Footer content */ footerComponent?: () => JSX.Element; /** * Custom text part renderer */ textComponent?: (props: ChatMessageTextComponentProps) => JSX.Element | null; /** * Custom reasoning renderer, called once per reasoning part at that part's own * stream position. It changes how reasoning renders, not whether: reasoning * renders by default, and `showReasoning: false` suppresses this renderer * along with it. */ reasoningComponent?: (props: ChatMessageReasoningComponentProps) => JSX.Element | null; /** * The index UI state */ indexUiState: object; /** * Set the index UI state */ setIndexUiState: (state: object) => void; /** * The full conversation. Forwarded to tool and text components so those that * only receive object IDs (e.g. Grouped Results) can hydrate records from a * preceding search tool's hits. Defaults to `context.messages` when omitted. */ messages?: TMessage[]; /** * @deprecated Read `context.status` instead. Overrides `context.status` when * provided, for callers written against the previous API. */ status?: ChatStatus; /** * @deprecated Read `context.tools` instead. Overrides `context.tools` when * provided, for callers written against the previous API. */ tools?: ClientSideTools; /** * @deprecated Read `context.onClose` instead. Overrides `context.onClose` * when provided, for callers written against the previous API. */ onClose?: () => void; /** * Optional suggestions element */ suggestionsElement?: VNode; /** * Optional loader element, rendered under the message's parts. Set by * `ChatMessages` when `loaderPosition` is `message-inline`. */ loaderElement?: VNode; /** * Whether to render the reasoning an agent sends. `true` by default, so * reasoning that arrives is shown. Pass `false` to suppress it in this * widget. It cannot make an agent send reasoning: whether reasoning reaches * the client at all is the agent's own `sendReasoning` setting. */ showReasoning?: boolean; /** * Optional class names */ classNames?: Partial; /** * Optional translations */ translations?: Partial; /** * Whether to render text and reasoning parts as markdown. * * When `true` (default), they are compiled with `markdown-to-jsx` (links, * code blocks, emphasis, …). When `false`, they render as plain text with * newlines preserved — useful for user messages where the source is the * human's literal input and incidental markdown syntax (`*`, `_`, …) * shouldn't be transformed. Note that opting out means links in the output * are no longer clickable. */ parseMarkdown?: boolean; }; export declare function createChatMessageComponent({ createElement, Fragment, }: Renderer): (userProps: ChatComponentPropsWithContext, TMessage>) => JSX.Element | null;