Skip to content

ChatMessage Component ​

Renders a single message in the chat: markdown text, images, file attachments, tool calls, sources, and the approval / question cards of a paused turn.

New in 0.4.0

Stop notices and warnings under an answer, cards for paused turns, image thumbnails, the built-in button row (toolbar), an editor for your own messages, and an AI label.

Import ​

tsx
import { ChatMessage } from "@cognipeer/chat-ui";

Usage ​

tsx
<ChatMessage
  message={{
    id: "msg-1",
    conversationId: "c-1",
    role: "assistant",
    content: "Hello! How can I help you?",
    createdAt: new Date(),
    updatedAt: new Date(),
  }}
/>

Props ​

PropTypeDefaultDescription
messageMessagerequiredThe message to render
isStreamingbooleanfalseWhether this message is streaming
streamingTextstring-Current streaming text (used while isStreaming)
showAvatarbooleantrueShow the avatar
showTimestampbooleanfalseShow the time
enableCitationsbooleantrueSources and inline markers under assistant messages
actionsChatActionsConfig-How approval / question cards behave under this message. Without onResolve they are read-only; see Approvals and Questions
renderActions(props: MessageActionProps) => ReactNode-Custom action buttons (shown on hover)
renderAvatar(role) => ReactNode-Custom avatar
renderImage(props: ImageRenderProps) => ReactNode-Draw an image yourself, e.g. fetch it with credentials and show a blob URL
renderStopNotice(props: StopNoticeRenderProps) => ReactNode-Replace the notice under an answer that stopped early
resolveFileUrl(file, { disposition? }) => Promise<string | undefined>-How to get a URL for a stored file that has none of its own (useChat returns one, ChatTransport.getFileUrl)
toolbarMessageToolbarConfig-The built-in row under the message: copy, onRegenerate, onEdit, feedback, persistent. ChatMessageList builds it from Chat's messageActions and feedback props
onSaveEdit(content: string) => Promise<boolean> | boolean | void-Receives the new text of one of the person's messages once toolbar.onEdit opened the editor. Resolve false to keep the editor open
aiLabelstring-Labels an assistant message with this text ("AI-generated")
classNamestring-Additional class names

Message content ​

content is a string, or an array of parts:

tsx
content: [
  { type: "text", text: "Here is the chart" },
  { type: "image_url", image_url: { url: "https://cdn.example.com/chart.png" } },
]
  • Text parts are joined, one per line, and rendered as markdown.
  • Image parts (image_url, input_image, image) are drawn as pictures below the text, lazily loaded, each opening full size in a new tab. Only a safe URL is drawn: https:, blob:, relative or same-origin URLs, http: when the page is itself served over http, and base64 PNG / JPEG / GIF / WebP. javascript: URLs, SVG data URLs and other schemes are dropped.
  • Other parts are ignored.

Attachments ​

message.files shows under the text:

  • an image with a usable url (or a local previewUrl, for a file just sent from this page) as a thumbnail with its name and size; it opens full size in a new tab;
  • an image without a URL of its own (a conversation loaded from the server) is fetched through resolveFileUrl and then shown as a thumbnail;
  • any other file, or an image without a usable URL, as a chip with its name, extension and size, and a Download link when url is a safe link (http(s), blob: or relative) or, with resolveFileUrl, a Download button that fetches it;
  • a file whose expiresAt has passed, or that is marked expired, is a muted, struck-through chip marked Expired, without a download; a file whose conversionStatus is failed / skipped is tinted "No readable text"; a file with a deadline in the future says "Kept until ..." on hover.

Why an answer ended ​

An assistant message that was stopped (stopReason cancelled, limit, max_turns, budget_reached or error, or status cancelled / incomplete) shows a notice under its text (MessageStopNotice, a role="status" block) saying so, and whether the text above is a partial answer. A plain answer, and a pause, show none. metadata.warnings are listed under the answer (MessageWarnings). See Running turns, Stop and reattach.

A turn that only paused for a tool of the embedding page (client_tool) and has no text, files, tool rows or stop reason renders nothing: the host page answers it unseen.

Status and actions ​

A paused assistant message (status: "requires_action", pendingActions) shows an approval or question card per action; how a settled card looks comes from message.actionStates, which the app fills as cards settle and which a server may send for a reloaded history. See Approvals and Questions.

Examples ​

With Tool Calls ​

Tool calls of a finished message are read from metadata.toolCallDetails:

tsx
<ChatMessage
  message={{
    ...message,
    metadata: {
      toolCallDetails: [{ id: "call-1", name: "get_weather", args: { location: "New York" }, result: { temp: 22 } }],
      toolCallDurationSeconds: 2,
    },
  }}
/>

Streaming ​

tsx
<ChatMessage message={message} isStreaming streamingText="I'm currently writing..." />

With an Image ​

tsx
<ChatMessage
  message={{
    ...message,
    role: "user",
    content: [
      { type: "text", text: "Analyze this image" },
      { type: "image_url", image_url: { url: "data:image/png;base64,..." } },
    ],
  }}
/>

Images behind authentication ​

An <img> cannot send an Authorization header, so draw the image yourself:

tsx
<ChatMessage
  message={message}
  renderImage={({ src, alt }) => <AuthenticatedImage src={src} alt={alt} />}
/>

With Actions ​

tsx
<ChatMessage
  message={message}
  renderActions={() => (
    <div className="flex gap-2">
      <button>Like</button>
      <button>Copy</button>
    </div>
  )}
/>

Styling ​

Colours come from the theme variables; markdown is styled by the .chat-markdown rules in styles.css. See Theming.

Markdown Support ​

The component renders markdown content (GitHub-flavoured): bold and italic text, inline code, code blocks, lists, tables and links (links open in a new tab).

Studio · Pulse · Console · Agent SDK and more — the Cognipeer documentation hub