@assistant-ui/mcp-docs-server 0.1.33 → 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.
- package/.docs/organized/code-examples/waterfall.md +5 -5
- package/.docs/organized/code-examples/with-a2a.md +5 -5
- package/.docs/organized/code-examples/with-ag-ui.md +9 -9
- package/.docs/organized/code-examples/with-ai-sdk-v6.md +7 -7
- package/.docs/organized/code-examples/with-artifacts.md +37 -31
- package/.docs/organized/code-examples/with-assistant-transport.md +8 -8
- package/.docs/organized/code-examples/with-browser-extension.md +5 -5
- package/.docs/organized/code-examples/with-chain-of-thought.md +68 -47
- package/.docs/organized/code-examples/with-cloud-standalone.md +7 -7
- package/.docs/organized/code-examples/with-cloud.md +7 -7
- package/.docs/organized/code-examples/with-custom-thread-list.md +7 -7
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +8 -8
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +8 -8
- package/.docs/organized/code-examples/with-expo.md +33 -24
- package/.docs/organized/code-examples/with-external-store.md +5 -5
- package/.docs/organized/code-examples/with-ffmpeg.md +10 -10
- package/.docs/organized/code-examples/with-generative-ui.md +70 -64
- package/.docs/organized/code-examples/with-google-adk.md +6 -6
- package/.docs/organized/code-examples/with-heat-graph.md +5 -5
- package/.docs/organized/code-examples/with-image-generation.md +7 -7
- package/.docs/organized/code-examples/with-interactables.md +7 -7
- package/.docs/organized/code-examples/with-langchain.md +7 -7
- package/.docs/organized/code-examples/with-langgraph.md +30 -26
- package/.docs/organized/code-examples/with-livekit.md +8 -8
- package/.docs/organized/code-examples/with-mcp.md +8 -8
- package/.docs/organized/code-examples/with-opencode.md +6 -6
- package/.docs/organized/code-examples/with-react-hook-form.md +7 -7
- package/.docs/organized/code-examples/with-react-ink.md +295 -100
- package/.docs/organized/code-examples/with-react-router.md +11 -11
- package/.docs/organized/code-examples/with-resumable-stream.md +8 -8
- package/.docs/organized/code-examples/with-store.md +64 -64
- package/.docs/organized/code-examples/with-tanstack.md +8 -8
- package/.docs/organized/code-examples/with-tap-runtime.md +5 -5
- package/.docs/raw/docs/(docs)/architecture.mdx +52 -41
- package/.docs/raw/docs/(reference)/api-reference/external-store/message-conversion.mdx +1 -1
- package/.docs/raw/docs/(reference)/api-reference/external-store/runtime.mdx +3 -0
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +14 -3
- package/.docs/raw/docs/(reference)/api-reference/tools/toolkits.mdx +94 -3
- package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +5 -69
- package/.docs/raw/docs/ink/adapters.mdx +23 -1
- package/.docs/raw/docs/ink/hooks.mdx +20 -17
- package/.docs/raw/docs/migrations/toolkit-tools.mdx +14 -8
- package/.docs/raw/docs/react-native/hooks.mdx +25 -17
- package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +41 -0
- package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +3 -3
- package/.docs/raw/docs/runtimes/concepts/architecture.mdx +46 -4
- package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +54 -12
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +62 -4
- package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +12 -0
- package/.docs/raw/docs/runtimes/google-adk/hooks.mdx +9 -9
- package/.docs/raw/docs/runtimes/langgraph/streaming.mdx +13 -0
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +5 -5
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +3 -3
- package/.docs/raw/docs/tools/backend.mdx +19 -11
- package/.docs/raw/docs/tools/defining-tools.mdx +177 -52
- package/.docs/raw/docs/tools/index.mdx +7 -12
- package/.docs/raw/docs/tools/mcp.mdx +83 -15
- package/.docs/raw/docs/tools/multi-agent.mdx +5 -5
- package/.docs/raw/docs/tools/tool-ui.mdx +27 -27
- package/.docs/raw/docs/tools/user-managed-mcp.mdx +4 -4
- package/.docs/raw/docs/ui/mermaid.mdx +16 -9
- package/.docs/raw/docs/ui/part-grouping.mdx +2 -2
- package/.docs/raw/docs/ui/tool-fallback.mdx +16 -0
- package/.docs/raw/docs/utilities/react-o11y.mdx +2 -2
- package/dist/constants.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/prepare-docs/code-examples.js.map +1 -1
- package/dist/prepare-docs/copy-raw.js.map +1 -1
- package/dist/prepare-docs/prepare.js.map +1 -1
- package/dist/stdio.js.map +1 -1
- package/dist/tools/docs.js.map +1 -1
- package/dist/tools/examples.js.map +1 -1
- package/dist/tools/tests/test-setup.js.map +1 -1
- package/dist/utils/mdx.js.map +1 -1
- package/dist/utils/paths.js.map +1 -1
- package/package.json +4 -4
- /package/.docs/raw/docs/{(docs)/copilots → copilots}/assistant-frame.mdx +0 -0
- /package/.docs/raw/docs/{(docs)/copilots → copilots}/make-assistant-visible.mdx +0 -0
- /package/.docs/raw/docs/{(docs)/copilots → copilots}/model-context.mdx +0 -0
- /package/.docs/raw/docs/{(docs)/copilots → copilots}/motivation.mdx +0 -0
- /package/.docs/raw/docs/{(docs)/copilots → copilots}/use-assistant-instructions.mdx +0 -0
|
@@ -94,14 +94,14 @@ This simply displays the tool name and arguments passed to it, but not the resul
|
|
|
94
94
|
|
|
95
95
|
import { Thread } from "@/components/assistant-ui/thread";
|
|
96
96
|
import { PriceSnapshotToolUI } from "@/components/tools/price-snapshot/PriceSnapshotTool";
|
|
97
|
-
import { AuiProvider,
|
|
97
|
+
import { AuiProvider, defineToolkit, Tools, useAui } from "@assistant-ui/react";
|
|
98
98
|
|
|
99
|
-
const toolkit = {
|
|
99
|
+
const toolkit = defineToolkit({
|
|
100
100
|
price_snapshot: {
|
|
101
101
|
type: "backend",
|
|
102
102
|
render: PriceSnapshotToolUI,
|
|
103
103
|
},
|
|
104
|
-
}
|
|
104
|
+
});
|
|
105
105
|
|
|
106
106
|
export default function Home() {
|
|
107
107
|
const aui = useAui({ tools: Tools({ toolkit }) });
|
|
@@ -326,12 +326,12 @@ export const ToolFallback: ToolCallMessagePartComponent = ({
|
|
|
326
326
|
### Bind fallback UI
|
|
327
327
|
|
|
328
328
|
```tsx title="@/app/page.tsx"
|
|
329
|
-
const toolkit = {
|
|
329
|
+
const toolkit = defineToolkit({
|
|
330
330
|
price_snapshot: {
|
|
331
331
|
type: "backend",
|
|
332
332
|
render: PriceSnapshotToolUI,
|
|
333
333
|
},
|
|
334
|
-
}
|
|
334
|
+
});
|
|
335
335
|
|
|
336
336
|
export default function Home() {
|
|
337
337
|
const aui = useAui({ tools: Tools({ toolkit }) });
|
|
@@ -212,9 +212,9 @@ export function TransactionConfirmationPending(props: TransactionConfirmation) {
|
|
|
212
212
|
import { Thread } from "@/components/assistant-ui/thread";
|
|
213
213
|
import { PriceSnapshotToolUI } from "@/components/tools/price-snapshot/PriceSnapshotTool";
|
|
214
214
|
import { PurchaseStockToolUI } from "@/components/tools/purchase-stock/PurchaseStockTool";
|
|
215
|
-
import { AuiProvider,
|
|
215
|
+
import { AuiProvider, defineToolkit, Tools, useAui } from "@assistant-ui/react";
|
|
216
216
|
|
|
217
|
-
const toolkit = {
|
|
217
|
+
const toolkit = defineToolkit({
|
|
218
218
|
price_snapshot: {
|
|
219
219
|
type: "backend",
|
|
220
220
|
render: PriceSnapshotToolUI,
|
|
@@ -223,7 +223,7 @@ const toolkit = {
|
|
|
223
223
|
type: "backend",
|
|
224
224
|
render: PurchaseStockToolUI,
|
|
225
225
|
},
|
|
226
|
-
}
|
|
226
|
+
});
|
|
227
227
|
|
|
228
228
|
export default function Home() {
|
|
229
229
|
const aui = useAui({ tools: Tools({ toolkit }) });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Backend Tools
|
|
3
|
-
description: Wire assistant-ui toolkits into your server with the AI SDK —
|
|
3
|
+
description: Wire assistant-ui toolkits into your server with the AI SDK — AISDKToolkit, frontendTools, mixing client and server tools, and multi-modal results.
|
|
4
4
|
platforms: ["react"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -24,16 +24,18 @@ const {
|
|
|
24
24
|
} = await req.json();
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
## Generative toolkits: `
|
|
27
|
+
## Generative toolkits: `AISDKToolkit`
|
|
28
28
|
|
|
29
|
-
When you author tools in a [`"use generative"` file](/docs/tools/defining-tools#quick-start-use-generative), the same import resolves to the **server build** inside a route handler — schema plus any backend `execute`, with renderers stripped.
|
|
29
|
+
When you author tools in a [`"use generative"` file](/docs/tools/defining-tools#quick-start-use-generative), the same import resolves to the **server build** inside a route handler — schema plus any backend `execute`, with renderers stripped. Wrap it in an `AISDKToolkit` and call `.tools()` with the uploaded `tools`:
|
|
30
30
|
|
|
31
31
|
```ts title="app/api/chat/route.ts"
|
|
32
|
-
import {
|
|
32
|
+
import { AISDKToolkit } from "@assistant-ui/react-ai-sdk";
|
|
33
33
|
import { streamText, convertToModelMessages, type UIMessage } from "ai";
|
|
34
34
|
import { openai } from "@ai-sdk/openai";
|
|
35
35
|
import toolkit from "../../toolkit";
|
|
36
36
|
|
|
37
|
+
const aiToolkit = new AISDKToolkit({ toolkit });
|
|
38
|
+
|
|
37
39
|
export async function POST(req: Request) {
|
|
38
40
|
const { messages, system, tools } = await req.json();
|
|
39
41
|
|
|
@@ -41,24 +43,29 @@ export async function POST(req: Request) {
|
|
|
41
43
|
model: openai("gpt-5.4-nano"),
|
|
42
44
|
system,
|
|
43
45
|
messages: await convertToModelMessages(messages),
|
|
44
|
-
tools:
|
|
46
|
+
tools: await aiToolkit.tools({ frontend: tools }),
|
|
45
47
|
});
|
|
46
48
|
|
|
47
49
|
return result.toUIMessageStreamResponse();
|
|
48
50
|
}
|
|
49
51
|
```
|
|
50
52
|
|
|
51
|
-
`
|
|
53
|
+
`AISDKToolkit.tools()` registers every toolkit tool with the model using its schema, wires the backend `execute` where the server build carries one, and merges in the uploaded frontend tools. A server `execute` wins over an uploaded entry of the same name. Frontend and human tools (no server `execute`) are exposed schema-only and left for the client and the user to fulfill.
|
|
52
54
|
|
|
53
55
|
<Callout type="info">
|
|
54
|
-
If your toolkit spreads in MCP server tools (`defineMcpToolkit`),
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
If your toolkit spreads in MCP server tools (`defineMcpToolkit`), `.tools()`
|
|
57
|
+
also opens those connections. A module-scope `aiToolkit` pools them across
|
|
58
|
+
requests; see [MCP](/docs/tools/mcp) for the connection lifecycle and when to
|
|
59
|
+
call `aiToolkit.close()`. The older
|
|
60
|
+
`generativeTools({ toolkit, frontendTools })` is deprecated, MCP-less, and
|
|
61
|
+
superseded by `AISDKToolkit`.
|
|
57
62
|
</Callout>
|
|
58
63
|
|
|
59
64
|
## Client-defined tools: `frontendTools`
|
|
60
65
|
|
|
61
|
-
If
|
|
66
|
+
If a toolkit cannot go through the generative compiler, the AI SDK adapter still
|
|
67
|
+
serializes browser-executed tools into the request `tools`. Convert them to the
|
|
68
|
+
AI SDK shape with `frontendTools` and spread your own server tools alongside:
|
|
62
69
|
|
|
63
70
|
```ts title="app/api/chat/route.ts"
|
|
64
71
|
import { frontendTools } from "@assistant-ui/react-ai-sdk";
|
|
@@ -86,7 +93,8 @@ export async function POST(req: Request) {
|
|
|
86
93
|
}
|
|
87
94
|
```
|
|
88
95
|
|
|
89
|
-
`
|
|
96
|
+
`AISDKToolkit.tools()` calls `frontendTools` for you under the hood; reach for
|
|
97
|
+
`frontendTools` directly when you're not on the generative build.
|
|
90
98
|
|
|
91
99
|
<Callout type="tip">
|
|
92
100
|
`toToolsJSONSchema` emits the uploaded tools in alphabetical order, so two
|
|
@@ -8,23 +8,25 @@ Tools let the model take actions: fetch data, call an API, query a database, dri
|
|
|
8
8
|
|
|
9
9
|
This page covers how to **author** tools. To render a tool call as a custom component, see [Tool UI](/docs/tools/tool-ui). To wire tools into your server, see [Backend tools](/docs/tools/backend).
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Define tools with `"use generative"`
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Use `"use generative"` + `defineToolkit` for toolkits. The compiler co-locates
|
|
14
|
+
the schema, executor, and renderer in one file and splits them across the
|
|
15
|
+
client/server boundary for you.
|
|
14
16
|
|
|
15
17
|
<Callout type="info">
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
elsewhere — an MCP server, a separate backend route, a LangGraph node — and you
|
|
23
|
-
only want to attach a renderer. These are render-only entries with an explicit
|
|
24
|
-
`type`.
|
|
18
|
+
You can still use the generative toolkit pattern when a tool executes
|
|
19
|
+
elsewhere:
|
|
20
|
+
|
|
21
|
+
- for MCP servers, spread `defineMcpToolkit({ ... })`;
|
|
22
|
+
- for non-MCP tools defined by another backend or runtime, write
|
|
23
|
+
`execute: externalTool()` and provide a renderer.
|
|
25
24
|
</Callout>
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
In a `"use generative"` file every tool declares an `execute`, and you never
|
|
27
|
+
write `type` yourself — the compiler infers it. For render-only external tools,
|
|
28
|
+
`externalTool()` is the escape hatch that satisfies the compiler without
|
|
29
|
+
emitting schema or executable code on the server.
|
|
28
30
|
|
|
29
31
|
## Quick start (`"use generative"`)
|
|
30
32
|
|
|
@@ -55,6 +57,17 @@ export default defineConfig({
|
|
|
55
57
|
});
|
|
56
58
|
```
|
|
57
59
|
|
|
60
|
+
For Expo, wrap your Metro config with `withAui`:
|
|
61
|
+
|
|
62
|
+
```js title="metro.config.js"
|
|
63
|
+
const { getDefaultConfig } = require("expo/metro-config");
|
|
64
|
+
const { withAui } = require("@assistant-ui/metro");
|
|
65
|
+
|
|
66
|
+
module.exports = withAui(getDefaultConfig(__dirname));
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
For a bare React Native app, import `getDefaultConfig` from `@react-native/metro-config` instead of `expo/metro-config`.
|
|
70
|
+
|
|
58
71
|
</Step>
|
|
59
72
|
<Step>
|
|
60
73
|
|
|
@@ -128,21 +141,23 @@ export function MyRuntimeProvider({ children }: { children: React.ReactNode }) {
|
|
|
128
141
|
|
|
129
142
|
### Expose the toolkit to the model on your server
|
|
130
143
|
|
|
131
|
-
The same import resolves to the **server build** inside a route handler.
|
|
144
|
+
The same import resolves to the **server build** inside a route handler. Wrap it in an `AISDKToolkit` so the model is configured with every tool's schema:
|
|
132
145
|
|
|
133
146
|
```ts title="app/api/chat/route.ts"
|
|
134
|
-
import {
|
|
147
|
+
import { AISDKToolkit } from "@assistant-ui/react-ai-sdk";
|
|
135
148
|
import { streamText, convertToModelMessages } from "ai";
|
|
136
149
|
import { openai } from "@ai-sdk/openai";
|
|
137
150
|
import toolkit from "../../toolkit";
|
|
138
151
|
|
|
152
|
+
const aiToolkit = new AISDKToolkit({ toolkit });
|
|
153
|
+
|
|
139
154
|
export async function POST(req: Request) {
|
|
140
155
|
const { messages, tools } = await req.json();
|
|
141
156
|
|
|
142
157
|
const result = streamText({
|
|
143
158
|
model: openai("gpt-5.4-nano"),
|
|
144
159
|
messages: await convertToModelMessages(messages),
|
|
145
|
-
tools:
|
|
160
|
+
tools: await aiToolkit.tools({ frontend: tools }),
|
|
146
161
|
});
|
|
147
162
|
|
|
148
163
|
return result.toUIMessageStreamResponse();
|
|
@@ -164,9 +179,10 @@ The tool's **kind is inferred from its `execute`** and written back as a `type`
|
|
|
164
179
|
| --- | --- | --- | --- |
|
|
165
180
|
| plain `async () => …` | **backend** | schema + `execute` (guarded `server-only`) | schema + `render` |
|
|
166
181
|
| `async () => { "use client"; … }` | **frontend** | schema only | schema + `execute` + `render`/`renderText` |
|
|
167
|
-
| `
|
|
182
|
+
| `humanTool()` | **human** | schema only | schema + `render` |
|
|
168
183
|
| `stubTool()` | **frontend** (executor supplied at runtime) | schema only | schema + `render`/`renderText` |
|
|
169
184
|
| `providerTool({ … })` | **provider** | schema + provider config | schema + provider config |
|
|
185
|
+
| `externalTool()` | **backend** (defined elsewhere) | omitted | `type: "backend"` + `render`/`renderText` |
|
|
170
186
|
|
|
171
187
|
The compiler also enforces, at build time:
|
|
172
188
|
|
|
@@ -176,6 +192,26 @@ The compiler also enforces, at build time:
|
|
|
176
192
|
|
|
177
193
|
## Tool kinds
|
|
178
194
|
|
|
195
|
+
### Backend tools
|
|
196
|
+
|
|
197
|
+
Run on your server. Author a plain `execute` (no `"use client"`); the compiler moves it to the server build behind `import "server-only"` and keeps only the schema and `render` on the client. A backend tool can still carry a `render` to show its call as a trace:
|
|
198
|
+
|
|
199
|
+
```tsx
|
|
200
|
+
geocode_location: {
|
|
201
|
+
description: "Geocode a location name into latitude/longitude.",
|
|
202
|
+
parameters: z.object({ query: z.string() }),
|
|
203
|
+
execute: async ({ query }) => geocodeLocation(query),
|
|
204
|
+
render: GeocodeToolUI,
|
|
205
|
+
},
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
<Callout type="tip">
|
|
209
|
+
A backend tool authored this way **has** an `execute`. To attach a renderer to
|
|
210
|
+
a tool whose execution lives entirely elsewhere (an MCP server, a different
|
|
211
|
+
backend route) — where there is no real executor to write — use
|
|
212
|
+
`externalTool()` or `defineMcpToolkit()`.
|
|
213
|
+
</Callout>
|
|
214
|
+
|
|
179
215
|
### Frontend tools
|
|
180
216
|
|
|
181
217
|
Run in the browser. Author a real `execute` with a leading `"use client"`:
|
|
@@ -196,35 +232,15 @@ copy_to_clipboard: {
|
|
|
196
232
|
},
|
|
197
233
|
```
|
|
198
234
|
|
|
199
|
-
### Backend tools
|
|
200
|
-
|
|
201
|
-
Run on your server. Author a plain `execute` (no `"use client"`); the compiler moves it to the server build behind `import "server-only"` and keeps only the schema and `render` on the client. A backend tool can still carry a `render` to show its call as a trace:
|
|
202
|
-
|
|
203
|
-
```tsx
|
|
204
|
-
geocode_location: {
|
|
205
|
-
description: "Geocode a location name into latitude/longitude.",
|
|
206
|
-
parameters: z.object({ query: z.string() }),
|
|
207
|
-
execute: async ({ query }) => geocodeLocation(query),
|
|
208
|
-
render: GeocodeToolUI,
|
|
209
|
-
},
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
<Callout type="tip">
|
|
213
|
-
A backend tool authored this way **has** an `execute`. To attach a renderer to
|
|
214
|
-
a tool whose execution lives entirely elsewhere (an MCP server, a different
|
|
215
|
-
backend route) — where there is no `execute` to write — use a [plain
|
|
216
|
-
toolkit](#render-only-tools-for-externally-executed-tools) instead.
|
|
217
|
-
</Callout>
|
|
218
|
-
|
|
219
235
|
### Human tools
|
|
220
236
|
|
|
221
|
-
Pause the run until the user supplies a result through the rendered UI. Author `execute:
|
|
237
|
+
Pause the run until the user supplies a result through the rendered UI. Author `execute: humanTool()` and a `render` that calls `addResult` exactly once:
|
|
222
238
|
|
|
223
239
|
```tsx
|
|
224
240
|
select_date: {
|
|
225
241
|
description: "Ask the user to select a date.",
|
|
226
242
|
parameters: z.object({ prompt: z.string() }),
|
|
227
|
-
execute:
|
|
243
|
+
execute: humanTool(),
|
|
228
244
|
render: ({ args, result, addResult }) => {
|
|
229
245
|
if (result) return <p>Selected {result.date}</p>;
|
|
230
246
|
return (
|
|
@@ -237,7 +253,7 @@ select_date: {
|
|
|
237
253
|
},
|
|
238
254
|
```
|
|
239
255
|
|
|
240
|
-
`
|
|
256
|
+
`humanTool` is imported from `@assistant-ui/react`. See [Tool UI → Human-in-the-loop](/docs/tools/tool-ui#user-input-collection) for the full pattern.
|
|
241
257
|
|
|
242
258
|
### Provider tools
|
|
243
259
|
|
|
@@ -252,9 +268,68 @@ web_search: {
|
|
|
252
268
|
},
|
|
253
269
|
```
|
|
254
270
|
|
|
255
|
-
###
|
|
271
|
+
### Externally defined tools
|
|
272
|
+
|
|
273
|
+
Use `externalTool()` when a non-MCP tool is already defined and executed by
|
|
274
|
+
another system (for example a separate backend route or LangGraph node), but you
|
|
275
|
+
want assistant-ui to render its tool calls. Import `externalTool` from
|
|
276
|
+
`@assistant-ui/react`:
|
|
277
|
+
|
|
278
|
+
```tsx
|
|
279
|
+
web_search: {
|
|
280
|
+
parameters: z.object({ query: z.string() }),
|
|
281
|
+
execute: externalTool(),
|
|
282
|
+
render: ({ args, result }) => (
|
|
283
|
+
<SearchResults query={args.query} results={result?.results ?? []} />
|
|
284
|
+
),
|
|
285
|
+
},
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
The compiler omits this entry from the server build, so the model still gets
|
|
289
|
+
the tool definition from the external system. The client build keeps only
|
|
290
|
+
`type: "backend"` and the renderer (or `renderText`) for matching tool-call
|
|
291
|
+
message parts.
|
|
256
292
|
|
|
257
|
-
|
|
293
|
+
### Tool stubs (supply the executor elsewhere)
|
|
294
|
+
|
|
295
|
+
Sometimes a tool's executor can't live in the build-split `"use generative"` file, usually because it has to close over React state (a `useState` setter, a ref). Declare the model-facing contract with `execute: stubTool()`, then supply the real executor at runtime with `useAuiToolOverrides` from the component that owns the state:
|
|
296
|
+
|
|
297
|
+
```tsx title="app/toolkit.tsx"
|
|
298
|
+
"use generative";
|
|
299
|
+
|
|
300
|
+
import { defineToolkit, stubTool } from "@assistant-ui/react";
|
|
301
|
+
import { manageTasksParameters } from "./state";
|
|
302
|
+
|
|
303
|
+
export default defineToolkit({
|
|
304
|
+
manage_tasks: {
|
|
305
|
+
description: "Add, toggle, or clear tasks on the board.",
|
|
306
|
+
parameters: manageTasksParameters,
|
|
307
|
+
execute: stubTool(),
|
|
308
|
+
renderText: { running: "Updating tasks…", complete: "Tasks updated" },
|
|
309
|
+
},
|
|
310
|
+
});
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
```tsx title="app/TaskBoard.tsx"
|
|
314
|
+
import { useAuiToolOverrides } from "@assistant-ui/react";
|
|
315
|
+
|
|
316
|
+
function TaskBoardToolOverrides({ setTasks }) {
|
|
317
|
+
useAuiToolOverrides({
|
|
318
|
+
manage_tasks: {
|
|
319
|
+
execute: async ({ action, title }) => {
|
|
320
|
+
// close over setTasks here, then return a payload for the model
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
});
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
`stubTool()` has no runtime implementation: it marks the executor as supplied later, while the compiler still ships the schema to the backend so the model can call the tool. The override registers above the toolkit default, so its `execute` wins for that name. To turn a tool off at runtime instead, see [Disabling a tool](#disabling-a-tool). See [Dynamic tools](/docs/tools/dynamic-tools) for the full walkthrough.
|
|
329
|
+
|
|
330
|
+
<Callout type="warn">
|
|
331
|
+
`useAuiToolOverrides` is experimental and its API may change.
|
|
332
|
+
</Callout>
|
|
258
333
|
|
|
259
334
|
## Rendering a tool call
|
|
260
335
|
|
|
@@ -271,29 +346,32 @@ If you don't provide a renderer, add the [`ToolFallback`](/docs/ui/tool-fallback
|
|
|
271
346
|
|
|
272
347
|
## Render-only tools (for externally-executed tools)
|
|
273
348
|
|
|
274
|
-
|
|
349
|
+
Prefer `"use generative"` with `externalTool()` for non-MCP tools, or
|
|
350
|
+
`defineMcpToolkit()` for MCP servers. If a file cannot go through the generative
|
|
351
|
+
compiler, declare a `"use client"` toolkit object with an explicit
|
|
352
|
+
`type: "backend"` and only a `render`:
|
|
275
353
|
|
|
276
354
|
```tsx title="app/tool-ui.tsx"
|
|
277
355
|
"use client";
|
|
278
356
|
|
|
279
|
-
import
|
|
357
|
+
import { defineToolkit } from "@assistant-ui/react";
|
|
280
358
|
|
|
281
|
-
export const toolkit = {
|
|
359
|
+
export const toolkit = defineToolkit({
|
|
282
360
|
web_search: {
|
|
283
361
|
type: "backend",
|
|
284
362
|
render: ({ args, result }) => (
|
|
285
363
|
<SearchResults query={args.query} results={result?.results ?? []} />
|
|
286
364
|
),
|
|
287
365
|
},
|
|
288
|
-
}
|
|
366
|
+
});
|
|
289
367
|
```
|
|
290
368
|
|
|
291
369
|
Register it exactly like a generative toolkit: `useAui({ tools: Tools({ toolkit }) })`. The key must match the tool name your backend or MCP server publishes. Render-only entries upload no schema and run no browser code — they only attach UI to matching tool-call message parts.
|
|
292
370
|
|
|
293
371
|
<Callout type="warn">
|
|
294
|
-
This `{ type: "backend", render }` shape is **plain-toolkit only**.
|
|
295
|
-
|
|
296
|
-
declare an `execute`, and you never author `type` there.
|
|
372
|
+
This `{ type: "backend", render }` shape is **plain-toolkit only**. Inside a
|
|
373
|
+
`"use generative"` file, use `execute: externalTool()` instead; generative
|
|
374
|
+
tools must declare an `execute`, and you never author `type` there.
|
|
297
375
|
</Callout>
|
|
298
376
|
|
|
299
377
|
## Organizing toolkits
|
|
@@ -311,12 +389,28 @@ export type GetWeatherArgs = z.infer<typeof getWeatherParameters>;
|
|
|
311
389
|
|
|
312
390
|
### Split tools across files and merge them
|
|
313
391
|
|
|
392
|
+
Each file you split into is its own `"use generative"` module that default-exports a `defineToolkit(...)`:
|
|
393
|
+
|
|
394
|
+
```tsx title="app/tools/weather.tsx"
|
|
395
|
+
"use generative";
|
|
396
|
+
|
|
397
|
+
import { defineToolkit } from "@assistant-ui/react";
|
|
398
|
+
|
|
399
|
+
export default defineToolkit({
|
|
400
|
+
get_weather: {
|
|
401
|
+
/* description, parameters, execute, render */
|
|
402
|
+
},
|
|
403
|
+
});
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
Merge them by spreading their default imports into a parent toolkit:
|
|
407
|
+
|
|
314
408
|
```tsx title="app/toolkit.tsx"
|
|
315
409
|
"use generative";
|
|
316
410
|
|
|
317
411
|
import { defineToolkit } from "@assistant-ui/react";
|
|
318
|
-
import
|
|
319
|
-
import
|
|
412
|
+
import weatherTools from "./tools/weather";
|
|
413
|
+
import databaseTools from "./tools/database";
|
|
320
414
|
|
|
321
415
|
export default defineToolkit({
|
|
322
416
|
...weatherTools,
|
|
@@ -324,11 +418,26 @@ export default defineToolkit({
|
|
|
324
418
|
});
|
|
325
419
|
```
|
|
326
420
|
|
|
327
|
-
|
|
421
|
+
The compiler splits each file across the client/server boundary on its own, then checks that the spread import resolves to a `"use generative"` module before allowing it, so a backend `execute` can't leak to the client. Two rules follow:
|
|
422
|
+
|
|
423
|
+
- **Spread a default import** (`import weatherTools from "./tools/weather"`). Relative paths and `tsconfig` path aliases like `@/tools/weather` both resolve. Only the default export crosses the generative-module boundary, so a named import (or any opaque, non-generative import) is rejected.
|
|
424
|
+
- You can also spread a local `defineToolkit(...)` or `defineMcpToolkit(...)` binding declared in the same file.
|
|
328
425
|
|
|
329
426
|
### Add MCP server tools
|
|
330
427
|
|
|
331
|
-
|
|
428
|
+
`defineMcpToolkit` exposes tools from an MCP server. For an MCP-only toolkit, export it directly:
|
|
429
|
+
|
|
430
|
+
```tsx title="app/mcp-toolkit.tsx"
|
|
431
|
+
"use generative";
|
|
432
|
+
|
|
433
|
+
import { defineMcpToolkit } from "@assistant-ui/react";
|
|
434
|
+
|
|
435
|
+
export default defineMcpToolkit({
|
|
436
|
+
docs: { type: "http", url: "https://mcp.example.com/mcp" },
|
|
437
|
+
});
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
To expose MCP tools alongside your own, spread it into a `defineToolkit`:
|
|
332
441
|
|
|
333
442
|
```tsx
|
|
334
443
|
"use generative";
|
|
@@ -339,6 +448,7 @@ export default defineToolkit({
|
|
|
339
448
|
...defineMcpToolkit({
|
|
340
449
|
docs: { type: "http", url: "https://mcp.example.com/mcp" },
|
|
341
450
|
}),
|
|
451
|
+
// ...your own tools
|
|
342
452
|
});
|
|
343
453
|
```
|
|
344
454
|
|
|
@@ -408,6 +518,21 @@ While a tool runs, its arguments arrive as partial JSON. Use [`useToolArgsStatus
|
|
|
408
518
|
|
|
409
519
|
Set `disabled: true` to keep a tool known to the client but hidden from the model in the current scope.
|
|
410
520
|
|
|
521
|
+
To toggle a tool off at runtime without editing the toolkit, register the same flag through `useAuiToolOverrides`:
|
|
522
|
+
|
|
523
|
+
```tsx
|
|
524
|
+
import { useAuiToolOverrides } from "@assistant-ui/react";
|
|
525
|
+
|
|
526
|
+
function GuestModeTools() {
|
|
527
|
+
useAuiToolOverrides({
|
|
528
|
+
delete_account: { disabled: true },
|
|
529
|
+
});
|
|
530
|
+
return null;
|
|
531
|
+
}
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
The override registers above the toolkit default, so the tool drops out of the set sent to the model. Mount the override only while the tool should be hidden (for example, for signed-out users); unmounting it restores the toolkit default.
|
|
535
|
+
|
|
411
536
|
## Migrating from the component APIs
|
|
412
537
|
|
|
413
538
|
`makeAssistantTool`, `useAssistantTool`, `makeAssistantToolUI`, and `useAssistantToolUI` are deprecated. See [Migrating Tools to Toolkits](/docs/migrations/toolkit-tools) for the mechanical migration.
|
|
@@ -13,7 +13,7 @@ Tools are how the model takes action: fetch data, call an API, query a database,
|
|
|
13
13
|
Author a toolkit with the `"use generative"` directive — frontend, backend, human, and provider tools, with the schema, executor, and renderer in one file.
|
|
14
14
|
</Card>
|
|
15
15
|
<Card title="Backend Tools" href="/docs/tools/backend">
|
|
16
|
-
Wire a toolkit into your AI SDK route with `
|
|
16
|
+
Wire a toolkit into your AI SDK route with `AISDKToolkit` / `frontendTools`, mix client and server tools, and round-trip multi-modal results.
|
|
17
17
|
</Card>
|
|
18
18
|
<Card title="Tool UI" href="/docs/tools/tool-ui">
|
|
19
19
|
Render tool calls as custom components — loading and result states, human-in-the-loop, approvals, and streaming.
|
|
@@ -23,22 +23,17 @@ Tools are how the model takes action: fetch data, call an API, query a database,
|
|
|
23
23
|
</Card>
|
|
24
24
|
</Cards>
|
|
25
25
|
|
|
26
|
-
##
|
|
26
|
+
## Define tools with `"use generative"`
|
|
27
27
|
|
|
28
28
|
<Callout type="info">
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
**Plain `satisfies Toolkit`** — for tools that already execute elsewhere (an
|
|
34
|
-
MCP server, a separate backend route, a LangGraph node) where you only attach a
|
|
35
|
-
renderer.
|
|
29
|
+
Use `"use generative"` + `defineToolkit` for toolkits. For tools that execute
|
|
30
|
+
elsewhere, spread `defineMcpToolkit({ ... })` for MCP servers or use
|
|
31
|
+
`execute: externalTool()` to attach a renderer to a non-MCP external tool.
|
|
36
32
|
</Callout>
|
|
37
33
|
|
|
38
34
|
In a `"use generative"` file every tool declares an `execute` and the kind is
|
|
39
|
-
**inferred** from it (you never write `type`).
|
|
40
|
-
|
|
41
|
-
[Defining Tools](/docs/tools/defining-tools#two-ways-to-define-a-toolkit).
|
|
35
|
+
**inferred** from it (you never write `type`). See
|
|
36
|
+
[Defining Tools](/docs/tools/defining-tools#define-tools-with-use-generative).
|
|
42
37
|
|
|
43
38
|
## Rendering AI output as UI
|
|
44
39
|
|