@assistant-ui/mcp-docs-server 0.1.22 → 0.1.23

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 (74) hide show
  1. package/.docs/organized/code-examples/waterfall.md +801 -0
  2. package/.docs/organized/code-examples/with-ag-ui.md +38 -26
  3. package/.docs/organized/code-examples/with-ai-sdk-v6.md +38 -28
  4. package/.docs/organized/code-examples/with-artifacts.md +467 -0
  5. package/.docs/organized/code-examples/with-assistant-transport.md +31 -24
  6. package/.docs/organized/code-examples/with-chain-of-thought.md +41 -32
  7. package/.docs/organized/code-examples/with-cloud-standalone.md +675 -0
  8. package/.docs/organized/code-examples/with-cloud.md +34 -27
  9. package/.docs/organized/code-examples/with-custom-thread-list.md +34 -27
  10. package/.docs/organized/code-examples/with-elevenlabs-scribe.md +41 -30
  11. package/.docs/organized/code-examples/with-expo.md +2031 -0
  12. package/.docs/organized/code-examples/with-external-store.md +32 -25
  13. package/.docs/organized/code-examples/with-ffmpeg.md +31 -27
  14. package/.docs/organized/code-examples/with-langgraph.md +96 -38
  15. package/.docs/organized/code-examples/with-parent-id-grouping.md +32 -25
  16. package/.docs/organized/code-examples/with-react-hook-form.md +63 -58
  17. package/.docs/organized/code-examples/with-react-router.md +38 -30
  18. package/.docs/organized/code-examples/with-store.md +16 -24
  19. package/.docs/organized/code-examples/with-tanstack.md +36 -26
  20. package/.docs/organized/code-examples/with-tap-runtime.md +10 -24
  21. package/.docs/raw/docs/(docs)/cli.mdx +13 -6
  22. package/.docs/raw/docs/(docs)/guides/attachments.mdx +26 -3
  23. package/.docs/raw/docs/(docs)/guides/chain-of-thought.mdx +5 -5
  24. package/.docs/raw/docs/(docs)/guides/context-api.mdx +53 -52
  25. package/.docs/raw/docs/(docs)/guides/dictation.mdx +0 -2
  26. package/.docs/raw/docs/(docs)/guides/message-timing.mdx +169 -0
  27. package/.docs/raw/docs/(docs)/guides/quoting.mdx +327 -0
  28. package/.docs/raw/docs/(docs)/guides/speech.mdx +0 -1
  29. package/.docs/raw/docs/(docs)/index.mdx +12 -2
  30. package/.docs/raw/docs/(docs)/installation.mdx +8 -2
  31. package/.docs/raw/docs/(docs)/llm.mdx +9 -7
  32. package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar-more.mdx +1 -1
  33. package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar.mdx +2 -2
  34. package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +27 -27
  35. package/.docs/raw/docs/(reference)/api-reference/primitives/composer.mdx +60 -0
  36. package/.docs/raw/docs/(reference)/api-reference/primitives/message-part.mdx +78 -4
  37. package/.docs/raw/docs/(reference)/api-reference/primitives/message.mdx +32 -0
  38. package/.docs/raw/docs/(reference)/api-reference/primitives/selection-toolbar.mdx +61 -0
  39. package/.docs/raw/docs/(reference)/api-reference/primitives/thread.mdx +1 -1
  40. package/.docs/raw/docs/(reference)/legacy/styled/assistant-modal.mdx +1 -6
  41. package/.docs/raw/docs/(reference)/legacy/styled/decomposition.mdx +2 -2
  42. package/.docs/raw/docs/(reference)/legacy/styled/markdown.mdx +1 -6
  43. package/.docs/raw/docs/(reference)/legacy/styled/thread.mdx +1 -5
  44. package/.docs/raw/docs/(reference)/migrations/v0-12.mdx +17 -17
  45. package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +205 -0
  46. package/.docs/raw/docs/cloud/ai-sdk.mdx +292 -0
  47. package/.docs/raw/docs/cloud/authorization.mdx +178 -79
  48. package/.docs/raw/docs/cloud/{persistence/langgraph.mdx → langgraph.mdx} +2 -2
  49. package/.docs/raw/docs/cloud/overview.mdx +29 -39
  50. package/.docs/raw/docs/react-native/adapters.mdx +118 -0
  51. package/.docs/raw/docs/react-native/custom-backend.mdx +210 -0
  52. package/.docs/raw/docs/react-native/hooks.mdx +364 -0
  53. package/.docs/raw/docs/react-native/index.mdx +332 -0
  54. package/.docs/raw/docs/react-native/primitives.mdx +653 -0
  55. package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +7 -15
  56. package/.docs/raw/docs/runtimes/assistant-transport.mdx +103 -0
  57. package/.docs/raw/docs/runtimes/custom/external-store.mdx +25 -2
  58. package/.docs/raw/docs/runtimes/data-stream.mdx +1 -3
  59. package/.docs/raw/docs/runtimes/langgraph/index.mdx +113 -9
  60. package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +1 -4
  61. package/.docs/raw/docs/ui/attachment.mdx +4 -2
  62. package/.docs/raw/docs/ui/message-timing.mdx +92 -0
  63. package/.docs/raw/docs/ui/part-grouping.mdx +1 -1
  64. package/.docs/raw/docs/ui/reasoning.mdx +4 -4
  65. package/.docs/raw/docs/ui/scrollbar.mdx +2 -2
  66. package/.docs/raw/docs/ui/syntax-highlighting.mdx +55 -50
  67. package/.docs/raw/docs/ui/thread.mdx +16 -9
  68. package/dist/index.d.ts +1 -1
  69. package/dist/index.d.ts.map +1 -1
  70. package/package.json +3 -3
  71. package/src/tools/tests/integration.test.ts +2 -2
  72. package/src/tools/tests/json-parsing.test.ts +1 -1
  73. package/src/tools/tests/mcp-protocol.test.ts +1 -3
  74. package/.docs/raw/docs/cloud/persistence/ai-sdk.mdx +0 -108
