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

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 (112) hide show
  1. package/.docs/organized/code-examples/waterfall.md +15 -17
  2. package/.docs/organized/code-examples/with-a2a.md +19 -19
  3. package/.docs/organized/code-examples/with-ag-ui.md +25 -20
  4. package/.docs/organized/code-examples/with-ai-sdk-v6.md +6 -4
  5. package/.docs/organized/code-examples/with-artifacts.md +34 -28
  6. package/.docs/organized/code-examples/with-assistant-transport.md +59 -47
  7. package/.docs/organized/code-examples/with-browser-extension.md +17 -5
  8. package/.docs/organized/code-examples/with-chain-of-thought.md +376 -78
  9. package/.docs/organized/code-examples/with-cloud-standalone.md +20 -19
  10. package/.docs/organized/code-examples/with-cloud.md +6 -4
  11. package/.docs/organized/code-examples/with-custom-thread-list.md +9 -7
  12. package/.docs/organized/code-examples/with-elevenlabs-conversational.md +18 -16
  13. package/.docs/organized/code-examples/with-elevenlabs-scribe.md +9 -8
  14. package/.docs/organized/code-examples/with-expo.md +23 -17
  15. package/.docs/organized/code-examples/with-external-store.md +4 -2
  16. package/.docs/organized/code-examples/with-ffmpeg.md +317 -280
  17. package/.docs/organized/code-examples/with-generative-ui.md +1018 -214
  18. package/.docs/organized/code-examples/with-google-adk.md +4 -2
  19. package/.docs/organized/code-examples/with-heat-graph.md +8 -6
  20. package/.docs/organized/code-examples/with-image-generation.md +19 -17
  21. package/.docs/organized/code-examples/with-interactables.md +312 -234
  22. package/.docs/organized/code-examples/with-langchain.md +9 -7
  23. package/.docs/organized/code-examples/with-langgraph.md +82 -78
  24. package/.docs/organized/code-examples/with-livekit.md +19 -17
  25. package/.docs/organized/code-examples/with-mcp.md +13 -7
  26. package/.docs/organized/code-examples/with-opencode.md +61 -61
  27. package/.docs/organized/code-examples/with-react-hook-form.md +14 -12
  28. package/.docs/organized/code-examples/with-react-ink.md +2 -2
  29. package/.docs/organized/code-examples/with-react-router.md +11 -9
  30. package/.docs/organized/code-examples/with-resumable-stream.md +10 -9
  31. package/.docs/organized/code-examples/with-store.md +14 -12
  32. package/.docs/organized/code-examples/with-tanstack.md +8 -9
  33. package/.docs/organized/code-examples/with-tap-runtime.md +21 -19
  34. package/.docs/raw/docs/(docs)/architecture.mdx +43 -2
  35. package/.docs/raw/docs/(docs)/cli.mdx +1 -2
  36. package/.docs/raw/docs/(docs)/copilots/model-context.mdx +34 -26
  37. package/.docs/raw/docs/(docs)/copilots/motivation.mdx +32 -26
  38. package/.docs/raw/docs/(docs)/installation.mdx +1 -1
  39. package/.docs/raw/docs/(reference)/api-reference/adapters/persistence.mdx +5 -1
  40. package/.docs/raw/docs/(reference)/api-reference/external-store/message-conversion.mdx +14 -14
  41. package/.docs/raw/docs/(reference)/api-reference/external-store/runtime.mdx +11 -1
  42. package/.docs/raw/docs/(reference)/api-reference/generative-ui/index.mdx +18 -0
  43. package/.docs/raw/docs/(reference)/api-reference/generative-ui/rendering.mdx +33 -0
  44. package/.docs/raw/docs/(reference)/api-reference/generative-ui/spec.mdx +45 -0
  45. package/.docs/raw/docs/(reference)/api-reference/hooks/composer-triggers.mdx +41 -41
  46. package/.docs/raw/docs/(reference)/api-reference/hooks/model-context.mdx +19 -1
  47. package/.docs/raw/docs/(reference)/api-reference/hooks/primitives.mdx +122 -122
  48. package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +32 -2
  49. package/.docs/raw/docs/(reference)/api-reference/model-context/context.mdx +6 -0
  50. package/.docs/raw/docs/(reference)/api-reference/overview.mdx +4 -6
  51. package/.docs/raw/docs/(reference)/api-reference/primitives/message.mdx +30 -0
  52. package/.docs/raw/docs/(reference)/api-reference/tools/component-tools.mdx +20 -3
  53. package/.docs/raw/docs/(reference)/api-reference/tools/index.mdx +8 -8
  54. package/.docs/raw/docs/(reference)/api-reference/tools/rendering.mdx +52 -4
  55. package/.docs/raw/docs/(reference)/api-reference/tools/toolkits.mdx +6 -7
  56. package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +58 -46
  57. package/.docs/raw/docs/cloud/ai-sdk.mdx +0 -2
  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/hooks.mdx +98 -85
  65. package/.docs/raw/docs/ink/migration.mdx +1 -1
  66. package/.docs/raw/docs/ink/primitives.mdx +2 -2
  67. package/.docs/raw/docs/integrations/frameworks/ai-sdk.mdx +1 -1
  68. package/.docs/raw/docs/integrations/index.mdx +2 -2
  69. package/.docs/raw/docs/integrations/persistence/custom-adapter.mdx +17 -2
  70. package/.docs/raw/docs/migrations/toolkit-tools.mdx +226 -0
  71. package/.docs/raw/docs/primitives/chain-of-thought.mdx +10 -16
  72. package/.docs/raw/docs/primitives/message.mdx +9 -10
  73. package/.docs/raw/docs/react-native/hooks.mdx +57 -82
  74. package/.docs/raw/docs/react-native/migration.mdx +1 -1
  75. package/.docs/raw/docs/react-native/primitives.mdx +2 -2
  76. package/.docs/raw/docs/runtimes/a2a/client-and-hooks.mdx +3 -0
  77. package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +122 -1
  78. package/.docs/raw/docs/runtimes/concepts/threads.mdx +7 -1
  79. package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +18 -7
  80. package/.docs/raw/docs/runtimes/google-adk/hooks.mdx +108 -38
  81. package/.docs/raw/docs/runtimes/langgraph/generative-ui.mdx +2 -2
  82. package/.docs/raw/docs/runtimes/langgraph/streaming.mdx +1 -1
  83. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +64 -50
  84. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +98 -86
  85. package/.docs/raw/docs/tools/backend.mdx +136 -0
  86. package/.docs/raw/docs/tools/defining-tools.mdx +413 -0
  87. package/.docs/raw/docs/tools/dynamic-tools.mdx +110 -0
  88. package/.docs/raw/docs/tools/generative-ui.mdx +214 -0
  89. package/.docs/raw/docs/tools/index.mdx +76 -0
  90. package/.docs/raw/docs/{guides → tools}/interactables.mdx +1 -1
  91. package/.docs/raw/docs/{integrations/tools → tools}/mcp.mdx +77 -50
  92. package/.docs/raw/docs/{guides → tools}/multi-agent.mdx +17 -19
  93. package/.docs/raw/docs/tools/tool-ui.mdx +967 -0
  94. package/.docs/raw/docs/{integrations/tools/react-mcp.mdx → tools/user-managed-mcp.mdx} +3 -3
  95. package/.docs/raw/docs/ui/directive-text.mdx +3 -3
  96. package/.docs/raw/docs/ui/mcp-config.mdx +4 -4
  97. package/.docs/raw/docs/ui/part-grouping.mdx +84 -50
  98. package/.docs/raw/docs/ui/reasoning.mdx +4 -5
  99. package/.docs/raw/docs/ui/tool-group.mdx +5 -6
  100. package/.docs/raw/docs/utilities/heat-graph.mdx +1 -1
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/prepare-docs/code-examples.d.ts.map +1 -1
  103. package/dist/prepare-docs/copy-raw.d.ts.map +1 -1
  104. package/dist/utils/paths.d.ts.map +1 -1
  105. package/package.json +3 -3
  106. package/.docs/organized/code-examples/with-parent-id-grouping.md +0 -596
  107. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool-ui.mdx +0 -151
  108. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool.mdx +0 -230
  109. package/.docs/raw/docs/guides/generative-ui.mdx +0 -142
  110. package/.docs/raw/docs/guides/tool-ui.mdx +0 -858
  111. package/.docs/raw/docs/guides/tools.mdx +0 -736
  112. /package/.docs/raw/docs/{guides → tools}/mcp-apps.mdx +0 -0
