@assistant-ui/mcp-docs-server 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/.docs/organized/code-examples/with-ai-sdk-v5.md +15 -13
  2. package/.docs/organized/code-examples/with-cloud.md +19 -25
  3. package/.docs/organized/code-examples/with-external-store.md +9 -7
  4. package/.docs/organized/code-examples/with-ffmpeg.md +21 -21
  5. package/.docs/organized/code-examples/with-langgraph.md +72 -46
  6. package/.docs/organized/code-examples/with-parent-id-grouping.md +9 -7
  7. package/.docs/organized/code-examples/with-react-hook-form.md +19 -21
  8. package/.docs/raw/docs/api-reference/integrations/react-data-stream.mdx +194 -0
  9. package/.docs/raw/docs/api-reference/overview.mdx +7 -4
  10. package/.docs/raw/docs/api-reference/primitives/Composer.mdx +31 -0
  11. package/.docs/raw/docs/api-reference/primitives/Message.mdx +108 -3
  12. package/.docs/raw/docs/api-reference/primitives/Thread.mdx +59 -0
  13. package/.docs/raw/docs/api-reference/primitives/ThreadList.mdx +128 -0
  14. package/.docs/raw/docs/api-reference/primitives/ThreadListItem.mdx +160 -0
  15. package/.docs/raw/docs/api-reference/runtimes/AssistantRuntime.mdx +0 -11
  16. package/.docs/raw/docs/api-reference/runtimes/ComposerRuntime.mdx +3 -3
  17. package/.docs/raw/docs/copilots/assistant-frame.mdx +397 -0
  18. package/.docs/raw/docs/getting-started.mdx +53 -52
  19. package/.docs/raw/docs/guides/Attachments.mdx +7 -115
  20. package/.docs/raw/docs/guides/ToolUI.mdx +3 -3
  21. package/.docs/raw/docs/guides/Tools.mdx +152 -92
  22. package/.docs/raw/docs/guides/context-api.mdx +574 -0
  23. package/.docs/raw/docs/migrations/v0-12.mdx +125 -0
  24. package/.docs/raw/docs/runtimes/ai-sdk/use-chat.mdx +134 -55
  25. package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +182 -0
  26. package/.docs/raw/docs/runtimes/custom/local.mdx +16 -3
  27. package/.docs/raw/docs/runtimes/data-stream.mdx +287 -0
  28. package/.docs/raw/docs/runtimes/langgraph/index.mdx +0 -1
  29. package/.docs/raw/docs/runtimes/langserve.mdx +9 -11
  30. package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +5 -0
  31. package/.docs/raw/docs/ui/ThreadList.mdx +54 -16
  32. package/dist/{chunk-L4K23SWI.js → chunk-NVNFQ5ZO.js} +4 -1
  33. package/dist/index.js +1 -1
  34. package/dist/prepare-docs/prepare.js +1 -1
  35. package/dist/stdio.js +1 -1
  36. package/package.json +7 -7
  37. package/.docs/organized/code-examples/local-ollama.md +0 -1135
  38. package/.docs/organized/code-examples/search-agent-for-e-commerce.md +0 -1721
  39. package/.docs/organized/code-examples/with-ai-sdk.md +0 -1082
  40. package/.docs/organized/code-examples/with-openai-assistants.md +0 -1175
  41. package/.docs/raw/docs/concepts/architecture.mdx +0 -19
  42. package/.docs/raw/docs/concepts/runtime-layer.mdx +0 -163
  43. package/.docs/raw/docs/concepts/why.mdx +0 -9
  44. package/.docs/raw/docs/runtimes/ai-sdk/rsc.mdx +0 -226
  45. package/.docs/raw/docs/runtimes/ai-sdk/use-assistant-hook.mdx +0 -195
  46. package/.docs/raw/docs/runtimes/ai-sdk/use-chat-hook.mdx +0 -138
  47. package/.docs/raw/docs/runtimes/ai-sdk/use-chat-v5.mdx +0 -212