@@ -11,7 +11,7 @@ import {
11
11
  } from "@/generated/typeDocs";
12
12
 
13
13
  Each message can have any number of message parts.
14
- Message parts are usually one of text, reasoning, audio or tool-call.
14
+ Message parts are usually one of text, reasoning, audio, tool-call, or data.
15
15
 
16
16
  ## Message part Types
17
17
 
@@ -31,6 +31,12 @@ Audio content that can be played back.
31
31
 
32
32
  Interactive elements that represent tool operations.
33
33
 
34
+ ### Data
35
+
36
+ Custom data events that can be rendered as UI at their position in the message stream. Each data part has a `name` and a `data` payload.
37
+
38
+ You can use either the explicit format `{ type: "data", name: "workflow", data: {...} }` or the shorthand `data-*` prefixed format `{ type: "data-workflow", data: {...} }`. The prefixed format is automatically converted to a `DataMessagePart` (stripping the `data-` prefix as the `name`). Unknown message part types that don't match any built-in type are silently skipped with a console warning.
39
+
34
40
  ## Anatomy
35
41
 
36
42
  ```tsx
@@ -46,7 +52,7 @@ const TextMessagePart = () => {
46
52
  ### Plain Text
47
53
 
48
54
  ```tsx
49
- import { MessagePartPrimitive } from "@assistant/react";
55
+ import { MessagePartPrimitive } from "@assistant-ui/react";
50
56
 
51
57
  <MessagePartPrimitive.Text />;
52
58
  ```
@@ -70,7 +76,7 @@ Coming soon.
70
76
  Renders children only if the message part is in progress.
71
77
 
72
78
  ```tsx
73
- import { MessagePartPrimitive } from "@assistant/react";
79
+ import { MessagePartPrimitive } from "@assistant-ui/react";
74
80
 