@@ -475,7 +475,7 @@ Container `Box` for a single message.
475
475
 
476
476
  ### Parts
477
477
 
478
- 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. Default terminal-safe renderers are provided for text, reasoning, source, image, file, and data parts.
478
+ 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. Default terminal-safe renderers are provided for text, reasoning, source, image, file, and data parts.
479
479
 
480
480
  ```tsx
481
481
  <MessagePrimitive.Parts>
@@ -509,7 +509,7 @@ Override part rendering with app-owned components when you need richer terminal
509
509
  Deprecated. Use `MessagePrimitive.Parts` instead. See the [v0.11 migration guide](/docs/migrations/v0-11) for details.
510
510
  </Callout>
511
511
 
512
- Renders message content parts using render props. Tool call and data parts automatically render registered tool UIs (via `useAssistantTool` / `useAssistantDataUI`), falling back to render props if provided.
512
+ Renders message content parts using render props. Tool call and data parts automatically render registered toolkit renderers and data UIs (via `useAssistantDataUI`), falling back to render props if provided.
513
513
 
514
514
  ```tsx
515
515
  <MessagePrimitive.Content
@@ -52,7 +52,7 @@ Three versions of `ai` are supported. New projects should pick **v6**; v5 and v4
52
52
  AI SDK is the default choice for new projects on Next.js, Remix, or any framework with a Node-compatible API route. Pick it when:
53
53
 
54
54
  - You want a single direct path from the chat UI to your model with the smallest possible code surface.
55
- - You will compose with a framework like [Mastra](/docs/integrations/frameworks/mastra/overview), an [observability tool](/docs/integrations/observability/helicone), an [LLM gateway](/docs/integrations/gateways), or [tools through MCP](/docs/integrations/tools/mcp), all of which assume an AI SDK route.
55
+ - You will compose with a framework like [Mastra](/docs/integrations/frameworks/mastra/overview), an [observability tool](/docs/integrations/observability/helicone), an [LLM gateway](/docs/integrations/gateways), or [tools through MCP](/docs/tools/mcp), all of which assume an AI SDK route.
56
56
  - You want first-party `frontendTools`, attachments, multi-step tool calls, token-usage metadata, and persisted history via `withFormat`.
57
57
 
58
58
  If you need streaming agent state (subgraph events, generative UI messages), look at [LangGraph](/docs/runtimes/langgraph) instead. If you have a different protocol-shaped backend (A2A, AG-UI, OpenCode), see [pick a runtime](/docs/runtimes/pick-a-runtime).
@@ -60,14 +60,14 @@ Framework integrations that pair with assistant-ui at the API-route layer.
60
60
 
61
61
  ## Tools
62
62
 
63
- Pluggable tool catalogs and protocols.
63
+ Tool catalogs and protocols have their own [Tools](/docs/tools) section.
64
64
 
65
65
  <Cards>
66
66
  <Card
67
67
  icon={<McpIcon width={20} height={20} />}
68
68
  title="Model Context Protocol (MCP)"
69
69
  description="Connect any MCP server as a tool catalog through the AI SDK MCP client."
70
- href="/docs/integrations/tools/mcp"
70
+ href="/docs/tools/mcp"
71
71
  />
72
72
  </Cards>
73
73
 
@@ -65,7 +65,22 @@ export const messages = pgTable(
65
65
  );
