logoassistant-ui
Concepts

Runtime Layer

assistant-ui components are full stack components. This means that they include both the UI presentation, but also logic to communicate with an external system. This logic is handled by the runtime layer and APIs.

You interact with the runtime layer in two ways:

  • defining a runtime for your app
  • using the runtime APIs to interact with the runtime

Defining a runtime

assistant-ui ships with two low-level runtimes:

  • useLocalRuntime
  • useExternalStoreRuntime

Both of these runtimes let you implement your own runtime. The conceptual difference between the two is that useLocalRuntime takes ownership of the data layer, while useExternalStoreRuntime does not.

If you have a stateful API to integrate, use useExternalStoreRuntime, if you have a stateless API to integrate, use useLocalRuntime.

Higher level runtimes

For many services and APIs, assistant-ui provides deeper integrations. These are built with the two low-level runtimes mentioned above.

  • useEdgeRuntime: Connect to Vercel AI SDK backends or Edge Runtime backends
  • useVercelUseChatRuntime: Integrate with Vercel AI SDK's useChat hook
  • useVercelUseAssistantRuntime: Integrate with Vercel AI SDK's useAssistant hook (OpenAI Assistants API)
  • useVercelRSCRuntime: Integrate with Vercel AI SDK React Server Components
  • useLangGraphRuntime: Connect to LangGraph Cloud
  • useTrieveRuntime: Connect to Trieve.ai
  • ...

Runtime Providers

The following components accept a runtime prop:

  • AssistantRuntimeProvider
  • Thread

These components put the Runtime in the React Context, so that all child components can access the runtime.

Runtime Adapters

Most runtimes accept additional adapters to configure extra integrations:

  • ChatModelAdapter: Configures the backend API
  • AttachmentAdapter: Configures the file/media attachment API
  • SpeechSynthesisAdapter: Configures the speech API
  • FeedbackAdapter: Configures the feedback API

Using the runtime APIs

The same API used by the assistant-ui components is also available to you. This allows you to build your own UI components and integrate them with the runtime layer.

Runtime Hierarchy

The runtime API is nested as such:

The AssistantRuntime (which encompasses everything), is sometimes simply called Runtime.

Runtime Context Provider Components

The following components provide the runtime APIs:

// provides AssistantRuntime, ThreadListRuntime, ThreadRuntime, ComposerRuntime (ThreadComposer)
<AssistantRuntimeProvider runtime={runtime} />
 
// renders every message, provides MessageRuntime, ComposerRuntime (EditComposer)
<ThreadPrimitive.Messages components={{ Message, ... }} />
 
// renders every content part, provides ContentPartRuntime
<MessagePrimitive.Content components={{ Text, Image, Audio, UI, tools }} />
 
// renders every attachment, provides AttachmentRuntime (Thread or EditComposer)
<ComposerPrimitive.Attachments components={{ Attachment, ... }} />
 
// renders every attachment, provides AtatchmentRuntime (Message)
<MessagePrimitive.Attachments components={{ Attachment, ... }} />
 
// provides a custom TextContentPartRuntime
<TextContentPartProvider text="Hello!" />

Accessing runtime APIs

You can access the runtime APIs with react hooks:

const runtime = useAssistantRuntime();
const threadRuntime = useThreadRuntime();
const messageRuntime = useMessageRuntime();
const contentPartRuntime = useContentPartRuntime();
 
// thread manager has no separate hook (1:1 relationship with assistant runtime)
const ThreadListRuntime = useAssistantRuntime().threadList;
 
// composer runtime is multi-use
const composerRuntime = useComposerRuntime(); // refers to edit composer if available, otherwise thread composer
 
// thread manager has no separate hook (1:1 relationship with assistant runtime)
const threadComposer = useThreadRuntime().composer;
 
// thread manager has no separate hook (1:1 relationship with assistant runtime)
const editComposerRuntime = useMessageRuntime().composer;
 
// attachment runtime is multi-use
const attachmentRuntime = useAttachmentRuntime(); // refers to the closest attachment runtime
const threadComposerAttachmentRuntime = useThreadComposerAttachmentRuntime();
const editComposerAttachmentRuntime = useEditComposerAttachmentRuntime();
const messageAttachmentRuntime = useMessageAttachmentRuntime();

Accessing runtime state

Most runtimes also expose a state through two methods getState and subscribe. The following helper hooks subscribe to the state, so that your component is updated when the state changes:

useThreadList(); // get thread manager state
useThread(); // get thread state
useMessage(); // get message state
useContentPart(); // get content part state
useComposer(); // get composer state
useThreadComposer(); // get thread composer state
useEditComposer(); // get edit composer state
useAttachment(); // get attachment state
useThreadComposerAttachment(); // get thread composer attachment state
useEditComposerAttachment(); // get edit composer attachment state
useMessageAttachment(); // get message attachment state

You might not want to subscribe to evey update. In that case, pass a callback selector to the hook:

// only subscribe to role changes
const role = useMessage((state) => message.role);

On this page

Edit on Github