75
81
  <MessagePartPrimitive.InProgress>
76
82
  <LoadingIndicator />
@@ -101,6 +107,68 @@ const MyWeatherToolUI = makeAssistantToolUI({
101
107
  });
102
108
  ```
103
109
 
110
+ ### Data UI
111
+
112
+ You can map data events to UI components, similar to tool UIs. There are two approaches:
113
+
114
+ #### Inline configuration
115
+
116
+ Pass a `data` config to `MessagePrimitive.Parts`:
117
+
118
+ ```tsx
119
+ <MessagePrimitive.Parts
120
+ components={{
121
+ data: {
122
+ by_name: {
123
+ my_chart: ({ name, data }) => <ChartComponent data={data} />,
124
+ },
125
+ Fallback: ({ name, data }) => (
126
+ <pre>{JSON.stringify(data, null, 2)}</pre>
127
+ ),
128
+ },
129
+ }}
130
+ />
131
+ ```
132
+
133
+ #### Global registration
134
+
135
+ Use `makeAssistantDataUI` or `useAssistantDataUI` to register data UIs globally. Global registrations take priority over inline configuration.
136
+
137
+ ```tsx
138
+ import { makeAssistantDataUI } from "@assistant-ui/react";
139
+
140
+ const MyChartUI = makeAssistantDataUI({
141
+ name: "my_chart",
142
+ render: ({ name, data }) => <ChartComponent data={data} />,
143
+ });
144
+
145
+ // Place inside AssistantRuntimeProvider
146
+ function App() {
147
+ return (
148
+ <AssistantRuntimeProvider runtime={runtime}>
149
+ <Thread />
150
+ <MyChartUI />
151
+ </AssistantRuntimeProvider>
152
+ );
153
+ }
154
+ ```
155
+
156
+ The hook variant allows access to component state:
157
+
158
+ ```tsx
159
+ import { useAssistantDataUI } from "@assistant-ui/react";
160
+
161
+ function MyComponent() {
162
+ useAssistantDataUI({
163
+ name: "my_chart",
164
+ render: ({ name, data }) => <ChartComponent data={data} />,
165
+ });
166
+ return null;
167
+ }
168
+ ```
169
+
170
+ Each data component receives the full data part as props: `{ type: "data", name: string, data: T, status: MessagePartStatus }`.
171
+
104
172
  ## Context Provider
105
173
 
106
174
  Message part context is provided by `MessagePrimitive.Parts` or `TextMessagePartProvider`
@@ -108,7 +176,7 @@ Message part context is provided by `MessagePrimitive.Parts` or `TextMessagePart
108
176
  ### MessagePrimitive.Parts
109
177
 
110
178
  ```tsx
111
- import { MessagePrimitive } from "@assistant/react";
179
+ import { MessagePrimitive } from "@assistant-ui/react";
112
180
 
113
181
  <MessagePrimitive.Parts
114
182
  components={{
@@ -121,6 +189,12 @@ import { MessagePrimitive } from "@assistant/react";
121
189
  },
122
190
  Fallback: MyFallbackToolUI,
123
191
  },
192
+ data: {
193
+ by_name: {
194
+ my_chart: MyChartComponent,
195
+ },
196
+ Fallback: GenericDataComponent,
197
+ },
124
198
  }}
125
199
  />;
126
200
  ```
@@ -259,6 +259,38 @@ Renders a single attachment at the specified index within the message.
259
259
  ]}
260
260
  />
261
261
 