66
66
  ```
67
67
 
68
- The four message columns (`id`, `parent_id`, `format`, `content`) are the contract `withFormat` writes against. `format` lets multiple runtimes coexist on one row (e.g., `"aisdk-v6"` from `useChatRuntime`, a different value from another runtime).
68
+ The four message columns (`id`, `parent_id`, `format`, `content`) are the contract `withFormat` writes against. `format` records which adapter encoded the row so multiple runtimes can coexist on one table; `useChatRuntime` sets it from `fmt.format`.
69
+
70
+ <Callout type="warn">
71
+ `content` is not arbitrary JSON. It must be the payload the active format adapter produced via `fmt.encode(item)`, and it is read back through `fmt.decode`; the route handlers below are a pass-through that never inspects it. For `useChatRuntime` (AI SDK v6) a valid stored row looks like:
72
+
73
+ ```json
74
+ {
75
+ "id": "msg_abc",
76
+ "parent_id": null,
77
+ "format": "ai-sdk/v6",
78
+ "content": { "role": "user", "parts": [{ "type": "text", "text": "hello" }] }
79
+ }
80
+ ```
81
+
82
+ A row that satisfies the column types but carries a different shape (e.g. `{ "foo": "bar" }`) is accepted on write, then fails history reload. Seed test data through the adapter, not by hand-crafting `content`.
83
+ </Callout>
69
84
 
70
85
  ## Setup
71
86
 
@@ -678,7 +693,7 @@ Send a message in a fresh thread. Check the database:
678
693
 
679
694
  - The `threads` table has a new row with the current `userId`.
680
695
  - The `messages` table has at least two rows (user + assistant) for that thread.
681
- - `format` is `"aisdk-v6"` (or whatever AI SDK's current format string is).
696
+ - `format` matches what `fmt.format` wrote (`"ai-sdk/v6"` for AI SDK v6) and `content` is the encoded `UIMessage` (a `role` plus `parts`), not a placeholder blob.
682
697
  - Reload the page; the thread list and the messages survive.
683
698
 
684
699
  </Step>
@@ -0,0 +1,226 @@
1
+ ---
2
+ title: Migrating Tools to Toolkits
3
+ description: Move makeAssistantTool, useAssistantTool, makeAssistantToolUI, and useAssistantToolUI registrations to the toolkit API.
4
+ ---
5
+
6
+ The component and hook based tool APIs are deprecated:
7
+
8
+ - `makeAssistantTool`
9
+ - `useAssistantTool`
10
+ - `makeAssistantToolUI`
11
+ - `useAssistantToolUI`
12
+
13
+ Use a toolkit registered with `Tools({ toolkit })` instead. Toolkits keep the model contract, browser execution, and tool-call rendering in one named map, which avoids duplicate registrations and makes the client/backend split explicit.
14
+
15
+ ## Before
16
+
17
+ ```tsx
18
+ import { AssistantRuntimeProvider, makeAssistantTool } from "@assistant-ui/react";
19
+ import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
20
+ import { z } from "zod";
21
+
22
+ const WeatherTool = makeAssistantTool({
23
+ toolName: "get_weather",
24
+ description: "Get the current weather for a city.",
25
+ parameters: z.object({
26
+ city: z.string(),
27
+ }),
28
+ execute: async ({ city }) => fetchWeather(city),
29
+ render: ({ args, result }) => (
30
+ <WeatherCard city={args.city} weather={result} />
31
+ ),
32
+ });
33
+
34
+ export function App() {
35
+ const runtime = useChatRuntime({ api: "/api/chat" });
36
+
37
+ return (
38
+ <AssistantRuntimeProvider runtime={runtime}>
39
+ <WeatherTool />
40
+ <Thread />
41
+ </AssistantRuntimeProvider>
42
+ );
43
+ }
44
+ ```
45
+
46
+ ## After
47
+
48
+ ```tsx title="app/toolkit.tsx"
49
+ "use generative";
50
+
51
+ import { defineToolkit } from "@assistant-ui/react";
52
+ import { z } from "zod";
53
+
54
+ export default defineToolkit({
55
+ get_weather: {
56
+ description: "Get the current weather for a city.",
57
+ parameters: z.object({
58
+ city: z.string(),
59
+ }),
60
+ execute: async ({ city }) => {
61
+ "use client";
62
+ return fetchWeather(city);
63
+ },
64
+ render: ({ args, result }) => (
65
+ <WeatherCard city={args.city} weather={result} />
66
+ ),
67
+ },
68
+ });
69
+ ```
70
+
71
+ ```tsx title="app/MyRuntimeProvider.tsx"
72
+ "use client";
73
+
74
+ import {
75
+ AssistantRuntimeProvider,
76
+ Tools,
77
+ useAui,
78
+ } from "@assistant-ui/react";
79
+ import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
80
+ import toolkit from "./toolkit";
81
+
82
+ export function App() {
83
+ const runtime = useChatRuntime({ api: "/api/chat" });
84
+ const aui = useAui({
85
+ tools: Tools({ toolkit }),
86
+ });
87
+
88
+ return (
89
+ <AssistantRuntimeProvider aui={aui} runtime={runtime}>
90
+ <Thread />
91
+ </AssistantRuntimeProvider>
92
+ );
93
+ }
94
+ ```
95
+
96
+ ## Mechanical Steps
97
+
98
+ 1. Create a `Toolkit` object.
99
+ 2. Move each `toolName` into the toolkit key.
100
+ 3. Move `description`, `parameters`, `execute`, `providerOptions`, `render`, `renderText`, and `display` onto the toolkit entry.
101
+ 4. Register the toolkit once with `useAui({ tools: Tools({ toolkit }) })`.
102
+ 5. Remove `<Tool />`, `<ToolUI />`, `useAssistantTool(...)`, and `useAssistantToolUI(...)` registrations.
103
+
104
+ ## UI-Only Tool Renderers
105
+
106
+ If you used `makeAssistantToolUI` or `useAssistantToolUI` for a backend, MCP, or LangGraph tool, the tool executes elsewhere, so there is no `execute` to author. That makes it a **render-only** entry, which belongs in a plain `satisfies Toolkit` object — not a `"use generative"` file (a generative tool must declare an `execute`). Author an explicit `type: "backend"` with just a `render`:
107
+
108
+ ```tsx
109
+ // app/tool-ui.tsx
110
+ "use client";
111
+
112
+ import type { Toolkit } from "@assistant-ui/react";
113
+
114
+ export const toolkit = {
115
+ web_search: {
116
+ type: "backend",
117
+ render: ({ args, result }) => (
118
+ <SearchResults query={args.query} results={result?.results ?? []} />
119
+ ),
120
+ },
121
+ } satisfies Toolkit;
122
+ ```
123
+
124
+ Register it like any toolkit: `useAui({ tools: Tools({ toolkit }) })`. Render-only entries upload no schema and run no browser code — they only attach UI for matching tool-call message parts.
125
+
126
+ For a one-off renderer that should only affect a particular message surface, use `MessagePrimitive.Parts` inline tool render overrides instead of a global registration.
127
+
128
+ ## Dynamic Tools
129
+
130
+ If a tool needs component state or props, keep the toolkit contract in a `"use generative"` file and use `stubTool()` for the executor. The component that owns the state supplies the real executor with `useAuiToolOverrides(...)`:
131
+
132
+ <Callout type="warn">
133
+ `useAuiToolOverrides` is experimental and its API may change.
134
+ </Callout>
135
+
136
+ ```tsx title="task-board-toolkit.tsx"
137
+ "use generative";
138
+
139
+ import { defineToolkit, stubTool } from "@assistant-ui/react";
140
+ import { z } from "zod";
141
+
142
+ export type Task = { id: string; title: string };
143
+
144
+ export default defineToolkit({
145
+ add_task: {
146
+ description: "Add a task to the board.",
147
+ parameters: z.object({ title: z.string() }),
148
+ execute: stubTool(),
149
+ renderText: {
150
+ running: "Adding task",
151
+ complete: "Task added",
152
+ },
153
+ },
154
+ });
155
+ ```
156
+
157
+ ```tsx title="TaskBoard.tsx"
158
+ import { AuiProvider, Tools, useAui, useAuiToolOverrides } from "@assistant-ui/react";
159
+ import { useState, type Dispatch, type SetStateAction } from "react";
160
+ import type { Task } from "./task-board-toolkit";
161
+ import toolkit from "./task-board-toolkit";
162
+
163
+ function TaskBoard() {
164
+ const [tasks, setTasks] = useState<Task[]>([]);
165
+
166
+ const aui = useAui({
167
+ tools: Tools({ toolkit }),
168
+ });
169
+
170
+ return (
171
+ <AuiProvider value={aui}>
172
+ <TaskBoardToolOverrides setTasks={setTasks} />
173
+ <TaskList tasks={tasks} />
174
+ </AuiProvider>
175
+ );
176
+ }
177
+
178
+ function TaskBoardToolOverrides({
179
+ setTasks,
180
+ }: {
181
+ setTasks: Dispatch<SetStateAction<Task[]>>;
182
+ }) {
183
+ useAuiToolOverrides({
184
+ add_task: {
185
+ execute: async ({ title }) => {
186
+ setTasks((prev) => [
187
+ ...prev,
188
+ { id: crypto.randomUUID(), title },
189
+ ]);
190
+ return { ok: true };
191
+ },
192
+ },
193
+ });
194
+ return null;
195
+ }
196
+ ```
197
+
198
+ This keeps the model-facing contract in the toolkit file while the component owns the stateful executor.
199
+
200
+ ## Generative Toolkits
201
+
202
+ For tools authored in a `"use generative"` file, export a toolkit with `defineToolkit(...)`. The compiler splits backend, frontend, and human tools for you. This is the default shape to use for docs and copy-paste examples:
203
+
204
+ ```tsx
205
+ "use generative";
206
+
207
+ import { defineToolkit } from "@assistant-ui/react";
208
+ import { z } from "zod";
209
+
210
+ export default defineToolkit({
211
+ create_chart: {
212
+ description: "Create a chart for the user.",
213
+ parameters: z.object({
214
+ title: z.string(),
215
+ values: z.array(z.number()),
216
+ }),
217
+ execute: async ({ title, values }) => {
218
+ "use client";
219
+ return renderChart(title, values);
220
+ },
221
+ render: ChartTool,
222
+ },
223
+ });
224
+ ```
225
+
226
+ Frontend and human tools produced by the generative compiler already have their schema defaults on the backend, so the client no longer re-uploads those schemas.
@@ -22,19 +22,16 @@ For new grouped reasoning/tool-call UI, use `MessagePrimitive.GroupedParts`. `Ch
22
22
  </Tab>
