@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
@@ -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
+ Tools,
357
+ type Toolkit,
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 = {
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
+ } satisfies Toolkit;
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:
@@ -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
 
@@ -417,24 +417,35 @@ If you build the `content` array fresh from the current chunk each iteration, to
417
417
 
418
418
  `LocalRuntime` supports OpenAI-compatible function calling. Register tools through `useAui` so the runtime exposes them to your adapter via `context.tools`:
419
419
 
420
- ```tsx
421
- import { useAui, Tools, type Toolkit } from "@assistant-ui/react";
420
+ ```tsx title="app/toolkit.tsx"
421
+ "use generative";
422
+
423
+ import { defineToolkit } from "@assistant-ui/react";
422
424
  import { z } from "zod";
423
425
 
424
- const myToolkit: Toolkit = {
426
+ export default defineToolkit({
425
427
  getWeather: {
426
428
  description: "Get the current weather in a location",
427
429
  parameters: z.object({
428
430
  location: z.string(),
429
431
  unit: z.enum(["celsius", "fahrenheit"]).default("celsius"),
430
432
  }),
431
- execute: async ({ location, unit }) => fetchWeather(location, unit),
433
+ execute: async ({ location, unit }) => {
434
+ "use client";
435
+ return fetchWeather(location, unit);
436
+ },
437
+ renderText: { running: "Checking the weather…", complete: "Weather ready" },
432
438
  },
433
- };
439
+ });
440
+ ```
441
+
442
+ ```tsx title="app/MyRuntimeProvider.tsx"
443
+ import { useAui, Tools } from "@assistant-ui/react";
444
+ import toolkit from "./toolkit";
434
445
 
