Reactive hooks for accessing runtime state in React Ink.
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-ink";
// 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-ink";
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-ink";
useAuiEvent("thread.message.created", (payload) => {
console.log("New message:", payload);
});Runtime Hooks
useAssistantRuntime
Get the AssistantRuntime from context. This is the top-level runtime with access to thread management.
import { useAssistantRuntime } from "@assistant-ui/react-ink";
const runtime = useAssistantRuntime();
// Switch threads
runtime.threads.switchToThread(threadId);
runtime.threads.switchToNewThread();
// Thread management
runtime.threads.rename(threadId, "New Title");
runtime.threads.delete(threadId);
// Access the current thread runtime
runtime.thread; // ThreadRuntimeuseLocalRuntime
Create an AssistantRuntime with a ChatModelAdapter.
import { useLocalRuntime } from "@assistant-ui/react-ink";
const runtime = useLocalRuntime(chatModel, {
initialMessages: [],
});| Option | Type | Description |
|---|---|---|
initialMessages | ThreadMessageLike[] | Messages to pre-populate |
Primitive Hooks
Low-level hooks for building custom components.
useThreadMessages
import { useThreadMessages } from "@assistant-ui/react-ink";
const messages = useThreadMessages(); // ThreadMessage[]useThreadIsRunning
import { useThreadIsRunning } from "@assistant-ui/react-ink";
const isRunning = useThreadIsRunning(); // booleanuseThreadIsEmpty
import { useThreadIsEmpty } from "@assistant-ui/react-ink";
const isEmpty = useThreadIsEmpty(); // booleanuseComposerSend
import { useComposerSend } from "@assistant-ui/react-ink";
const { send, canSend } = useComposerSend();useComposerCancel
import { useComposerCancel } from "@assistant-ui/react-ink";
const { cancel, canCancel } = useComposerCancel();useComposerAddAttachment
Add an attachment to the composer. Returns { addAttachment } — call it with a CreateAttachment object.
import { useComposerAddAttachment } from "@assistant-ui/react-ink";
import { readFile } from "fs/promises";
const { addAttachment } = useComposerAddAttachment();
const attachFile = async (path: string) => {
const content = await readFile(path, "utf-8");
await addAttachment({
name: path.split("/").pop() ?? "file.txt",
type: "document",
content: [{ type: "text", text: content }],
});
};useMessageReload
import { useMessageReload } from "@assistant-ui/react-ink";
const { reload, canReload } = useMessageReload();useMessageBranching
import { useMessageBranching } from "@assistant-ui/react-ink";
const { branchNumber, branchCount, goToPrev, goToNext } =
useMessageBranching();Model Context Hooks
useAssistantTool
Register a tool with an optional UI renderer. The tool definition is forwarded to the model, and when the model calls it, the execute function runs and the render component displays the result.
import { useAssistantTool } from "@assistant-ui/react-ink";
import { Text } from "ink";
useAssistantTool({
toolName: "get_weather",
description: "Get the current weather for a city",
parameters: {
type: "object",
properties: {
city: { type: "string" },
},
required: ["city"],
},
execute: async ({ city }) => {
const res = await fetch(`https://api.weather.example/${city}`);
return res.json();
},
render: ({ args, result }) => (
<Text>{args.city}: {result?.temperature}°F</Text>
),
});useAssistantToolUI
Register only a UI renderer for a tool (without tool definition or execute function).
import { useAssistantToolUI } from "@assistant-ui/react-ink";
import { Text } from "ink";
useAssistantToolUI({
toolName: "get_weather",
render: ({ args, result, status }) => (
<Text>
{status?.type === "running"
? `Loading weather for ${args.city}...`
: `${args.city}: ${result?.temperature}°F`}
</Text>
),
});useAssistantInstructions
Register system instructions in the model context.
import { useAssistantInstructions } from "@assistant-ui/react-ink";
useAssistantInstructions("You are a helpful terminal assistant.");makeAssistantTool
Create a component that registers a tool when mounted.
import { makeAssistantTool } from "@assistant-ui/react-ink";
import { Text } from "ink";
const WeatherTool = makeAssistantTool({
toolName: "get_weather",
description: "Get weather",
parameters: { type: "object", properties: { city: { type: "string" } }, required: ["city"] },
execute: async ({ city }) => ({ temperature: 72 }),
render: ({ args, result }) => <Text>{args.city}: {result?.temperature}°F</Text>,
});
// Mount inside AssistantProvider to register
<WeatherTool />