Context API は assistant-ui の状態管理システムへの直接的なアクセスを提供し、assistant ランタイムとシームレスに統合するカスタムコンポーネントの構築を可能にします。
assistant-ui 入門 – ガイド : コンテキスト API
作成 : Masashi Okumura (@classcat.com)
作成日時 : 03/20/2026
バージョン : assistant-ui@0.0.83
* 本記事は assistant-ui.com/docs の以下のページを参考にしています :
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
◆ お問合せ : 下記までお願いします。
- クラスキャット セールス・インフォメーション
- sales-info@classcat.com
- ClassCatJP

assistant-ui 入門 – ガイド : コンテキスト API
Context API は assistant-ui の状態管理システムへの直接的なアクセスを提供し、assistant ランタイムとシームレスに統合するカスタムコンポーネントの構築を可能にします。
イントロダクション
Context API は assistant-ui の強力な状態管理システムで、assistant の状態と機能への完全なアクセスを備えたカスタムコンポーネントの構築を可能にします。以下を提供します :
- Reactive 状態アクセス – 状態変化をサブスクライブし、自動的に再レンダリングします。
- アクション実行 – メッセージの送信やレスポンスのリロードのような操作をトリガーします。
- イベント・リスニング – ユーザ・インタラクションやシステムイベントに react (反応) する。
- スコープを考慮した (Scope-aware) 設計 – コンポーネントはそのコンテキスト (メッセージ、スレッド 等) を自動的に認識します。
これはすべての assistant-ui を支援する基盤です。組み込みコンポーネントがニーズに合わない場合、Context API を使用して同じ機能を持つカスタムコンポーネントを作成できます。
Context API は <AssistantRuntimeProvider> に提供するランタイムにより支援されています。このランタイムは、すべての assistant の状態を管理し、アクションを処理し、アプリケーション全体にわたりイベントをディスパッチする、統一的なストアとして機能します。
基本概念
スコープと階層
assistant-ui は状態をスコープ – 関連するデータとアクションへのアクセスを提供する論理的な境界 – でオーガナイズします。各スコープはチャットインターフェイスの特定のパーツに対応し、コンテキストを考慮した機能を自動的に提供します。
🗂️ ThreadList (threads) - 会話のリストを管理します
├── 📄 ThreadListItem (threadListItem) - リストの個々のスレッド
└── 💬 Thread (thread) - メッセージを含むアクティブな会話
├── 🔵 Message (message) - ユーザまたはアシスタントのメッセージ
│ ├── 📝 Part (part) - メッセージ内のコンテンツ (テキスト, ツール呼び出し, 等)
│ ├── 🧠 ChainOfThought (chainOfThought) - メッセージ内の推論ステップ
│ │ └── 📝 Part (part) - 個々の推論/ツール呼び出し ステップ
│ ├── 📎 Attachment (attachment) - メッセージに添付されたファイル
│ └── ✏️ Composer (composer) - 既存のメッセージ用の編集モード
│ └── 📎 Attachment (attachment) - 編集モード内のファイル
└── ✏️ Composer (composer) - 新しいメッセージ入力
└── 📎 Attachment (attachment) - 追加されるファイル
💡 Suggestions (suggestions) - フォローアップメッセージの提案
└── 💬 Suggestion (suggestion) - 個々の提案項目
🔧 Tools (tools) - ツール呼び出しのためのカスタム UI コンポーネント
🧩 ModelContext (modelContext) - モデルコンテキストとツール登録
スコープの仕組み :
- スコープは、コンポーネントがレンダリングされる場所により自動的に決定されます。
- <ThreadPrimitive.Messages> 内のボタンは message スコープを自動的に取得します。
- <ComposerPrimitive.Attachments> 内のボタンは attachment スコープを自動的に取得します。
- child スコープは parent スコープのデータにアクセスできます (e.g., message コンポーネントは thread データにアクセスできます)。
// Inside a message component
function MessageButton() {
// ✅ Available: message scope (current message)
const role = useAuiState((s) => s.message.role);
// ✅ Available: thread scope (parent)
const isRunning = useAuiState((s) => s.thread.isRunning);
}
状態管理モデル
Context API は予測可能な状態管理パターンに従います :
- State は immutable で、スコープを通して (下位に) 伝播します。
- Actions は、状態変化を引き起こすメソッドです。
- Events は、コンポーネントに状態変化とユーザインタラクションを通知します。
- Subscriptions によりコンポーネントは変化に反応できるようになります。
必須のフック
useAuiState
値が変化した際に自動的に再レンダリングを行いながら、反応的に (reactively) 状態を読み取ります。このフックは Zustand のセレクタ・パターンのように機能します – 必要な特定のデータを抽出する関数を提供すると、データが変更されたときだけ、コンポーネントは再レンダリングします。
import { useAuiState } from "@assistant-ui/react";
// 基本的な使用方法 - 単一プロパティを抽出
const role = useAuiState((s) => s.message.role); // "user" | "assistant"
const isRunning = useAuiState((s) => s.thread.isRunning); // boolean
// ネストされたデータにアクセス
const attachmentCount = useAuiState(
(s) => s.composer.attachments.length,
);
const lastMessage = useAuiState((s) => s.thread.messages.at(-1));
セレクタ関数は、コンポーネントの場所に対して利用可能なすべてのスコープを受け取り、特定の値を返す必要があります。コンポーネントは、返された値が変化した場合にのみ再レンダリングされます。
Common パターン :
// 複数のスコープにアクセス
const canSend = useAuiState(
(s) => !s.thread.isRunning && s.composer.text.length > 0,
);
// Compute derived state
const messageCount = useAuiState((s) => s.thread.messages.length);
// ❌ Bad - creates new object every time
const data = useAuiState((s) => ({
role: s.message.role,
content: s.message.content,
}));
// ✅ Good - returns stable values
const role = useAuiState((s) => s.message.role);
const content = useAuiState((s) => s.message.content);
useAui
命令型操作とアクションのための API インスタンスにアクセスできます。useAuiState とは異なり、このフックは変更されないステーブルなオブジェクトを返し、イベントハンドラや命令型操作に最適です。
import { useAui } from "@assistant-ui/react";
function CustomMessageActions() {
const aui = useAui();
// Perform actions in event handlers
const handleSend = () => {
aui.composer().send();
};
const handleReload = () => {
aui.message().reload();
};
// Read state imperatively when needed
const handleConditionalAction = () => {
const { isRunning } = aui.thread().getState();
const { text } = aui.composer().getState();
if (!isRunning && text.length > 0) {
aui.composer().send();
}
};
return (
<div>
<button onClick={handleSend}>Send</button>
<button onClick={handleReload}>Reload</button>
<button onClick={handleConditionalAction}>Smart Send</button>
</div>
);
}
API オブジェクトはステーブルで、再レンダリングを引き起こしません。以下のために使用してください :
- イベントハンドラとコールバックでアクションをトリガーする
- サブスクリプションを必要としない場合、現在の状態を命令的に読み取る
- ネストされたスコープにプログラム的にアクセスする
- アクションを実行する前にスコープの可用性を確認する
スコープ別に利用可能なアクション :
// Thread actions
aui.thread().append(message);
aui.thread().startRun(config);
aui.thread().resumeRun(config);
aui.thread().cancelRun();
aui.thread().getState();
aui.thread().message({ index: idx });
aui.thread().message({ id: messageId });
aui.thread().composer();
// Message actions
aui.message().reload();
aui.message().speak();
aui.message().stopSpeaking();
aui.message().submitFeedback({ type: "positive" | "negative" });
aui.message().switchToBranch({ position, branchId });
aui.message().getState();
aui.message().part({ index: idx });
aui.message().part({ toolCallId });
aui.message().composer();
// Part actions
aui.part().addToolResult(result);
aui.part().resumeToolCall(result);
aui.part().getState();
// Composer actions
aui.composer().send();
aui.composer().setText(text);
aui.composer().setRole(role);
aui.composer().addAttachment(file); // File object
aui.composer().addAttachment({ name, content }); // external source
await aui.composer().clearAttachments();
await aui.composer().reset();
aui.composer().getState();
// Attachment actions
aui.attachment().remove();
aui.attachment().getState();
// ThreadList actions
aui.threads().switchToNewThread();
aui.threads().switchToThread(threadId);
aui.threads().getState();
// ThreadListItem actions
aui.threadListItem().switchTo();
aui.threadListItem().rename(title);
aui.threadListItem().archive();
aui.threadListItem().unarchive();
aui.threadListItem().delete();
aui.threadListItem().getState();
// Suggestions actions
aui.suggestions().getState();
aui.suggestions().suggestion({ index: 0 });
// Suggestion actions
aui.suggestion().getState();
// ChainOfThought actions
aui.chainOfThought().getState();
aui.chainOfThought().setCollapsed(collapsed);
aui.chainOfThought().part({ index: 0 });
// ModelContext actions
aui.modelContext().getState();
aui.modelContext().register(provider);
// Tools actions
aui.tools().setToolUI(toolName, render);
aui.tools().getState();
useAuiEvent
アンマウント時に自動的にクリーンアップされるイベントをサブスクライブします。このフックは、ユーザーインタラクション、システムイベントへの対応、あるいは外部分析との連携に最適です。
import { useAuiEvent } from "@assistant-ui/react";
// Listen to current scope events (most common)
useAuiEvent("composer.send", (event) => {
console.log("Composer sent message in thread:", event.threadId);
});
// Listen to thread events
useAuiEvent("thread.runStart", (event) => {
console.log("Run started in thread:", event.threadId);
});
// Listen to all events of a type across all scopes
useAuiEvent({ event: "composer.send", scope: "*" }, (event) => {
console.log("Any composer sent a message:", event.threadId);
});
// Listen to ALL events (useful for debugging or analytics)
useAuiEvent("*", (event) => {
console.log("Event occurred:", event.event, event.payload);
});
// Practical example: Track user interactions
function AnalyticsTracker() {
useAuiEvent("composer.send", (event) => {
analytics.track("message_sent", {
threadId: event.threadId,
});
});
return null; // This component only tracks events
}
以上
