@assistant-ui/mcp-docs-server 0.1.39 → 0.2.0
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.
- package/.docs/organized/code-examples/waterfall.md +7 -7
- package/.docs/organized/code-examples/with-a2a.md +7 -7
- package/.docs/organized/code-examples/with-ag-ui.md +8 -8
- package/.docs/organized/code-examples/with-ai-sdk-v7.md +9 -9
- package/.docs/organized/code-examples/with-artifacts.md +463 -138
- package/.docs/organized/code-examples/with-assistant-transport.md +7 -7
- package/.docs/organized/code-examples/with-browser-extension.md +6 -6
- package/.docs/organized/code-examples/with-chain-of-thought.md +11 -11
- package/.docs/organized/code-examples/with-cloud-standalone.md +9 -9
- package/.docs/organized/code-examples/with-cloud.md +9 -9
- package/.docs/organized/code-examples/with-custom-thread-list.md +9 -9
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +11 -11
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +11 -11
- package/.docs/organized/code-examples/with-eve.md +8 -8
- package/.docs/organized/code-examples/with-expo.md +26 -46
- package/.docs/organized/code-examples/with-external-store.md +7 -7
- package/.docs/organized/code-examples/with-ffmpeg.md +9 -9
- package/.docs/organized/code-examples/with-generative-ui.md +10 -10
- package/.docs/organized/code-examples/with-google-adk.md +8 -8
- package/.docs/organized/code-examples/with-heat-graph.md +6 -6
- package/.docs/organized/code-examples/with-image-generation.md +9 -9
- package/.docs/organized/code-examples/with-interactables.md +9 -9
- package/.docs/organized/code-examples/with-langchain.md +9 -9
- package/.docs/organized/code-examples/with-langgraph.md +9 -9
- package/.docs/organized/code-examples/with-livekit.md +11 -11
- package/.docs/organized/code-examples/with-mcp.md +28 -23
- package/.docs/organized/code-examples/with-opencode.md +8 -11
- package/.docs/organized/code-examples/with-pi.md +14 -14
- package/.docs/organized/code-examples/with-react-hook-form.md +10 -10
- package/.docs/organized/code-examples/with-react-ink-web.md +5 -5
- package/.docs/organized/code-examples/with-react-ink.md +2 -2
- package/.docs/organized/code-examples/with-react-router.md +11 -11
- package/.docs/organized/code-examples/with-resumable-stream.md +10 -10
- package/.docs/organized/code-examples/with-store.md +6 -6
- package/.docs/organized/code-examples/with-tanstack.md +9 -9
- package/.docs/organized/code-examples/with-tap-runtime.md +7 -7
- package/.docs/organized/code-examples/with-virtualized-thread.md +8 -8
- package/.docs/raw/docs/(docs)/cli.mdx +2 -0
- package/.docs/raw/docs/(docs)/devtools.mdx +7 -2
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/a2ui.mdx +40 -0
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/index.mdx +3 -0
- package/.docs/raw/docs/(reference)/api-reference/hooks/primitives.mdx +19 -420
- package/.docs/raw/docs/(reference)/api-reference/hooks/state.mdx +4 -1
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +21 -0
- package/.docs/raw/docs/(reference)/api-reference/model-context/context.mdx +1 -9
- package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +1 -18
- package/.docs/raw/docs/cloud/langgraph.mdx +1 -1
- package/.docs/raw/docs/copilots/model-context.mdx +1 -1
- package/.docs/raw/docs/copilots/motivation.mdx +1 -1
- package/.docs/raw/docs/guides/attachments.mdx +3 -3
- package/.docs/raw/docs/guides/branching.mdx +2 -2
- package/.docs/raw/docs/guides/context-api.mdx +89 -111
- package/.docs/raw/docs/guides/editing.mdx +5 -5
- package/.docs/raw/docs/guides/electron.mdx +369 -0
- package/.docs/raw/docs/guides/index.mdx +10 -0
- package/.docs/raw/docs/guides/quoting.mdx +3 -3
- package/.docs/raw/docs/guides/resumable-stream-deployment.mdx +2 -2
- package/.docs/raw/docs/ink/hooks.mdx +3 -3
- package/.docs/raw/docs/ink/primitives.mdx +14 -7
- package/.docs/raw/docs/integrations/auth/better-auth.mdx +2 -2
- package/.docs/raw/docs/integrations/auth/clerk.mdx +2 -2
- package/.docs/raw/docs/integrations/auth/next-auth.mdx +3 -3
- package/.docs/raw/docs/integrations/observability/langsmith.mdx +1 -1
- package/.docs/raw/docs/integrations/persistence/custom-adapter.mdx +36 -9
- package/.docs/raw/docs/migrations/v0-15.mdx +156 -0
- package/.docs/raw/docs/primitives/composer.mdx +1 -1
- package/.docs/raw/docs/primitives/thread-list.mdx +2 -2
- package/.docs/raw/docs/react-native/hooks.mdx +3 -3
- package/.docs/raw/docs/react-native/index.mdx +2 -2
- package/.docs/raw/docs/react-native/primitives.mdx +39 -5
- package/.docs/raw/docs/runtimes/ai-sdk/overview.mdx +3 -3
- package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +4 -4
- package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +4 -4
- package/.docs/raw/docs/runtimes/ai-sdk/v6-legacy.mdx +4 -4
- package/.docs/raw/docs/runtimes/ai-sdk/v7.mdx +2 -2
- package/.docs/raw/docs/runtimes/concepts/threads.mdx +10 -10
- package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +2 -2
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +1 -1
- package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +3 -3
- package/.docs/raw/docs/runtimes/langchain.mdx +2 -2
- package/.docs/raw/docs/runtimes/langgraph/overview.mdx +1 -1
- package/.docs/raw/docs/runtimes/opencode/hooks.mdx +3 -1
- package/.docs/raw/docs/tools/a2ui.mdx +107 -0
- package/.docs/raw/docs/tools/interactables-legacy.mdx +4 -4
- package/.docs/raw/docs/tools/interactables.mdx +3 -3
- package/.docs/raw/docs/tools/mcp-apps.mdx +61 -2
- package/.docs/raw/docs/tools/user-managed-mcp.mdx +52 -7
- package/.docs/raw/docs/ui/follow-up-suggestions.mdx +2 -0
- package/.docs/raw/docs/ui/model-selector.mdx +1 -1
- package/.docs/raw/docs/ui/part-grouping.mdx +0 -4
- package/.docs/raw/docs/ui/reasoning.mdx +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/prepare-docs/code-examples.js.map +1 -1
- package/dist/prepare-docs/prepare.d.ts +1 -1
- package/dist/stdio.d.ts +1 -1
- package/dist/tools/docs.d.ts +6 -10
- package/dist/tools/docs.d.ts.map +1 -1
- package/dist/tools/docs.js +2 -2
- package/dist/tools/docs.js.map +1 -1
- package/dist/tools/examples.d.ts +4 -8
- package/dist/tools/examples.d.ts.map +1 -1
- package/dist/tools/examples.js +2 -2
- package/dist/tools/examples.js.map +1 -1
- package/dist/tools/resources.d.ts +1 -1
- package/dist/tools/resources.d.ts.map +1 -1
- package/dist/tools/resources.js +1 -1
- package/dist/tools/resources.js.map +1 -1
- package/dist/tools/search.d.ts +4 -10
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +2 -2
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/tests/mcp-test-client.d.ts +15 -0
- package/dist/tools/tests/mcp-test-client.d.ts.map +1 -0
- package/dist/tools/tests/mcp-test-client.js +68 -0
- package/dist/tools/tests/mcp-test-client.js.map +1 -0
- package/dist/tools/tests/test-setup.d.ts.map +1 -1
- package/dist/tools/xulux-templates.d.ts +9 -23
- package/dist/tools/xulux-templates.d.ts.map +1 -1
- package/dist/tools/xulux-templates.js +4 -4
- package/dist/tools/xulux-templates.js.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/security.js.map +1 -1
- package/package.json +4 -3
- package/src/index.ts +2 -2
- package/src/tools/docs.ts +2 -2
- package/src/tools/examples.ts +2 -2
- package/src/tools/resources.ts +1 -4
- package/src/tools/search.ts +2 -2
- package/src/tools/tests/completions.test.ts +40 -26
- package/src/tools/tests/integration.test.ts +3 -4
- package/src/tools/tests/mcp-protocol.test.ts +160 -175
- package/src/tools/tests/mcp-test-client.ts +111 -0
- package/src/tools/tests/resources.test.ts +97 -66
- package/src/tools/xulux-templates.ts +4 -4
|
@@ -202,24 +202,7 @@ const isThreadEmpty: AuiIf.Condition = (s) => s.thread.isEmpty;
|
|
|
202
202
|
|
|
203
203
|
### AuiIf
|
|
204
204
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
A thin wrapper around [useAuiState](/docs/api-reference/hooks/state#useauistate) that renders its children
|
|
208
|
-
when `condition` returns `true` and unmounts them when it returns
|
|
209
|
-
`false`. Keeps render logic declarative without mounting unused
|
|
210
|
-
subtrees.
|
|
211
|
-
|
|
212
|
-
```tsx
|
|
213
|
-
<AuiIf condition={(s) => s.thread.isRunning}>
|
|
214
|
-
<CancelButton />
|
|
215
|
-
</AuiIf>
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
```tsx
|
|
219
|
-
<AuiIf condition={(s) => s.thread.messages.length === 0}>
|
|
220
|
-
<EmptyState />
|
|
221
|
-
</AuiIf>
|
|
222
|
-
```
|
|
205
|
+
Renders `children` while `condition` selects `true` from the assistant state.
|
|
223
206
|
|
|
224
207
|
<ParametersTable {...AuiIf} />
|
|
225
208
|
{/* api-reference:end */}
|
|
@@ -6,7 +6,7 @@ description: Integrate cloud persistence and thread management with LangGraph Cl
|
|
|
6
6
|
|
|
7
7
|
## Overview
|
|
8
8
|
|
|
9
|
-
This guide shows how to integrate Assistant Cloud with [LangGraph Cloud](https://langchain
|
|
9
|
+
This guide shows how to integrate Assistant Cloud with [LangGraph Cloud](https://docs.langchain.com/langsmith/deploy-to-cloud-overview) using assistant-ui's runtime system and pre-built UI components.
|
|
10
10
|
|
|
11
11
|
## Prerequisites
|
|
12
12
|
|
|
@@ -112,7 +112,7 @@ function MyComponent() {
|
|
|
112
112
|
|
|
113
113
|
useEffect(() => {
|
|
114
114
|
// Register context provider
|
|
115
|
-
return aui.modelContext
|
|
115
|
+
return aui.modelContext.register({
|
|
116
116
|
getModelContext: () => ({
|
|
117
117
|
system: "You are a helpful search assistant...",
|
|
118
118
|
tools: { myTool },
|
|
@@ -158,7 +158,7 @@ function SmartTransactionHistory({ userProfile }) {
|
|
|
158
158
|
const aui = useAui();
|
|
159
159
|
|
|
160
160
|
useEffect(() => {
|
|
161
|
-
return aui.modelContext
|
|
161
|
+
return aui.modelContext.register({
|
|
162
162
|
getModelContext: () => ({
|
|
163
163
|
system: `
|
|
164
164
|
User spending patterns:
|
|
@@ -503,14 +503,14 @@ Add attachments from external sources (URLs, API data, CMS references) without n
|
|
|
503
503
|
const aui = useAui();
|
|
504
504
|
|
|
505
505
|
// Add an attachment from an external source
|
|
506
|
-
await aui.composer
|
|
506
|
+
await aui.composer.addAttachment({
|
|
507
507
|
name: "report.pdf",
|
|
508
508
|
contentType: "application/pdf",
|
|
509
509
|
content: [{ type: "text", text: "Extracted document content..." }],
|
|
510
510
|
});
|
|
511
511
|
|
|
512
512
|
// Optionally provide id and type
|
|
513
|
-
await aui.composer
|
|
513
|
+
await aui.composer.addAttachment({
|
|
514
514
|
id: "cms-doc-123",
|
|
515
515
|
type: "document",
|
|
516
516
|
name: "Product Spec",
|
|
@@ -532,7 +532,7 @@ const handleMultipleFiles = async (files: FileList) => {
|
|
|
532
532
|
const filesToAdd = Array.from(files).slice(0, maxFiles);
|
|
533
533
|
|
|
534
534
|
for (const file of filesToAdd) {
|
|
535
|
-
await aui.composer
|
|
535
|
+
await aui.composer.addAttachment(file);
|
|
536
536
|
}
|
|
537
537
|
};
|
|
538
538
|
```
|
|
@@ -54,7 +54,7 @@ const AssistantMessage = () => (
|
|
|
54
54
|
|
|
55
55
|
## Programmatic Branch Navigation
|
|
56
56
|
|
|
57
|
-
For headless or keyboard-shortcut flows, navigate directly to a branch by id via `aui.message
|
|
57
|
+
For headless or keyboard-shortcut flows, navigate directly to a branch by id via `aui.message.switchToBranch`:
|
|
58
58
|
|
|
59
59
|
```tsx
|
|
60
60
|
import { useAui } from "@assistant-ui/react";
|
|
@@ -62,7 +62,7 @@ import { useAui } from "@assistant-ui/react";
|
|
|
62
62
|
const SwitchToBranch = ({ branchId }: { branchId: string }) => {
|
|
63
63
|
const aui = useAui();
|
|
64
64
|
return (
|
|
65
|
-
<button onClick={() => aui.message
|
|
65
|
+
<button onClick={() => aui.message.switchToBranch({ branchId })}>
|
|
66
66
|
Go to branch
|
|
67
67
|
</button>
|
|
68
68
|
);
|
|
@@ -122,7 +122,7 @@ const content = useAuiState((s) => s.message.content);
|
|
|
122
122
|
|
|
123
123
|
### useAui
|
|
124
124
|
|
|
125
|
-
Access the API instance for imperative operations and actions. Unlike `useAuiState`, this hook
|
|
125
|
+
Access the API instance for imperative operations and actions. Unlike `useAuiState`, this hook does not subscribe to state updates: the client's identity only changes on structural changes (a scope resolving to a different instance), making it well suited for event handlers and imperative operations.
|
|
126
126
|
|
|
127
127
|
```tsx
|
|
128
128
|
import { useAui } from "@assistant-ui/react";
|
|
@@ -132,20 +132,20 @@ function CustomMessageActions() {
|
|
|
132
132
|
|
|
133
133
|
// Perform actions in event handlers
|
|
134
134
|
const handleSend = () => {
|
|
135
|
-
aui.composer
|
|
135
|
+
aui.composer.send();
|
|
136
136
|
};
|
|
137
137
|
|
|
138
138
|
const handleReload = () => {
|
|
139
|
-
aui.message
|
|
139
|
+
aui.message.reload();
|
|
140
140
|
};
|
|
141
141
|
|
|
142
142
|
// Read state imperatively when needed
|
|
143
143
|
const handleConditionalAction = () => {
|
|
144
|
-
const { isRunning } = aui.thread
|
|
145
|
-
const { text } = aui.composer
|
|
144
|
+
const { isRunning } = aui.thread.getState();
|
|
145
|
+
const { text } = aui.composer.getState();
|
|
146
146
|
|
|
147
147
|
if (!isRunning && text.length > 0) {
|
|
148
|
-
aui.composer
|
|
148
|
+
aui.composer.send();
|
|
149
149
|
}
|
|
150
150
|
};
|
|
151
151
|
|
|
@@ -159,7 +159,7 @@ function CustomMessageActions() {
|
|
|
159
159
|
}
|
|
160
160
|
```
|
|
161
161
|
|
|
162
|
-
The API object
|
|
162
|
+
The API object doesn't cause re-renders on state updates. Use it for:
|
|
163
163
|
|
|
164
164
|
- **Triggering actions** in event handlers and callbacks
|
|
165
165
|
- **Reading current state** imperatively when you don't need subscriptions
|
|
@@ -170,80 +170,80 @@ The API object is stable and doesn't cause re-renders. Use it for:
|
|
|
170
170
|
|
|
171
171
|
```tsx
|
|
172
172
|
// Thread actions
|
|
173
|
-
aui.thread
|
|
174
|
-
aui.thread
|
|
175
|
-
aui.thread
|
|
176
|
-
aui.thread
|
|
177
|
-
aui.thread
|
|
178
|
-
aui.thread
|
|
179
|
-
aui.thread
|
|
180
|
-
aui.thread
|
|
173
|
+
aui.thread.append(message);
|
|
174
|
+
aui.thread.startRun(config);
|
|
175
|
+
aui.thread.resumeRun(config);
|
|
176
|
+
aui.thread.cancelRun();
|
|
177
|
+
aui.thread.getState();
|
|
178
|
+
aui.thread.message({ index: idx });
|
|
179
|
+
aui.thread.message({ id: messageId });
|
|
180
|
+
aui.thread.composer();
|
|
181
181
|
|
|
182
182
|
// Message actions
|
|
183
|
-
aui.message
|
|
184
|
-
aui.message
|
|
185
|
-
aui.message
|
|
186
|
-
aui.message
|
|
187
|
-
aui.message
|
|
188
|
-
aui.message
|
|
189
|
-
aui.message
|
|
190
|
-
aui.message
|
|
191
|
-
aui.message
|
|
183
|
+
aui.message.reload();
|
|
184
|
+
aui.message.speak();
|
|
185
|
+
aui.message.stopSpeaking();
|
|
186
|
+
aui.message.submitFeedback({ type: "positive" | "negative" });
|
|
187
|
+
aui.message.switchToBranch({ position, branchId });
|
|
188
|
+
aui.message.getState();
|
|
189
|
+
aui.message.part({ index: idx });
|
|
190
|
+
aui.message.part({ toolCallId });
|
|
191
|
+
aui.message.composer();
|
|
192
192
|
|
|
193
193
|
// Part actions
|
|
194
|
-
aui.part
|
|
195
|
-
aui.part
|
|
196
|
-
aui.part
|
|
194
|
+
aui.part.addToolResult(result);
|
|
195
|
+
aui.part.resumeToolCall(result);
|
|
196
|
+
aui.part.getState();
|
|
197
197
|
|
|
198
198
|
// Composer actions
|
|
199
|
-
aui.composer
|
|
200
|
-
aui.composer
|
|
201
|
-
aui.composer
|
|
202
|
-
aui.composer
|
|
203
|
-
aui.composer
|
|
204
|
-
await aui.composer
|
|
205
|
-
await aui.composer
|
|
206
|
-
aui.composer
|
|
199
|
+
aui.composer.send();
|
|
200
|
+
aui.composer.setText(text);
|
|
201
|
+
aui.composer.setRole(role);
|
|
202
|
+
aui.composer.addAttachment(file); // File object
|
|
203
|
+
aui.composer.addAttachment({ name, content }); // external source
|
|
204
|
+
await aui.composer.clearAttachments();
|
|
205
|
+
await aui.composer.reset();
|
|
206
|
+
aui.composer.getState();
|
|
207
207
|
|
|
208
208
|
// Attachment actions
|
|
209
|
-
aui.attachment
|
|
210
|
-
aui.attachment
|
|
209
|
+
aui.attachment.remove();
|
|
210
|
+
aui.attachment.getState();
|
|
211
211
|
|
|
212
212
|
// ThreadList actions
|
|
213
|
-
aui.threads
|
|
214
|
-
aui.threads
|
|
215
|
-
aui.threads
|
|
216
|
-
await aui.threads
|
|
217
|
-
aui.threads
|
|
213
|
+
aui.threads.switchToNewThread();
|
|
214
|
+
aui.threads.switchToThread(threadId);
|
|
215
|
+
aui.threads.reload();
|
|
216
|
+
await aui.threads.getLoadThreadsPromise();
|
|
217
|
+
aui.threads.getState();
|
|
218
218
|
|
|
219
219
|
// ThreadListItem actions
|
|
220
|
-
aui.threadListItem
|
|
221
|
-
aui.threadListItem
|
|
222
|
-
aui.threadListItem
|
|
223
|
-
aui.threadListItem
|
|
224
|
-
aui.threadListItem
|
|
225
|
-
aui.threadListItem
|
|
226
|
-
aui.threadListItem
|
|
220
|
+
aui.threadListItem.switchTo();
|
|
221
|
+
aui.threadListItem.rename(title);
|
|
222
|
+
aui.threadListItem.updateCustom(custom);
|
|
223
|
+
aui.threadListItem.archive();
|
|
224
|
+
aui.threadListItem.unarchive();
|
|
225
|
+
aui.threadListItem.delete();
|
|
226
|
+
aui.threadListItem.getState();
|
|
227
227
|
|
|
228
228
|
// Suggestions actions
|
|
229
|
-
aui.suggestions
|
|
230
|
-
aui.suggestions
|
|
229
|
+
aui.suggestions.getState();
|
|
230
|
+
aui.suggestions.suggestion({ index: 0 });
|
|
231
231
|
|
|
232
232
|
// Suggestion actions
|
|
233
|
-
aui.suggestion
|
|
233
|
+
aui.suggestion.getState();
|
|
234
234
|
|
|
235
235
|
// ChainOfThought actions
|
|
236
|
-
aui.chainOfThought
|
|
237
|
-
aui.chainOfThought
|
|
238
|
-
aui.chainOfThought
|
|
236
|
+
aui.chainOfThought.getState();
|
|
237
|
+
aui.chainOfThought.setCollapsed(collapsed);
|
|
238
|
+
aui.chainOfThought.part({ index: 0 });
|
|
239
239
|
|
|
240
240
|
// ModelContext actions — see /docs/copilots/model-context for full usage
|
|
241
|
-
aui.modelContext
|
|
242
|
-
aui.modelContext
|
|
241
|
+
aui.modelContext.register(provider);
|
|
242
|
+
aui.modelContext.getState();
|
|
243
243
|
|
|
244
244
|
// Tools actions
|
|
245
|
-
aui.tools
|
|
246
|
-
aui.tools
|
|
245
|
+
aui.tools.setToolUI(toolName, render);
|
|
246
|
+
aui.tools.getState();
|
|
247
247
|
```
|
|
248
248
|
|
|
249
249
|
### useAuiEvent
|
|
@@ -320,7 +320,7 @@ function MessageButton() {
|
|
|
320
320
|
|
|
321
321
|
// Automatically uses the current message scope
|
|
322
322
|
const handleReload = () => {
|
|
323
|
-
aui.message
|
|
323
|
+
aui.message.reload();
|
|
324
324
|
};
|
|
325
325
|
|
|
326
326
|
return <button onClick={handleReload}>Reload</button>;
|
|
@@ -329,16 +329,10 @@ function MessageButton() {
|
|
|
329
329
|
|
|
330
330
|
### Checking Scope Availability
|
|
331
331
|
|
|
332
|
-
|
|
332
|
+
Read scopes that may be unavailable through the optional view — they resolve to `undefined` instead of throwing:
|
|
333
333
|
|
|
334
334
|
```tsx
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
// Check if message scope exists
|
|
338
|
-
if (aui.message.source) {
|
|
339
|
-
// Safe to use message scope
|
|
340
|
-
const { role } = aui.message().getState();
|
|
341
|
-
}
|
|
335
|
+
const role = useAuiState((s) => s.optional.message?.role);
|
|
342
336
|
```
|
|
343
337
|
|
|
344
338
|
### Accessing Nested Scopes
|
|
@@ -349,24 +343,24 @@ Navigate through the scope hierarchy programmatically:
|
|
|
349
343
|
const aui = useAui();
|
|
350
344
|
|
|
351
345
|
// Access specific message by ID or index
|
|
352
|
-
const messageById = aui.thread
|
|
353
|
-
const messageByIndex = aui.thread
|
|
346
|
+
const messageById = aui.thread.message({ id: "msg_123" });
|
|
347
|
+
const messageByIndex = aui.thread.message({ index: 0 });
|
|
354
348
|
|
|
355
349
|
// Access part by index or tool call ID
|
|
356
|
-
const partByIndex = aui.message
|
|
357
|
-
const partByToolCall = aui.message
|
|
350
|
+
const partByIndex = aui.message.part({ index: 0 });
|
|
351
|
+
const partByToolCall = aui.message.part({ toolCallId: "call_123" });
|
|
358
352
|
|
|
359
353
|
// Access attachment by index
|
|
360
|
-
const attachment = aui.composer
|
|
354
|
+
const attachment = aui.composer.attachment({ index: 0 }).getState();
|
|
361
355
|
|
|
362
356
|
// Access thread list item by ID, index, or the "main" selector
|
|
363
|
-
const threadItem = aui.threads
|
|
364
|
-
const threadByIndex = aui.threads
|
|
365
|
-
const archivedThread = aui.threads
|
|
357
|
+
const threadItem = aui.threads.item({ id: "thread_123" });
|
|
358
|
+
const threadByIndex = aui.threads.item({ index: 0 });
|
|
359
|
+
const archivedThread = aui.threads.item({ index: 0, archived: true });
|
|
366
360
|
|
|
367
361
|
// Traverse to the main thread directly
|
|
368
|
-
const mainThread = aui.threads
|
|
369
|
-
const message = aui.threads
|
|
362
|
+
const mainThread = aui.threads.thread("main");
|
|
363
|
+
const message = aui.threads.thread("main").message({ id: "msg_123" });
|
|
370
364
|
```
|
|
371
365
|
|
|
372
366
|
## Common Patterns
|
|
@@ -389,7 +383,7 @@ function CopyButton() {
|
|
|
389
383
|
const aui = useAui();
|
|
390
384
|
|
|
391
385
|
const handleCopy = () => {
|
|
392
|
-
navigator.clipboard.writeText(aui.message
|
|
386
|
+
navigator.clipboard.writeText(aui.message.getCopyText());
|
|
393
387
|
};
|
|
394
388
|
|
|
395
389
|
return <button onClick={handleCopy}>Copy</button>;
|
|
@@ -410,10 +404,10 @@ function SmartComposer() {
|
|
|
410
404
|
<div>
|
|
411
405
|
<textarea
|
|
412
406
|
value={text}
|
|
413
|
-
onChange={(e) => aui.composer
|
|
407
|
+
onChange={(e) => aui.composer.setText(e.target.value)}
|
|
414
408
|
disabled={isRunning}
|
|
415
409
|
/>
|
|
416
|
-
<button onClick={() => aui.composer
|
|
410
|
+
<button onClick={() => aui.composer.send()} disabled={!canSend}>
|
|
417
411
|
Send
|
|
418
412
|
</button>
|
|
419
413
|
</div>
|
|
@@ -439,24 +433,18 @@ function MessageCounter() {
|
|
|
439
433
|
|
|
440
434
|
### Resolution Dynamics
|
|
441
435
|
|
|
442
|
-
|
|
436
|
+
Scopes are resolved during render and bound into the client. State updates never change the client's identity; a structural change (for example, switching threads) produces a new client and re-renders consumers through React:
|
|
443
437
|
|
|
444
438
|
```tsx
|
|
445
439
|
const aui = useAui();
|
|
446
440
|
|
|
447
|
-
//
|
|
448
|
-
|
|
449
|
-
thread1.append({ role: "user", content: "Hello" });
|
|
441
|
+
// Bound to the thread current at this render
|
|
442
|
+
aui.thread.append({ role: "user", content: "Hello" });
|
|
450
443
|
|
|
451
|
-
//
|
|
452
|
-
|
|
453
|
-
// This could be a different thread
|
|
454
|
-
const thread2 = aui.thread();
|
|
455
|
-
thread2.cancelRun(); // Cancels the current thread's run, not necessarily thread1's
|
|
444
|
+
// After a thread switch, the component re-renders with a new client.
|
|
445
|
+
// Accessors read from a previous render keep pointing at the old thread.
|
|
456
446
|
```
|
|
457
447
|
|
|
458
|
-
For most use cases, this behavior is intuitive. In advanced scenarios where you need to track specific instances, store the resolved reference.
|
|
459
|
-
|
|
460
448
|
### Performance Optimization
|
|
461
449
|
|
|
462
450
|
**Selector optimization:**
|
|
@@ -570,16 +558,8 @@ These events fire at the same transition you can observe via state. They are kep
|
|
|
570
558
|
// ❌ This will throw if not inside a message component
|
|
571
559
|
const role = useAuiState((s) => s.message.role);
|
|
572
560
|
|
|
573
|
-
// ✅
|
|
574
|
-
|
|
575
|
-
const aui = useAui();
|
|
576
|
-
|
|
577
|
-
const role = useAuiState((s) =>
|
|
578
|
-
aui.message.source !== undefined ? s.message.role : "none",
|
|
579
|
-
);
|
|
580
|
-
|
|
581
|
-
return <div>Role: {role}</div>;
|
|
582
|
-
}
|
|
561
|
+
// ✅ Read through the optional view — unavailable scopes resolve to undefined
|
|
562
|
+
const role = useAuiState((s) => s.optional.message?.role ?? "none");
|
|
583
563
|
```
|
|
584
564
|
|
|
585
565
|
**"Maximum update depth exceeded" / Infinite re-renders**
|
|
@@ -601,7 +581,7 @@ const content = useAuiState((s) => s.message.content);
|
|
|
601
581
|
```tsx
|
|
602
582
|
// ❌ Storing scope references can lead to stale data
|
|
603
583
|
const aui = useAui();
|
|
604
|
-
const thread = aui.thread
|
|
584
|
+
const thread = aui.thread; // This reference might become stale
|
|
605
585
|
|
|
606
586
|
useEffect(() => {
|
|
607
587
|
// This might reference the wrong thread if user switched
|
|
@@ -613,7 +593,7 @@ const aui = useAui();
|
|
|
613
593
|
|
|
614
594
|
useEffect(() => {
|
|
615
595
|
// Always gets the current thread
|
|
616
|
-
aui.thread
|
|
596
|
+
aui.thread.cancelRun();
|
|
617
597
|
}, [aui]);
|
|
618
598
|
```
|
|
619
599
|
|
|
@@ -625,19 +605,17 @@ const value = useAuiState((s) => s.scope.property);
|
|
|
625
605
|
|
|
626
606
|
// Perform action
|
|
627
607
|
const aui = useAui();
|
|
628
|
-
aui.scope
|
|
608
|
+
aui.scope.action();
|
|
629
609
|
|
|
630
610
|
// Listen to events
|
|
631
611
|
useAuiEvent("source.event", (e) => {});
|
|
632
612
|
|
|
633
|
-
//
|
|
634
|
-
|
|
635
|
-
/* scope exists */
|
|
636
|
-
}
|
|
613
|
+
// Read a scope that may be unavailable
|
|
614
|
+
const maybe = useAuiState((s) => s.optional.scope?.property);
|
|
637
615
|
|
|
638
616
|
// Get state imperatively
|
|
639
|
-
const state = aui.scope
|
|
617
|
+
const state = aui.scope.getState();
|
|
640
618
|
|
|
641
619
|
// Navigate scopes
|
|
642
|
-
aui.thread
|
|
620
|
+
aui.thread.message({ id: "..." }).getState();
|
|
643
621
|
```
|
|
@@ -66,9 +66,9 @@ const AssistantMessage = () => {
|
|
|
66
66
|
};
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
`ActionBarPrimitive.Edit` calls `aui.composer
|
|
69
|
+
`ActionBarPrimitive.Edit` calls `aui.composer.beginEdit()` under the hood and is disabled when the composer is already in edit mode.
|
|
70
70
|
|
|
71
|
-
`ComposerPrimitive.Cancel` calls `aui.composer
|
|
71
|
+
`ComposerPrimitive.Cancel` calls `aui.composer.cancel()`, which exits edit mode and restores the original message content. See [Composer primitives](/docs/primitives/composer) for the full composer API.
|
|
72
72
|
|
|
73
73
|
## Detecting Edit Mode
|
|
74
74
|
|
|
@@ -76,7 +76,7 @@ The `isEditing` flag is available on both `ThreadComposerState` and `EditCompose
|
|
|
76
76
|
|
|
77
77
|
## Imperative API
|
|
78
78
|
|
|
79
|
-
`aui.composer
|
|
79
|
+
`aui.composer.beginEdit()` is the programmatic entry point for entering edit mode on a message. Use it for headless or keyboard-shortcut-driven flows where `ActionBarPrimitive.Edit` is not rendered:
|
|
80
80
|
|
|
81
81
|
```tsx
|
|
82
82
|
import { useAui } from "@assistant-ui/react";
|
|
@@ -84,12 +84,12 @@ import { useAui } from "@assistant-ui/react";
|
|
|
84
84
|
const EditButton = () => {
|
|
85
85
|
const aui = useAui();
|
|
86
86
|
return (
|
|
87
|
-
<button onClick={() => aui.composer
|
|
87
|
+
<button onClick={() => aui.composer.beginEdit()}>Edit</button>
|
|
88
88
|
);
|
|
89
89
|
};
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
`aui.composer
|
|
92
|
+
`aui.composer.cancel()` exits edit mode without re-submitting.
|
|
93
93
|
|
|
94
94
|
## Editing While Streaming
|
|
95
95
|
|