@assistant-ui/mcp-docs-server 0.1.31 → 0.1.32

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 (247) hide show
  1. package/.docs/organized/code-examples/waterfall.md +8 -8
  2. package/.docs/organized/code-examples/with-a2a.md +10 -10
  3. package/.docs/organized/code-examples/with-ag-ui.md +11 -11
  4. package/.docs/organized/code-examples/with-ai-sdk-v6.md +13 -13
  5. package/.docs/organized/code-examples/with-artifacts.md +13 -13
  6. package/.docs/organized/code-examples/with-assistant-transport.md +10 -10
  7. package/.docs/organized/code-examples/with-browser-extension.md +345 -0
  8. package/.docs/organized/code-examples/with-chain-of-thought.md +54 -17
  9. package/.docs/organized/code-examples/with-cloud-standalone.md +13 -13
  10. package/.docs/organized/code-examples/with-cloud.md +13 -13
  11. package/.docs/organized/code-examples/with-custom-thread-list.md +13 -13
  12. package/.docs/organized/code-examples/with-elevenlabs-conversational.md +17 -16
  13. package/.docs/organized/code-examples/with-elevenlabs-scribe.md +17 -16
  14. package/.docs/organized/code-examples/with-expo.md +24 -24
  15. package/.docs/organized/code-examples/with-external-store.md +10 -10
  16. package/.docs/organized/code-examples/with-ffmpeg.md +13 -13
  17. package/.docs/organized/code-examples/with-generative-ui.md +210 -13
  18. package/.docs/organized/code-examples/with-google-adk.md +10 -10
  19. package/.docs/organized/code-examples/with-heat-graph.md +8 -8
  20. package/.docs/organized/code-examples/with-image-generation.md +454 -0
  21. package/.docs/organized/code-examples/with-interactables.md +13 -13
  22. package/.docs/organized/code-examples/with-langchain.md +12 -12
  23. package/.docs/organized/code-examples/with-langgraph.md +15 -12
  24. package/.docs/organized/code-examples/with-livekit.md +18 -17
  25. package/.docs/organized/code-examples/with-mcp.md +748 -0
  26. package/.docs/organized/code-examples/with-opencode.md +11 -11
  27. package/.docs/organized/code-examples/with-parent-id-grouping.md +11 -11
  28. package/.docs/organized/code-examples/with-react-hook-form.md +14 -14
  29. package/.docs/organized/code-examples/with-react-ink.md +4 -4
  30. package/.docs/organized/code-examples/with-react-router.md +15 -15
  31. package/.docs/organized/code-examples/with-resumable-stream.md +660 -0
  32. package/.docs/organized/code-examples/with-store.md +8 -8
  33. package/.docs/organized/code-examples/with-tanstack.md +14 -14
  34. package/.docs/organized/code-examples/with-tap-runtime.md +11 -10
  35. package/.docs/raw/docs/(docs)/cli.mdx +1 -0
  36. package/.docs/raw/docs/(docs)/index.mdx +2 -2
  37. package/.docs/raw/docs/(docs)/installation.mdx +1 -1
  38. package/.docs/raw/docs/(reference)/api-reference/adapters/attachments.mdx +26 -24
  39. package/.docs/raw/docs/(reference)/api-reference/adapters/feedback.mdx +20 -0
  40. package/.docs/raw/docs/(reference)/api-reference/adapters/index.mdx +20 -12
  41. package/.docs/raw/docs/(reference)/api-reference/adapters/model.mdx +44 -0
  42. package/.docs/raw/docs/(reference)/api-reference/adapters/persistence.mdx +37 -16
  43. package/.docs/raw/docs/(reference)/api-reference/adapters/runtime.mdx +12 -23
  44. package/.docs/raw/docs/(reference)/api-reference/adapters/suggestions.mdx +20 -0
  45. package/.docs/raw/docs/(reference)/api-reference/context-providers/assistant-runtime-provider.mdx +37 -8
  46. package/.docs/raw/docs/(reference)/api-reference/context-providers/index.mdx +11 -9
  47. package/.docs/raw/docs/(reference)/api-reference/context-providers/scoped-providers.mdx +64 -0
  48. package/.docs/raw/docs/(reference)/api-reference/external-store/index.mdx +22 -0
  49. package/.docs/raw/docs/(reference)/api-reference/external-store/message-conversion.mdx +52 -0
  50. package/.docs/raw/docs/(reference)/api-reference/external-store/runtime.mdx +36 -0
  51. package/.docs/raw/docs/(reference)/api-reference/hooks/composer-triggers.mdx +98 -0
  52. package/.docs/raw/docs/(reference)/api-reference/hooks/index.mdx +18 -13
  53. package/.docs/raw/docs/(reference)/api-reference/hooks/model-context.mdx +18 -57
  54. package/.docs/raw/docs/(reference)/api-reference/hooks/primitives.mdx +640 -0
  55. package/.docs/raw/docs/(reference)/api-reference/hooks/runtimes.mdx +15 -28
  56. package/.docs/raw/docs/(reference)/api-reference/hooks/state.mdx +64 -18
  57. package/.docs/raw/docs/(reference)/api-reference/hooks/utilities.mdx +434 -0
  58. package/.docs/raw/docs/(reference)/api-reference/integrations/cloud-ai-sdk.mdx +24 -0
  59. package/.docs/raw/docs/(reference)/api-reference/integrations/index.mdx +11 -12
  60. package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +79 -0
  61. package/.docs/raw/docs/(reference)/api-reference/model-context/context.mdx +52 -0
  62. package/.docs/raw/docs/(reference)/api-reference/model-context/index.mdx +22 -0
  63. package/.docs/raw/docs/(reference)/api-reference/model-context/registry.mdx +20 -0
  64. package/.docs/raw/docs/(reference)/api-reference/overview.mdx +110 -131
  65. package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar-more.mdx +78 -221
  66. package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar.mdx +127 -242
  67. package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +39 -20
  68. package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-modal.mdx +66 -87
  69. package/.docs/raw/docs/(reference)/api-reference/primitives/attachment.mdx +50 -58
  70. package/.docs/raw/docs/(reference)/api-reference/primitives/branch-picker.mdx +80 -48
  71. package/.docs/raw/docs/(reference)/api-reference/primitives/chain-of-thought.mdx +67 -0
  72. package/.docs/raw/docs/(reference)/api-reference/primitives/composer.mdx +323 -461
  73. package/.docs/raw/docs/(reference)/api-reference/primitives/error.mdx +36 -43
  74. package/.docs/raw/docs/(reference)/api-reference/primitives/index.mdx +29 -24
  75. package/.docs/raw/docs/(reference)/api-reference/primitives/message-part.mdx +63 -245
  76. package/.docs/raw/docs/(reference)/api-reference/primitives/message.mdx +175 -591
  77. package/.docs/raw/docs/(reference)/api-reference/primitives/queue-item.mdx +65 -0
  78. package/.docs/raw/docs/(reference)/api-reference/primitives/selection-toolbar.mdx +35 -22
  79. package/.docs/raw/docs/(reference)/api-reference/primitives/suggestion.mdx +57 -140
  80. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list-item-more.mdx +70 -161
  81. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list-item.mdx +84 -108
  82. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list.mdx +77 -96
  83. package/.docs/raw/docs/(reference)/api-reference/primitives/thread.mdx +173 -349
  84. package/.docs/raw/docs/(reference)/api-reference/runtimes/assistant-runtime.mdx +9 -21
  85. package/.docs/raw/docs/(reference)/api-reference/runtimes/attachment-runtime.mdx +10 -21
  86. package/.docs/raw/docs/(reference)/api-reference/runtimes/composer-runtime.mdx +15 -70
  87. package/.docs/raw/docs/(reference)/api-reference/runtimes/index.mdx +18 -13
  88. package/.docs/raw/docs/(reference)/api-reference/runtimes/message-part-runtime.mdx +25 -28
  89. package/.docs/raw/docs/(reference)/api-reference/runtimes/message-runtime.mdx +11 -63
  90. package/.docs/raw/docs/(reference)/api-reference/runtimes/queue-state.mdx +20 -0
  91. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-item-runtime.mdx +11 -48
  92. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-runtime.mdx +10 -47
  93. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-runtime.mdx +18 -30
  94. package/.docs/raw/docs/(reference)/api-reference/tools/component-tools.mdx +68 -0
  95. package/.docs/raw/docs/(reference)/api-reference/tools/index.mdx +39 -0
  96. package/.docs/raw/docs/(reference)/api-reference/tools/rendering.mdx +79 -0
  97. package/.docs/raw/docs/(reference)/api-reference/tools/status.mdx +42 -0
  98. package/.docs/raw/docs/(reference)/api-reference/tools/toolkits.mdx +92 -0
  99. package/.docs/raw/docs/(reference)/api-reference/transport/assistant-transport.mdx +48 -0
  100. package/.docs/raw/docs/(reference)/api-reference/transport/frame.mdx +62 -0
  101. package/.docs/raw/docs/(reference)/api-reference/transport/index.mdx +22 -0
  102. package/.docs/raw/docs/(reference)/api-reference/utilities/index.mdx +19 -0
  103. package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +131 -0
  104. package/.docs/raw/docs/(reference)/api-reference/voice/index.mdx +22 -0
  105. package/.docs/raw/docs/(reference)/api-reference/voice/session.mdx +54 -0
  106. package/.docs/raw/docs/(reference)/api-reference/voice/speech-dictation.mdx +36 -0
  107. package/.docs/raw/docs/cloud/ai-sdk.mdx +1 -1
  108. package/.docs/raw/docs/cloud/index.mdx +2 -2
  109. package/.docs/raw/docs/guides/attachments.mdx +4 -4
  110. package/.docs/raw/docs/guides/branching.mdx +1 -1
  111. package/.docs/raw/docs/guides/chain-of-thought.mdx +5 -5
  112. package/.docs/raw/docs/guides/context-api.mdx +4 -4
  113. package/.docs/raw/docs/guides/dictation.mdx +2 -2
  114. package/.docs/raw/docs/guides/editing.mdx +1 -1
  115. package/.docs/raw/docs/guides/generative-ui.mdx +142 -0
  116. package/.docs/raw/docs/guides/image-generation.mdx +74 -0
  117. package/.docs/raw/docs/guides/index.mdx +2 -2
  118. package/.docs/raw/docs/guides/interactables.mdx +2 -2
  119. package/.docs/raw/docs/guides/latex.mdx +2 -2
  120. package/.docs/raw/docs/guides/mcp-apps.mdx +231 -0
  121. package/.docs/raw/docs/guides/mentions.mdx +2 -2
  122. package/.docs/raw/docs/guides/message-timing.mdx +38 -5
  123. package/.docs/raw/docs/guides/multi-agent.mdx +2 -2
  124. package/.docs/raw/docs/guides/quoting.mdx +1 -1
  125. package/.docs/raw/docs/guides/resumable-stream-deployment.mdx +212 -0
  126. package/.docs/raw/docs/guides/resumable-stream-stores.mdx +152 -0
  127. package/.docs/raw/docs/guides/resumable-streams.mdx +210 -0
  128. package/.docs/raw/docs/guides/slash-commands.mdx +1 -1
  129. package/.docs/raw/docs/guides/speech.mdx +2 -2
  130. package/.docs/raw/docs/guides/suggestions.mdx +88 -4
  131. package/.docs/raw/docs/guides/tool-ui.mdx +2 -2
  132. package/.docs/raw/docs/guides/tools.mdx +66 -5
  133. package/.docs/raw/docs/guides/voice.mdx +2 -2
  134. package/.docs/raw/docs/ink/adapters.mdx +37 -1
  135. package/.docs/raw/docs/ink/custom-backend.mdx +59 -8
  136. package/.docs/raw/docs/ink/index.mdx +10 -11
  137. package/.docs/raw/docs/ink/primitives.mdx +349 -8
  138. package/.docs/raw/docs/integrations/auth/better-auth.mdx +1 -1
  139. package/.docs/raw/docs/integrations/auth/clerk.mdx +1 -1
  140. package/.docs/raw/docs/integrations/auth/next-auth.mdx +1 -1
  141. package/.docs/raw/docs/integrations/frameworks/ai-sdk.mdx +2 -2
  142. package/.docs/raw/docs/integrations/frameworks/cloudflare-agents/overview.mdx +282 -0
  143. package/.docs/raw/docs/integrations/frameworks/mastra/overview.mdx +2 -2
  144. package/.docs/raw/docs/integrations/frameworks/mastra/separate-server.mdx +1 -1
  145. package/.docs/raw/docs/integrations/gateways/index.mdx +9 -4
  146. package/.docs/raw/docs/integrations/index.mdx +15 -3
  147. package/.docs/raw/docs/integrations/observability/langfuse.mdx +8 -1
  148. package/.docs/raw/docs/integrations/observability/langsmith.mdx +8 -4
  149. package/.docs/raw/docs/integrations/tools/react-mcp.mdx +337 -0
  150. package/.docs/raw/docs/primitives/composer.mdx +53 -0
  151. package/.docs/raw/docs/primitives/index.mdx +2 -2
  152. package/.docs/raw/docs/primitives/suggestion.mdx +9 -0
  153. package/.docs/raw/docs/react-native/hooks.mdx +2 -2
  154. package/.docs/raw/docs/react-native/index.mdx +4 -4
  155. package/.docs/raw/docs/runtimes/a2a/client-and-hooks.mdx +4 -4
  156. package/.docs/raw/docs/runtimes/a2a/overview.mdx +2 -2
  157. package/.docs/raw/docs/runtimes/ag-ui/overview.mdx +2 -2
  158. package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +32 -1
  159. package/.docs/raw/docs/runtimes/ai-sdk/overview.mdx +2 -2
  160. package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +7 -2
  161. package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +1 -1
  162. package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +7 -0
  163. package/.docs/raw/docs/runtimes/custom/data-stream.mdx +27 -2
  164. package/.docs/raw/docs/runtimes/custom/external-store.mdx +9 -1
  165. package/.docs/raw/docs/runtimes/custom/overview.mdx +2 -2
  166. package/.docs/raw/docs/runtimes/google-adk/overview.mdx +2 -2
  167. package/.docs/raw/docs/runtimes/langchain.mdx +2 -2
  168. package/.docs/raw/docs/runtimes/langgraph/overview.mdx +2 -2
  169. package/.docs/raw/docs/runtimes/opencode/overview.mdx +2 -2
  170. package/.docs/raw/docs/runtimes/opencode/quickstart.mdx +1 -1
  171. package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +12 -5
  172. package/.docs/raw/docs/ui/composer-trigger-popover.mdx +11 -1
  173. package/.docs/raw/docs/ui/mcp-config.mdx +102 -0
  174. package/.docs/raw/docs/ui/model-selector.mdx +8 -8
  175. package/.docs/raw/docs/ui/sources.mdx +17 -0
  176. package/.docs/raw/docs/ui/streamdown.mdx +34 -2
  177. package/.docs/raw/docs/ui/thread-list.mdx +2 -2
  178. package/.docs/raw/docs/ui/thread.mdx +2 -2
  179. package/README.md +14 -72
  180. package/dist/constants.d.ts +12 -9
  181. package/dist/constants.d.ts.map +1 -1
  182. package/dist/constants.js +13 -9
  183. package/dist/constants.js.map +1 -1
  184. package/dist/index.d.ts +7 -3
  185. package/dist/index.d.ts.map +1 -1
  186. package/dist/index.js +25 -24
  187. package/dist/index.js.map +1 -1
  188. package/dist/prepare-docs/code-examples.d.ts +4 -1
  189. package/dist/prepare-docs/code-examples.d.ts.map +1 -1
  190. package/dist/prepare-docs/code-examples.js +109 -121
  191. package/dist/prepare-docs/code-examples.js.map +1 -1
  192. package/dist/prepare-docs/copy-raw.d.ts +4 -1
  193. package/dist/prepare-docs/copy-raw.d.ts.map +1 -1
  194. package/dist/prepare-docs/copy-raw.js +45 -42
  195. package/dist/prepare-docs/copy-raw.js.map +1 -1
  196. package/dist/prepare-docs/prepare.d.ts +1 -2
  197. package/dist/prepare-docs/prepare.js +17 -17
  198. package/dist/prepare-docs/prepare.js.map +1 -1
  199. package/dist/stdio.d.ts +1 -3
  200. package/dist/stdio.js +6 -3
  201. package/dist/stdio.js.map +1 -1
  202. package/dist/tools/docs.d.ts +20 -15
  203. package/dist/tools/docs.d.ts.map +1 -1
  204. package/dist/tools/docs.js +140 -161
  205. package/dist/tools/docs.js.map +1 -1
  206. package/dist/tools/examples.d.ts +20 -15
  207. package/dist/tools/examples.d.ts.map +1 -1
  208. package/dist/tools/examples.js +74 -86
  209. package/dist/tools/examples.js.map +1 -1
  210. package/dist/tools/tests/test-setup.d.ts +5 -2
  211. package/dist/tools/tests/test-setup.d.ts.map +1 -1
  212. package/dist/tools/tests/test-setup.js +21 -28
  213. package/dist/tools/tests/test-setup.js.map +1 -1
  214. package/dist/utils/logger.d.ts +8 -5
  215. package/dist/utils/logger.d.ts.map +1 -1
  216. package/dist/utils/logger.js +17 -17
  217. package/dist/utils/logger.js.map +1 -1
  218. package/dist/utils/mcp-format.d.ts +8 -5
  219. package/dist/utils/mcp-format.d.ts.map +1 -1
  220. package/dist/utils/mcp-format.js +9 -9
  221. package/dist/utils/mcp-format.js.map +1 -1
  222. package/dist/utils/mdx.d.ts +8 -6
  223. package/dist/utils/mdx.d.ts.map +1 -1
  224. package/dist/utils/mdx.js +22 -22
  225. package/dist/utils/mdx.js.map +1 -1
  226. package/dist/utils/paths.d.ts +9 -6
  227. package/dist/utils/paths.d.ts.map +1 -1
  228. package/dist/utils/paths.js +66 -76
  229. package/dist/utils/paths.js.map +1 -1
  230. package/dist/utils/security.d.ts +4 -1
  231. package/dist/utils/security.d.ts.map +1 -1
  232. package/dist/utils/security.js +19 -40
  233. package/dist/utils/security.js.map +1 -1
  234. package/package.json +5 -5
  235. package/.docs/raw/docs/(reference)/api-reference/adapters/feedback-speech.mdx +0 -41
  236. package/.docs/raw/docs/(reference)/api-reference/context-providers/text-message-part-provider.mdx +0 -40
  237. package/.docs/raw/docs/(reference)/api-reference/integrations/react-data-stream.mdx +0 -260
  238. package/.docs/raw/docs/(reference)/api-reference/integrations/react-hook-form.mdx +0 -103
  239. package/.docs/raw/docs/(reference)/api-reference/integrations/vercel-ai-sdk.mdx +0 -254
  240. package/dist/prepare-docs/prepare.d.ts.map +0 -1
  241. package/dist/stdio.d.ts.map +0 -1
  242. /package/.docs/raw/docs/{(reference)/migrations → migrations}/deprecation-policy.mdx +0 -0
  243. /package/.docs/raw/docs/{(reference) → migrations}/react-compatibility.mdx +0 -0
  244. /package/.docs/raw/docs/{(reference)/migrations → migrations}/react-langgraph-v0-7.mdx +0 -0
  245. /package/.docs/raw/docs/{(reference)/migrations → migrations}/v0-11.mdx +0 -0
  246. /package/.docs/raw/docs/{(reference)/migrations → migrations}/v0-12.mdx +0 -0
  247. /package/.docs/raw/docs/{(reference)/migrations → migrations}/v0-14.mdx +0 -0
