Reactive hooks for accessing runtime state in React Native.
State Hooks
useAuiState
The primary hook for accessing reactive state. It accepts a selector function for fine-grained re-renders — the component only re-renders when the selected value changes (shallow equality).
import { useAuiState } from "@assistant-ui/react-native";
// Thread state
const messages = useAuiState((s) => s.thread.messages);
const isRunning = useAuiState((s) => s.thread.isRunning);
const isEmpty = useAuiState((s) => s.thread.isEmpty);
// Composer state
const text = useAuiState((s) => s.composer.text);
const composerIsEmpty = useAuiState((s) => s.composer.isEmpty);
const attachments = useAuiState((s) => s.composer.attachments);
// Message state (inside a message context)
const role = useAuiState((s) => s.message.role);
const isLast = useAuiState((s) => s.message.isLast);
// Thread list item state
const threadId = useAuiState((s) => s.threadListItem.id);
const title = useAuiState((s) => s.threadListItem.title);useAui
Access the store methods for imperative actions.
import { useAui } from "@assistant-ui/react-native";
const aui = useAui();
// Composer actions
aui.composer().setText("Hello");
aui.composer().send();
// Thread actions
aui.thread().cancelRun();useAuiEvent
Subscribe to events without causing re-renders.
import { useAuiEvent } from "@assistant-ui/react-native";
useAuiEvent("thread.modelContextUpdate", ({ threadId }) => {
console.log("Model context updated:", threadId);
});Runtime Hooks
useLocalRuntime
Create an AssistantRuntime with a ChatModelAdapter.
import { useLocalRuntime } from "@assistant-ui/react-native";
const runtime = useLocalRuntime(chatModel, {
initialMessages: [],
});| Option | Type | Description |
|---|---|---|
initialMessages | ThreadMessageLike[] | Messages to pre-populate |
maxSteps | number | Maximum tool call steps per run |
cloud | AssistantCloud | Optional cloud instance for persistence |
adapters | object | Optional adapter overrides (see below) |
unstable_humanToolNames | string[] | Tool names that pause the run until a result is added via addResult |
The adapters option accepts the following fields (all optional):
| Adapter | Type | Description |
|---|---|---|
history | ThreadHistoryAdapter | Load and save thread message history |
attachments | AttachmentAdapter | Handle file and attachment uploads |
speech | SpeechSynthesisAdapter | Text-to-speech playback |
dictation | DictationAdapter | Speech-to-text input |
feedback | FeedbackAdapter | Thumbs up/down feedback |
suggestion | SuggestionAdapter | Prompt suggestions |
useRemoteThreadListRuntime
Create an AssistantRuntime with a persistent thread list backed by a RemoteThreadListAdapter. This wraps any runtime hook (such as one calling useLocalRuntime or a custom AI SDK hook) and layers thread-list management on top.
import { useRemoteThreadListRuntime } from "@assistant-ui/react-native";
const runtime = useRemoteThreadListRuntime({
runtimeHook: () => useLocalRuntime(chatModel),
adapter: myThreadListAdapter,
});| Option | Type | Description |
|---|---|---|
runtimeHook | () => AssistantRuntime | Hook that returns a per-thread runtime |
adapter | RemoteThreadListAdapter | Backend adapter for listing/creating/archiving threads |
allowNesting | boolean | When true, silently becomes a no-op if already inside another useRemoteThreadListRuntime |
Model Context Hooks
Tools
Author tools in a "use generative" file with defineToolkit, the same API as on the web (Defining Tools). The tool definition is forwarded to the model; when the model calls it, the execute function runs and the render component displays the result.
Add the @assistant-ui/metro plugin so Metro compiles the "use generative" directive:
const { getDefaultConfig } = require("expo/metro-config");
const { withAui } = require("@assistant-ui/metro");
module.exports = withAui(getDefaultConfig(__dirname));"use generative";
import { defineToolkit } from "@assistant-ui/react-native";
import { Text, View } from "react-native";
import { z } from "zod";
export default defineToolkit({
get_weather: {
description: "Get the current weather for a city",
parameters: z.object({ city: z.string() }),
execute: async ({ city }) => {
"use client";
const res = await fetch(`https://api.weather.example/${city}`);
return res.json();
},
render: ({ args, result }) => (
<View>
<Text>
{args.city}: {result?.temperature}°F
</Text>
</View>
),
},
});import { AuiProvider, Tools, useAui } from "@assistant-ui/react-native";
import toolkit from "./weather-toolkit";
function ToolProvider({ children }: { children: React.ReactNode }) {
const aui = useAui({ tools: Tools({ toolkit }) });
return <AuiProvider value={aui}>{children}</AuiProvider>;
}useAssistantDataUI
Register a UI renderer for a named data message part.
import { useAssistantDataUI } from "@assistant-ui/react-native";
useAssistantDataUI({
name: "weather_card",
render: ({ data }) => (
<View>
<Text>{data.city}: {data.temperature}°F</Text>
</View>
),
});useAssistantInstructions
Register system instructions in the model context.
import { useAssistantInstructions } from "@assistant-ui/react-native";
useAssistantInstructions("You are a helpful weather assistant.");useInlineRender
Wrap a tool UI component so that inline state updates (from a parent component's render) are reflected without remounting. Use this when the render function closes over props that change over time.
import { defineToolkit, useInlineRender } from "@assistant-ui/react-native";
import { Text } from "react-native";
import { useMemo } from "react";
export function useMyToolToolkit(someOuterProp: string) {
const stableRender = useInlineRender(({ args, result }) => (
<Text>{someOuterProp}: {result?.value}</Text>
));
return useMemo(
() =>
defineToolkit({
my_tool: {
type: "backend",
render: stableRender,
},
}),
[stableRender],
);
}Import the toolkit hook, pass its result to useAui({ tools: Tools({ toolkit }) }), and provide the returned aui with AuiProvider, as shown in the Tools section above.
makeAssistantDataUI
Create a component that registers a data UI renderer when mounted.
import { makeAssistantDataUI } from "@assistant-ui/react-native";
const WeatherCard = makeAssistantDataUI({
name: "weather_card",
render: ({ data }) => <Text>{data.city}: {data.temperature}°F</Text>,
});
<WeatherCard />Shared Providers
These context providers are re-exported from @assistant-ui/core/react and are used internally by the primitives to scope the aui store to a particular item (message, part, thread list item, etc.). They are available for advanced custom rendering scenarios.
MessageByIndexProvider
Scopes the aui context to a specific message by its index in the thread.
import { MessageByIndexProvider } from "@assistant-ui/react-native";
<MessageByIndexProvider index={2}>
{/* children can read s.message, s.composer */}
</MessageByIndexProvider>PartByIndexProvider
Scopes the aui context to a specific message part by its index.
import { PartByIndexProvider } from "@assistant-ui/react-native";
<PartByIndexProvider index={0}>
{/* children can read s.part */}
</PartByIndexProvider>TextMessagePartProvider
Provides a synthetic text part context from a plain string. Useful for rendering text outside the normal message-part pipeline.
import { TextMessagePartProvider } from "@assistant-ui/react-native";
<TextMessagePartProvider text="Hello world" isRunning={false}>
{/* children can read s.part as a text part */}
</TextMessagePartProvider>| Prop | Type | Description |
|---|---|---|
text | string | The text content |
isRunning | boolean | Whether the part is still streaming (default false) |
ChainOfThoughtByIndicesProvider
Scopes the aui context to a slice of message parts that form a chain-of-thought block.
import { ChainOfThoughtByIndicesProvider } from "@assistant-ui/react-native";
<ChainOfThoughtByIndicesProvider startIndex={1} endIndex={3}>
{/* children can read s.chainOfThought */}
</ChainOfThoughtByIndicesProvider>ChainOfThoughtPartByIndexProvider
Scopes the aui context to a specific part within a chain-of-thought block.
import { ChainOfThoughtPartByIndexProvider } from "@assistant-ui/react-native";
<ChainOfThoughtPartByIndexProvider index={0}>
{/* children can read s.part */}
</ChainOfThoughtPartByIndexProvider>ThreadListItemByIndexProvider
Scopes the aui context to a specific thread list item by its index.
import { ThreadListItemByIndexProvider } from "@assistant-ui/react-native";
<ThreadListItemByIndexProvider index={0} archived={false}>
{/* children can read s.threadListItem */}
</ThreadListItemByIndexProvider>SuggestionByIndexProvider
Scopes the aui context to a specific suggestion by its index.
import { SuggestionByIndexProvider } from "@assistant-ui/react-native";
<SuggestionByIndexProvider index={0}>
{/* children can read s.suggestion */}
</SuggestionByIndexProvider>