23
23
  <Tab>
24
24
  ```tsx
25
- import { MessagePrimitive } from "@assistant-ui/react";
25
+ import { MessagePrimitive, groupPartByType } from "@assistant-ui/react";
26
26
 
27
27
  function AssistantMessage() {
28
28
  return (
29
29
  <MessagePrimitive.Root>
30
30
  <MessagePrimitive.GroupedParts
31
- groupBy={(part) => {
32
- if (part.type === "reasoning")
33
- return ["group-chainOfThought", "group-reasoning"];
34
- if (part.type === "tool-call")
35
- return ["group-chainOfThought", "group-tool"];
36
- return null;
37
- }}
31
+ groupBy={groupPartByType({
32
+ reasoning: ["group-chainOfThought", "group-reasoning"],
33
+ "tool-call": ["group-chainOfThought", "group-tool"],
34
+ })}
38
35
  >
39
36
  {({ part, children }) => {
40
37
  switch (part.type) {
@@ -67,17 +64,14 @@ function AssistantMessage() {
67
64
  Group reasoning and tool-call parts directly in your assistant message:
68
65
 
69
66
  ```tsx
70
- import { MessagePrimitive } from "@assistant-ui/react";
67
+ import { MessagePrimitive, groupPartByType } from "@assistant-ui/react";
71
68
 
