Documents
message-part
message-part
Type
External
Status
Published
Created
Mar 17, 2026
Updated
Mar 27, 2026
Updated by
Dosu Bot

import {
MessagePartRuntime,
TextMessagePartState,
AudioMessagePartState,
ToolCallMessagePartState,
} from "@/generated/typeDocs";

Each message can have any number of message parts.
Message parts are usually one of text, reasoning, audio, tool-call, or data.

Message part Types#

Text#

Standard text content, used for both user and assistant messages.

Reasoning#

Exposes the assistant's reasoning process, showing how it arrived at its responses. This is typically used only in assistant messages.

Audio#

Audio content that can be played back.

Tool Call#

Interactive elements that represent tool operations.

Data#

Custom data events that can be rendered as UI at their position in the message stream. Each data part has a name and a data payload.

You can use either the explicit format { type: "data", name: "workflow", data: {...} } or the shorthand data-* prefixed format { type: "data-workflow", data: {...} }. The prefixed format is automatically converted to a DataMessagePart (stripping the data- prefix as the name). Unknown message part types that don't match any built-in type are silently skipped with a console warning.

Streaming Data Parts#

Data parts can be sent from the server using appendData() on the stream controller:

controller.appendData({
  type: "data",
  name: "chart",
  data: { labels: ["Q1", "Q2"], values: [10, 20] },
});

Register a renderer with makeAssistantDataUI to display data parts:

import { makeAssistantDataUI } from "@assistant-ui/react";

const ChartUI = makeAssistantDataUI({
  name: "chart",
  render: ({ data }) => <MyChart data={data} />,
});

Anatomy#

import { MessagePartPrimitive } from "@assistant-ui/react";

const TextMessagePart = () => {
  return <MessagePartPrimitive.Text />;
};

Primitives#

Plain Text#

import { MessagePartPrimitive } from "@assistant-ui/react";

<MessagePartPrimitive.Text />;

Markdown Text#

Renders the message's text as Markdown.

import { MarkdownTextPrimitive } from "@assistant-ui/react-markdown";

<MarkdownTextPrimitive />;

Audio#

Coming soon.

InProgress#

Renders children only if the message part is in progress.

import { MessagePartPrimitive } from "@assistant-ui/react";

<MessagePartPrimitive.InProgress>
  <LoadingIndicator />
</MessagePartPrimitive.InProgress>;

Tool UI#

You can map tool calls to UI components. We provide a few utility functions to make this easier, such as makeAssistantToolUI.

const MyWeatherToolUI = makeAssistantToolUI({
  toolName: "get_weather",
  render: function MyWeatherToolUI({ args, result }) {
    return (
      <div className="mb-4 flex flex-col items-center">
        <pre className="whitespace-pre-wrap break-all text-center">
          get_weather({JSON.stringify(args)})
        </pre>
        {result !== undefined && (
          <pre className="whitespace-pre-wrap break-all text-center">
            {JSON.stringify(result)}
          </pre>
        )}
      </div>
    );
  },
});

Data UI#

You can map data events to UI components, similar to tool UIs. There are two approaches:

Inline configuration#

Pass a data config to MessagePrimitive.Parts:

<MessagePrimitive.Parts>
  {({ part }) => {
    if (part.type === "data" && part.name === "my_chart") return <ChartComponent data={part.data} />;
    if (part.type === "data") return <pre>{JSON.stringify(part.data, null, 2)}</pre>;
    return null;
  }}
</MessagePrimitive.Parts>

Global registration#

Use makeAssistantDataUI or useAssistantDataUI to register data UIs globally. Global registrations take priority over inline configuration.

import { makeAssistantDataUI } from "@assistant-ui/react";

const MyChartUI = makeAssistantDataUI({
  name: "my_chart",
  render: ({ name, data }) => <ChartComponent data={data} />,
});

// Place inside AssistantRuntimeProvider
function App() {
  return (
    <AssistantRuntimeProvider runtime={runtime}>
      <Thread />
      <MyChartUI />
    </AssistantRuntimeProvider>
  );
}

The hook variant allows access to component state:

import { useAssistantDataUI } from "@assistant-ui/react";

function MyComponent() {
  useAssistantDataUI({
    name: "my_chart",
    render: ({ name, data }) => <ChartComponent data={data} />,
  });
  return null;
}

Each data component receives the full data part as props: { type: "data", name: string, data: T, status: MessagePartStatus }.

Messages (Sub-Agent)#

Renders nested messages from a tool call part's messages field. This is used in multi-agent setups where a sub-agent's conversation is embedded inside a tool call.

import { MessagePartPrimitive } from "@assistant-ui/react";

<MessagePartPrimitive.Messages>
  {({ message }) => {
    if (message.role === "user") return <MyUserMessage />;
    return <MyAssistantMessage />;
  }}
</MessagePartPrimitive.Messages>;

This primitive must be used inside a tool call part context (e.g. inside a makeAssistantToolUI render function). It reads the messages field from the current ToolCallMessagePart and renders them in a readonly thread context.

Parent tool UI registrations are inherited — tools registered via makeAssistantToolUI at the parent level are available inside sub-agent messages.

See the Multi-Agent Guide for detailed usage.

Context Provider#

Message part context is provided by MessagePrimitive.Parts or TextMessagePartProvider

MessagePrimitive.Parts#

import { MessagePrimitive } from "@assistant-ui/react";

<MessagePrimitive.Parts>
  {({ part }) => {
    if (part.type === "text") return <MyText />;
    if (part.type === "reasoning") return <MyReasoning {...part} />;
    if (part.type === "audio") return <MyAudio {...part} />;
    if (part.type === "tool-call" && part.toolName === "get_weather") return <MyWeatherToolUI {...part} />;
    if (part.type === "tool-call") return <MyFallbackToolUI {...part} />;
    if (part.type === "data" && part.name === "my_chart") return <MyChartComponent {...part} />;
    if (part.type === "data") return <GenericDataComponent {...part} />;
    return null;
  }}
</MessagePrimitive.Parts>;

TextMessagePartProvider#

This is a helper context provider to allow you to reuse the message part components outside a message part.

import { TextMessagePartProvider } from "@assistant-ui/react";

<TextMessagePartProvider text="Hello world" isRunning={false}>
  <MessagePartPrimitive.Text />
</TextMessagePartProvider>;

Runtime API#

useAui (Message Part Actions)#

import { useAui } from "@assistant-ui/react";

const aui = useAui();
aui.part().addToolResult(result);
const partState = aui.part().getState();

<ParametersTable {...MessagePartRuntime} />

useAuiState (Message Part State)#

import { useAuiState } from "@assistant-ui/react";

const type = useAuiState((s) => s.part.type);
const status = useAuiState((s) => s.part.status);

<ParametersTable {...TextMessagePartState} />
<ParametersTable {...AudioMessagePartState} />
<ParametersTable {...ToolCallMessagePartState} />

useMessagePartText#

import { useMessagePartText } from "@assistant-ui/react";

const { text, status } = useMessagePartText();

<ParametersTable {...TextMessagePartState} />