@@ -0,0 +1,337 @@
1
+ ---
2
+ title: User-managed MCP servers
3
+ description: Let end users add and authenticate MCP servers from the browser with @assistant-ui/react-mcp.
4
+ ---
5
+
6
+ [`@assistant-ui/react-mcp`](https://npmjs.com/package/@assistant-ui/react-mcp) is the user-facing layer for MCP. Where the [server-side MCP guide](/docs/integrations/tools/mcp) wires a single fixed set of MCP servers into your API route, this package lets *end users* see a list of connectors, sign in via OAuth, paste a custom server URL, and have the resulting tool catalog flow into the chat — automatically.
7
+
8
+ Two ways a server reaches the user:
9
+
10
+ - **Connector** — a preset declared by the app developer with `defineConnector(...)`. The user just clicks Connect (and completes auth).
11
+ - **Custom server** — the user supplies the URL, name, and auth in `<McpAddFormPrimitive>`. Hide the add UI to disable.
12
+
13
+ Both flow through one connection lifecycle, one persisted state surface, and one tool registration path.
14
+
15
+ ## How it works
16
+
17
+ ```
18
+ useAui({ mcp: McpManagerResource({ connectors }) })
19
+ │
20
+ ├─ Tap resource — connection lifecycle, server lookup, OAuth/bearer auth
21
+ ├─ Auto-mounts the modelContext scope when no chat runtime provides one
22
+ └─ Registers connected tools as frontend tools — your chat sees them automatically
23
+ ```
24
+
25
+ The manager is a single tap resource. Mount it with `useAui` like any other scope. OAuth (PKCE + RFC 7591 dynamic client registration), bearer, and "no auth" are first-class. Token refresh runs inside the MCP SDK on 401; this package mediates persistence and the redirect step.
26
+
27
+ ## Setup
28
+
29
+ <Steps>
30
+ <Step>
31
+
32
+ ### Install
33
+
34
+ <InstallCommand npm={["@assistant-ui/react-mcp"]} />
35
+
36
+ </Step>
37
+ <Step>
38
+
39
+ ### Mount the manager
40
+
41
+ Declare your connectors and provide the `mcp` scope on `useAui`. No provider wrapper, no imperative hooks:
42
+
43
+ ```tsx title="app/providers.tsx"
44
+ "use client";
45
+
46
+ import { AuiProvider, useAui } from "@assistant-ui/react";
47
+ import { McpManagerResource, defineConnector } from "@assistant-ui/react-mcp";
48
+
49
+ const connectors = [
50
+ defineConnector({
51
+ id: "linear",
52
+ name: "Linear",
53
+ url: "https://mcp.linear.app",
54
+ auth: { type: "oauth", scopes: ["read"] },
55
+ icon: "/icons/linear.svg",
56
+ }),
57
+ defineConnector({
58
+ id: "weather",
59
+ name: "Weather",
60
+ url: "https://mcp.example.com/weather",
61
+ auth: { type: "none" },
62
+ }),
63
+ ];
64
+
65
+ export function Providers({ children }: { children: React.ReactNode }) {
66
+ const aui = useAui({ mcp: McpManagerResource({ connectors }) });
67
+ return <AuiProvider value={aui}>{children}</AuiProvider>;
68
+ }
69
+ ```
70
+
71
+ Defaults baked in:
72
+
73
+ - `storage` — `McpLocalStorage()` (override for production; see [Storage](#storage))
74
+ - `oauthRedirectUri` — `${window.location.origin}/mcp/callback`
75
+ - `autoConnect` — `true` (connect on mount when usable auth is persisted)
76
+
77
+ </Step>
78
+ <Step>
79
+
80
+ ### Pick your UI
81
+
82
+ You have two options:
83
+
84
+ **Drop-in shadcn dialog** (recommended for most apps) — install the `mcp-config` component via the assistant-ui registry, then render `<McpConfigDialog />` anywhere inside the provider. You get a styled trigger, server cards, status badges, error banners, and the add form for free:
85
+
86
+ <InstallCommand shadcn={["mcp-config"]} />
87
+
88
+ ```tsx title="app/page.tsx"
89
+ import { McpConfigDialog } from "@/components/assistant-ui/mcp-config";
90
+
91
+ export default function Page() {
92
+ return (
93
+ <header className="flex items-center justify-between">
94
+ <h1>My app</h1>
95
+ <McpConfigDialog />
96
+ </header>
97
+ );
98
+ }
99
+ ```
100
+
101
+ Pass children to override the trigger:
102
+
103
+ ```tsx
104
+ <McpConfigDialog>
105
+ <Button variant="ghost">Servers</Button>
106
+ </McpConfigDialog>
107
+ ```
108
+
109
+ **Compose your own from primitives** — three namespaces, all unstyled and `data-*`-driven. The iteration primitives take a **render function** so the body re-runs per server with the right scope:
110
+
111
+ ```tsx title="app/mcp/page.tsx"
112
+ "use client";
113
+
114
+ import {
115
+ McpManagerPrimitive,
116
+ McpServerPrimitive,
117
+ } from "@assistant-ui/react-mcp";
118
+
119
+ const ServerCard = () => (
120
+ <McpServerPrimitive.Root>
121
+ <McpServerPrimitive.Icon />
122
+ <McpServerPrimitive.Name />
123
+ <McpServerPrimitive.Status />
124
+ <McpServerPrimitive.ConnectButton>Connect</McpServerPrimitive.ConnectButton>
125
+ <McpServerPrimitive.DisconnectButton>Disconnect</McpServerPrimitive.DisconnectButton>
126
+ <McpServerPrimitive.OAuthLink>Authorize ↗</McpServerPrimitive.OAuthLink>
127
+ <McpServerPrimitive.RemoveButton>Remove</McpServerPrimitive.RemoveButton>
128
+ <McpServerPrimitive.Error />
129
+ </McpServerPrimitive.Root>
130
+ );
131
+
132
+ export default function McpPage() {
133
+ return (
134
+ <McpManagerPrimitive.Root>
135
+ <h2>Connectors</h2>
136
+ <McpManagerPrimitive.Connectors>
137
+ {() => <ServerCard />}
138
+ </McpManagerPrimitive.Connectors>
139
+
140
+ <h2>Your servers</h2>
141
+ <McpManagerPrimitive.CustomServers>
142
+ {() => <ServerCard />}
143
+ </McpManagerPrimitive.CustomServers>
144
+
145
+ <McpManagerPrimitive.AddCustomTrigger>
146
+ Add custom server
147
+ </McpManagerPrimitive.AddCustomTrigger>
148
+ </McpManagerPrimitive.Root>
149
+ );
150
+ }
151
+ ```
152
+
153
+ To disable custom servers entirely, just don't render `AddCustomTrigger` and `CustomServers`.
154
+
155
+ The iteration primitives wrap each item in an `McpServerByIdProvider`, so the nested `<McpServerPrimitive.*>` automatically reads the right scope. `<ConnectButton>`, `<DisconnectButton>`, `<OAuthLink>` and `<RemoveButton>` only render when the relevant state matches — no manual gating. `<RemoveButton>` is also hidden on connector items (which the user can't remove).
156
+
157
+ </Step>
158
+ <Step>
159
+
160
+ ### Add the custom-server form
161
+
162
+ ```tsx
163
+ <McpAddFormPrimitive.Root onSubmitted={() => closeDialog()}>
164
+ <McpAddFormPrimitive.NameField />
165
+ <McpAddFormPrimitive.UrlField />
166
+ <McpAddFormPrimitive.AuthSelect /> {/* none | bearer | oauth */}
167
+ <McpAddFormPrimitive.AuthFields /> {/* token or scope input depending on selection */}
168
+ <McpAddFormPrimitive.Error />
169
+ <McpAddFormPrimitive.Submit>Add</McpAddFormPrimitive.Submit>
170
+ <McpAddFormPrimitive.Cancel>Cancel</McpAddFormPrimitive.Cancel>
171
+ </McpAddFormPrimitive.Root>
172
+ ```
173
+
174
+ The form owns its own draft state and submits via `aui.mcp().addCustomServer(...)`. Pass a render function to `AuthFields` to fully customize it.
175
+
176
+ </Step>
177
+ <Step>
178
+
179
+ ### Handle the OAuth callback
180
+
181
+ Add a route at `/mcp/callback` (or whatever you set `oauthRedirectUri` to):
182
+
183
+ ```tsx title="app/mcp/callback/page.tsx"
184
+ "use client";
185
+
186
+ import { McpOAuthCallback } from "@assistant-ui/react-mcp";
187
+ import { useRouter } from "next/navigation";
188
+ import { Providers } from "../../providers";
189
+
190
+ export default function Callback() {
191
+ const router = useRouter();
192
+ return (
193
+ <Providers>
194
+ <McpOAuthCallback onComplete={() => router.replace("/mcp")} />
195
+ </Providers>
196
+ );
197
+ }
198
+ ```
199
+
200
+ The callback reads `?state=...&code=...` from the URL, derives the target server id (encoded in the OAuth `state` parameter automatically), and calls `completeAuth` on the right server.
201
+
202
+ </Step>
203
+ <Step>
204
+
205
+ ### That's it — the chat sees your tools
206
+
207
+ `McpManagerResource` registers connected tools as **frontend tools** with the `modelContext` scope. Any chat runtime mounted in the same store (e.g. `@assistant-ui/react-ai-sdk`'s `useChatRuntime`) sees them and exposes them to the model — no `useMcpTools` hook, no adapter call.
208
+
209
+ ```tsx
210
+ "use client";
211
+ import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
212
+
213
+ export function Chat() {
214
+ const runtime = useChatRuntime({ api: "/api/chat" });
215
+ /* … */
216
+ }
217
+ ```
218
+
219
+ Tool names are prefixed `serverId__toolName` to avoid collisions across connected servers. The toolkit re-registers whenever a server connects / disconnects or its tool list changes.
220
+
221
+ If no chat runtime is mounted, `McpManagerResource` brings its own minimal `modelContext` along. Tools are still callable directly:
222
+
223
+ ```ts
224
+ // In an event handler — never in render. See the tap conventions.
225
+ const aui = useAui();
226
+ const out = await aui.mcp().server({ id: "linear" }).callTool("search", { q });
227
+ ```
228
+
229
+ </Step>
230
+ </Steps>
231
+
232
+ ## Storage
233
+
234
+ All persisted state — custom server records, OAuth tokens, PKCE verifiers, DCR client info — goes through a single `MCPStorage` resource. Three built-ins:
235
+
236
+ - `McpLocalStorage()` — default. Stores under the `aui-mcp:` prefix in `window.localStorage`.
237
+ - `McpMemoryStorage()` — in-process Map. Use for SSR/tests where localStorage is absent.
238
+ - `McpCustomStorage({...})` — bring your own load/save. Use for app-controlled backends (e.g. POST to your API).
239
+
240
+ ```tsx
241
+ import { McpManagerResource, McpCustomStorage } from "@assistant-ui/react-mcp";
242
+
243
+ const aui = useAui({
244
+ mcp: McpManagerResource({
245
+ connectors,
246
+ storage: McpCustomStorage({
247
+ loadCustomServers: async () => fetch("/api/mcp/servers").then((r) => r.json()),
248
+ saveCustomServers: async (records) =>
249
+ fetch("/api/mcp/servers", { method: "PUT", body: JSON.stringify(records) }),
250
+ loadAuthState: async (id) =>
251
+ fetch(`/api/mcp/auth/${id}`).then((r) => (r.ok ? r.json() : null)),
252
+ saveAuthState: async (id, state) =>
253
+ fetch(`/api/mcp/auth/${id}`, { method: "PUT", body: JSON.stringify(state) }),
254
+ clearAuthState: async (id) =>
255
+ fetch(`/api/mcp/auth/${id}`, { method: "DELETE" }),
256
+ }),
257
+ }),
258
+ });
259
+ ```
260
+
261
+ <Callout type="warn">
262
+ `McpLocalStorage` stores tokens in plain text and is XSS-exposed. For anything beyond local prototyping, use `McpCustomStorage` against an HTTP-only-cookie-backed endpoint, or wrap localStorage with your own encrypted serializer.
263
+ </Callout>
264
+
265
+ ## Auth
266
+
267
+ Three modes, declared per-connector or per-custom-record:
268
+
269
+ ```ts
270
+ { type: "none" } // no auth header
271
+ { type: "bearer", token?: "…" } // Authorization: Bearer …
272
+ { type: "oauth", // PKCE + DCR + refresh
273
+ scopes?: ["read"],
274
+ authorizationEndpoint?: "…", // overrides RFC 8414 discovery
275
+ tokenEndpoint?: "…",
276
+ registrationEndpoint?: "…",
277
+ clientId?: "…", // skip DCR with a static client
278
+ clientSecret?: "…",
279
+ }
280
+ ```
281
+
282
+ The OAuth provider implements the MCP SDK's `OAuthClientProvider`. The SDK handles discovery (RFC 8414), DCR (RFC 7591), PKCE, token exchange, and refresh; this package mediates `MCPStorage` reads/writes and the redirect step. The server id is embedded in the OAuth `state` parameter so a single `/mcp/callback` route knows which server to complete.
283
+
284
+ ## State & methods
285
+
286
+ Render-time state — `useAuiState`:
287
+
288
+ ```ts
289
+ import { useAuiState } from "@assistant-ui/store";
290
+
291
+ const isHydrated = useAuiState((s) => s.mcp.isHydrated);
292
+ const connectionState = useAuiState((s) => s.mcpServer.connectionState);
293
+ // ^ requires McpServerByIdProvider
294
+ ```
295
+
296
+ Imperative methods — `useAui` + resolve in a callback (never during render — see the [tap skill](https://github.com/assistant-ui/assistant-ui/blob/main/.claude/skills/tap/SKILL.md) for why):
297
+
298
+ ```ts
299
+ const aui = useAui();
300
+
301
+ // inside an event handler:
302
+ await aui.mcp().addCustomServer({ name, url, auth: { type: "bearer", token } });
303
+ await aui.mcp().server({ id }).connect();
304
+ await aui.mcp().server({ id }).callTool("echo", { text: "hi" });
305
+ ```
306
+
307
+ ## v1 scope
308
+
309
+ What ships:
310
+
311
+ - Tool listing and invocation, auto-registered as frontend tools
312
+ - OAuth (PKCE + DCR), bearer, none
313
+ - StreamableHTTP transport
314
+ - Manual connect/disconnect
315
+
316
+ What's deferred:
317
+
318
+ - Resources, prompts, sampling
319
+ - Auto-reconnect with backoff
320
+ - Per-tool enable/disable persistence
321
+ - Per-tool consent prompts
322
+ - Out-of-the-box token encryption (use `McpCustomStorage` against a server endpoint)
323
+
324
+ ## Related
325
+
326
+ <Cards>
327
+ <Card
328
+ title="Server-side MCP"
329
+ description="App-developer-controlled MCP servers wired into the API route."
330
+ href="/docs/integrations/tools/mcp"
331
+ />
332
+ <Card
333
+ title="Tools and tool UI"
334
+ description="Build custom renderers for tool calls and approvals."
335
+ href="/docs/guides/tools"
336
+ />
337
+ </Cards>
@@ -526,6 +526,46 @@ Use `onSubmit` on `Root` to intercept submission:
526
526
  </ComposerPrimitive.Root>
527
527
  ```
528
528
 
529
+ ### Gate Sending on External State
530
+
531
+ Sometimes you want users to type while sending is temporarily blocked, for example while tool configuration, auth, or the first model context is still loading. Disabling the entire thread via `isDisabled` works but also disables the text input, which feels broken.
532
+
533
+ Use `isSendDisabled` on the runtime adapter to keep the input usable while blocking send:
534
+
535
+ ```tsx
536
+ const runtime = useExternalStoreRuntime({
537
+ isSendDisabled: !toolsLoaded,
538
+ onNew,
539
+ messages,
540
+ // ...
541
+ });
542
+ ```
543
+
544
+ When `isSendDisabled` is `true`:
545
+
546
+ - `composer.canSend` becomes `false`
547
+ - `<ComposerPrimitive.Send>` is disabled
548
+ - Enter and the `Cmd/Ctrl+Shift+Enter` steer hotkey become no-ops
549
+ - `aui.composer().send()` short-circuits at the runtime, so direct calls cannot escape the gate
550
+
551
+ Read the same flag from React with `<AuiIf>` to render hints alongside the input:
552
+
553
+ ```tsx
554
+ <ComposerPrimitive.Root>
555
+ <ComposerPrimitive.Input placeholder="Ask anything..." />
556
+ <AuiIf condition={(s) => !s.composer.canSend}>
557
+ <p className="text-sm text-muted-foreground">Loading tools, hang on...</p>
558
+ </AuiIf>
559
+ <ComposerPrimitive.Send>Send</ComposerPrimitive.Send>
560
+ </ComposerPrimitive.Root>
561
+ ```
562
+
563
+ `canSend` reflects the composer's own willingness to send (editing mode, non-empty content, `isSendDisabled` not set). Cross-thread gating like an in-flight run without queue support is layered on top by `<ComposerPrimitive.Send>` automatically.
564
+
565
+ `isSendDisabled` only gates the thread composer. Saving an in-progress message edit is unaffected, since it is a per-message action rather than a new send.
566
+
567
+ For the difference between `isDisabled` and `isSendDisabled`, see the [external store adapter reference](/docs/runtimes/custom/external-store).
568
+
529
569
  ### Ctrl+Enter to Submit
530
570
 
531
571
  ```tsx
@@ -537,6 +577,19 @@ Use `onSubmit` on `Root` to intercept submission:
537
577
 
538
578
  With `submitMode="ctrlEnter"`, plain Enter inserts a newline and Ctrl/Cmd+Enter submits.
539
579
 
580
+ ### Mobile / touch devices
581
+
582
+ ```tsx
583
+ <ComposerPrimitive.Root>
584
+ <ComposerPrimitive.Input unstable_insertNewlineOnTouchEnter />
585
+ <ComposerPrimitive.Send>Send</ComposerPrimitive.Send>
586
+ </ComposerPrimitive.Root>
587
+ ```
588
+
589
+ `unstable_insertNewlineOnTouchEnter` switches Enter to insert a newline on touch-primary devices (detected via `(pointer: coarse) and (not (any-pointer: fine))`), so the on-screen Return key never accidentally sends a half-finished message. Submission moves to the explicit Send button, matching WhatsApp, Slack, Discord, iMessage, ChatGPT, and Claude.ai.
590
+
591
+ Desktop behavior is unchanged. A tablet paired with a hardware keyboard still gets `submitMode`'s usual semantics if you set `submitMode="ctrlEnter"` or `"none"` — the flag only downgrades the default `"enter"` mode.
592
+
540
593
  ### Floating Composer
541
594
 
542
595
  Primitives aren't bound to any layout. Here's how the floating composer on this docs site is built, using the same `ComposerPrimitive.Root` and `ComposerPrimitive.Input` positioned with CSS:
@@ -1,6 +1,6 @@
1
1
  ---
2
- title: Overview
3
- description: Unstyled, accessible building blocks for AI chat interfaces.
2
+ title: Headless Chat Primitives
3
+ description: Unstyled, accessible Radix-style building blocks for React AI chat interfaces — Thread, Composer, Message, and more, ready to compose with assistant-ui.
4
4
  platforms: ["react"]
5
5
  ---
6
6
 
@@ -128,6 +128,15 @@ When `send={false}`, the `clearComposer` prop controls whether the suggestion re
128
128
  - **`clearComposer={true}`** (default): replaces the current composer text
129
129
  - **`clearComposer={false}`**: appends the suggestion to the existing text
130
130
 
131
+ ### Static configuration vs. runtime suggestions
132
+
133
+ There are two separate data flows for suggestions:
134
+
135
+ - **Static configuration** flows through the `suggestions` scope. Pass an array to `Suggestions(...)` in your runtime provider; render it with `ThreadPrimitive.Suggestions`. Best for welcome screen prompts.
136
+ - **Runtime / dynamic suggestions** flow through `thread.suggestions`. Populate it via `SuggestionAdapter` (local runtime) or the `suggestions` field on `useExternalStoreRuntime`; render it with the shadcn `ThreadFollowupSuggestions` component or your own component reading `useAuiState((s) => s.thread.suggestions)`. Best for follow up prompts after a turn.
137
+
138
+ See [Suggested Prompts](/docs/guides/suggestions) for end to end examples.
139
+
131
140
  ### ThreadPrimitive.Suggestion (Legacy)
132
141
 
133
142
  `ThreadPrimitive.Suggestion` is a self-contained button that takes a `prompt` prop directly. The newer pattern (`ThreadPrimitive.Suggestions` + `SuggestionPrimitive` parts) is preferred for structured suggestions with title and description:
@@ -55,8 +55,8 @@ Subscribe to events without causing re-renders.
55
55
  ```tsx
56
56
  import { useAuiEvent } from "@assistant-ui/react-native";
57
57
 
58
- useAuiEvent("thread.runStart", (payload) => {
59
- console.log("Run started:", payload);
58
+ useAuiEvent("thread.modelContextUpdate", ({ threadId }) => {
59
+ console.log("Model context updated:", threadId);
60
60
  });
61
61
  ```
62
62
 
@@ -1,6 +1,6 @@
1
1
  ---
2
- title: Getting Started
3
- description: Build AI chat interfaces for iOS and Android with @assistant-ui/react-native.
2
+ title: React Native AI Chat
3
+ description: Build AI chat for iOS and Android with @assistant-ui/react-native — streaming, tools, attachments, and platform-native components from the same primitives as the web SDK.
4
4
  ---
5
5
 
6
6
  ## Quick Start
@@ -69,7 +69,7 @@ export const maxDuration = 30;
69
69
  export async function POST(req: Request) {
70
70
  const { messages } = await req.json();
71
71
  const result = streamText({
72
- model: openai("gpt-4o-mini"),
72
+ model: openai("gpt-5.4-nano"),
73
73
  messages: await convertToModelMessages(messages),
74
74
  });
75
75
  return result.toUIMessageStreamResponse();
@@ -85,7 +85,7 @@ export const maxDuration = 30;
85
85
  export async function POST(req: Request) {
86
86
  const { messages } = await req.json();
87
87
  const result = streamText({
88
- model: anthropic("claude-sonnet-4-20250514"),
88
+ model: anthropic("claude-sonnet-4-6"),
89
89
  messages: await convertToModelMessages(messages),
90
90
  });
91
91
  return result.toUIMessageStreamResponse();
@@ -3,9 +3,9 @@ title: Client and hooks
3
3
  description: A2AClient, useA2ARuntime options, hooks, task states, artifacts, errors.
4
4
  ---
5
5
 
6
- import { Network } from "lucide-react";
6
+ import { A2AIcon } from "@/components/icons/a2a";
7
7
 
8
- Deep dive on the runtime's API surface. Start with [overview](/docs/runtimes/a2a) and [quickstart](/docs/runtimes/a2a/quickstart) if you have not already.
8
+ Deep dive on the runtime's API surface. Start with [overview](/docs/runtimes/a2a/overview) and [quickstart](/docs/runtimes/a2a/quickstart) if you have not already.
9
9
 
10
10
  ## A2AClient
11
11
 
@@ -378,10 +378,10 @@ This prepends `/{tenant}` to all API paths (e.g. `/my-org/message:send`).
378
378
 
379
379
  <Cards>
380
380
  <Card
381
- icon={<Network width={20} height={20} />}
381
+ icon={<A2AIcon width={20} height={20} />}
382
382
  title="A2A overview"
383
383
  description="What A2A is and when to pick it."
384
- href="/docs/runtimes/a2a"
384
+ href="/docs/runtimes/a2a/overview"
385
385
  />
386
386
  <Card
387
387
  title="Quickstart"
@@ -1,6 +1,6 @@
1
1
  ---
2
- title: Overview
3
- description: Connect to any A2A v1.0 protocol-compliant agent server.
2
+ title: A2A Agent Runtime
3
+ description: Connect any A2A v1.0 protocol-compliant agent server to a React chat UI with assistant-ui — full streaming, tool calls, and message metadata supported.
4
4
  ---
5
5
 
6
6
  `@assistant-ui/react-a2a` is a runtime adapter for the [A2A (Agent-to-Agent) v1.0 protocol](https://github.com/a2aproject/A2A). Use it when your backend speaks A2A; the adapter handles the wire protocol so you can focus on the UI.
@@ -1,6 +1,6 @@
1
1
  ---
2
- title: Overview
3
- description: Connect to AG-UI (Agent-User Interaction) protocol agents.
2
+ title: AG-UI Agent Runtime
3
+ description: Wire AG-UI (Agent-User Interaction) protocol agents into a React chat UI with assistant-ui — bidirectional events, generative UI, and human-in-the-loop.
4
4
  ---
5
5
 
6
6
  `@assistant-ui/react-ag-ui` is a runtime adapter for the [AG-UI (Agent-User Interaction) protocol](https://github.com/ag-ui-protocol/ag-ui). It lets your assistant-ui frontend speak to any AG-UI-compliant agent server, including CopilotKit-based backends.
@@ -62,13 +62,43 @@ const runtime = useAgUiRuntime({
62
62
  });
63
63
  ```
64
64
 
65
+ ## Interrupts (experimental)
66
+
67
+ <Callout type="warn">
68
+ The interrupt API is experimental and may change without notice.
69
+ </Callout>
70
+
71
+ When the agent emits `RUN_FINISHED` with `outcome = { type: "interrupt", interrupts: [...] }`, the active assistant message is marked `requires-action` with `reason: "interrupt"` and the `Interrupt[]` payload is written to `metadata.custom.agui.interrupts`. Render an approval / input UI from there.
72
+
73
+ `useAgUiRuntime` returns an `AgUiAssistantRuntime` with two extra methods:
74
+
75
+ | Method | Description |
76
+ | --- | --- |
77
+ | `unstable_getPendingInterrupts(): readonly AgUiInterrupt[]` | Snapshot of the open interrupts on the most recent assistant message. |
78
+ | `unstable_submitInterruptResponses(responses: ResumeEntry[]): Promise<void>` | Submits one `ResumeEntry` per open interrupt and resumes the run. |
79
+
80
+ `responses` must address every open interrupt; missing entries, unknown ids, or expired interrupts (`expiresAt`) reject before any network call. Each entry is `{ interruptId, status: "resolved" | "cancelled", payload? }`. The next `RunAgentInput` carries `resume: ResumeEntry[]`.
81
+
82
+ ```tsx
83
+ const runtime = useAgUiRuntime({ agent });
84
+ const pending = runtime.unstable_getPendingInterrupts();
85
+
86
+ await runtime.unstable_submitInterruptResponses(
87
+ pending.map((i) => ({
88
+ interruptId: i.id,
89
+ status: "resolved",
90
+ payload: { approved: true },
91
+ })),
92
+ );
93
+ ```
94
+
65
95
  ## Supported events
66
96
 
67
97
  The runtime parses the AG-UI event stream and maps each event type to assistant-ui state.
68
98
 
69
99
  | Event | Effect |
70
100
  | --- | --- |
71
- | `RUN_STARTED` / `RUN_FINISHED` | Toggles thread `isRunning`. |
101
+ | `RUN_STARTED` / `RUN_FINISHED` | Toggles thread `isRunning`. `RUN_FINISHED.outcome` is honored (success / interrupt). |
72
102
  | `RUN_CANCELLED` | Marks the in-flight assistant message as cancelled. |
73
103
  | `RUN_ERROR` | Marks the message as errored; fires `onError`. |
74
104
  | `TEXT_MESSAGE_START` / `_CONTENT` / `_END` | Streams text content into an assistant message. |
@@ -98,6 +128,7 @@ The runtime parses the AG-UI event stream and maps each event type to assistant-
98
128
  | Message editing | Yes |
99
129
  | Message reload | Yes |
100
130
  | Run resumption | Yes |
131
+ | Interrupts (human-in-the-loop) | Experimental (`unstable_*` API, see [Interrupts](#interrupts-experimental)) |
101
132
  | Multi-thread | Experimental (`adapters.threadList`) |
102
133
  | History persistence | Via [history adapter](/docs/runtimes/concepts/adapters#history-adapter) |
103
134
 
@@ -1,6 +1,6 @@
1
1
  ---
2
- title: Overview
3
- description: Vercel AI SDK integration for assistant-ui across major versions.
2
+ title: Vercel AI SDK Runtime
3
+ description: Connect the Vercel AI SDK to a React chat UI via assistant-ui — useChat hooks, custom transports, frontend tools, attachments, multi-step agents, and token usage.
4
4
  ---
5
5
 
6
6
  import { VercelIcon } from "@/components/icons/vercel";
@@ -35,7 +35,7 @@ import { openai } from "@ai-sdk/openai";
35
35
 
36
36
  export async function POST(req: Request) {
37
37
  const { messages } = await req.json();
38
- const result = streamText({ model: openai("gpt-4"), messages });
38
+ const result = streamText({ model: openai("gpt-5.4-nano"), messages });
39
39
  return result.toDataStreamResponse();
40
40
  }
41
41
  ```
@@ -53,7 +53,10 @@ import { useDataStreamRuntime } from "@assistant-ui/react-data-stream";
53
53
  import { Thread } from "@/components/assistant-ui/thread";
54
54
 
55
55
  export default function Home() {
56
- const runtime = useDataStreamRuntime({ api: "/api/chat" });
56
+ const runtime = useDataStreamRuntime({
57
+ api: "/api/chat",
58
+ protocol: "data-stream",
59
+ });
57
60
  return (
58
61
  <AssistantRuntimeProvider runtime={runtime}>
59
62
  <div className="h-full">
@@ -64,6 +67,8 @@ export default function Home() {
64
67
  }
65
68
  ```
66
69
 
70
+ AI SDK v4's `toDataStreamResponse()` emits the data stream wire format, so `protocol: "data-stream"` is required to pair with it; the default `protocol: "ui-message-stream"` expects the SSE format introduced in AI SDK v6.
71
+
67
72
  </Step>
68
73
  </Steps>
69
74
 
@@ -40,7 +40,7 @@ export const maxDuration = 30;
40
40
  export async function POST(req: Request) {
41
41
  const { messages }: { messages: Message[] } = await req.json();
42
42
  const result = streamText({
43
- model: openai("gpt-4o"),
43
+ model: openai("gpt-5.4-nano"),
44
44
  messages,
45
45
  tools: {
46
46
  get_current_weather: tool({
@@ -491,6 +491,8 @@ const runtime = useAISDKRuntime(chat);
491
491
 
492
492
  [`examples/with-ai-sdk-v6`](https://github.com/assistant-ui/assistant-ui/tree/main/examples/with-ai-sdk-v6) shows a complete reference implementation.
493
493
 
494
+ For responses that should survive a page reload mid-stream, see [Resumable streams](/docs/guides/resumable-streams), which wraps the same v6 byte stream in `assistant-stream/resumable`.
495
+
494
496
  ## Next
495
497
 
496
498
  <Cards>
@@ -504,4 +506,9 @@ const runtime = useAISDKRuntime(chat);
504
506
  description="Single-thread, AssistantCloud, custom thread list."
505
507
  href="/docs/runtimes/concepts/threads"
506
508
  />
509
+ <Card
510
+ title="Resumable streams"
511
+ description="Survive page reloads and connection drops mid-response."
512
+ href="/docs/guides/resumable-streams"
513
+ />
507
514
  </Cards>