@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
|
@@ -305,7 +305,7 @@ export const threadListAdapter: RemoteThreadListAdapter = {
|
|
|
305
305
|
async append() {},
|
|
306
306
|
withFormat: (fmt) => ({
|
|
307
307
|
async load() {
|
|
308
|
-
const { remoteId } = aui.threadListItem
|
|
308
|
+
const { remoteId } = aui.threadListItem.getState();
|
|
309
309
|
if (!remoteId) return { messages: [] };
|
|
310
310
|
const rows = await fetch(
|
|
311
311
|
`/api/threads/${remoteId}/messages`,
|
|
@@ -322,7 +322,7 @@ export const threadListAdapter: RemoteThreadListAdapter = {
|
|
|
322
322
|
};
|
|
323
323
|
},
|
|
324
324
|
async append(item) {
|
|
325
|
-
const { remoteId } = await aui.threadListItem
|
|
325
|
+
const { remoteId } = await aui.threadListItem.initialize();
|
|
326
326
|
await fetch(`/api/threads/${remoteId}/messages`, {
|
|
327
327
|
method: "POST",
|
|
328
328
|
body: JSON.stringify({
|
|
@@ -422,7 +422,7 @@ export const threadListAdapter: RemoteThreadListAdapter = {
|
|
|
422
422
|
async append() {},
|
|
423
423
|
withFormat: (fmt) => ({
|
|
424
424
|
async load() {
|
|
425
|
-
const { remoteId } = aui.threadListItem
|
|
425
|
+
const { remoteId } = aui.threadListItem.getState();
|
|
426
426
|
if (!remoteId) return { messages: [] };
|
|
427
427
|
const rows = await fetch(
|
|
428
428
|
`${API_URL}/threads/${remoteId}/messages`,
|
|
@@ -439,7 +439,7 @@ export const threadListAdapter: RemoteThreadListAdapter = {
|
|
|
439
439
|
};
|
|
440
440
|
},
|
|
441
441
|
async append(item) {
|
|
442
|
-
const { remoteId } = await aui.threadListItem
|
|
442
|
+
const { remoteId } = await aui.threadListItem.initialize();
|
|
443
443
|
await fetch(`${API_URL}/threads/${remoteId}/messages`, {
|
|
444
444
|
method: "POST",
|
|
445
445
|
body: JSON.stringify({
|
|
@@ -541,7 +541,7 @@ export const threadListAdapter: RemoteThreadListAdapter = {
|
|
|
541
541
|
async append() {},
|
|
542
542
|
withFormat: (fmt) => ({
|
|
543
543
|
async load() {
|
|
544
|
-
const { remoteId } = aui.threadListItem
|
|
544
|
+
const { remoteId } = aui.threadListItem.getState();
|
|
545
545
|
if (!remoteId) return { messages: [] };
|
|
546
546
|
const rows = await fetch(
|
|
547
547
|
`${API_URL}/threads/${remoteId}/messages`,
|
|
@@ -558,7 +558,7 @@ export const threadListAdapter: RemoteThreadListAdapter = {
|
|
|
558
558
|
};
|
|
559
559
|
},
|
|
560
560
|
async append(item) {
|
|
561
|
-
const { remoteId } = await aui.threadListItem
|
|
561
|
+
const { remoteId } = await aui.threadListItem.initialize();
|
|
562
562
|
await fetch(`${API_URL}/threads/${remoteId}/messages`, {
|
|
563
563
|
method: "POST",
|
|
564
564
|
body: JSON.stringify({
|
|
@@ -592,6 +592,32 @@ The top-level `load`/`append` on the history adapter are required by the type bu
|
|
|
592
592
|
</Step>
|
|
593
593
|
<Step>
|
|
594
594
|
|
|
595
|
+
### Support in-place updates (optional)
|
|
596
|
+
|
|
597
|
+
The optional `update(item, localMessageId)` method on the object returned from `withFormat` lets the runtime rewrite an already-persisted message in place. It receives the same `{ parentId, message }` item shape as `append`, plus the id of the row to rewrite.
|
|
598
|
+
|
|
599
|
+
The runtime calls `update` after a run for persisted messages whose content changed, to finalize assistant messages persisted early while waiting for tool call approval, and to refresh run timing metadata.
|
|
600
|
+
|
|
601
|
+
`update` is opt-in. When it is absent, messages paused for tool approval are not persisted until the run reaches a terminal status, so a page refresh during the pause loses the pending approval state. Implementing `update` enables early persistence.
|
|
602
|
+
|
|
603
|
+
```tsx title="runtime/thread-adapter.tsx"
|
|
604
|
+
async update(item, localMessageId) {
|
|
605
|
+
const { remoteId } = await aui.threadListItem.initialize();
|
|
606
|
+
await fetch(`${API_URL}/threads/${remoteId}/messages/${localMessageId}`, {
|
|
607
|
+
method: "PATCH",
|
|
608
|
+
body: JSON.stringify({
|
|
609
|
+
format: fmt.format,
|
|
610
|
+
content: fmt.encode(item),
|
|
611
|
+
}),
|
|
612
|
+
});
|
|
613
|
+
},
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
The backend needs a matching update route keyed by message id, mirroring the append route from the earlier step.
|
|
617
|
+
|
|
618
|
+
</Step>
|
|
619
|
+
<Step>
|
|
620
|
+
|
|
595
621
|
### Mount the runtime
|
|
596
622
|
|
|
597
623
|
Wrap the app in a `useRemoteThreadListRuntime` that delegates per-thread runtime to `useChatRuntime`:
|
|
@@ -694,7 +720,7 @@ Send a message in a fresh thread. Check the database:
|
|
|
694
720
|
|
|
695
721
|
- The `threads` table has a new row with the current `userId`.
|
|
696
722
|
- The `messages` table has at least two rows (user + assistant) for that thread.
|
|
697
|
-
- `format` matches what `fmt.format` wrote (`"ai-sdk/v6"`
|
|
723
|
+
- `format` matches what `fmt.format` wrote (`"ai-sdk/v6"`) and `content` is the encoded `UIMessage` (a `role` plus `parts`), not a placeholder blob. The format string names the stored `UIMessage` shape, not the installed AI SDK major; it stays `"ai-sdk/v6"` on AI SDK v7 and must never be renamed, or previously stored history stops matching.
|
|
698
724
|
- Reload the page; the thread list and the messages survive.
|
|
699
725
|
|
|
700
726
|
</Step>
|
|
@@ -702,9 +728,10 @@ Send a message in a fresh thread. Check the database:
|
|
|
702
728
|
|
|
703
729
|
## Notes
|
|
704
730
|
|
|
705
|
-
- **First-message race.** `append` may fire before the thread row exists. The `unstable_Provider` example above always awaits `aui.threadListItem
|
|
706
|
-
- **Reload after async auth.** If `auth()` resolves after the initial `list()` call, threads won't appear until the user refreshes. Call `aui.threads
|
|
731
|
+
- **First-message race.** `append` may fire before the thread row exists. The `unstable_Provider` example above always awaits `aui.threadListItem.initialize()` before writing; do the same in any custom implementation.
|
|
732
|
+
- **Reload after async auth.** If `auth()` resolves after the initial `list()` call, threads won't appear until the user refreshes. Call `aui.threads.reload()` from a `useEffect` watching the session. Pattern is documented in [threads](/docs/runtimes/concepts/threads#reloading-after-async-authentication).
|
|
707
733
|
- **Format string.** The `format` column is *not* a free-text label; it identifies the on-disk shape so multiple runtimes can coexist. Don't strip it. Don't make assumptions about its value (`useChatRuntime` is responsible for setting and decoding it).
|
|
734
|
+
- **Pending approvals need `update`.** Tool call approvals persist across reloads only when the formatted adapter implements `update`; omitting it keeps the pre-approval snapshot out of storage by design.
|
|
708
735
|
- **`unstable_Provider` synchronous-children rule.** The Provider must render `children` on first commit; do not gate them behind suspense, loading state, or `useEffect`. Load data inside an always-rendered child.
|
|
709
736
|
|
|
710
737
|
## Related
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Migration to v0.15
|
|
3
|
+
description: Drops the v0.12-era legacy runtime hooks, the deprecated tools map, and the "mcp-app" group key. Scope accessors become properties.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Version 0.15 finishes the deprecation cycle started in v0.12: the legacy context hooks are removed in favor of `useAui` / `useAuiState`, and `aui` scope accessors become properties.
|
|
7
|
+
|
|
8
|
+
## Migrate with an AI Agent
|
|
9
|
+
|
|
10
|
+
Paste this into an AI coding agent to run the migration for you:
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
Migrate this codebase from assistant-ui v0.14 to v0.15.
|
|
14
|
+
|
|
15
|
+
1. Read the migration guide: https://assistant-ui.com/docs/migrations/v0-15
|
|
16
|
+
2. Run `npx assistant-ui@latest upgrade` to apply the codemods.
|
|
17
|
+
3. Apply the remaining changes from the guide by hand:
|
|
18
|
+
- Replace removed legacy hooks with the useAui / useAuiState
|
|
19
|
+
equivalents from the guide's mapping table.
|
|
20
|
+
- Replace availability checks with `aui.<scope>.source != null`.
|
|
21
|
+
- Replace `s.tools.tools` reads with `s.tools.toolUIs`.
|
|
22
|
+
- Replace the "mcp-app" groupPartByType key with "standalone-tool-call".
|
|
23
|
+
4. Typecheck, build, and run tests; fix any remaining fallout.
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Automatic Migration
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx assistant-ui@latest upgrade
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This runs the `v0-15/aui-accessor-calls-to-properties` codemod, which rewrites nullary accessor calls (`aui.thread()`) to property access (`aui.thread`).
|
|
33
|
+
|
|
34
|
+
## Scope Accessors Are Properties
|
|
35
|
+
|
|
36
|
+
Nullary scope accessors are now properties. Calling them still works but is deprecated:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// Before
|
|
40
|
+
aui.thread().getState();
|
|
41
|
+
aui.threads().switchToNewThread();
|
|
42
|
+
|
|
43
|
+
// After
|
|
44
|
+
aui.thread.getState();
|
|
45
|
+
aui.threads.switchToNewThread();
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Selecting an unavailable scope no longer throws: `aui.thread` always succeeds and is always truthy. Its `source` is `null` when the scope is unavailable, and any other property read (or a call) throws. Check availability via:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
if (aui.thread.source != null) {
|
|
52
|
+
// scope is available
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Accessors expose `source`, `query`, and `name` selection metadata as properties — previously found on the accessor function, now on the same names on the proxy. These three names are reserved and never resolve to scope methods.
|
|
57
|
+
|
|
58
|
+
## Legacy Context Hooks Removed
|
|
59
|
+
|
|
60
|
+
The v0.12-era runtime hooks are removed. Replace state reads with `useAuiState` and actions with `useAui`:
|
|
61
|
+
|
|
62
|
+
| Removed | Replacement |
|
|
63
|
+
| ------------------------------------------------------------- | ----------------------------------------------- |
|
|
64
|
+
| `useAssistantRuntime()` | `useAui()` |
|
|
65
|
+
| `useThreadList(selector)` | `useAuiState((s) => s.threads)` |
|
|
66
|
+
| `useThreadRuntime()` | `useAui().thread` |
|
|
67
|
+
| `useThread(selector)` | `useAuiState((s) => s.thread)` |
|
|
68
|
+
| `useThreadComposer(selector)` | `useAuiState((s) => s.thread.composer)` |
|
|
69
|
+
| `useThreadModelContext(selector)` | `useAuiState((s) => s.thread.modelContext)` |
|
|
70
|
+
| `useMessageRuntime()` | `useAui().message` |
|
|
71
|
+
| `useMessage(selector)` | `useAuiState((s) => s.message)` |
|
|
72
|
+
| `useEditComposer(selector)` | `useAuiState((s) => s.message.composer)` |
|
|
73
|
+
| `useComposerRuntime()` | `useAui().composer` |
|
|
74
|
+
| `useComposer(selector)` | `useAuiState((s) => s.composer)` |
|
|
75
|
+
| `useMessagePartRuntime()` | `useAui().part` |
|
|
76
|
+
| `useMessagePart(selector)` | `useAuiState((s) => s.part)` |
|
|
77
|
+
| `useAttachmentRuntime()` | `useAui().attachment` |
|
|
78
|
+
| `useAttachment(selector)` | `useAuiState((s) => s.attachment)` |
|
|
79
|
+
| `useThreadListItemRuntime()` | `useAui().threadListItem` |
|
|
80
|
+
| `useThreadListItem(selector)` | `useAuiState((s) => s.threadListItem)` |
|
|
81
|
+
|
|
82
|
+
The attachment variants (`useThreadComposerAttachment(Runtime)`, `useEditComposerAttachment(Runtime)`, `useMessageAttachment(Runtime)`) are removed with them; use `useAui().attachment` / `useAuiState((s) => s.attachment)`.
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
// Before
|
|
86
|
+
const runtime = useAssistantRuntime();
|
|
87
|
+
const isRunning = useThread((s) => s.isRunning);
|
|
88
|
+
runtime.threads.switchToNewThread();
|
|
89
|
+
|
|
90
|
+
// After
|
|
91
|
+
const aui = useAui();
|
|
92
|
+
const isRunning = useAuiState((s) => s.thread.isRunning);
|
|
93
|
+
aui.threads.switchToNewThread();
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## `ToolsState.tools` Removed
|
|
97
|
+
|
|
98
|
+
The component-only tool-UI map is replaced by `toolUIs`, whose entries carry the renderer alongside its presentation options:
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
// Before
|
|
102
|
+
const Render = useAuiState((s) => s.tools.tools[toolName]?.[0]);
|
|
103
|
+
|
|
104
|
+
// After
|
|
105
|
+
const Render = useAuiState((s) => s.tools.toolUIs[toolName]?.[0]?.render);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## `"mcp-app"` Group Key Removed
|
|
109
|
+
|
|
110
|
+
`groupPartByType` no longer accepts the `"mcp-app"` key. Use `"standalone-tool-call"`, a superset that matches MCP-app tool calls plus any tool call whose registered UI opts into standalone display:
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
// Before
|
|
114
|
+
groupPartByType({
|
|
115
|
+
"tool-call": ["group-tool"],
|
|
116
|
+
"mcp-app": [],
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// After
|
|
120
|
+
groupPartByType({
|
|
121
|
+
"tool-call": ["group-tool"],
|
|
122
|
+
"standalone-tool-call": [],
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## `useAui` `{ parent }` Config Removed
|
|
127
|
+
|
|
128
|
+
The second argument (`useAui(clients, { parent })`) is removed. Provide the parent via context instead: wrap with `AuiProvider` and call the context form beneath it.
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
// Before
|
|
132
|
+
const aui = useAui(scopes, { parent });
|
|
133
|
+
|
|
134
|
+
// After
|
|
135
|
+
const Scoped = ({ children }) => {
|
|
136
|
+
const aui = useAui(scopes); // extends the AuiProvider parent
|
|
137
|
+
return <AuiProvider value={aui}>{children}</AuiProvider>;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
<AuiProvider value={parent}>
|
|
141
|
+
<Scoped />
|
|
142
|
+
</AuiProvider>;
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Where `{ parent: null }` was used to detach from context, `<AuiProvider value={null}>` now provides an isolated empty root (experimental).
|
|
146
|
+
|
|
147
|
+
## Still Deprecated (not removed)
|
|
148
|
+
|
|
149
|
+
- Primitive `If` components (`ThreadPrimitive.If`, `MessagePrimitive.If`, `ThreadPrimitive.Empty`) — replaced by `AuiIf`. The codemod migrates these.
|
|
150
|
+
- `useMessagePartText` / `useMessagePartReasoning` / `useMessagePartSource` / `useMessagePartImage` / `useMessagePartFile` / `useMessagePartData` — use `useAuiState` to select and narrow `s.part`.
|
|
151
|
+
- The `components` prop on primitives — replaced by the children render function pattern (see the [v0.14 guide](/docs/migrations/v0-14)).
|
|
152
|
+
|
|
153
|
+
## Getting Help
|
|
154
|
+
|
|
155
|
+
- File issues at https://github.com/assistant-ui/assistant-ui/issues
|
|
156
|
+
- See the [deprecation policy](/docs/migrations/deprecation-policy) for the support window
|
|
@@ -570,7 +570,7 @@ When `isSendDisabled` is `true`:
|
|
|
570
570
|
- `composer.canSend` becomes `false`
|
|
571
571
|
- `<ComposerPrimitive.Send>` is disabled
|
|
572
572
|
- Enter and the `Cmd/Ctrl+Shift+Enter` steer hotkey become no-ops
|
|
573
|
-
- `aui.composer
|
|
573
|
+
- `aui.composer.send()` short-circuits at the runtime, so direct calls cannot escape the gate
|
|
574
574
|
|
|
575
575
|
Read the same flag from React with `<AuiIf>` to render hints alongside the input:
|
|
576
576
|
|
|
@@ -253,7 +253,7 @@ Button that appends the next page of threads. Renders a `<button>` element unles
|
|
|
253
253
|
</ThreadListPrimitive.LoadMore>
|
|
254
254
|
```
|
|
255
255
|
|
|
256
|
-
For scroll-driven loading, wrap `aui.threads
|
|
256
|
+
For scroll-driven loading, wrap `aui.threads.loadMore()` in your own `IntersectionObserver` at the application layer; assistant-ui ships the explicit button to keep the primitive surface predictable.
|
|
257
257
|
|
|
258
258
|
```tsx
|
|
259
259
|
import { useAui, useAuiState } from "@assistant-ui/react";
|
|
@@ -271,7 +271,7 @@ function LoadMoreSentinel() {
|
|
|
271
271
|
const el = ref.current;
|
|
272
272
|
if (!el || disabled) return;
|
|
273
273
|
const observer = new IntersectionObserver(([entry]) => {
|
|
274
|
-
if (entry?.isIntersecting) aui.threads
|
|
274
|
+
if (entry?.isIntersecting) aui.threads.loadMore();
|
|
275
275
|
});
|
|
276
276
|
observer.observe(el);
|
|
277
277
|
return () => observer.disconnect();
|
|
@@ -41,11 +41,11 @@ import { useAui } from "@assistant-ui/react-native";
|
|
|
41
41
|
const aui = useAui();
|
|
42
42
|
|
|
43
43
|
// Composer actions
|
|
44
|
-
aui.composer
|
|
45
|
-
aui.composer
|
|
44
|
+
aui.composer.setText("Hello");
|
|
45
|
+
aui.composer.send();
|
|
46
46
|
|
|
47
47
|
// Thread actions
|
|
48
|
-
aui.thread
|
|
48
|
+
aui.thread.cancelRun();
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
### useAuiEvent
|
|
@@ -197,7 +197,7 @@ function Composer() {
|
|
|
197
197
|
>
|
|
198
198
|
<TextInput
|
|
199
199
|
value={text}
|
|
200
|
-
onChangeText={(t) => aui.composer
|
|
200
|
+
onChangeText={(t) => aui.composer.setText(t)}
|
|
201
201
|
placeholder="Message..."
|
|
202
202
|
multiline
|
|
203
203
|
style={{
|
|
@@ -211,7 +211,7 @@ function Composer() {
|
|
|
211
211
|
}}
|
|
212
212
|
/>
|
|
213
213
|
<Pressable
|
|
214
|
-
onPress={() => aui.composer
|
|
214
|
+
onPress={() => aui.composer.send()}
|
|
215
215
|
disabled={isEmpty}
|
|
216
216
|
style={{
|
|
217
217
|
marginLeft: 8,
|
|
@@ -31,7 +31,9 @@ Container `View` for the thread area.
|
|
|
31
31
|
|
|
32
32
|
### ThreadPrimitive.Messages
|
|
33
33
|
|
|
34
|
-
`FlatList`-based message list
|
|
34
|
+
Deprecated `FlatList`-based message list kept for backwards compatibility. It uses `ThreadPrimitive.MessagesFlatList` internally, but keeps the previous no-auto-scroll default so existing apps with custom scroll handling do not change behavior on upgrade.
|
|
35
|
+
|
|
36
|
+
Use `ThreadPrimitive.MessagesFlatList` for new React Native threads.
|
|
35
37
|
|
|
36
38
|
```tsx
|
|
37
39
|
<ThreadPrimitive.Messages>
|
|
@@ -53,7 +55,29 @@ You can also provide role-specific components:
|
|
|
53
55
|
| Prop | Type | Description |
|
|
54
56
|
|------|------|-------------|
|
|
55
57
|
| `components` | `MessageComponents` | Component map — provide either a `Message` component (used for all roles) or role-specific `UserMessage`, `AssistantMessage`, and optionally `SystemMessage`. Edit composers can be set via `EditComposer` or role-specific variants (`UserEditComposer`, `AssistantEditComposer`, `SystemEditComposer`). |
|
|
56
|
-
| `...rest` | `
|
|
58
|
+
| `...rest` | `ThreadPrimitive.MessagesFlatList` props | Same props as `ThreadPrimitive.MessagesFlatList`, with the auto-scroll options defaulting to `false` on this deprecated wrapper |
|
|
59
|
+
|
|
60
|
+
### ThreadPrimitive.MessagesFlatList
|
|
61
|
+
|
|
62
|
+
Canonical React Native message viewport backed by `FlatList`. It scopes each row to its message, forwards refs to the underlying `FlatList`, and handles scroll-to-bottom behavior for common chat flows.
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
<ThreadPrimitive.MessagesFlatList autoScroll>
|
|
66
|
+
{() => <MyMessage />}
|
|
67
|
+
</ThreadPrimitive.MessagesFlatList>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
| Prop | Type | Description |
|
|
71
|
+
|------|------|-------------|
|
|
72
|
+
| `children` | `({ message }) => ReactNode` | Render function for each message |
|
|
73
|
+
| `components` | `MessageComponents` | Component map alternative to `children` |
|
|
74
|
+
| `autoScroll` | `boolean` | Automatically keeps the list at the bottom while it is already near the bottom. Defaults to `true` |
|
|
75
|
+
| `scrollToBottomOnRunStart` | `boolean` | Scrolls to the bottom when a run starts. Defaults to `true` |
|
|
76
|
+
| `scrollToBottomOnInitialize` | `boolean` | Scrolls to the bottom when messages first appear. Defaults to `true` |
|
|
77
|
+
| `scrollToBottomOnThreadSwitch` | `boolean` | Scrolls to the bottom when switching threads. Defaults to `true` |
|
|
78
|
+
| `...rest` | `FlatListProps` | Standard FlatList props, except `data`, `renderItem`, and `children` |
|
|
79
|
+
|
|
80
|
+
The built-in auto-scroll behavior assumes the default, non-inverted `FlatList` direction.
|
|
57
81
|
|
|
58
82
|
### ThreadPrimitive.MessageByIndex
|
|
59
83
|
|
|
@@ -541,10 +565,20 @@ import { ActionBarPrimitive } from "@assistant-ui/react-native";
|
|
|
541
565
|
|
|
542
566
|
### ActionBarPrimitive.Copy
|
|
543
567
|
|
|
544
|
-
`Pressable` that copies the message content. Supports function-as-children for copy state feedback.
|
|
568
|
+
`Pressable` that copies the message content. Pass a platform clipboard writer through `copyToClipboard`. Supports function-as-children for copy state feedback.
|
|
545
569
|
|
|
546
570
|
```tsx
|
|
547
|
-
|
|
571
|
+
import * as Clipboard from "expo-clipboard";
|
|
572
|
+
|
|
573
|
+
const copyToClipboard = async (text: string) => {
|
|
574
|
+
const didCopy = await Clipboard.setStringAsync(text);
|
|
575
|
+
if (!didCopy) throw new Error("Clipboard write failed");
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
<ActionBarPrimitive.Copy
|
|
579
|
+
copiedDuration={3000}
|
|
580
|
+
copyToClipboard={copyToClipboard}
|
|
581
|
+
>
|
|
548
582
|
{({ isCopied }) => <Text>{isCopied ? "Copied!" : "Copy"}</Text>}
|
|
549
583
|
</ActionBarPrimitive.Copy>
|
|
550
584
|
```
|
|
@@ -552,7 +586,7 @@ import { ActionBarPrimitive } from "@assistant-ui/react-native";
|
|
|
552
586
|
| Prop | Type | Description |
|
|
553
587
|
|------|------|-------------|
|
|
554
588
|
| `copiedDuration` | `number` | Duration in ms to show "copied" state (default: 3000) |
|
|
555
|
-
| `copyToClipboard` | `(text: string) => void
|
|
589
|
+
| `copyToClipboard` | `(text: string) => void \| Promise<void>` | Platform clipboard writer |
|
|
556
590
|
|
|
557
591
|
### ActionBarPrimitive.Edit
|
|
558
592
|
|
|
@@ -11,9 +11,9 @@ import { VercelIcon } from "@/components/icons/vercel";
|
|
|
11
11
|
|
|
12
12
|
| AI SDK | Runtime package | Docs |
|
|
13
13
|
| --- | --- | --- |
|
|
14
|
-
| `ai@^7` + `@ai-sdk/react@^4` | `@assistant-ui/react-ai-sdk` (latest) | [v7 (current)](/docs/runtimes/ai-sdk/v7) |
|
|
15
|
-
| `ai@^6` + `@ai-sdk/react@^3` | `@assistant-ui/react-ai-sdk@1.
|
|
16
|
-
| `ai@^5` + `@ai-sdk/react@^2` | `@assistant-ui/react-ai-sdk@
|
|
14
|
+
| `ai@^7` + `@ai-sdk/react@^4` | `@assistant-ui/react-ai-sdk@^1.4` (latest) | [v7 (current)](/docs/runtimes/ai-sdk/v7) |
|
|
15
|
+
| `ai@^6` + `@ai-sdk/react@^3` | `@assistant-ui/react-ai-sdk@1.3.40` | [v6 (legacy)](/docs/runtimes/ai-sdk/v6-legacy) |
|
|
16
|
+
| `ai@^5` + `@ai-sdk/react@^2` | `@assistant-ui/react-ai-sdk@1.1.21` | [v5 (legacy)](/docs/runtimes/ai-sdk/v5-legacy) |
|
|
17
17
|
| `ai@^4` | `@assistant-ui/react-data-stream` | [v4 (legacy)](/docs/runtimes/ai-sdk/v4-legacy) |
|
|
18
18
|
|
|
19
19
|
New projects should target v7. v6, v5, and v4 are documented for projects that have not migrated yet; all have known compatibility gaps and receive no new features.
|
|
@@ -11,9 +11,9 @@ AI SDK v4 is a legacy version. New projects should use [AI SDK v7](/docs/runtime
|
|
|
11
11
|
|
|
12
12
|
## Why legacy
|
|
13
13
|
|
|
14
|
-
Vercel ships AI SDK majors roughly yearly; v4 is
|
|
14
|
+
Vercel ships AI SDK majors roughly yearly; v4 is three majors behind v7. The current `@assistant-ui/react-ai-sdk` package targets the current AI SDK major (v7) exclusively, so v4 users plug into [`@assistant-ui/react-data-stream`](/docs/runtimes/custom/data-stream) instead — the same data stream protocol that v4's `toDataStreamResponse()` emits.
|
|
15
15
|
|
|
16
|
-
This page is reference for existing v4 projects. Plan to migrate to
|
|
16
|
+
This page is reference for existing v4 projects. Plan to migrate to v7 when feasible.
|
|
17
17
|
|
|
18
18
|
## Setup
|
|
19
19
|
|
|
@@ -95,9 +95,9 @@ When you are ready to upgrade:
|
|
|
95
95
|
|
|
96
96
|
AI SDK provides codemods at [ai-sdk.dev/docs/migration-guides](https://ai-sdk.dev/docs/migration-guides) that handle the package-side rewrites.
|
|
97
97
|
|
|
98
|
-
## Alternative: react-ai-sdk@0.
|
|
98
|
+
## Alternative: react-ai-sdk@0.10.16
|
|
99
99
|
|
|
100
|
-
An older release line of `@assistant-ui/react-ai-sdk`
|
|
100
|
+
An older release line of `@assistant-ui/react-ai-sdk` supported AI SDK v4 directly; its last release was `0.10.16`. It is no longer maintained and has no upgrade path; if you are starting a new v4 project, use `@assistant-ui/react-data-stream` instead.
|
|
101
101
|
|
|
102
102
|
## Related
|
|
103
103
|
|
|
@@ -6,12 +6,12 @@ description: Reference for projects still on AI SDK v5. New projects should use
|
|
|
6
6
|
import { VercelIcon } from "@/components/icons/vercel";
|
|
7
7
|
|
|
8
8
|
<Callout type="warn">
|
|
9
|
-
AI SDK v5 is a legacy version. New projects should use [AI SDK v7](/docs/runtimes/ai-sdk/v7). v5 users
|
|
9
|
+
AI SDK v5 is a legacy version. New projects should use [AI SDK v7](/docs/runtimes/ai-sdk/v7). v5 users pin `@assistant-ui/react-ai-sdk@1.1.21` (the last v5-compatible release); later releases target newer AI SDK majors.
|
|
10
10
|
</Callout>
|
|
11
11
|
|
|
12
12
|
## Why legacy
|
|
13
13
|
|
|
14
|
-
AI SDK v6 introduced major API changes: async `convertToModelMessages`, a new tool schema, and `toUIMessageStreamResponse()`. v5 still works but no longer receives new features in `@assistant-ui/react-ai-sdk`. Pinning to
|
|
14
|
+
AI SDK v6 introduced major API changes: async `convertToModelMessages`, a new tool schema, and `toUIMessageStreamResponse()`. v5 still works but no longer receives new features in `@assistant-ui/react-ai-sdk`. Pinning to `1.1.21` keeps you on the v5-compatible surface.
|
|
15
15
|
|
|
16
16
|
This page is reference for existing v5 projects. Plan to migrate to v7 when feasible.
|
|
17
17
|
|
|
@@ -22,7 +22,7 @@ This page is reference for existing v5 projects. Plan to migrate to v7 when feas
|
|
|
22
22
|
|
|
23
23
|
### Install v5-compatible versions
|
|
24
24
|
|
|
25
|
-
<InstallCommand npm={["@assistant-ui/react", "@assistant-ui/react-ai-sdk@
|
|
25
|
+
<InstallCommand npm={["@assistant-ui/react", "@assistant-ui/react-ai-sdk@1.1.21", "ai@^5", "@ai-sdk/openai@^1", "zod"]} />
|
|
26
26
|
|
|
27
27
|
</Step>
|
|
28
28
|
<Step>
|
|
@@ -98,7 +98,7 @@ const runtime = useVercelUseChatRuntime(chat);
|
|
|
98
98
|
| Feature | v5 | v6 |
|
|
99
99
|
| --- | --- | --- |
|
|
100
100
|
| `ai` package | `ai@^5` | `ai@^6` |
|
|
101
|
-
| `@assistant-ui/react-ai-sdk` | `@
|
|
101
|
+
| `@assistant-ui/react-ai-sdk` | `@1.1.21` | `@1.3.40` |
|
|
102
102
|
| `@ai-sdk/openai` | `^1` | `^3` |
|
|
103
103
|
| Message type | `Message` | `UIMessage` |
|
|
104
104
|
| `convertToModelMessages` | Sync | Async (`await`) |
|
|
@@ -4,7 +4,7 @@ description: Reference for projects still on AI SDK v6. New projects should use
|
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
<Callout type="warn">
|
|
7
|
-
AI SDK v6 is a legacy version. New projects should use [AI SDK v7](/docs/runtimes/ai-sdk/v7). v6 users
|
|
7
|
+
AI SDK v6 is a legacy version. New projects should use [AI SDK v7](/docs/runtimes/ai-sdk/v7). v6 users pin `@assistant-ui/react-ai-sdk@1.3.40` (the last v6-compatible release); later releases target v7.
|
|
8
8
|
</Callout>
|
|
9
9
|
|
|
10
10
|
Requires `ai@^6` and `@ai-sdk/react@^3`. For other versions see the [overview](/docs/runtimes/ai-sdk/overview).
|
|
@@ -52,17 +52,17 @@ npm init -y
|
|
|
52
52
|
<PlatformTabs>
|
|
53
53
|
<Tab value="React">
|
|
54
54
|
|
|
55
|
-
<InstallCommand npm={["@assistant-ui/react", "@assistant-ui/react-ai-sdk", "ai@^6", "@ai-sdk/react@^3", "@ai-sdk/openai", "zod"]} />
|
|
55
|
+
<InstallCommand npm={["@assistant-ui/react", "@assistant-ui/react-ai-sdk@1.3.40", "ai@^6", "@ai-sdk/react@^3", "@ai-sdk/openai", "zod"]} />
|
|
56
56
|
|
|
57
57
|
</Tab>
|
|
58
58
|
<Tab value="React Native">
|
|
59
59
|
|
|
60
|
-
<InstallCommand expo={["@assistant-ui/react-native", "@assistant-ui/react-ai-sdk", "ai@^6", "@ai-sdk/react@^3", "@ai-sdk/openai", "zod"]} />
|
|
60
|
+
<InstallCommand expo={["@assistant-ui/react-native", "@assistant-ui/react-ai-sdk@1.3.40", "ai@^6", "@ai-sdk/react@^3", "@ai-sdk/openai", "zod"]} />
|
|
61
61
|
|
|
62
62
|
</Tab>
|
|
63
63
|
<Tab value="React Ink">
|
|
64
64
|
|
|
65
|
-
<InstallCommand npm={["@assistant-ui/react-ink", "@assistant-ui/react-ai-sdk", "ai@^6", "@ai-sdk/react@^3", "@ai-sdk/openai", "zod", "ink", "react"]} />
|
|
65
|
+
<InstallCommand npm={["@assistant-ui/react-ink", "@assistant-ui/react-ai-sdk@1.3.40", "ai@^6", "@ai-sdk/react@^3", "@ai-sdk/openai", "zod", "ink", "react"]} />
|
|
66
66
|
|
|
67
67
|
</Tab>
|
|
68
68
|
</PlatformTabs>
|
|
@@ -3,7 +3,7 @@ title: AI SDK v7
|
|
|
3
3
|
description: Integrate Vercel AI SDK v7 with assistant-ui for streaming chat.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Current-version integration. Requires `ai@^7` and `@ai-sdk/react@^4`. For older versions see the [overview](/docs/runtimes/ai-sdk).
|
|
6
|
+
Current-version integration. Requires `ai@^7` and `@ai-sdk/react@^4`. For older versions see the [overview](/docs/runtimes/ai-sdk/overview).
|
|
7
7
|
|
|
8
8
|
## Quickstart
|
|
9
9
|
|
|
@@ -601,7 +601,7 @@ Beyond transports and adapters, `useChatRuntime` accepts options that control th
|
|
|
601
601
|
|
|
602
602
|
### onThreadIdChange
|
|
603
603
|
|
|
604
|
-
Called whenever the active thread's settled ID
|
|
604
|
+
Called whenever the runtime changes the active thread's settled ID, e.g. to sync the active thread to a URL query param. Changes supplied through the controlled `threadId` option are not echoed back through this callback.
|
|
605
605
|
|
|
606
606
|
```tsx
|
|
607
607
|
const runtime = useChatRuntime({
|
|
@@ -149,7 +149,7 @@ const adapterWithHistory: RemoteThreadListAdapter = {
|
|
|
149
149
|
const history = useMemo<ThreadHistoryAdapter>(
|
|
150
150
|
() => ({
|
|
151
151
|
async load() {
|
|
152
|
-
const { remoteId } = aui.threadListItem
|
|
152
|
+
const { remoteId } = aui.threadListItem.getState();
|
|
153
153
|
if (!remoteId) return { messages: [] };
|
|
154
154
|
const rows = await fetch(
|
|
155
155
|
`/api/threads/${remoteId}/messages`,
|
|
@@ -157,7 +157,7 @@ const adapterWithHistory: RemoteThreadListAdapter = {
|
|
|
157
157
|
return { messages: rows.map(toThreadMessage) };
|
|
158
158
|
},
|
|
159
159
|
async append({ message, parentId }) {
|
|
160
|
-
const { remoteId } = await aui.threadListItem
|
|
160
|
+
const { remoteId } = await aui.threadListItem.initialize();
|
|
161
161
|
await fetch(`/api/threads/${remoteId}/messages`, {
|
|
162
162
|
method: "POST",
|
|
163
163
|
body: JSON.stringify({ message, parentId }),
|
|
@@ -181,11 +181,11 @@ const adapterWithHistory: RemoteThreadListAdapter = {
|
|
|
181
181
|
|
|
182
182
|
### Avoiding the first-message race
|
|
183
183
|
|
|
184
|
-
`append` may be called before the thread record exists in your backend. Always await `aui.threadListItem
|
|
184
|
+
`append` may be called before the thread record exists in your backend. Always await `aui.threadListItem.initialize()` before writing:
|
|
185
185
|
|
|
186
186
|
```ts
|
|
187
187
|
async append({ message, parentId }) {
|
|
188
|
-
const { remoteId } = await aui.threadListItem
|
|
188
|
+
const { remoteId } = await aui.threadListItem.initialize();
|
|
189
189
|
await saveMessage(remoteId, parentId, message);
|
|
190
190
|
}
|
|
191
191
|
```
|
|
@@ -194,14 +194,14 @@ async append({ message, parentId }) {
|
|
|
194
194
|
|
|
195
195
|
### Reloading after async authentication
|
|
196
196
|
|
|
197
|
-
If your adapter depends on a user that resolves asynchronously (oidc, `next-auth`, `better-auth`), the initial `list()` may run before the user is available. Call `aui.threads
|
|
197
|
+
If your adapter depends on a user that resolves asynchronously (oidc, `next-auth`, `better-auth`), the initial `list()` may run before the user is available. Call `aui.threads.reload()` after auth completes:
|
|
198
198
|
|
|
199
199
|
```tsx
|
|
200
200
|
function ReloadOnAuth() {
|
|
201
201
|
const aui = useAui();
|
|
202
202
|
const { isLoading, user } = useAuth();
|
|
203
203
|
useEffect(() => {
|
|
204
|
-
if (!isLoading && user) aui.threads
|
|
204
|
+
if (!isLoading && user) aui.threads.reload();
|
|
205
205
|
}, [isLoading, user?.id]);
|
|
206
206
|
return null;
|
|
207
207
|
}
|
|
@@ -211,7 +211,7 @@ function ReloadOnAuth() {
|
|
|
211
211
|
|
|
212
212
|
### Paginating the thread list
|
|
213
213
|
|
|
214
|
-
If your backend returns thread pages, return a `nextCursor` from `list()` and consume `aui.threads
|
|
214
|
+
If your backend returns thread pages, return a `nextCursor` from `list()` and consume `aui.threads.hasMore` plus `aui.threads.loadMore()` in the UI. The runtime threads `params.after` back through `list()` on every `loadMore()`; the initial call passes no `params`, so treat a missing `after` as "first page". `reload()` resets the cursor so the next load starts from page 1 again.
|
|
215
215
|
|
|
216
216
|
```ts title="threadListAdapter.ts (excerpt)"
|
|
217
217
|
async list({ after } = {}) {
|
|
@@ -271,7 +271,7 @@ A few invariants worth knowing when wiring a custom UI on top of `loadMore()`:
|
|
|
271
271
|
name: "list",
|
|
272
272
|
type: "(params?: { after?: string }) => Promise<{ threads: RemoteThreadMetadata[]; nextCursor?: string }>",
|
|
273
273
|
description:
|
|
274
|
-
"Hydrate threads on mount. Each thread must include status and remoteId; title, externalId, and custom are optional. Return a `nextCursor` to enable `aui.threads
|
|
274
|
+
"Hydrate threads on mount. Each thread must include status and remoteId; title, externalId, and custom are optional. Return a `nextCursor` to enable `aui.threads.loadMore()`; the runtime will pass it back as `params.after` on the next call.",
|
|
275
275
|
required: true,
|
|
276
276
|
},
|
|
277
277
|
{
|
|
@@ -291,7 +291,7 @@ A few invariants worth knowing when wiring a custom UI on top of `loadMore()`:
|
|
|
291
291
|
name: "updateCustom",
|
|
292
292
|
type: "(remoteId: string, custom: Record<string, unknown> | undefined) => Promise<void>",
|
|
293
293
|
description:
|
|
294
|
-
"Optional. Persist replacement custom metadata from `aui.threadListItem
|
|
294
|
+
"Optional. Persist replacement custom metadata from `aui.threadListItem.updateCustom(custom)`.",
|
|
295
295
|
},
|
|
296
296
|
{
|
|
297
297
|
name: "archive",
|
|
@@ -361,7 +361,7 @@ function ThreadListItemMeta() {
|
|
|
361
361
|
}
|
|
362
362
|
```
|
|
363
363
|
|
|
364
|
-
`custom` is preserved across `rename`, `archive`, `unarchive`, and `generateTitle`. To replace it from your UI, implement `RemoteThreadListAdapter.updateCustom` and call `aui.threadListItem
|
|
364
|
+
`custom` is preserved across `rename`, `archive`, `unarchive`, and `generateTitle`. To replace it from your UI, implement `RemoteThreadListAdapter.updateCustom` and call `aui.threadListItem.updateCustom(custom)`. The cloud adapter persists this through `cloud.threads.update(threadId, { metadata })`. If your adapter mutates thread metadata through a separate application path, return the updated values from `fetch()` or call `aui.threads.reload()` to re-run `list()`.
|
|
365
365
|
|
|
366
366
|
## ExternalStoreThreadListAdapter
|
|
367
367
|
|
|
@@ -536,8 +536,8 @@ function useResumeOnMount(threadId: string) {
|
|
|
536
536
|
r.json(),
|
|
537
537
|
);
|
|
538
538
|
if (status.isRunning) {
|
|
539
|
-
const parentId = aui.thread
|
|
540
|
-
aui.thread
|
|
539
|
+
const parentId = aui.thread.getState().messages.at(-1)?.id ?? null;
|
|
540
|
+
aui.thread.resumeRun({ parentId });
|
|
541
541
|
}
|
|
542
542
|
})();
|
|
543
543
|
}, [aui, threadId]);
|
|
@@ -741,7 +741,7 @@ useExternalStoreRuntime({
|
|
|
741
741
|
name: "isSendDisabled",
|
|
742
742
|
type: "boolean",
|
|
743
743
|
description:
|
|
744
|
-
"Blocks new-message sending while leaving the input usable. When true, the thread composer's canSend becomes false, the Send button is disabled, Enter and the steer hotkey are no-ops, and aui.composer
|
|
744
|
+
"Blocks new-message sending while leaving the input usable. When true, the thread composer's canSend becomes false, the Send button is disabled, Enter and the steer hotkey are no-ops, and aui.composer.send() short-circuits. Edit composers (saving message edits) ignore this flag. Use this to gate sending on external React state (e.g. while tools or auth are still loading).",
|
|
745
745
|
default: "false",
|
|
746
746
|
},
|
|
747
747
|
{
|