logoassistant-ui
Radix UI Primitives

ContentPart

Each message can have any number of content parts.
Content parts are usually one of text, audio or tool-call.

Anatomy

import { ContentPartPrimitive } from "@assistant-ui/react";
 
const TextContentPart = () => {
  return <ContentPartPrimitive.Text />;
};

Primitives

Plain Text

import { ContentPartPrimitive } from "@assistant/react";
 
<ContentPartPrimitive.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 content part is in progress.

import { ContentPartPrimitive } from "@assistant/react";
 
<ContentPartPrimitive.InProgress>
  <LoadingIndicator />
</ContentPartPrimitive.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" in result && (
          <pre className="whitespace-pre-wrap break-all text-center">
            {JSON.stringify(result.result)}
          </pre>
        )}
      </div>
    );
  },
});

Context Provider

Content part context is provided by MessagePrimitive.Content or TextContentPartProvider

MessagePrimitive.Content

import { MessagePrimitive } from "@assistant/react";
 
<MessagePrimitive.Content
  components={{
    Text: MyText,
    Audio: MyAudio,
    tools: {
      by_name: {
        get_weather: MyWeatherToolUI,
      },
      Fallback: MyFallbackToolUI,
    },
  }}
/>;

TextContentPartProvider

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

import { TextContentPartProvider } from "@assistant-ui/react";
 
<TextContentPartProvider text="Hello world" isRunning={false}>
  <ContentPart.Text />
</TextContentPartProvider>;

Runtime API

useContentPartRuntime

import { useContentPartRuntime } from "@assistant-ui/react";
 
const contentPartRuntime = useContentPartRuntime();

ContentPartRuntime

addToolResult:

(result: any) => void

Add tool result to a tool call content part that has no tool result yet. This is useful when you are collecting a tool result via user input ("human tool calls").

path:

ContentPartRuntimePath

getState:

() => ContentPartState

subscribe:

(callback: () => void) => Unsubscribe

useContentPart

import { useContentPart } from "@assistant-ui/react";
 
const contentPart = useContentPart();

TextContentPartState

type:

"text"

text:

string

status:

{ readonly type: "running"; } | { readonly type: "complete"; } | { readonly type: "incomplete"; readonly reason: "length" | "cancelled" | "content-filter" | "other" | "error"; readonly error?: unknown; } | { readonly type: "requires-action"; readonly reason: "tool-calls"; }

AudioContentPartState

type:

"audio"

audio:

{ readonly data: string; readonly format: "mp3" | "wav"; }

status:

{ readonly type: "running"; } | { readonly type: "complete"; } | { readonly type: "incomplete"; readonly reason: "length" | "cancelled" | "content-filter" | "other" | "error"; readonly error?: unknown; } | { readonly type: "requires-action"; readonly reason: "tool-calls"; }

ToolCallContentPartState

type:

"tool-call"

toolCallId:

string

toolName:

string

args:

ReadonlyJSONObject

result?:

unknown

isError?:

boolean | undefined

argsText:

string

status:

{ readonly type: "running"; } | { readonly type: "complete"; } | { readonly type: "incomplete"; readonly reason: "length" | "cancelled" | "content-filter" | "other" | "error"; readonly error?: unknown; } | { readonly type: "requires-action"; readonly reason: "tool-calls"; }

useContentPartText

import { useContentPartText } from "@assistant-ui/react";
 
const contentPartText = useContentPartText();

TextContentPartState

type:

"text"

text:

string

status:

{ readonly type: "running"; } | { readonly type: "complete"; } | { readonly type: "incomplete"; readonly reason: "length" | "cancelled" | "content-filter" | "other" | "error"; readonly error?: unknown; } | { readonly type: "requires-action"; readonly reason: "tool-calls"; }

On this page

Edit on Github