72
69
  <MessagePrimitive.Root>
73
70
  <MessagePrimitive.GroupedParts
74
- groupBy={(part) => {
75
- if (part.type === "reasoning")
76
- return ["group-chainOfThought", "group-reasoning"];
77
- if (part.type === "tool-call")
78
- return ["group-chainOfThought", "group-tool"];
79
- return null;
80
- }}
71
+ groupBy={groupPartByType({
72
+ reasoning: ["group-chainOfThought", "group-reasoning"],
73
+ "tool-call": ["group-chainOfThought", "group-tool"],
74
+ })}
81
75
  >
82
76
  {({ part, children }) => {
83
77
  switch (part.type) {
@@ -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,46 @@ const runtime = useRemoteThreadListRuntime({
114
114
 
115
115
  ## Model Context Hooks
116
116
 
117
- ### useAssistantTool
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.
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" },
117
+ ### Tools
118
+
119
+ Register tools with a toolkit. 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.
120
+
121
+ ```tsx title="weather-toolkit.tsx"
122
+ import type { Toolkit } from "@assistant-ui/react-native";
123
+ import { Text, View } from "react-native";
124
+
125
+ export const toolkit = {
126
+ get_weather: {
127
+ type: "frontend",
128
+ description: "Get the current weather for a city",
129
+ parameters: {
130
+ type: "object",
131
+ properties: {
132
+ city: { type: "string" },
133
+ },
134
+ required: ["city"],
131
135
  },
132
- required: ["city"],
133
- },
134
- execute: async ({ city }) => {
135
- const res = await fetch(`https://api.weather.example/${city}`);
136
- return res.json();
136
+ execute: async ({ city }) => {
137
+ const res = await fetch(`https://api.weather.example/${city}`);
138
+ return res.json();
139
+ },
140
+ render: ({ args, result }) => (
141
+ <View>
142
+ <Text>{args.city}: {result?.temperature}°F</Text>
143
+ </View>
144
+ ),
137
145
  },
138
- render: ({ args, result }) => (
139
- <View>
140
- <Text>{args.city}: {result?.temperature}°F</Text>
141
- </View>
142
- ),
143
- });
146
+ } satisfies Toolkit;
144
147
  ```
145
148
 
146
- ### useAssistantToolUI
149
+ ```tsx title="ToolProvider.tsx"
150
+ import { AuiProvider, Tools, useAui } from "@assistant-ui/react-native";
151
+ import { toolkit } from "./weather-toolkit";
147
152
 
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
- });
153
+ function ToolProvider({ children }: { children: React.ReactNode }) {
154
+ const aui = useAui({ tools: Tools({ toolkit }) });
155
+ return <AuiProvider value={aui}>{children}</AuiProvider>;
156
+ }
163
157
  ```
164
158
 
165
159
  ### useAssistantDataUI
@@ -193,49 +187,30 @@ useAssistantInstructions("You are a helpful weather assistant.");
193
187
 
194
188
  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
189
 
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 />
190
+ ```tsx title="my-tool-toolkit.tsx"
191
+ import { type Toolkit, useInlineRender } from "@assistant-ui/react-native";
192
+ import { Text } from "react-native";
193
+ import { useMemo } from "react";
194
+
195
+ export function useMyToolToolkit(someOuterProp: string) {
196
+ const stableRender = useInlineRender(({ args, result }) => (
197
+ <Text>{someOuterProp}: {result?.value}</Text>
198
+ ));
199
+
200
+ return useMemo(
201
+ () =>
202
+ ({
203
+ my_tool: {
204
+ type: "backend",
205
+ render: stableRender,
206
+ },
207
+ }) satisfies Toolkit,
208
+ [stableRender],
209
+ );
210
+ }
223
211
  ```
224
212
 
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
- ```
213
+ 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
214
 
240
215
  ### makeAssistantDataUI
241
216
 
@@ -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. |