@@ -0,0 +1,574 @@
1
+ ---
2
+ title: Context API
3
+ ---
4
+
5
+ The Context API provides direct access to assistant-ui's state management system, enabling you to build custom components that integrate seamlessly with the assistant runtime.
6
+
7
+ ## Introduction
8
+
9
+ The Context API is assistant-ui's powerful state management system that enables you to build custom components with full access to the assistant's state and capabilities. It provides:
10
+
11
+ - **Reactive state access** - Subscribe to state changes with automatic re-renders
12
+ - **Action execution** - Trigger operations like sending messages or reloading responses
13
+ - **Event listening** - React to user interactions and system events
14
+ - **Scope-aware design** - Components automatically know their context (message, thread, etc.)
15
+
16
+ It's the foundation that powers all assistant-ui primitives. When the built-in components don't meet your needs, you can use the Context API to create custom components with the same capabilities.
17
+
18
+ The Context API is backed by the runtime you provide to `<AssistantRuntimeProvider>`. This runtime acts as a unified store that manages all assistant state, handles actions, and dispatches events across your entire application.
19
+
20
+ ## Core Concepts
21
+
22
+ ### Scopes and Hierarchy
23
+
24
+ assistant-ui organizes state into **scopes** - logical boundaries that provide access to relevant data and actions. Each scope corresponds to a specific part of the chat interface and automatically provides context-aware functionality.
25
+
26
+ ```
27
+ 🗂️ ThreadList (threads) - Manages the list of conversations
28
+ ├── 📄 ThreadListItem (threadListItem) - Individual thread in the list
29
+ └── 💬 Thread (thread) - Active conversation with messages
30
+ ├── 🔵 Message (message) - User or assistant message
31
+ │ ├── 📝 Part (part) - Content within a message (text, tool calls, etc.)
32
+ │ ├── 📎 Attachment (attachment) - Files attached to messages
33
+ │ └── ✏️ Composer (composer) - Edit mode for existing messages
34
+ │ └── 📎 Attachment (attachment) - Files in edit mode
35
+ └── ✏️ Composer (composer) - New message input
36
+ └── 📎 Attachment (attachment) - Files being added
37
+
38
+ 🔧 ToolUIs (toolUIs) - Custom UI components for tool calls
39
+ ```
40
+
41
+ **How scopes work:**
42
+
43
+ - Scopes are **automatically determined** by where your component is rendered
44
+ - A button inside a `<ThreadPrimitive.Messages>` automatically gets `message` scope
45
+ - A button inside a `<ComposerPrimitive.Attachments>` automatically gets `attachment` scope
46
+ - Child scopes can access parent scope data (e.g., a `message` component can access `thread` data)
47
+
48
+ ```tsx
49
+ // Inside a message component
50
+ function MessageButton() {
51
+ // ✅ Available: message scope (current message)
52
+ const role = useAssistantState(({ message }) => message.role);
53
+
54
+ // ✅ Available: thread scope (parent)
55
+ const isRunning = useAssistantState(({ thread }) => thread.isRunning);
56
+ }
57
+ ```
58
+
59
+ ### State Management Model
60
+
61
+ The Context API follows a predictable state management pattern:
62
+
63
+ 1. **State** is immutable and flows down through scopes
64
+ 2. **Actions** are methods that trigger state changes
65
+ 3. **Events** notify components of state changes and user interactions
66
+ 4. **Subscriptions** let components react to changes
67
+
68
+ ## Essential Hooks
69
+
70
+ ### useAssistantState
71
+
72
+ Read state reactively with automatic re-renders when values change. This hook works like Zustand's selector pattern - you provide a function that extracts the specific data you need, and your component only re-renders when that data changes.
73
+
74
+ ```tsx
75
+ import { useAssistantState } from "@assistant-ui/react";
76
+
77
+ // Basic usage - extract a single property
78
+ const role = useAssistantState(({ message }) => message.role); // "user" | "assistant"
79
+ const isRunning = useAssistantState(({ thread }) => thread.isRunning); // boolean
80
+
81
+ // Access nested data
82
+ const attachmentCount = useAssistantState(
83
+ ({ composer }) => composer.attachments.length,
84
+ );
85
+ const lastMessage = useAssistantState(({ thread }) => thread.messages.at(-1));
86
+ ```
87
+
88
+ The selector function receives all available scopes for your component's location and should return a specific value. The component re-renders only when that returned value changes.
89
+
90
+ **Common patterns:**
91
+
92
+ ```tsx
93
+ // Access multiple scopes
94
+ const canSend = useAssistantState(
95
+ ({ thread, composer }) => !thread.isRunning && composer.text.length > 0,
96
+ );
97
+
98
+ // Compute derived state
99
+ const messageCount = useAssistantState(({ thread }) => thread.messages.length);
100
+ ```
101
+
102
+ **Important:** Never create new objects in selectors. Return primitive values or stable references to avoid infinite re-renders.
103
+
104
+ ```tsx
105
+ // ❌ Bad - creates new object every time
106
+ const data = useAssistantState(({ message }) => ({
107
+ role: message.role,
108
+ content: message.content,
109
+ }));
110
+
111
+ // ✅ Good - returns stable values
112
+ const role = useAssistantState(({ message }) => message.role);
113
+ const content = useAssistantState(({ message }) => message.content);
114
+ ```
115
+
116
+ ### useAssistantApi
117
+
118
+ Access the API instance for imperative operations and actions. Unlike `useAssistantState`, this hook returns a stable object that never changes, making it perfect for event handlers and imperative operations.
119
+
120
+ ```tsx
121
+ import { useAssistantApi } from "@assistant-ui/react";
122
+
123
+ function CustomMessageActions() {
124
+ const api = useAssistantApi();
125
+
126
+ // Perform actions in event handlers
127
+ const handleSend = () => {
128
+ api.composer().send();
129
+ };
130
+
131
+ const handleReload = () => {
132
+ api.message().reload();
133
+ };
134
+
135
+ // Read state imperatively when needed
136
+ const handleConditionalAction = () => {
137
+ const { isRunning } = api.thread().getState();
138
+ const { text } = api.composer().getState();
139
+
140
+ if (!isRunning && text.length > 0) {
141
+ api.composer().send();
142
+ }
143
+ };
144
+
145
+ return (
146
+ <div>
147
+ <button onClick={handleSend}>Send</button>
148
+ <button onClick={handleReload}>Reload</button>
149
+ <button onClick={handleConditionalAction}>Smart Send</button>
150
+ </div>
151
+ );
152
+ }
153
+ ```
154
+
155
+ The API object is stable and doesn't cause re-renders. Use it for:
156
+
157
+ - **Triggering actions** in event handlers and callbacks
158
+ - **Reading current state** imperatively when you don't need subscriptions
159
+ - **Accessing nested scopes** programmatically
160
+ - **Checking scope availability** before performing actions
161
+
162
+ **Available actions by scope:**
163
+
164
+ ```tsx
165
+ // Thread actions
166
+ api.thread().append(message);
167
+ api.thread().startRun(config);
168
+ api.thread().cancelRun();
169
+ api.thread().switchToNewThread();
170
+ api.thread().switchToThread(threadId);
171
+ api.thread().getState();
172
+ api.thread().message(idOrIndex);
173
+ api.thread().composer;
174
+
175
+ // Message actions
176
+ api.message().reload();
177
+ api.message().speak();
178
+ api.message().stopSpeaking();
179
+ api.message().submitFeedback({ type: "positive" | "negative" });
180
+ api.message().switchToBranch({ position, branchId });
181
+ api.message().getState();
182
+ api.message().part(indexOrToolCallId);
183
+ api.message().composer;
184
+
185
+ // Part actions
186
+ api.part().addResult(result);
187
+ api.part().getState();
188
+
189
+ // Composer actions
190
+ api.composer().send();
191
+ api.composer().setText(text);
192
+ api.composer().setRole(role);
193
+ api.composer().addAttachment(file);
194
+ api.composer().clearAttachments();
195
+ api.composer().reset();
196
+ api.composer().getState();
197
+
198
+ // Attachment actions
199
+ api.attachment().remove();
200
+ api.attachment().getState();
201
+
202
+ // ThreadList actions
203
+ api.threads().switchToNewThread();
204
+ api.threads().switchToThread(threadId);
205
+ api.threads().getState();
206
+
207
+ // ThreadListItem actions
208
+ api.threadListItem().switchTo();
209
+ api.threadListItem().rename(title);
210
+ api.threadListItem().archive();
211
+ api.threadListItem().unarchive();
212
+ api.threadListItem().delete();
213
+ api.threads().getState();
214
+
215
+ // ToolUIs actions
216
+ api.toolUIs().setToolUI(toolName, render);
217
+ api.toolUIs().getState();
218
+ ```
219
+
220
+ ### useAssistantEvent
221
+
222
+ Subscribe to events with automatic cleanup on unmount. This hook is perfect for reacting to user interactions, system events, or integrating with external analytics.
223
+
224
+ ```tsx
225
+ import { useAssistantEvent } from "@assistant-ui/react";
226
+
227
+ // Listen to current scope events (most common)
228
+ useAssistantEvent("composer.send", (event) => {
229
+ console.log("Current composer sent message:", event.message);
230
+ });
231
+
232
+ // Listen to all events of a type across all scopes
233
+ useAssistantEvent({ event: "composer.send", scope: "*" }, (event) => {
234
+ console.log("Any composer sent a message:", event);
235
+ });
236
+
237
+ // Listen to ALL events (useful for debugging or analytics)
238
+ useAssistantEvent("*", (event) => {
239
+ console.log("Event occurred:", event.type, "from:", event.source);
240
+ // Send to analytics, logging, etc.
241
+ });
242
+
243
+ // Practical example: Track user interactions
244
+ function AnalyticsTracker() {
245
+ useAssistantEvent("composer.send", (event) => {
246
+ analytics.track("message_sent", {
247
+ messageLength: event.message.content.length,
248
+ hasAttachments: event.message.attachments.length > 0,
249
+ });
250
+ });
251
+
252
+ return null; // This component only tracks events
253
+ }
254
+ ```
255
+
256
+ **Event name patterns:**
257
+
258
+ - Event names follow `source.action` format (e.g., `composer.send`, `thread.run-start`)
259
+ - Use `"*"` as the event name to listen to all events
260
+ - The `scope` parameter controls which instances trigger the event
261
+
262
+ ## Working with Scopes
263
+
264
+ ### Available Scopes
265
+
266
+ Each scope provides access to specific state and actions:
267
+
268
+ - **ThreadList** (`threads`): Collection and management of threads
269
+ - **ThreadListItem** (`threadListItem`): Individual thread in the list
270
+ - **Thread** (`thread`): Conversation with messages
271
+ - **Message** (`message`): Individual message (user or assistant)
272
+ - **Part** (`part`): Content part within a message (text, tool calls, etc.)
273
+ - **Composer** (`composer`): Text input for sending or editing messages
274
+ - **Attachment** (`attachment`): File or media attached to a message or composer
275
+ - **ToolUIs** (`toolUIs`): Tool UI components
276
+
277
+ ### Scope Resolution
278
+
279
+ The Context API automatically resolves the current scope based on component location:
280
+
281
+ ```tsx
282
+ function MessageButton() {
283
+ const api = useAssistantApi();
284
+
285
+ // Automatically uses the current message scope
286
+ const handleReload = () => {
287
+ api.message().reload();
288
+ };
289
+
290
+ return <button onClick={handleReload}>Reload</button>;
291
+ }
292
+ ```
293
+
294
+ ### Checking Scope Availability
295
+
296
+ Before accessing a scope, check if it's available:
297
+
298
+ ```tsx
299
+ const api = useAssistantApi();
300
+
301
+ // Check if message scope exists
302
+ if (api.message.source) {
303
+ // Safe to use message scope
304
+ const { role } = api.message().getState();
305
+ }
306
+ ```
307
+
308
+ ### Accessing Nested Scopes
309
+
310
+ Navigate through the scope hierarchy programmatically:
311
+
312
+ ```tsx
313
+ const api = useAssistantApi();
314
+
315
+ // Access specific message by ID or index
316
+ const messageById = api.thread().message({ id: "msg_123" });
317
+ const messageByIndex = api.thread().message({ index: 0 });
318
+
319
+ // Access part by index or tool call ID
320
+ const partByIndex = api.message().part({ index: 0 });
321
+ const partByToolCall = api.message().part({ toolCallId: "call_123" });
322
+
323
+ // Access attachment by index
324
+ const attachment = api.composer().attachment({ index: 0 }).getState();
325
+
326
+ // Access thread from thread list
327
+ const thread = api.threads().thread("main");
328
+ const threadItem = api.threads().item({ id: "thread_123" });
329
+ ```
330
+
331
+ ## Common Patterns
332
+
333
+ ### Conditional Rendering
334
+
335
+ ```tsx
336
+ function RunIndicator() {
337
+ const isRunning = useAssistantState(({ thread }) => thread.isRunning);
338
+
339
+ if (!isRunning) return null;
340
+ return <div>Assistant is thinking...</div>;
341
+ }
342
+ ```
343
+
344
+ ### Custom Action Buttons
345
+
346
+ ```tsx
347
+ function CopyButton() {
348
+ const api = useAssistantApi();
349
+
350
+ const handleCopy = () => {
351
+ navigator.clipboard.writeText(api.message().getCopyText());
352
+ };
353
+
354
+ return <button onClick={handleCopy}>Copy</button>;
355
+ }
356
+ ```
357
+
358
+ ### State-Aware Components
359
+
360
+ ```tsx
361
+ function SmartComposer() {
362
+ const api = useAssistantApi();
363
+ const isRunning = useAssistantState(({ thread }) => thread.isRunning);
364
+ const text = useAssistantState(({ composer }) => composer.text);
365
+
366
+ const canSend = !isRunning && text.length > 0;
367
+
368
+ return (
369
+ <div>
370
+ <textarea
371
+ value={text}
372
+ onChange={(e) => api.composer().setText(e.target.value)}
373
+ disabled={isRunning}
374
+ />
375
+ <button onClick={() => api.composer().send()} disabled={!canSend}>
376
+ Send
377
+ </button>
378
+ </div>
379
+ );
380
+ }
381
+ ```
382
+
383
+ ### Event-Driven Updates
384
+
385
+ ```tsx
386
+ function MessageCounter() {
387
+ const [sendCount, setSendCount] = useState(0);
388
+
389
+ useAssistantEvent("composer.send", () => {
390
+ setSendCount((c) => c + 1);
391
+ });
392
+
393
+ return <div>Messages sent: {sendCount}</div>;
394
+ }
395
+ ```
396
+
397
+ ## Advanced Topics
398
+
399
+ ### Resolution Dynamics
400
+
401
+ When you call `api.scope()`, the API resolves the current scope at that moment. This resolution happens each time you call the function, which matters when dealing with changing contexts:
402
+
403
+ ```tsx
404
+ const api = useAssistantApi();
405
+
406
+ // Get current thread
407
+ const thread1 = api.thread();
408
+ thread1.append({ role: "user", content: "Hello" });
409
+
410
+ // User might switch threads here
411
+
412
+ // This could be a different thread
413
+ const thread2 = api.thread();
414
+ thread2.cancelRun(); // Cancels the current thread's run, not necessarily thread1's
415
+ ```
416
+
417
+ For most use cases, this behavior is intuitive. In advanced scenarios where you need to track specific instances, store the resolved reference.
418
+
419
+ ### Performance Optimization
420
+
421
+ **Selector optimization:**
422
+
423
+ ```tsx
424
+ // ❌ Expensive computation in selector (runs on every store update)
425
+ const result = useAssistantState(
426
+ ({ thread }) => thread.messages.filter((m) => m.role === "user").length,
427
+ );
428
+
429
+ // ✅ Memoize expensive computations
430
+ const messages = useAssistantState(({ thread }) => thread.messages);
431
+ const userCount = useMemo(
432
+ () => messages.filter((m) => m.role === "user").length,
433
+ [messages],
434
+ );
435
+ ```
436
+
437
+ **Minimize re-renders:**
438
+
439
+ ```tsx
440
+ // ❌ Subscribes to entire thread state
441
+ const thread = useAssistantState(({ thread }) => thread);
442
+
443
+ // ✅ Subscribe only to needed values
444
+ const isRunning = useAssistantState(({ thread }) => thread.isRunning);
445
+ ```
446
+
447
+ ## API Reference
448
+
449
+ ### Hooks
450
+
451
+ | Hook | Purpose | Returns |
452
+ | ----------------------------------- | -------------------------- | -------------- |
453
+ | `useAssistantState(selector)` | Subscribe to state changes | Selected value |
454
+ | `useAssistantApi()` | Get API instance | API object |
455
+ | `useAssistantEvent(event, handler)` | Subscribe to events | void |
456
+
457
+ ### Scope States
458
+
459
+ | Scope | Key State Properties | Description |
460
+ | -------------- | --------------------------------------------------------------------------------- | ------------------------------------------------ |
461
+ | ThreadList | `mainThreadId`, `threadIds`, `isLoading`, `threadItems` | Manages all available conversation threads |
462
+ | ThreadListItem | `id`, `title`, `status`, `remoteId`, `externalId` | Individual thread metadata and status |
463
+ | Thread | `isRunning`, `isLoading`, `isDisabled`, `messages`, `capabilities`, `suggestions` | Active conversation state and message history |
464
+ | Message | `role`, `content`, `status`, `attachments`, `parentId`, `branchNumber`, `isLast` | Individual message content and metadata |
465
+ | Composer | `text`, `role`, `attachments`, `isEmpty`, `canCancel`, `type`, `isEditing` | Text input state for new/edited messages |
466
+ | Part | `type`, `content`, `status`, `text`, `toolCallId`, `toolName` | Content parts within messages (text, tool calls) |
467
+ | Attachment | `id`, `type`, `name`, `url`, `size`, `mimeType` | File attachments metadata and content |
468
+
469
+ ### Available Actions by Scope
470
+
471
+ | Scope | Actions | Use Cases |
472
+ | -------------- | --------------------------------------------------------------------- | ----------------------------------------- |
473
+ | ThreadList | `switchToNewThread()`, `switchToThread(id)`, `getState()` | Thread navigation and creation |
474
+ | ThreadListItem | `switchTo()`, `rename(title)`, `archive()`, `unarchive()`, `delete()` | Thread management operations |
475
+ | Thread | `append(message)`, `startRun()`, `cancelRun()`, `switchToNewThread()` | Message handling and conversation control |
476
+ | Message | `reload()`, `speak()`, `stopSpeaking()`, `submitFeedback(feedback)` | Message interactions and regeneration |
477
+ | Composer | `send()`, `setText(text)`, `addAttachment(file)`, `reset()` | Text input and message composition |
478
+ | Part | `addResult(result)`, `getState()` | Tool call result handling |
479
+ | Attachment | `remove()`, `getState()` | File management |
480
+
481
+ ### Common Events
482
+
483
+ | Event | Description |
484
+ | -------------------------------- | ----------------------------- |
485
+ | `thread.run-start` | Assistant starts generating |
486
+ | `thread.run-end` | Assistant finishes generating |
487
+ | `thread.initialize` | Thread is initialized |
488
+ | `thread.model-context-update` | Model context is updated |
489
+ | `composer.send` | Message is sent |
490
+ | `composer.attachment-add` | Attachment added to composer |
491
+ | `thread-list-item.switched-to` | Switched to a thread |
492
+ | `thread-list-item.switched-away` | Switched away from a thread |
493
+
494
+ ## Troubleshooting
495
+
496
+ ### Common Errors
497
+
498
+ **"Cannot access [scope] outside of [scope] context"**
499
+
500
+ ```tsx
501
+ // ❌ This will throw if not inside a message component
502
+ const role = useAssistantState(({ message }) => message.role);
503
+
504
+ // ✅ Check scope availability first
505
+ function SafeMessageButton() {
506
+ const api = useAssistantApi();
507
+
508
+ const role = useAssistantState(({ message }) =>
509
+ api.message.source !== undefined ? message.role : "none",
510
+ );
511
+
512
+ return <div>Role: {role}</div>;
513
+ }
514
+ ```
515
+
516
+ **"Maximum update depth exceeded" / Infinite re-renders**
517
+
518
+ ```tsx
519
+ // ❌ Creating new objects in selectors causes infinite re-renders
520
+ const data = useAssistantState(({ message }) => ({
521
+ role: message.role,
522
+ content: message.content, // New object every time!
523
+ }));
524
+
525
+ // ✅ Return primitive values or use separate selectors
526
+ const role = useAssistantState(({ message }) => message.role);
527
+ const content = useAssistantState(({ message }) => message.content);
528
+ ```
529
+
530
+ **"Scope resolution failed" / Stale scope references**
531
+
532
+ ```tsx
533
+ // ❌ Storing scope references can lead to stale data
534
+ const api = useAssistantApi();
535
+ const thread = api.thread(); // This reference might become stale
536
+
537
+ useEffect(() => {
538
+ // This might reference the wrong thread if user switched
539
+ thread.cancelRun();
540
+ }, [thread]);
541
+
542
+ // ✅ Resolve scopes fresh each time
543
+ const api = useAssistantApi();
544
+
545
+ useEffect(() => {
546
+ // Always gets the current thread
547
+ api.thread().cancelRun();
548
+ }, [api]);
549
+ ```
550
+
551
+ ## Quick Reference
552
+
553
+ ```tsx
554
+ // Read state
555
+ const value = useAssistantState(({ scope }) => scope.property);
556
+
557
+ // Perform action
558
+ const api = useAssistantApi();
559
+ api.scope().action();
560
+
561
+ // Listen to events
562
+ useAssistantEvent("source.event", (e) => {});
563
+
564
+ // Check scope availability
565
+ if (api.scope.source) {
566
+ /* scope exists */
567
+ }
568
+
569
+ // Get state imperatively
570
+ const state = api.scope().getState();
571
+
572
+ // Navigate scopes
573
+ api.thread().message({ id: "..." }).getState();
574
+ ```
@@ -0,0 +1,125 @@
1
+ ---
2
+ title: Migration to v0.12
3
+ ---
4
+
5
+ ## Major Architecture Change: Unified State API
6
+
7
+ Version 0.12 introduces a complete rewrite of the state management system with a more consistent API.
8
+
9
+ ## Breaking Changes
10
+
11
+ ### 1. Context Hooks Replaced with Unified State API
12
+
13
+ All individual context hooks have been replaced with a single `useAssistantState` hook and `useAssistantApi` for actions.
14
+
15
+ #### What changed
16
+
17
+ The following hooks have been removed:
18
+
19
+ **Removed Hooks:**
20
+
21
+ - `useMessageUtils` → Use `useAssistantState(({ message }) => message.isHovering)` / `useAssistantState(({ message }) => message.isCopied)`
22
+ - `useMessageUtilsStore` → Use `useAssistantApi()` with `api.message().setIsHovering()` / `api.message().setIsCopied()`
23
+ - `useToolUIs` → Use `useAssistantState(({ toolUIs }) => toolUIs)` and `useAssistantApi()` with `api.toolUIs()`
24
+ - `useToolUIsStore` → Use `useAssistantApi()` with `api.toolUIs()`
25
+
26
+ **Deprecated Hooks:**
27
+
28
+ - `useAssistantRuntime` → Use `useAssistantApi()`
29
+ - `useThread` → Use `useAssistantState(({ thread }) => thread)`
30
+ - `useThreadRuntime` → Use `useAssistantApi()` with `api.thread()`
31
+ - `useMessage` → Use `useAssistantState(({ message }) => message)`
32
+ - `useMessageRuntime` → Use `useAssistantApi()` with `api.message()`
33
+ - `useComposer` → Use `useAssistantState(({ composer }) => composer)`
34
+ - `useComposerRuntime` → Use `useAssistantApi()` with `api.composer()`
35
+ - `useEditComposer` → Use `useAssistantState(({ message }) => message.composer)`
36
+ - `useThreadListItem` → Use `useAssistantState(({ threadListItem }) => threadListItem)`
37
+ - `useThreadListItemRuntime` → Use `useAssistantApi()` with `api.threadListItem()`
38
+ - `useMessagePart` → Use `useAssistantState(({ part }) => part)`
39
+ - `useMessagePartRuntime` → Use `useAssistantApi()` with `api.part()`
40
+ - `useAttachment` → Use `useAssistantState(({ attachment }) => attachment)`
41
+ - `useAttachmentRuntime` → Use `useAssistantApi()` with `api.attachment()`
42
+ - `useThreadModelContext` / `useThreadModelConfig` → Use `useAssistantState(({ thread }) => thread.modelContext)`
43
+ - `useThreadComposer` → Use `useAssistantState(({ thread }) => thread.composer)`
44
+ - `useThreadList` → Use `useAssistantState(({ threads }) => threads)`
45
+
46
+ #### Migration Examples
47
+
48
+ **Before:**
49
+
50
+ ```tsx
51
+ import {
52
+ useThread,
53
+ useThreadRuntime,
54
+ useComposer,
55
+ useComposerRuntime,
56
+ useMessage,
57
+ useMessageRuntime,
58
+ } from "@assistant-ui/react";
59
+
60
+ function MyComponent() {
61
+ // Reading state
62
+ const messages = useThread((t) => t.messages);
63
+ const isRunning = useThread((t) => t.isRunning);
64
+ const composerText = useComposer((c) => c.text);
65
+ const messageRole = useMessage((m) => m.role);
66
+
67
+ // Using runtime for actions
68
+ const threadRuntime = useThreadRuntime();
69
+ const composerRuntime = useComposerRuntime();
70
+ const messageRuntime = useMessageRuntime();
71
+
72
+ const handleSend = () => {
73
+ composerRuntime.send();
74
+ };
75
+
76
+ const handleReload = () => {
77
+ messageRuntime.reload();
78
+ };
79
+
80
+ const handleCancel = () => {
81
+ threadRuntime.cancelRun();
82
+ };
83
+
84
+ return null;
85
+ }
86
+ ```
87
+
88
+ **After:**
89
+
90
+ ```tsx
91
+ import { useAssistantState, useAssistantApi } from "@assistant-ui/react";
92
+
93
+ function MyComponent() {
94
+ // Reading state - all through single hook
95
+ const messages = useAssistantState(({ thread }) => thread.messages);
96
+ const isRunning = useAssistantState(({ thread }) => thread.isRunning);
97
+ const composerText = useAssistantState(({ composer }) => composer.text);
98
+ const messageRole = useAssistantState(({ message }) => message.role);
99
+
100
+ // Using API for actions
101
+ const api = useAssistantApi();
102
+
103
+ const handleSend = () => {
104
+ api.composer().send();
105
+ };
106
+
107
+ const handleReload = () => {
108
+ api.message().reload();
109
+ };
110
+
111
+ const handleCancel = () => {
112
+ api.thread().cancelRun();
113
+ };
114
+
115
+ return null;
116
+ }
117
+ ```
118
+
119
+ ## Getting Help
120
+
121
+ If you encounter issues during migration:
122
+
123
+ 1. Check the updated API documentation for detailed examples
124
+ 2. Review the example applications in the repository
125
+ 3. Report issues at https://github.com/assistant-ui/assistant-ui/issues