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

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 (134) hide show
  1. package/.docs/organized/code-examples/waterfall.md +20 -22
  2. package/.docs/organized/code-examples/with-a2a.md +24 -24
  3. package/.docs/organized/code-examples/with-ag-ui.md +30 -25
  4. package/.docs/organized/code-examples/with-ai-sdk-v6.md +11 -9
  5. package/.docs/organized/code-examples/with-artifacts.md +49 -37
  6. package/.docs/organized/code-examples/with-assistant-transport.md +63 -51
  7. package/.docs/organized/code-examples/with-browser-extension.md +22 -10
  8. package/.docs/organized/code-examples/with-chain-of-thought.md +406 -87
  9. package/.docs/organized/code-examples/with-cloud-standalone.md +25 -24
  10. package/.docs/organized/code-examples/with-cloud.md +11 -9
  11. package/.docs/organized/code-examples/with-custom-thread-list.md +14 -12
  12. package/.docs/organized/code-examples/with-elevenlabs-conversational.md +23 -21
  13. package/.docs/organized/code-examples/with-elevenlabs-scribe.md +14 -13
  14. package/.docs/organized/code-examples/with-expo.md +44 -29
  15. package/.docs/organized/code-examples/with-external-store.md +9 -7
  16. package/.docs/organized/code-examples/with-ffmpeg.md +322 -285
  17. package/.docs/organized/code-examples/with-generative-ui.md +1066 -256
  18. package/.docs/organized/code-examples/with-google-adk.md +10 -8
  19. package/.docs/organized/code-examples/with-heat-graph.md +13 -11
  20. package/.docs/organized/code-examples/with-image-generation.md +19 -17
  21. package/.docs/organized/code-examples/with-interactables.md +317 -239
  22. package/.docs/organized/code-examples/with-langchain.md +14 -12
  23. package/.docs/organized/code-examples/with-langgraph.md +91 -83
  24. package/.docs/organized/code-examples/with-livekit.md +24 -22
  25. package/.docs/organized/code-examples/with-mcp.md +18 -12
  26. package/.docs/organized/code-examples/with-opencode.md +66 -66
  27. package/.docs/organized/code-examples/with-react-hook-form.md +19 -17
  28. package/.docs/organized/code-examples/with-react-ink.md +297 -102
  29. package/.docs/organized/code-examples/with-react-router.md +17 -15
  30. package/.docs/organized/code-examples/with-resumable-stream.md +15 -14
  31. package/.docs/organized/code-examples/with-store.md +78 -76
  32. package/.docs/organized/code-examples/with-tanstack.md +13 -14
  33. package/.docs/organized/code-examples/with-tap-runtime.md +26 -24
  34. package/.docs/raw/docs/(docs)/architecture.mdx +94 -42
  35. package/.docs/raw/docs/(docs)/cli.mdx +1 -2
  36. package/.docs/raw/docs/(docs)/installation.mdx +1 -1
  37. package/.docs/raw/docs/(reference)/api-reference/adapters/persistence.mdx +5 -1
  38. package/.docs/raw/docs/(reference)/api-reference/external-store/message-conversion.mdx +15 -15
  39. package/.docs/raw/docs/(reference)/api-reference/external-store/runtime.mdx +14 -1
  40. package/.docs/raw/docs/(reference)/api-reference/generative-ui/index.mdx +18 -0
  41. package/.docs/raw/docs/(reference)/api-reference/generative-ui/rendering.mdx +33 -0
  42. package/.docs/raw/docs/(reference)/api-reference/generative-ui/spec.mdx +45 -0
  43. package/.docs/raw/docs/(reference)/api-reference/hooks/composer-triggers.mdx +41 -41
  44. package/.docs/raw/docs/(reference)/api-reference/hooks/model-context.mdx +19 -1
  45. package/.docs/raw/docs/(reference)/api-reference/hooks/primitives.mdx +122 -122
  46. package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +43 -2
  47. package/.docs/raw/docs/(reference)/api-reference/model-context/context.mdx +6 -0
  48. package/.docs/raw/docs/(reference)/api-reference/overview.mdx +4 -6
  49. package/.docs/raw/docs/(reference)/api-reference/primitives/message.mdx +30 -0
  50. package/.docs/raw/docs/(reference)/api-reference/tools/component-tools.mdx +20 -3
  51. package/.docs/raw/docs/(reference)/api-reference/tools/index.mdx +8 -8
  52. package/.docs/raw/docs/(reference)/api-reference/tools/rendering.mdx +52 -4
  53. package/.docs/raw/docs/(reference)/api-reference/tools/toolkits.mdx +100 -10
  54. package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +7 -59
  55. package/.docs/raw/docs/cloud/ai-sdk.mdx +0 -2
  56. package/.docs/raw/docs/{(docs)/copilots → copilots}/model-context.mdx +34 -26
  57. package/.docs/raw/docs/{(docs)/copilots → copilots}/motivation.mdx +32 -26
  58. package/.docs/raw/docs/guides/chain-of-thought.mdx +7 -9
  59. package/.docs/raw/docs/guides/context-api.mdx +2 -1
  60. package/.docs/raw/docs/guides/index.mdx +3 -12
  61. package/.docs/raw/docs/guides/mentions.mdx +4 -4
  62. package/.docs/raw/docs/guides/slash-commands.mdx +1 -1
  63. package/.docs/raw/docs/guides/suggestions.mdx +1 -1
  64. package/.docs/raw/docs/ink/adapters.mdx +23 -1
  65. package/.docs/raw/docs/ink/hooks.mdx +101 -85
  66. package/.docs/raw/docs/ink/migration.mdx +1 -1
  67. package/.docs/raw/docs/ink/primitives.mdx +2 -2
  68. package/.docs/raw/docs/integrations/frameworks/ai-sdk.mdx +1 -1
  69. package/.docs/raw/docs/integrations/index.mdx +2 -2
  70. package/.docs/raw/docs/integrations/persistence/custom-adapter.mdx +17 -2
  71. package/.docs/raw/docs/migrations/toolkit-tools.mdx +232 -0
  72. package/.docs/raw/docs/primitives/chain-of-thought.mdx +10 -16
  73. package/.docs/raw/docs/primitives/message.mdx +9 -10
  74. package/.docs/raw/docs/react-native/hooks.mdx +62 -79
  75. package/.docs/raw/docs/react-native/migration.mdx +1 -1
  76. package/.docs/raw/docs/react-native/primitives.mdx +2 -2
  77. package/.docs/raw/docs/runtimes/a2a/client-and-hooks.mdx +3 -0
  78. package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +41 -0
  79. package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +122 -1
  80. package/.docs/raw/docs/runtimes/concepts/architecture.mdx +46 -4
  81. package/.docs/raw/docs/runtimes/concepts/threads.mdx +7 -1
  82. package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +54 -12
  83. package/.docs/raw/docs/runtimes/custom/external-store.mdx +62 -4
  84. package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +30 -7
  85. package/.docs/raw/docs/runtimes/google-adk/hooks.mdx +108 -38
  86. package/.docs/raw/docs/runtimes/langgraph/generative-ui.mdx +2 -2
  87. package/.docs/raw/docs/runtimes/langgraph/streaming.mdx +14 -1
  88. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +64 -50
  89. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +98 -86
  90. package/.docs/raw/docs/tools/backend.mdx +144 -0
  91. package/.docs/raw/docs/tools/defining-tools.mdx +538 -0
  92. package/.docs/raw/docs/tools/dynamic-tools.mdx +110 -0
  93. package/.docs/raw/docs/tools/generative-ui.mdx +214 -0
  94. package/.docs/raw/docs/tools/index.mdx +71 -0
  95. package/.docs/raw/docs/{guides → tools}/interactables.mdx +1 -1
  96. package/.docs/raw/docs/{integrations/tools → tools}/mcp.mdx +145 -50
  97. package/.docs/raw/docs/{guides → tools}/multi-agent.mdx +15 -17
  98. package/.docs/raw/docs/tools/tool-ui.mdx +967 -0
  99. package/.docs/raw/docs/{integrations/tools/react-mcp.mdx → tools/user-managed-mcp.mdx} +7 -7
  100. package/.docs/raw/docs/ui/directive-text.mdx +3 -3
  101. package/.docs/raw/docs/ui/mcp-config.mdx +4 -4
  102. package/.docs/raw/docs/ui/mermaid.mdx +16 -9
  103. package/.docs/raw/docs/ui/part-grouping.mdx +84 -50
  104. package/.docs/raw/docs/ui/reasoning.mdx +4 -5
  105. package/.docs/raw/docs/ui/tool-fallback.mdx +16 -0
  106. package/.docs/raw/docs/ui/tool-group.mdx +5 -6
  107. package/.docs/raw/docs/utilities/heat-graph.mdx +1 -1
  108. package/.docs/raw/docs/utilities/react-o11y.mdx +2 -2
  109. package/dist/constants.js.map +1 -1
  110. package/dist/index.d.ts.map +1 -1
  111. package/dist/index.js.map +1 -1
  112. package/dist/prepare-docs/code-examples.d.ts.map +1 -1
  113. package/dist/prepare-docs/code-examples.js.map +1 -1
  114. package/dist/prepare-docs/copy-raw.d.ts.map +1 -1
  115. package/dist/prepare-docs/copy-raw.js.map +1 -1
  116. package/dist/prepare-docs/prepare.js.map +1 -1
  117. package/dist/stdio.js.map +1 -1
  118. package/dist/tools/docs.js.map +1 -1
  119. package/dist/tools/examples.js.map +1 -1
  120. package/dist/tools/tests/test-setup.js.map +1 -1
  121. package/dist/utils/mdx.js.map +1 -1
  122. package/dist/utils/paths.d.ts.map +1 -1
  123. package/dist/utils/paths.js.map +1 -1
  124. package/package.json +5 -5
  125. package/.docs/organized/code-examples/with-parent-id-grouping.md +0 -596
  126. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool-ui.mdx +0 -151
  127. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool.mdx +0 -230
  128. package/.docs/raw/docs/guides/generative-ui.mdx +0 -142
  129. package/.docs/raw/docs/guides/tool-ui.mdx +0 -858
  130. package/.docs/raw/docs/guides/tools.mdx +0 -736
  131. /package/.docs/raw/docs/{(docs)/copilots → copilots}/assistant-frame.mdx +0 -0
  132. /package/.docs/raw/docs/{(docs)/copilots → copilots}/make-assistant-visible.mdx +0 -0
  133. /package/.docs/raw/docs/{(docs)/copilots → copilots}/use-assistant-instructions.mdx +0 -0
  134. /package/.docs/raw/docs/{guides → tools}/mcp-apps.mdx +0 -0
