# Hooks URL: /docs/ink/hooks Reactive hooks for accessing runtime state in React Ink. State Hooks \[#state-hooks] useAuiState \[#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). ```tsx 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 \[#useaui] Access the store methods for imperative actions. ```tsx 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 \[#useauievent] Subscribe to events without causing re-renders. ```tsx import { useAuiEvent } from "@assistant-ui/react-ink"; useAuiEvent("thread.message.created", (payload) => { console.log("New message:", payload); }); ``` Runtime Hooks \[#runtime-hooks] useAssistantRuntime \[#useassistantruntime] Get the `AssistantRuntime` from context. This is the top-level runtime with access to thread management. ```tsx 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; // ThreadRuntime ``` useLocalRuntime \[#uselocalruntime] Create an `AssistantRuntime` with a `ChatModelAdapter`. ```tsx import { useLocalRuntime } from "@assistant-ui/react-ink"; const runtime = useLocalRuntime(chatModel, { initialMessages: [], }); ``` | Option | Type | Description | | ----------------- | --------------------- | ------------------------ | | `initialMessages` | `ThreadMessageLike[]` | Messages to pre-populate | Primitive Hooks \[#primitive-hooks] Low-level hooks for building custom components. useThreadMessages \[#usethreadmessages] ```tsx import { useThreadMessages } from "@assistant-ui/react-ink"; const messages = useThreadMessages(); // ThreadMessage[] ``` useThreadIsRunning \[#usethreadisrunning] ```tsx import { useThreadIsRunning } from "@assistant-ui/react-ink"; const isRunning = useThreadIsRunning(); // boolean ``` useThreadIsEmpty \[#usethreadisempty] ```tsx import { useThreadIsEmpty } from "@assistant-ui/react-ink"; const isEmpty = useThreadIsEmpty(); // boolean ``` useComposerSend \[#usecomposersend] ```tsx import { useComposerSend } from "@assistant-ui/react-ink"; const { send, canSend } = useComposerSend(); ``` useComposerCancel \[#usecomposercancel] ```tsx import { useComposerCancel } from "@assistant-ui/react-ink"; const { cancel, canCancel } = useComposerCancel(); ``` useComposerAddAttachment \[#usecomposeraddattachment] Add an attachment to the composer. Returns `{ addAttachment }` — call it with a `CreateAttachment` object. ```tsx 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 \[#usemessagereload] ```tsx import { useMessageReload } from "@assistant-ui/react-ink"; const { reload, canReload } = useMessageReload(); ``` useMessageBranching \[#usemessagebranching] ```tsx import { useMessageBranching } from "@assistant-ui/react-ink"; const { branchNumber, branchCount, goToPrev, goToNext } = useMessageBranching(); ``` Model Context Hooks \[#model-context-hooks] useAssistantTool \[#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. ```tsx 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 }) => ( {args.city}: {result?.temperature}°F ), }); ``` useAssistantToolUI \[#useassistanttoolui] Register only a UI renderer for a tool (without tool definition or execute function). ```tsx import { useAssistantToolUI } from "@assistant-ui/react-ink"; import { Text } from "ink"; useAssistantToolUI({ toolName: "get_weather", render: ({ args, result, status }) => ( {status?.type === "running" ? `Loading weather for ${args.city}...` : `${args.city}: ${result?.temperature}°F`} ), }); ``` useAssistantInstructions \[#useassistantinstructions] Register system instructions in the model context. ```tsx import { useAssistantInstructions } from "@assistant-ui/react-ink"; useAssistantInstructions("You are a helpful terminal assistant."); ``` makeAssistantTool \[#makeassistanttool] Create a component that registers a tool when mounted. ```tsx 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 }) => {args.city}: {result?.temperature}°F, }); // Mount inside AssistantProvider to register ```