262
+ ### useMessageQuote()
263
+
264
+ A hook that returns the quote info attached to the current message, if any. Reads from `message.metadata.custom.quote`.
265
+
266
+ ```tsx
267
+ import { useMessageQuote } from "@assistant-ui/react";
268
+
269
+ const QuoteBlock = () => {
270
+ const quote = useMessageQuote();
271
+ if (!quote) return null;
272
+
273
+ return (
274
+ <div className="mb-2 flex items-start gap-1.5 text-sm italic text-muted-foreground">
275
+ {quote.text}
276
+ </div>
277
+ );
278
+ };
279
+ ```
280
+
281
+ **Returns:** `QuoteInfo | undefined`
282
+
283
+ ```typescript
284
+ type QuoteInfo = {
285
+ readonly text: string; // the quoted plain text
286
+ readonly messageId: string; // the source message ID
287
+ };
288
+ ```
289
+
290
+ <Callout type="info">
291
+ See the [Quoting guide](/docs/guides/quoting) for a complete walkthrough.
292
+ </Callout>
293
+
262
294
  ### Error
263
295
 
264
296
  Renders children only if the message has an error status.
@@ -0,0 +1,61 @@
1
+ ---
2
+ title: SelectionToolbarPrimitive
3
+ description: A floating toolbar that appears when text is selected within a message.
4
+ ---
5
+
6
+ A floating toolbar that appears near the user's text selection within a message. Used to provide contextual actions like quoting selected text.
7
+
8
+ ## Anatomy
9
+
10
+ ```tsx
11
+ import { SelectionToolbarPrimitive } from "@assistant-ui/react";
12
+
13
+ const FloatingSelectionToolbar = () => (
14
+ <SelectionToolbarPrimitive.Root>
15
+ <SelectionToolbarPrimitive.Quote>Quote</SelectionToolbarPrimitive.Quote>
16
+ </SelectionToolbarPrimitive.Root>
17
+ );
18
+ ```
19
+
20
+ Place this component inside `ThreadPrimitive.Root`:
21
+
22
+ ```tsx
23
+ <ThreadPrimitive.Root>
24
+ <ThreadPrimitive.Viewport>...</ThreadPrimitive.Viewport>
25
+ <FloatingSelectionToolbar />
26
+ </ThreadPrimitive.Root>
27
+ ```
28
+
29
+ ## API Reference
30
+
31
+ ### Root
32
+
33
+ A floating container that renders as a portal positioned above the text selection. Only renders when there is a valid text selection within a single message.
34
+
35
+ This primitive renders a `<div>` element.
36
+
37
+ **Behavior:**
38
+
39
+ - Listens for `mouseup` and `keyup` events to detect completed selections
40
+ - Validates the selection is within a single message using `data-message-id` attributes
41
+ - Renders a portal with `position: fixed`, centered above the selection
42
+ - Prevents `mousedown` from clearing the text selection when clicking the toolbar
43
+ - Hides automatically on scroll or when the selection is cleared
44
+ - Cross-message selections are ignored
45
+
46
+ ### Quote
47
+
48
+ A button that captures the currently selected text and sets it as a quote in the thread composer.
49
+
50
+ This primitive renders a `<button>` element.
51
+
52
+ **Behavior:**
53
+
54
+ - Reads selection info from the Root context (not `window.getSelection()`)
55
+ - Calls `composer.setQuote({ text, messageId })` on the thread composer
56
+ - Clears the text selection after quoting
57
+ - Disabled when no selection info is available
58
+
59
+ <Callout type="info">
60
+ See the [Quoting guide](/docs/guides/quoting) for a complete walkthrough including composer preview, sent message display, and backend handling.
61
+ </Callout>
@@ -14,7 +14,7 @@ import { ThreadPrimitive } from "@assistant-ui/react";
14
14
  const Thread = () => (
15
15
  <ThreadPrimitive.Root>
16
16
  <ThreadPrimitive.Viewport>
17
- <ThreadPrimitive.Empty>...</ThreadPrimitive.Empty>
17
+ <AuiIf condition={(s) => s.thread.isEmpty}>...</AuiIf>
18
18
  <ThreadPrimitive.Messages components={...} />
19
19
  </ThreadPrimitive.Viewport>
20
20
  <Composer />
@@ -24,7 +24,7 @@ A chat bubble shown in the bottom right corner of the screen. Useful for support
24
24
 
25
25
  Add the following to your `tailwind.config.ts`:
26
26
 
27
- <Tabs items={["Tailwind", "Tailwind + shadcn-ui", "Not using Tailwind"]}>
27
+ <Tabs items={["Tailwind", "Tailwind + shadcn-ui"]}>
28
28
 
29
29
  ```ts title="/tailwind.config.ts" tab="Tailwind"
30
30
  {
@@ -49,11 +49,6 @@ Add the following to your `tailwind.config.ts`:
49
49
  }
50
50
  ```
51
51
 
52
- ```ts title="/app/layout.tsx" tab="Not using Tailwind"
53
- import "@assistant-ui/react-ui/styles/index.css";
54
- import "@assistant-ui/react-ui/styles/modal.css";
55
- ```
56
-
57
52
  </Tabs>
58
53
 
59
54
  </Step>
@@ -181,10 +181,10 @@ import { AuiIf } from "@assistant-ui/react";
181
181
  const MyComposerAction: FC = () => {
182
182
  return (
183
183
  <>
184
- <AuiIf condition={({ thread }) => !thread.isRunning}>
184
+ <AuiIf condition={(s) => !s.thread.isRunning}>
185
185
  <Composer.Send />
186
186
  </AuiIf>
187
- <AuiIf condition={({ thread }) => thread.isRunning}>
187
+ <AuiIf condition={(s) => s.thread.isRunning}>
188
188
  <Composer.Cancel />
189
189
  </AuiIf>
190
190
  </>
@@ -20,7 +20,7 @@ Allow the assistant to display rich text using markdown.
20
20
 
21
21
  ### Setup styles
22
22
 
23
- <Tabs items={["Tailwind", "Tailwind + shadcn-ui", "Not using Tailwind"]}>
23
+ <Tabs items={["Tailwind", "Tailwind + shadcn-ui"]}>
24
24
 
25
25
  ```ts {3} title="/tailwind.config.ts" tab="Tailwind"
26
26
  {
@@ -40,11 +40,6 @@ Allow the assistant to display rich text using markdown.
40
40
  }
41
41
  ```
42
42
 
43
- ```ts title="/app/layout.tsx" tab="Not using Tailwind"
44
- import "@assistant-ui/react-ui/styles/index.css";
45
- import "@assistant-ui/react-ui/styles/markdown.css";
46
- ```
47
-
48
43
  </Tabs>
49
44
 
50
45
  </Step>
@@ -24,7 +24,7 @@ The raw message list and message composer UI. Useful for full screen chat use ca
24
24
 
25
25
  Add the following to your `tailwind.config.ts`:
26
26
 
27
- <Tabs items={["Tailwind", "Tailwind + shadcn-ui", "Not using Tailwind"]}>
27
+ <Tabs items={["Tailwind", "Tailwind + shadcn-ui"]}>
28
28
 
29
29
  ```ts title="/tailwind.config.ts" tab="Tailwind"
30
30
  {
@@ -49,10 +49,6 @@ Add the following to your `tailwind.config.ts`:
49
49
  }
50
50
  ```
51
51
 
52
- ```ts title="/app/layout.tsx" tab="Not using Tailwind"
53
- import "@assistant-ui/react-ui/styles/index.css";
54
- ```
55
-
56
52
  </Tabs>
57
53
 
58
54
  </Step>
@@ -63,7 +63,7 @@ import { useAui, useAuiState, useAuiEvent } from "@assistant-ui/react";
63
63
 
64
64
  function MyComponent() {
65
65
  const aui = useAui();
66
- const isRunning = useAuiState(({ thread }) => thread.isRunning);
66
+ const isRunning = useAuiState((s) => s.thread.isRunning);
67
67
 
68
68
  useAuiEvent("thread.started", () => {
69
69
  console.log("Thread started");
@@ -116,30 +116,30 @@ The following hooks have been removed:
116
116
 
117
117
  **Removed Hooks:**
118
118
 
119
- - `useMessageUtils` → Use `useAuiState(({ message }) => message.isHovering)` / `useAuiState(({ message }) => message.isCopied)`
119
+ - `useMessageUtils` → Use `useAuiState((s) => s.message.isHovering)` / `useAuiState((s) => s.message.isCopied)`
120
120
  - `useMessageUtilsStore` → Use `useAui()` with `aui.message().setIsHovering()` / `aui.message().setIsCopied()`
121
- - `useToolUIs` → Use `useAuiState(({ tools }) => tools)` and `useAui()` with `aui.tools()`
121
+ - `useToolUIs` → Use `useAuiState((s) => s.tools)` and `useAui()` with `aui.tools()`
122
122
  - `useToolUIsStore` → Use `useAui()` with `aui.tools()`
123
123
 
124
124
  **Deprecated Hooks:**
125
125
 
126
126
  - `useAssistantRuntime` → Use `useAui()`
127
- - `useThread` → Use `useAuiState(({ thread }) => thread)`
127
+ - `useThread` → Use `useAuiState((s) => s.thread)`
128
128
  - `useThreadRuntime` → Use `useAui()` with `aui.thread()`
129
- - `useMessage` → Use `useAuiState(({ message }) => message)`
129
+ - `useMessage` → Use `useAuiState((s) => s.message)`
130
130
  - `useMessageRuntime` → Use `useAui()` with `aui.message()`
131
- - `useComposer` → Use `useAuiState(({ composer }) => composer)`
131
+ - `useComposer` → Use `useAuiState((s) => s.composer)`
132
132
  - `useComposerRuntime` → Use `useAui()` with `aui.composer()`
133
- - `useEditComposer` → Use `useAuiState(({ message }) => message.composer)`
134
- - `useThreadListItem` → Use `useAuiState(({ threadListItem }) => threadListItem)`
133
+ - `useEditComposer` → Use `useAuiState((s) => s.message.composer)`
134
+ - `useThreadListItem` → Use `useAuiState((s) => s.threadListItem)`
135
135
  - `useThreadListItemRuntime` → Use `useAui()` with `aui.threadListItem()`
136
- - `useMessagePart` → Use `useAuiState(({ part }) => part)`
136
+ - `useMessagePart` → Use `useAuiState((s) => s.part)`
137
137
  - `useMessagePartRuntime` → Use `useAui()` with `aui.part()`
138
- - `useAttachment` → Use `useAuiState(({ attachment }) => attachment)`
138
+ - `useAttachment` → Use `useAuiState((s) => s.attachment)`
139
139
  - `useAttachmentRuntime` → Use `useAui()` with `aui.attachment()`
140
- - `useThreadModelContext` / `useThreadModelConfig` → Use `useAuiState(({ thread }) => thread.modelContext)`
141
- - `useThreadComposer` → Use `useAuiState(({ thread }) => thread.composer)`
142
- - `useThreadList` → Use `useAuiState(({ threads }) => threads)`
140
+ - `useThreadModelContext` / `useThreadModelConfig` → Use `useAuiState((s) => s.thread.modelContext)`
141
+ - `useThreadComposer` → Use `useAuiState((s) => s.thread.composer)`
142
+ - `useThreadList` → Use `useAuiState((s) => s.threads)`
143
143
 
144
144
  #### Migration Examples
145
145
 
@@ -190,10 +190,10 @@ import { useAuiState, useAui } from "@assistant-ui/react";
190
190
 
191
191
  function MyComponent() {
192
192
  // Reading state - all through single hook
193
- const messages = useAuiState(({ thread }) => thread.messages);
194
- const isRunning = useAuiState(({ thread }) => thread.isRunning);
195
- const composerText = useAuiState(({ composer }) => composer.text);
196
- const messageRole = useAuiState(({ message }) => message.role);
193
+ const messages = useAuiState((s) => s.thread.messages);
194
+ const isRunning = useAuiState((s) => s.thread.isRunning);
195
+ const composerText = useAuiState((s) => s.composer.text);
196
+ const messageRole = useAuiState((s) => s.message.role);
197
197
 
198
198
  // Using client for actions
199
199
  const aui = useAui();
@@ -0,0 +1,205 @@
1
+ ---
2
+ title: AI SDK + assistant-ui
3
+ description: Integrate cloud persistence using assistant-ui runtime and pre-built components.
4
+ ---
5
+
6
+
7
+ ## Overview
8
+
9
+ This guide shows how to integrate Assistant Cloud with the [AI SDK](https://sdk.vercel.ai/) using assistant-ui's runtime system and pre-built UI components.
10
+
11
+ ## What You Get
12
+
13
+ This integration provides:
14
+
15
+ - **`<Thread />`** — A complete chat interface with messages, composer, and status indicators
16
+ - **`<ThreadList />`** — A sidebar showing all conversations with auto-generated titles, plus new/delete/manage actions
17
+ - **Automatic Persistence** — Messages save as they stream. Threads are created automatically on first message.
18
+ - **Runtime Integration** — The assistant-ui runtime handles all cloud synchronization behind the scenes.
19
+
20
+ ## How It Works
21
+
22
+ The `useChatRuntime` hook from `@assistant-ui/react-ai-sdk` wraps AI SDK's `useChat` and adds cloud persistence via the `cloud` parameter. The runtime automatically:
23
+
24
+ 1. Creates a cloud thread on the first user message
25
+ 2. Persists messages as they complete streaming
26
+ 3. Generates a conversation title after the assistant's first response
27
+ 4. Loads historical messages when switching threads via `<ThreadList />`
28
+
29
+ You provide the AI SDK endpoint (`api: "/api/chat"`) and the cloud configuration—everything else is handled.
30
+
31
+ ## Prerequisites
32
+
33
+ <Callout type="info">
34
+ You need an assistant-cloud account to follow this guide. [Sign up here](https://cloud.assistant-ui.com/) to get started.
35
+ </Callout>
36
+
37
+ ## Setup Guide
38
+
39
+ <Steps>
40
+
41
+ <Step>
42
+
43
+ ### Create a Cloud Project
44
+
45
+ Create a new project in the [assistant-cloud dashboard](https://cloud.assistant-ui.com/) and from the settings page, copy:
46
+
47
+ - **Frontend API URL**: `https://proj-[ID].assistant-api.com`
48
+ - **Assistant Cloud API Key**: `sk_aui_proj_*`
49
+
50
+ </Step>
51
+
52
+ <Step>
53
+
54
+ ### Configure Environment Variables
55
+
56
+ Add the following environment variables to your project:
57
+
58
+ ```bash title=".env.local"
59
+ # Frontend API URL from your cloud project settings
60
+ NEXT_PUBLIC_ASSISTANT_BASE_URL=https://proj-[YOUR-ID].assistant-api.com
61
+
62
+ # API key for server-side operations
63
+ ASSISTANT_API_KEY=your-api-key-here
64
+ ```
65
+
66
+ </Step>
67
+
68
+ <Step>
69
+
70
+ ### Install Dependencies
71
+
72
+ Install the required packages:
73
+
74
+ <InstallCommand npm={["@assistant-ui/react", "@assistant-ui/react-ai-sdk"]} />
75
+
76
+ </Step>
77
+
78
+ <Step>
79
+
80
+ ### Set Up the Cloud Runtime
81
+
82
+ Create a client-side AssistantCloud instance and integrate it with your AI SDK runtime:
83
+
84
+ ```tsx title="app/chat/page.tsx"
85
+ "use client";
86
+
87
+ import { AssistantCloud, AssistantRuntimeProvider } from "@assistant-ui/react";
88
+ import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
89
+ import { ThreadList } from "@/components/assistant-ui/thread-list";
90
+ import { Thread } from "@/components/assistant-ui/thread";
91
+
92
+ export default function ChatPage() {
93
+ const cloud = new AssistantCloud({
94
+ baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
95
+ anonymous: true, // Creates browser-session based user ID
96
+ });
97
+
98
+ const runtime = useChatRuntime({
99
+ cloud,
100
+ });
101
+
102
+ return (
103
+ <AssistantRuntimeProvider runtime={runtime}>
104
+ <div className="grid h-dvh grid-cols-[200px_1fr] gap-x-2 px-4 py-4">
105
+ <ThreadList />
106
+ <Thread />
107
+ </div>
108
+ </AssistantRuntimeProvider>
109
+ );
110
+ }
111
+ ```
112
+
113
+ </Step>
114
+
115
+ </Steps>
116
+
117
+ ## Telemetry
118
+
119
+ The `useChatRuntime` hook captures full run telemetry including timing data. This integrates with the assistant-ui runtime to provide:
120
+
121
+ **Automatically captured:**
122
+ - `status` — `"completed"`, `"incomplete"`, or `"error"`
123
+ - `duration_ms` — Total run duration (measured client-side)
124
+ - `steps` — Per-step breakdowns with timing, usage, and tool calls
125
+ - `tool_calls` — Tool invocations with name, arguments, results, and source
126
+ - `total_steps` — Number of reasoning/tool steps
127
+ - `output_text` — Full response text (truncated at 50K characters)
128
+
129
+ **Requires route configuration:**
130
+ - `model_id` — The model used
131
+ - `input_tokens` / `output_tokens` — Token usage statistics
132
+
133
+ To capture model and usage data, add the `messageMetadata` callback to your AI SDK route:
134
+
135
+ ```tsx title="app/api/chat/route.ts"
136
+ import { streamText } from "ai";
137
+
138
+ export async function POST(req: Request) {
139
+ const result = streamText({
140
+ model: openai("gpt-5-mini"),
141
+ messages,
142
+ });
143
+
144
+ return result.toUIMessageStreamResponse({
145
+ messageMetadata: ({ part }) => {
146
+ if (part.type === "finish-step") {
147
+ return {
148
+ modelId: part.response.modelId,
149
+ usage: part.usage,
150
+ };
151
+ }
152
+ return undefined;
153
+ },
154
+ });
155
+ }
156
+ ```
157
+
158
+ Without this configuration, model and token data will be omitted from telemetry reports.
159
+
160
+ ### Customizing Reports
161
+
162
+ Use the `beforeReport` hook to add custom metadata or filter reports:
163
+
164
+ ```tsx
165
+ const cloud = new AssistantCloud({
166
+ baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
167
+ telemetry: {
168
+ beforeReport: (report) => ({
169
+ ...report,
170
+ metadata: { userTier: "pro", region: "us-east" },
171
+ }),
172
+ },
173
+ });
174
+ ```
175
+
176
+ Return `null` from `beforeReport` to skip reporting a specific run. To disable telemetry entirely, pass `telemetry: false`.
177
+
178
+ ## Authentication
179
+
180
+ The example above uses anonymous mode (browser session-based user ID) via the env var. For production apps with user accounts, pass an explicit cloud instance:
181
+
182
+ ```tsx
183
+ import { useAuth } from "@clerk/nextjs";
184
+ import { AssistantCloud } from "@assistant-ui/react";
185
+ import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
186
+
187
+ function Chat() {
188
+ const { getToken } = useAuth();
189
+
190
+ const cloud = useMemo(() => new AssistantCloud({
191
+ baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
192
+ authToken: async () => getToken({ template: "assistant-ui" }),
193
+ }), [getToken]);
194
+
195
+ const runtime = useChatRuntime({ cloud });
196
+ // ...
197
+ }
198
+ ```
199
+
200
+ See the [Cloud Authorization](/docs/cloud/authorization) guide for other auth providers.
201
+
202
+
203
+ ## Complete Example
204
+
205
+ Check out the [with-cloud example](https://github.com/assistant-ui/assistant-ui/tree/main/examples/with-cloud) on GitHub for a fully working implementation.