@@ -117,7 +117,7 @@ For most new code, prefer `MessagePrimitive.Parts` with a `children` render func
117
117
  Tool call parts resolve in this order:
118
118
 
119
119
  1. **`tools.Override`**: if provided inline through the deprecated `components` prop, handles **all** tool calls
120
- 2. **Globally registered tools**: tools registered via `makeAssistantTool` / `useAssistantToolUI`
120
+ 2. **Globally registered tools**: tools registered via `Tools({ toolkit })`
121
121
  3. **`tools.by_name[toolName]`**: per-`MessagePrimitive.Parts` inline overrides from the deprecated `components` prop
122
122
  4. **`tools.Fallback`**: catch-all for unmatched tool calls from the deprecated `components` prop
123
123
  5. **`part.toolUI`**: the resolved tool UI exposed directly in the children render function
@@ -250,17 +250,16 @@ Renders each content part with type-based component resolution.
250
250
 
251
251
  ### GroupedParts
252
252
 
253
- Groups adjacent message parts into a nested tree. Use `groupBy` to return group keys for parts that should be grouped, then switch on `part.type` in the render function. Group cases render `children`; leaf cases render their own UI.
253
+ Groups adjacent message parts into a nested tree. Use `groupBy` to map each part to a group-key path, then switch on `part.type` in the render function. Group cases render `children`; leaf cases render their own UI. Prefer the `groupPartByType` helper for the common `part.type → path` case.
254
254
 