435
446
  function MyRuntimeProvider({ children }: { children: React.ReactNode }) {
436
447
  const runtime = useLocalRuntime(MyModelAdapter);
437
- const aui = useAui({ tools: Tools({ toolkit: myToolkit }) });
448
+ const aui = useAui({ tools: Tools({ toolkit }) });
438
449
 
439
450
  return (
440
451
  <AssistantRuntimeProvider aui={aui} runtime={runtime}>
@@ -444,7 +455,7 @@ function MyRuntimeProvider({ children }: { children: React.ReactNode }) {
444
455
  }
445
456
  ```
446
457
 
447
- See the [tools guide](/docs/guides/tools) for advanced patterns.
458
+ See the [tools guide](/docs/tools/defining-tools) for advanced patterns.
448
459
 
449
460
  ### Human-in-the-loop approval
450
461
 
@@ -257,7 +257,7 @@ When an ADK Python 2.0+ Workflow's `RequestInput` node pauses execution to ask t
257
257
  <Tab value="React">
258
258
 
259
259
  ```tsx
260
- import { makeAssistantToolUI } from "@assistant-ui/react";
260
+ import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
261
261
  import { useAdkSubmitInput } from "@assistant-ui/react-google-adk";
262
262
 
263
263
  type RequestInputArgs = {
@@ -267,12 +267,10 @@ type RequestInputArgs = {
267
267
  response_schema?: unknown;
268
268
  };
269
269
 
270
- export const RequestInputToolUI = makeAssistantToolUI<
270
+ export const RequestInputToolUI: ToolCallMessagePartComponent<
271
271
  RequestInputArgs,
272
272
  unknown
273
- >({
274
- toolName: "adk_request_input",
275
- render: function RequestInputUI({ toolCallId, args, result }) {
273
+ > = function RequestInputUI({ toolCallId, args, result }) {
276
274
  const submitInput = useAdkSubmitInput();
277
275
 
278
276
  if (result !== undefined) {
@@ -294,15 +292,14 @@ export const RequestInputToolUI = makeAssistantToolUI<
294
292
  <button type="submit">Submit</button>
295
293
  </form>
296
294
  );
297
- },
298
- });
295
+ };
299
296
  ```
300
297
 
301
298
  </Tab>
302
299
  <Tab value="React Native">
303
300
 
304
301
  ```tsx
305
- import { makeAssistantToolUI } from "@assistant-ui/react-native";
302
+ import type { ToolCallMessagePartComponent } from "@assistant-ui/react-native";
306
303
  import { useAdkSubmitInput } from "@assistant-ui/react-google-adk";
307
304
  import { useState } from "react";
308
305
  import { Pressable, Text, TextInput, View } from "react-native";
@@ -314,12 +311,10 @@ type RequestInputArgs = {
314
311
  response_schema?: unknown;
315
312
  };
316
313
 
317
- export const RequestInputToolUI = makeAssistantToolUI<
314
+ export const RequestInputToolUI: ToolCallMessagePartComponent<
318
315
  RequestInputArgs,
319
316
  unknown
320
- >({
321
- toolName: "adk_request_input",
322
- render: function RequestInputUI({ toolCallId, args, result }) {
317
+ > = function RequestInputUI({ toolCallId, args, result }) {
323
318
  const submitInput = useAdkSubmitInput();
324
319
  const [value, setValue] = useState("");
325
320
 
@@ -336,15 +331,14 @@ export const RequestInputToolUI = makeAssistantToolUI<
336
331
  </Pressable>
337
332
  </View>
338
333
  );
339
- },
340
- });
334
+ };
341
335
  ```
342
336
 
343
337
  </Tab>
344
338
  <Tab value="React Ink">
345
339
 
346
340
  ```tsx
347
- import { makeAssistantToolUI } from "@assistant-ui/react-ink";
341
+ import type { ToolCallMessagePartComponent } from "@assistant-ui/react-ink";
348
342
  import { useAdkSubmitInput } from "@assistant-ui/react-google-adk";
349
343
  import { useState } from "react";
350
344
  import { Box, Text, useInput } from "ink";
@@ -356,12 +350,10 @@ type RequestInputArgs = {
356
350
  response_schema?: unknown;
357
351
  };
358
352
 
359
- export const RequestInputToolUI = makeAssistantToolUI<
353
+ export const RequestInputToolUI: ToolCallMessagePartComponent<
360
354
  RequestInputArgs,
361
355
  unknown
362
- >({
363
- toolName: "adk_request_input",
364
- render: function RequestInputUI({ toolCallId, args, result }) {
356
+ > = function RequestInputUI({ toolCallId, args, result }) {
365
357
  const submitInput = useAdkSubmitInput();
366
358
  const [value, setValue] = useState("");
367
359
 
@@ -383,53 +375,131 @@ export const RequestInputToolUI = makeAssistantToolUI<
383
375
  <Text dimColor>Press enter to submit.</Text>
384
376
  </Box>
385
377
  );
386
- },
387
- });
378
+ };
388
379
  ```
389
380
 
390
381
  </Tab>
391
382
  </PlatformTabs>
392
383
 
393
- Register the tool UI inside `AssistantRuntimeProvider`:
384
+ Register the renderer with a backend toolkit entry inside `AssistantRuntimeProvider`:
394
385
 
395
386
  <PlatformTabs>
396
387
  <Tab value="React">
397
388
 
398
389
  ```tsx
399
- <AssistantRuntimeProvider runtime={runtime}>
400
- <RequestInputToolUI />
401
- <Thread />
402
- </AssistantRuntimeProvider>
390
+ import {
391
+ AssistantRuntimeProvider,
392
+ Tools,
393
+ type Toolkit,
394
+ useAui,
395
+ } from "@assistant-ui/react";
396
+ import {
397
+ createAdkStream,
398
+ useAdkRuntime,
399
+ } from "@assistant-ui/react-google-adk";
400
+ import { Thread } from "@/components/assistant-ui/thread";
401
+
402
+ const toolkit = {
403
+ adk_request_input: {
404
+ type: "backend",
405
+ render: RequestInputToolUI,
406
+ },
407
+ } satisfies Toolkit;
408
+
409
+ function App() {
410
+ const runtime = useAdkRuntime({
411
+ stream: createAdkStream({ api: "/api/chat" }),
412
+ });
413
+ const aui = useAui({ tools: Tools({ toolkit }) });
414
+
415
+ return (
416
+ <AssistantRuntimeProvider aui={aui} runtime={runtime}>
417
+ <Thread />
418
+ </AssistantRuntimeProvider>
419
+ );
420
+ }
403
421
  ```
404
422
 
405
423
  </Tab>
406
424
  <Tab value="React Native">
407
425
 
408
426
  ```tsx
427
+ import {
428
+ AssistantRuntimeProvider,
429
+ Tools,
430
+ type Toolkit,
431
+ useAui,
432
+ } from "@assistant-ui/react-native";
433
+ import {
434
+ createAdkStream,
435
+ useAdkRuntime,
436
+ } from "@assistant-ui/react-google-adk";
409
437
  import { View } from "react-native";
410
438
  import { Thread } from "@/components/assistant-ui/thread";
411
439
 
412
- <AssistantRuntimeProvider runtime={runtime}>
413
- <RequestInputToolUI />
414
- <View style={{ flex: 1 }}>
415
- <Thread />
416
- </View>
417
- </AssistantRuntimeProvider>;
440
+ const API_URL = process.env.EXPO_PUBLIC_API_URL ?? "http://localhost:3000";
441
+
442
+ const toolkit = {
443
+ adk_request_input: {
444
+ type: "backend",
445
+ render: RequestInputToolUI,
446
+ },
447
+ } satisfies Toolkit;
448
+
449
+ function App() {
450
+ const runtime = useAdkRuntime({
451
+ stream: createAdkStream({ api: `${API_URL}/api/chat` }),
452
+ });
453
+ const aui = useAui({ tools: Tools({ toolkit }) });
454
+
455
+ return (
456
+ <AssistantRuntimeProvider aui={aui} runtime={runtime}>
457
+ <View style={{ flex: 1 }}>
458
+ <Thread />
459
+ </View>
460
+ </AssistantRuntimeProvider>
461
+ );
462
+ }
418
463
  ```
419
464
 
420
465
  </Tab>
421
466
  <Tab value="React Ink">
422
467
 
423
468
  ```tsx
469
+ import {
470
+ AssistantRuntimeProvider,
471
+ Tools,
472
+ type Toolkit,
473
+ useAui,
474
+ } from "@assistant-ui/react-ink";
475
+ import {
476
+ createAdkStream,
477
+ useAdkRuntime,
478
+ } from "@assistant-ui/react-google-adk";
424
479
  import { Box } from "ink";
425
480
  import { Thread } from "./components/thread.js";
426
481
 
427
- <AssistantRuntimeProvider runtime={runtime}>
428
- <RequestInputToolUI />
429
- <Box flexDirection="column">
430
- <Thread />
431
- </Box>
432
- </AssistantRuntimeProvider>;
482
+ const toolkit = {
483
+ adk_request_input: {
484
+ type: "backend",
485
+ render: RequestInputToolUI,
486
+ },
487
+ } satisfies Toolkit;
488
+
489
+ function App() {
490
+ const runtime = useAdkRuntime({
491
+ stream: createAdkStream({ api: "http://localhost:3000/api/chat" }),
492
+ });
493
+ const aui = useAui({ tools: Tools({ toolkit }) });
494
+
495
+ return (
496
+ <AssistantRuntimeProvider aui={aui} runtime={runtime}>
497
+ <Box flexDirection="column">
498
+ <Thread />
499
+ </Box>
500
+ </AssistantRuntimeProvider>
501
+ );
502
+ }
433
503
  ```
434
504
 
435
505
  </Tab>
@@ -1,9 +1,9 @@
1
1
  ---
2
- title: Generative UI
2
+ title: LangGraph Generative UI
3
3
  description: Render structured UI components emitted by LangGraph alongside assistant messages.
4
4
  ---
5
5
 
6
- LangGraph's [Generative UI](https://docs.langchain.com/langsmith/generative-ui-react) lets your graph emit structured UI components alongside assistant messages via `push_ui_message` (Python) or `typedUi().push()` (TypeScript). The assistant-ui adapter translates these into [`DataMessagePart`s](/docs/guides/tool-ui) on the associated assistant message, which you render with the existing `makeAssistantDataUI` API.
6
+ LangGraph's [Generative UI](https://docs.langchain.com/langsmith/generative-ui-react) lets your graph emit structured UI components alongside assistant messages via `push_ui_message` (Python) or `typedUi().push()` (TypeScript). The assistant-ui adapter translates these into [`DataMessagePart`s](/docs/tools/tool-ui) on the associated assistant message, which you render with the existing `makeAssistantDataUI` API.
7
7
 
8
8
  ## Enable the `custom` stream mode
9
9
 
@@ -102,7 +102,7 @@ function MyComponent() {
102
102
 
103
103
  ## Generative UI
104
104
 
105
- LangGraph can emit structured UI components alongside assistant messages via `push_ui_message` (Python) or `typedUi().push()` (TypeScript). The assistant-ui adapter translates these into [`DataMessagePart`s](/docs/guides/tool-ui) on the associated assistant message, which you render with the existing `makeAssistantDataUI` API.
105
+ LangGraph can emit structured UI components alongside assistant messages via `push_ui_message` (Python) or `typedUi().push()` (TypeScript). The assistant-ui adapter translates these into [`DataMessagePart`s](/docs/tools/tool-ui) on the associated assistant message, which you render with the existing `makeAssistantDataUI` API.
106
106
 
107
107
  See [Generative UI](/docs/runtimes/langgraph/generative-ui) for full setup: enabling the `custom` stream channel, emitting UI messages, registering renderers, dynamic loading, and persisting UI state across thread switches.
108
108
 
@@ -64,43 +64,52 @@ type PriceSnapshotToolResult = {
64
64
  };
65
65
  ```
66
66
 
67
- Then, we use `makeAssistantToolUI` to define the tool UI:
67
+ Then, we define a tool UI renderer:
68
68
 
69
69
  ```tsx title="@/components/tools/price-snapshot/PriceSnapshotTool.tsx"
70
70
  "use client";
71
71
 
72
- import { makeAssistantToolUI } from "@assistant-ui/react";
72
+ import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
73
73
 
74
- export const PriceSnapshotTool = makeAssistantToolUI<
74
+ export const PriceSnapshotToolUI: ToolCallMessagePartComponent<
75
75
  PriceSnapshotToolArgs,
76
76
  string
77
- >({
78
- toolName: "price_snapshot",
79
- render: function PriceSnapshotUI({ args, result }) {
80
- return (
81
- <div className="mb-4 flex flex-col items-center">
82
- <pre className="whitespace-pre-wrap break-all text-center">
83
- price_snapshot({JSON.stringify(args)})
84
- </pre>
85
- </div>
86
- );
87
- },
88
- });
77
+ > = function PriceSnapshotUI({ args, result }) {
78
+ return (
79
+ <div className="mb-4 flex flex-col items-center">
80
+ <pre className="whitespace-pre-wrap break-all text-center">
81
+ price_snapshot({JSON.stringify(args)})
82
+ </pre>
83
+ </div>
84
+ );
85
+ };
89
86
  ```
90
87
 
91
88
  This simply displays the tool name and arguments passed to it, but not the result.
92
89
 
93
90
  ### Bind tool UI
94
91
 
95
- ```tsx title="@/app/page.tsx" {1,8}
96
- import { PriceSnapshotTool } from "@/components/tools/price-snapshot/PriceSnapshotTool";
92
+ ```tsx title="@/app/page.tsx" {1-3,10}
93
+ "use client";
94
+
95
+ import { Thread } from "@/components/assistant-ui/thread";
96
+ import { PriceSnapshotToolUI } from "@/components/tools/price-snapshot/PriceSnapshotTool";
97
+ import { AuiProvider, Tools, type Toolkit, useAui } from "@assistant-ui/react";
98
+
99
+ const toolkit = {
100
+ price_snapshot: {
101
+ type: "backend",
102
+ render: PriceSnapshotToolUI,
103
+ },
104
+ } satisfies Toolkit;
97
105
 
98
106
  export default function Home() {
107
+ const aui = useAui({ tools: Tools({ toolkit }) });
108
+
99
109
  return (
100
- <div className="flex h-full flex-col">
101
- <PriceSnapshotTool />
110
+ <AuiProvider value={aui}>
102
111
  <Thread />
103
- </div>
112
+ </AuiProvider>
104
113
  );
105
114
  }
106
115
  ```
@@ -201,7 +210,7 @@ We will import the new `<PriceSnapshot />` component and use it in the `render`
201
210
  "use client";
202
211
 
203
212
  import { PriceSnapshot } from "./price-snapshot";
204
- import { makeAssistantToolUI } from "@assistant-ui/react";
213
+ import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
205
214
 
206
215
  type PriceSnapshotToolArgs = {
207
216
  ticker: string;
@@ -216,34 +225,31 @@ type PriceSnapshotToolResult = {
216
225
  };
217
226
  };
218
227
 
219
- export const PriceSnapshotTool = makeAssistantToolUI<
228
+ export const PriceSnapshotToolUI: ToolCallMessagePartComponent<
220
229
  PriceSnapshotToolArgs,
221
230
  string
222
- >({
223
- toolName: "price_snapshot",
224
- render: function PriceSnapshotUI({ args, result }) {
225
- let resultObj: PriceSnapshotToolResult | { error: string };
226
- try {
227
- resultObj = result ? JSON.parse(result) : {};
228
- } catch (e) {
229
- resultObj = { error: result! };
230
- }
231
-
232
- return (
233
- <div className="mb-4 flex flex-col items-center gap-2">
234
- <pre className="whitespace-pre-wrap break-all text-center">
235
- price_snapshot({JSON.stringify(args)})
236
- </pre>
237
- {"snapshot" in resultObj && (
238
- <PriceSnapshot ticker={args.ticker} {...resultObj.snapshot} />
239
- )}
240
- {"error" in resultObj && (
241
- <p className="text-red-500">{resultObj.error}</p>
242
- )}
243
- </div>
244
- );
245
- },
246
- });
231
+ > = function PriceSnapshotUI({ args, result }) {
232
+ let resultObj: PriceSnapshotToolResult | { error: string };
233
+ try {
234
+ resultObj = result ? JSON.parse(result) : {};
235
+ } catch (e) {
236
+ resultObj = { error: result! };
237
+ }
238
+
239
+ return (
240
+ <div className="mb-4 flex flex-col items-center gap-2">
241
+ <pre className="whitespace-pre-wrap break-all text-center">
242
+ price_snapshot({JSON.stringify(args)})
243
+ </pre>
244
+ {"snapshot" in resultObj && (
245
+ <PriceSnapshot ticker={args.ticker} {...resultObj.snapshot} />
246
+ )}
247
+ {"error" in resultObj && (
248
+ <p className="text-red-500">{resultObj.error}</p>
249
+ )}
250
+ </div>
251
+ );
252
+ };
247
253
  ```
248
254
 
249
255
  ### Try it out!
@@ -320,12 +326,20 @@ export const ToolFallback: ToolCallMessagePartComponent = ({
320
326
  ### Bind fallback UI
321
327
 
322
328
  ```tsx title="@/app/page.tsx"
329
+ const toolkit = {
330
+ price_snapshot: {
331
+ type: "backend",
332
+ render: PriceSnapshotToolUI,
333
+ },
334
+ } satisfies Toolkit;
335
+
323
336
  export default function Home() {
337
+ const aui = useAui({ tools: Tools({ toolkit }) });
338
+
324
339
  return (
325
- <div className="flex h-full flex-col">
326
- <PriceSnapshotTool />
340
+ <AuiProvider value={aui}>
327
341
  <Thread />
328
- </div>
342
+ </AuiProvider>
329
343
  );
330
344
  }
331
345
  ```