255
255
  ```tsx
256
+ import { MessagePrimitive, groupPartByType } from "@assistant-ui/react";
257
+
256
258
  <MessagePrimitive.GroupedParts
257
- groupBy={(part) => {
258
- if (part.type === "reasoning")
259
- return ["group-chainOfThought", "group-reasoning"];
260
- if (part.type === "tool-call")
261
- return ["group-chainOfThought", "group-tool"];
262
- return null;
263
- }}
259
+ groupBy={groupPartByType({
260
+ reasoning: ["group-chainOfThought", "group-reasoning"],
261
+ "tool-call": ["group-chainOfThought", "group-tool"],
262
+ })}
264
263
  >
265
264
  {({ part, children }) => {
266
265
  switch (part.type) {
@@ -514,7 +513,7 @@ import { MessagePrimitive, AuiIf } from "@assistant-ui/react";
514
513
  </MessagePrimitive.Root>;
515
514
  ```
516
515
 
517
- `s.message.status` is a discriminated union of `running | requires-action | complete | incomplete`, defined only on assistant messages. The `role === "assistant"` guard keeps the predicate type-safe. For tool-call-driven generative UI that defers rendering inside the part itself, see [Deferred Rendering](/docs/guides/tool-ui#deferred-rendering) in the Generative UI guide.
516
+ `s.message.status` is a discriminated union of `running | requires-action | complete | incomplete`, defined only on assistant messages. The `role === "assistant"` guard keeps the predicate type-safe. For tool-call-driven generative UI that defers rendering inside the part itself, see [Deferred Rendering](/docs/tools/tool-ui#deferred-rendering) in the Generative UI guide.
518
517
 
519
518
  ### Legacy and Unstable APIs
520
519
 
@@ -114,52 +114,54 @@ const runtime = useRemoteThreadListRuntime({
114
114
 
115
115
  ## Model Context Hooks
116
116
 
117
- ### useAssistantTool
117
+ ### Tools
118
118
 
119
- Register a tool with an optional UI renderer. The tool definition is forwarded to the model, and when the model calls it, the `execute` function runs and the `render` component displays the result.
119
+ Author tools in a `"use generative"` file with `defineToolkit`, the same API as on the web ([Defining Tools](/docs/tools/defining-tools)). The tool definition is forwarded to the model; when the model calls it, the `execute` function runs and the `render` component displays the result.
120
120
 
121
- ```tsx
122
- import { useAssistantTool } from "@assistant-ui/react-native";
123
-
124
- useAssistantTool({
125
- toolName: "get_weather",
126
- description: "Get the current weather for a city",
127
- parameters: {
128
- type: "object",
129
- properties: {
130
- city: { type: "string" },
121
+ Add the [`@assistant-ui/metro`](https://www.npmjs.com/package/@assistant-ui/metro) plugin so Metro compiles the `"use generative"` directive:
122
+
123
+ ```js title="metro.config.js"
124
+ const { getDefaultConfig } = require("expo/metro-config");
125
+ const { withAui } = require("@assistant-ui/metro");
126
+
127
+ module.exports = withAui(getDefaultConfig(__dirname));
128
+ ```
129
+
130
+ ```tsx title="weather-toolkit.tsx"
131
+ "use generative";
132
+
133
+ import { defineToolkit } from "@assistant-ui/react-native";
134
+ import { Text, View } from "react-native";
135
+ import { z } from "zod";
136
+
137
+ export default defineToolkit({
138
+ get_weather: {
139
+ description: "Get the current weather for a city",
140
+ parameters: z.object({ city: z.string() }),
141
+ execute: async ({ city }) => {
142
+ "use client";
143
+ const res = await fetch(`https://api.weather.example/${city}`);
144
+ return res.json();
131
145
  },
132
- required: ["city"],
146
+ render: ({ args, result }) => (
147
+ <View>
148
+ <Text>
149
+ {args.city}: {result?.temperature}°F
150
+ </Text>
151
+ </View>
152
+ ),
133
153
  },
134
- execute: async ({ city }) => {
135
- const res = await fetch(`https://api.weather.example/${city}`);
136
- return res.json();
137
- },
138
- render: ({ args, result }) => (
139
- <View>
140
- <Text>{args.city}: {result?.temperature}°F</Text>
141
- </View>
142
- ),
143
154
  });
144
155
  ```
145
156
 
146
- ### useAssistantToolUI
157
+ ```tsx title="ToolProvider.tsx"
158
+ import { AuiProvider, Tools, useAui } from "@assistant-ui/react-native";
159
+ import toolkit from "./weather-toolkit";
147
160
 
148
- Register only a UI renderer for a tool (without tool definition or execute function).
149
-
150
- ```tsx
151
- import { useAssistantToolUI } from "@assistant-ui/react-native";
152
-
153
- useAssistantToolUI({
154
- toolName: "get_weather",
155
- render: ({ args, result, status }) => (
156
- <View>
157
- {status?.type === "running"
158
- ? <Text>Loading weather for {args.city}...</Text>
159
- : <Text>{args.city}: {result?.temperature}°F</Text>}
160
- </View>
161
- ),
162
- });
161
+ function ToolProvider({ children }: { children: React.ReactNode }) {
162
+ const aui = useAui({ tools: Tools({ toolkit }) });
163
+ return <AuiProvider value={aui}>{children}</AuiProvider>;
164
+ }
163
165
  ```
164
166
 
165
167
  ### useAssistantDataUI
@@ -193,49 +195,30 @@ useAssistantInstructions("You are a helpful weather assistant.");
193
195
 
194
196
  Wrap a tool UI component so that inline state updates (from a parent component's render) are reflected without remounting. Use this when the render function closes over props that change over time.
195
197
 
196
- ```tsx
197
- import { useInlineRender } from "@assistant-ui/react-native";
198
-
199
- const stableRender = useInlineRender(({ args, result }) => (
200
- <Text>{someOuterProp}: {result?.value}</Text>
201
- ));
202
-
203
- useAssistantToolUI({ toolName: "my_tool", render: stableRender });
204
- ```
205
-
206
- ### makeAssistantTool
207
-
208
- Create a component that registers a tool when mounted. Useful for declarative tool registration.
209
-
210
- ```tsx
211
- import { makeAssistantTool } from "@assistant-ui/react-native";
212
-
213
- const WeatherTool = makeAssistantTool({
214
- toolName: "get_weather",
215
- description: "Get weather",
216
- parameters: { type: "object", properties: { city: { type: "string" } }, required: ["city"] },
217
- execute: async ({ city }) => ({ temperature: 72 }),
218
- render: ({ args, result }) => <Text>{args.city}: {result?.temperature}°F</Text>,
219
- });
220
-
221
- // Mount inside AssistantRuntimeProvider to register
222
- <WeatherTool />
198
+ ```tsx title="my-tool-toolkit.tsx"
199
+ import { defineToolkit, useInlineRender } from "@assistant-ui/react-native";
200
+ import { Text } from "react-native";
201
+ import { useMemo } from "react";
202
+
203
+ export function useMyToolToolkit(someOuterProp: string) {
204
+ const stableRender = useInlineRender(({ args, result }) => (
205
+ <Text>{someOuterProp}: {result?.value}</Text>
206
+ ));
207
+
208
+ return useMemo(
209
+ () =>
210
+ defineToolkit({
211
+ my_tool: {
212
+ type: "backend",
213
+ render: stableRender,
214
+ },
215
+ }),
216
+ [stableRender],
217
+ );
218
+ }
223
219
  ```
224
220
 
225
- ### makeAssistantToolUI
226
-
227
- Create a component that registers only a tool UI renderer when mounted.
228
-
229
- ```tsx
230
- import { makeAssistantToolUI } from "@assistant-ui/react-native";
231
-
232
- const WeatherToolUI = makeAssistantToolUI({
233
- toolName: "get_weather",
234
- render: ({ args, result }) => <Text>{args.city}: {result?.temperature}°F</Text>,
235
- });
236
-
237
- <WeatherToolUI />
238
- ```
221
+ Import the toolkit hook, pass its result to `useAui({ tools: Tools({ toolkit }) })`, and provide the returned `aui` with `AuiProvider`, as shown in the [Tools](#tools) section above.
239
222
 
240
223
  ### makeAssistantDataUI
241
224
 
@@ -9,7 +9,7 @@ If you already have an assistant-ui web app, most of your code transfers directl
9
9
 
10
10
  - **Runtime setup** — `useChatRuntime`, `useLocalRuntime`, `ChatModelAdapter`, and all runtime options work identically.
11
11
  - **AI SDK integration** — `@assistant-ui/react-ai-sdk` works with React Native. Your `useChatRuntime` + `AssistantChatTransport` setup transfers directly.
12
- - **Tool definitions** — `useAssistantTool`, `makeAssistantTool`, and tool UI renderers use the same API.
12
+ - **Tool definitions** — `Tools({ toolkit })` and toolkit renderers use the same API.
13
13
  - **State hooks** — `useAuiState`, `useAui`, and selector patterns are the same.
14
14
  - **Backend code** — Your API routes, streaming endpoints, and server-side logic need zero changes.
15
15
 
@@ -338,7 +338,7 @@ Container `View` for a single message.
338
338
 
339
339
  ### MessagePrimitive.Content
340
340
 
341
- Renders message content parts using render-prop functions instead of the component-map approach used by `MessagePrimitive.Parts`. Each part type receives a `part` object and its `index`. Registered tool UIs (via `useAssistantTool`) are automatically dispatched and take priority over `renderToolCall`.
341
+ Renders message content parts using render-prop functions instead of the component-map approach used by `MessagePrimitive.Parts`. Each part type receives a `part` object and its `index`. Registered toolkit renderers are automatically dispatched and take priority over `renderToolCall`.
342
342
 
343
343
  ```tsx
344
344
  <MessagePrimitive.Content
@@ -364,7 +364,7 @@ Renders message content parts using render-prop functions instead of the compone
364
364
 
365
365
  ### MessagePrimitive.Parts
366
366
 
367
- Renders message content parts via a `components` prop. Tool call and data parts automatically render registered tool UIs (via `useAssistantTool` / `useAssistantDataUI`), falling back to components provided here. A default `Text` component using React Native's `<Text>` is provided out of the box.
367
+ Renders message content parts via a `components` prop. Tool call and data parts automatically render registered toolkit renderers and data UIs (via `useAssistantDataUI`), falling back to components provided here. A default `Text` component using React Native's `<Text>` is provided out of the box.
368
368
 
369
369
  ```tsx
370
370
  <MessagePrimitive.Parts>
@@ -19,6 +19,7 @@ const client = new A2AClient({
19
19
  headers: { Authorization: "Bearer <token>" },
20
20
  tenant: "my-org",
21
21
  extensions: ["urn:a2a:ext:my-extension"],
22
+ fetchOptions: { credentials: "include" },
22
23
  });
23
24
  ```
24
25
 
@@ -37,6 +38,7 @@ const runtime = useA2ARuntime({ client });
37
38
  | `headers` | `Record<string, string>` or `() => Record<string, string>` | Static or dynamic headers (e.g. for auth tokens). |
38
39
  | `tenant` | `string` | Tenant ID for multi-tenant servers (prepended to URL paths). |
39
40
  | `extensions` | `string[]` | Extension URIs to negotiate via `A2A-Extensions` header. |
41
+ | `fetchOptions` | `RequestInit` (partial) | Extra fetch options applied to every request (e.g. `{ credentials: "include" }`). `headers`, `body`, `method`, and `signal` are managed internally. |
40
42
 
41
43
  ### Client methods
42
44
 
@@ -67,6 +69,7 @@ Pass either a pre-built `client` or a `baseUrl` (the runtime creates a client fo
67
69
  | `tenant` | `string` | Tenant ID for multi-tenant servers. Only used with `baseUrl`. |
68
70
  | `headers` | `Record<string, string>` or `() => Record<string, string>` | Headers for the auto-created client. |
69
71
  | `extensions` | `string[]` | Extension URIs to negotiate. Only used with `baseUrl`. |
72
+ | `fetchOptions` | `RequestInit` (partial) | Extra fetch options for the auto-created client (e.g. `{ credentials: "include" }`). `headers`, `body`, `method`, and `signal` are managed internally. Only used with `baseUrl`. |
70
73
  | `contextId` | `string` | Initial context ID for the conversation. |
71
74
  | `configuration` | `A2ASendMessageConfiguration` | Default send message configuration. |
72
75
  | `onError` | `(error: Error) => void` | Error callback. |
@@ -29,6 +29,47 @@ Reference for the runtime's API surface. Start with [quickstart](/docs/runtimes/
29
29
  | History | `adapters.history` | Per-thread message persistence. |
30
30
  | Thread list | `adapters.threadList` | Multi-thread switching (experimental, see below). |
31
31
 
32
+ ## Loading conversation history
33
+
34
+ If your backend exposes the persisted AG-UI messages of a conversation (for
35
+ example a `GET /agents/state` endpoint), use `fromAgUiMessages` to convert them
36
+ to assistant-ui messages and return them from the history adapter so the thread
37
+ is restored on page load:
38
+
39
+ ```tsx
40
+ import { fromAgUiMessages } from "@assistant-ui/react-ag-ui";
41
+ import { ExportedMessageRepository } from "@assistant-ui/react";
42
+
43
+ const runtime = useAgUiRuntime({
44
+ agent,
45
+ adapters: {
46
+ history: {
47
+ async load() {
48
+ const { messages } = await fetch("/agents/state").then((r) => r.json());
49
+ return ExportedMessageRepository.fromArray(fromAgUiMessages(messages));
50
+ },
51
+ async append({ message }) {
52
+ // persist the newly sent message on your backend
53
+ },
54
+ },
55
+ },
56
+ });
57
+ ```
58
+
59
+ Messages sent during the session are always forwarded to the agent through the
60
+ run input, independent of `append`. A no-op `append` is therefore only safe when
61
+ your backend already persists the conversation on its own; otherwise those
62
+ messages are gone on the next page load.
63
+
64
+ `fromAgUiMessages` accepts an optional second argument: pass
65
+ `{ showThinking: false }` to match a runtime configured with
66
+ `showThinking: false`, so imported reasoning messages are dropped at conversion
67
+ time, the same way a live run never stores them.
68
+
69
+ `fromAgUiMessages` reconstructs the text, reasoning, and tool calls of each
70
+ message. Non-text message content such as images and files is not restored, so a
71
+ backend that persists multimodal messages loads only their text on reload.
72
+
32
73
  ## Thread list (experimental)
33
74
 
34
75
  <Callout type="warn">
@@ -254,7 +254,7 @@ export async function POST(req: Request) {
254
254
  }
255
255
  ```
256
256
 
257
- Frontend tools are registered through `useAui` (see the [tools guide](/docs/guides/tools)) and serialized for the backend via `frontendTools`.
257
+ Frontend tools are registered through `useAui` (see the [tools guide](/docs/tools/defining-tools)) and serialized for the backend via `frontendTools`.
258
258
 
259
259
  ## Multi-step tool calls
260
260
 
@@ -286,6 +286,127 @@ export async function POST(req: Request) {
286
286
 
287
287
  Without a `stopWhen`, AI SDK runs a single inference step. Set `stepCountIs` (or one of AI SDK's other stop conditions) when your tools chain multiple calls.
288
288
 
289
+ ## Server-side tool approval
290
+
291
+ AI SDK v6 lets a tool gate its own execution with `needsApproval`. The server pauses, emits an `approval-requested` part, and resumes once the client posts an approval response. assistant-ui surfaces the gate as `approval` on the tool part and adds a `respondToApproval` prop on the renderer, so tool components stay decoupled from `chatHelpers`.
292
+
293
+ On the backend, mark the tool with `needsApproval` (boolean or function):
294
+
295
+ ```ts title="@/app/api/chat/route.ts"
296
+ import { openai } from "@ai-sdk/openai";
297
+ import { streamText, convertToModelMessages, tool } from "ai";
298
+ import { z } from "zod";
299
+
300
+ export async function POST(req: Request) {
301
+ const { messages } = await req.json();
302
+
303
+ const result = streamText({
304
+ model: openai("gpt-5.4-mini"),
305
+ messages: await convertToModelMessages(messages),
306
+ tools: {
307
+ deploy: tool({
308
+ description: "Deploy the current build to an environment.",
309
+ inputSchema: z.object({ target: z.string() }),
310
+ needsApproval: ({ input }) => input.target === "production",
311
+ execute: async ({ target }) => ({ deployed: target }),
312
+ }),
313
+ },
314
+ });
315
+
316
+ return result.toUIMessageStreamResponse();
317
+ }
318
+ ```
319
+
320
+ On the client, configure `useChat` with `sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses` so the response is sent back to the server when the user decides:
321
+
322
+ ```tsx title="@/app/page.tsx"
323
+ "use client";
324
+
325
+ import { useChat } from "@ai-sdk/react";
326
+ import {
327
+ AssistantRuntimeProvider,
328
+ useAISDKRuntime,
329
+ } from "@assistant-ui/react-ai-sdk";
330
+ import { lastAssistantMessageIsCompleteWithApprovalResponses } from "ai";
331
+ import { Thread } from "@/components/assistant-ui/thread";
332
+
333
+ export default function Page() {
334
+ const chat = useChat({
335
+ api: "/api/chat",
336
+ sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses,
337
+ });
338
+ const runtime = useAISDKRuntime(chat);
339
+
340
+ return (
341
+ <AssistantRuntimeProvider runtime={runtime}>
342
+ <Thread />
343
+ </AssistantRuntimeProvider>
344
+ );
345
+ }
346
+ ```
347
+
348
+ Render the gate with a toolkit entry. The `approval` field carries the gate state, and `respondToApproval` is the only correct way to acknowledge it (it reads the approval id from the part):
349
+
350
+ ```tsx title="@/app/page.tsx"
351
+ "use client";
352
+
353
+ import { useChat } from "@ai-sdk/react";
354
+ import {
355
+ AssistantRuntimeProvider,
356
+ defineToolkit,
357
+ Tools,
358
+ useAui,
359
+ } from "@assistant-ui/react";
360
+ import { useAISDKRuntime } from "@assistant-ui/react-ai-sdk";
361
+ import { lastAssistantMessageIsCompleteWithApprovalResponses } from "ai";
362
+ import { Thread } from "@/components/assistant-ui/thread";
363
+
364
+ const toolkit = defineToolkit({
365
+ deploy: {
366
+ type: "backend",
367
+ render: ({ args, approval, respondToApproval, result }) => {
368
+ if (approval?.approved === undefined) {
369
+ return (
370
+ <div>
371
+ <p>Approve deploy to {args.target}?</p>
372
+ <button onClick={() => respondToApproval({ approved: true })}>
373
+ Approve
374
+ </button>
375
+ <button
376
+ onClick={() =>
377
+ respondToApproval({ approved: false, reason: "user denied" })
378
+ }
379
+ >
380
+ Deny
381
+ </button>
382
+ </div>
383
+ );
384
+ }
385
+ if (approval?.approved === false) return <p>Denied</p>;
386
+ if (result === undefined) return <p>Approved, deploying…</p>;
387
+ return <p>Deployed {result.deployed}</p>;
388
+ },
389
+ },
390
+ });
391
+
392
+ export default function Page() {
393
+ const chat = useChat({
394
+ api: "/api/chat",
395
+ sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses,
396
+ });
397
+ const runtime = useAISDKRuntime(chat);
398
+ const aui = useAui({ tools: Tools({ toolkit }) });
399
+
400
+ return (
401
+ <AssistantRuntimeProvider aui={aui} runtime={runtime}>
402
+ <Thread />
403
+ </AssistantRuntimeProvider>
404
+ );
405
+ }
406
+ ```
407
+
408
+ See the [tool UI guide](/docs/tools/tool-ui#server-side-approval-gates) for the full three-state semantics of `approval.approved` and the `isAutomatic` flag.
409
+
289
410
  ## Quote context
290
411
 
291
412
  assistant-ui's composer can attach quote metadata to user messages (e.g. when the user selects text and clicks "Quote"). On the server, `injectQuoteContext` flattens that metadata into a markdown blockquote prefix so the LLM sees the quoted text:
@@ -7,8 +7,8 @@ assistant-ui exposes runtime integrations at three layers. Understanding which l
7
7
 
8
8
  ## The three layers
9
9
 
10
- ```mermaid
11
- graph TD
10
+ <Flow.Root
11
+ llm={`graph TD
12
12
  subgraph Framework["Framework adapters"]
13
13
  A1[react-ai-sdk]
14
14
  A2[react-langgraph]
@@ -34,8 +34,50 @@ graph TD
34
34
  A6 --> C2
35
35
  A7 --> C2
36
36
  P1 --> C1
37
- P2 --> C2
38
- ```
37
+ P2 --> C2`}
38
+ >
39
+ <Flow.Canvas
40
+ edges={[
41
+ { from: "datastream", to: "local", route: "down", midFrac: 0.4, laneOffset: -60 },
42
+ { from: "transport", to: "external", route: "down", midFrac: 0.65, toOffset: -14 },
43
+ { from: "adapters", to: "external", route: "down", midFrac: 0.4, toOffset: 14 },
44
+ ]}
45
+ >
46
+ <div className="grid max-w-2xl grid-cols-[1fr_1.6fr] gap-4">
47
+ <Flow.Group>
48
+ <Flow.GroupLabel>Protocol layers</Flow.GroupLabel>
49
+ <Flow.Column className="items-stretch gap-5">
50
+ <Flow.Row className="justify-start">
51
+ <Flow.Node flowId="datastream">DataStream</Flow.Node>
52
+ </Flow.Row>
53
+ <Flow.Row className="justify-end">
54
+ <Flow.Node flowId="transport">AssistantTransport</Flow.Node>
55
+ </Flow.Row>
56
+ </Flow.Column>
57
+ </Flow.Group>
58
+ <Flow.Group flowId="adapters">
59
+ <Flow.GroupLabel>Framework adapters</Flow.GroupLabel>
60
+ <Flow.Row className="flex-wrap justify-start">
61
+ <Flow.Node>react-ai-sdk</Flow.Node>
62
+ <Flow.Node>react-langgraph</Flow.Node>
63
+ <Flow.Node>react-langchain</Flow.Node>
64
+ <Flow.Node>react-google-adk</Flow.Node>
65
+ <Flow.Node>react-a2a</Flow.Node>
66
+ <Flow.Node>react-ag-ui</Flow.Node>
67
+ <Flow.Node>react-opencode</Flow.Node>
68
+ </Flow.Row>
69
+ </Flow.Group>
70
+ </div>
71
+ <div className="h-14" aria-hidden />
72
+ <Flow.Group className="mx-auto w-fit">
73
+ <Flow.GroupLabel>Core runtimes</Flow.GroupLabel>
74
+ <Flow.Row className="gap-10">
75
+ <Flow.Node flowId="local">LocalRuntime</Flow.Node>
76
+ <Flow.Node flowId="external">ExternalStoreRuntime</Flow.Node>
77
+ </Flow.Row>
78
+ </Flow.Group>
79
+ </Flow.Canvas>
80
+ </Flow.Root>
39
81
 
40
82
  Each upper layer is implemented in terms of a lower one. You can drop down a layer whenever you need more control, but most users start at the framework layer and never touch the others.
41
83
 
@@ -287,6 +287,12 @@ A few invariants worth knowing when wiring a custom UI on top of `loadMore()`:
287
287
  description: "Persist title changes from the UI.",
288
288
  required: true,
289
289
  },
290
+ {
291
+ name: "updateCustom",
292
+ type: "(remoteId: string, custom: Record<string, unknown> | undefined) => Promise<void>",
293
+ description:
294
+ "Optional. Persist replacement custom metadata from `aui.threadListItem().updateCustom(custom)`.",
295
+ },
290
296
  {
291
297
  name: "archive",
292
298
  type: "(remoteId: string) => Promise<void>",
@@ -355,7 +361,7 @@ function ThreadListItemMeta() {
355
361
  }
356
362
  ```
357
363
 
358
- `custom` is preserved across `rename`, `archive`, `unarchive`, and `generateTitle`. To mutate it, return updated values from a subsequent `fetch()` or call `runtime.threads.reload()`.
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()`.
359
365
 
360
366
  ## ExternalStoreThreadListAdapter
361
367
 
@@ -25,11 +25,17 @@ If you only need message streaming, [DataStream](/docs/runtimes/custom/data-stre
25
25
 
26
26
  ## Mental model
27
27
 
28
- ```mermaid
29
- graph LR
28
+ <Flow.Root
29
+ llm={`graph LR
30
30
  Frontend -->|Commands| Agent[Agent server]
31
- Agent -->|State snapshots| Frontend
32
- ```
31
+ Agent -->|State snapshots| Frontend`}
32
+ >
33
+ <Flow.Row>
34
+ <Flow.Node>Frontend</Flow.Node>
35
+ <Flow.Arrow label="Commands" reverseLabel="State snapshots" length={150} />
36
+ <Flow.Node>Agent server</Flow.Node>
37
+ </Flow.Row>
38
+ </Flow.Root>
33
39
 
34
40
  The frontend receives state snapshots and converts them to React components. The UI is a stateless view on top of the agent state.
35
41
 
@@ -37,21 +43,57 @@ The agent server receives commands from the frontend. When a user interacts with
37
43
 
38
44
  ### Command lifecycle
39
45
 
40
- ```mermaid
41
- graph LR
46
+ <Flow.Root
47
+ llm={`graph LR
42
48
  queued -->|sent to backend| in_transit
43
- in_transit -->|backend processes| applied
44
- ```
49
+ in_transit -->|backend processes| applied`}
50
+ >
51
+ <Flow.Row>
52
+ <Flow.Node>queued</Flow.Node>
53
+ <Flow.Arrow label="sent to backend" length={120} />
54
+ <Flow.Node>in_transit</Flow.Node>
55
+ <Flow.Arrow label="backend processes" length={132} />
56
+ <Flow.Node>applied</Flow.Node>
57
+ </Flow.Row>
58
+ </Flow.Root>
45
59
 
46
60
  The runtime alternates between **idle** (no active backend request) and **sending** (request in flight). When a new command is created while idle, it is sent immediately; otherwise it is queued until the current request completes.
47
61
 
48
- ```mermaid
49
- graph LR
62
+ <Flow.Root
63
+ llm={`graph LR
50
64
  idle -->|new command| sending
51
65
  sending -->|request completes| check{check queue}
52
66
  check -->|queue has commands| sending
53
- check -->|queue empty| idle
54
- ```
67
+ check -->|queue empty| idle`}
68
+ >
69
+ <Flow.Canvas
70
+ edges={[
71
+ {
72
+ from: "check",
73
+ to: "sending",
74
+ route: "loop-bottom",
75
+ label: "queue has commands",
76
+ laneOffset: 28,
77
+ },
78
+ {
79
+ from: "check",
80
+ to: "idle",
81
+ route: "loop-bottom",
82
+ label: "queue empty",
83
+ laneOffset: 60,
84
+ },
85
+ ]}
86
+ >
87
+ <Flow.Row>
88
+ <Flow.Node flowId="idle">idle</Flow.Node>
89
+ <Flow.Arrow label="new command" length={108} />
90
+ <Flow.Node flowId="sending">sending</Flow.Node>
91
+ <Flow.Arrow label="request completes" length={132} />
92
+ <Flow.Node flowId="check" variant="decision">check queue</Flow.Node>
93
+ </Flow.Row>
94
+ <div className="h-20" aria-hidden />
95
+ </Flow.Canvas>
96
+ </Flow.Root>
55
97
 
56
98
  To implement this you build two pieces:
57
99