@assistant-ui/mcp-docs-server 0.1.22 → 0.1.23

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 (74) hide show
  1. package/.docs/organized/code-examples/waterfall.md +801 -0
  2. package/.docs/organized/code-examples/with-ag-ui.md +38 -26
  3. package/.docs/organized/code-examples/with-ai-sdk-v6.md +38 -28
  4. package/.docs/organized/code-examples/with-artifacts.md +467 -0
  5. package/.docs/organized/code-examples/with-assistant-transport.md +31 -24
  6. package/.docs/organized/code-examples/with-chain-of-thought.md +41 -32
  7. package/.docs/organized/code-examples/with-cloud-standalone.md +675 -0
  8. package/.docs/organized/code-examples/with-cloud.md +34 -27
  9. package/.docs/organized/code-examples/with-custom-thread-list.md +34 -27
  10. package/.docs/organized/code-examples/with-elevenlabs-scribe.md +41 -30
  11. package/.docs/organized/code-examples/with-expo.md +2031 -0
  12. package/.docs/organized/code-examples/with-external-store.md +32 -25
  13. package/.docs/organized/code-examples/with-ffmpeg.md +31 -27
  14. package/.docs/organized/code-examples/with-langgraph.md +96 -38
  15. package/.docs/organized/code-examples/with-parent-id-grouping.md +32 -25
  16. package/.docs/organized/code-examples/with-react-hook-form.md +63 -58
  17. package/.docs/organized/code-examples/with-react-router.md +38 -30
  18. package/.docs/organized/code-examples/with-store.md +16 -24
  19. package/.docs/organized/code-examples/with-tanstack.md +36 -26
  20. package/.docs/organized/code-examples/with-tap-runtime.md +10 -24
  21. package/.docs/raw/docs/(docs)/cli.mdx +13 -6
  22. package/.docs/raw/docs/(docs)/guides/attachments.mdx +26 -3
  23. package/.docs/raw/docs/(docs)/guides/chain-of-thought.mdx +5 -5
  24. package/.docs/raw/docs/(docs)/guides/context-api.mdx +53 -52
  25. package/.docs/raw/docs/(docs)/guides/dictation.mdx +0 -2
  26. package/.docs/raw/docs/(docs)/guides/message-timing.mdx +169 -0
  27. package/.docs/raw/docs/(docs)/guides/quoting.mdx +327 -0
  28. package/.docs/raw/docs/(docs)/guides/speech.mdx +0 -1
  29. package/.docs/raw/docs/(docs)/index.mdx +12 -2
  30. package/.docs/raw/docs/(docs)/installation.mdx +8 -2
  31. package/.docs/raw/docs/(docs)/llm.mdx +9 -7
  32. package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar-more.mdx +1 -1
  33. package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar.mdx +2 -2
  34. package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +27 -27
  35. package/.docs/raw/docs/(reference)/api-reference/primitives/composer.mdx +60 -0
  36. package/.docs/raw/docs/(reference)/api-reference/primitives/message-part.mdx +78 -4
  37. package/.docs/raw/docs/(reference)/api-reference/primitives/message.mdx +32 -0
  38. package/.docs/raw/docs/(reference)/api-reference/primitives/selection-toolbar.mdx +61 -0
  39. package/.docs/raw/docs/(reference)/api-reference/primitives/thread.mdx +1 -1
  40. package/.docs/raw/docs/(reference)/legacy/styled/assistant-modal.mdx +1 -6
  41. package/.docs/raw/docs/(reference)/legacy/styled/decomposition.mdx +2 -2
  42. package/.docs/raw/docs/(reference)/legacy/styled/markdown.mdx +1 -6
  43. package/.docs/raw/docs/(reference)/legacy/styled/thread.mdx +1 -5
  44. package/.docs/raw/docs/(reference)/migrations/v0-12.mdx +17 -17
  45. package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +205 -0
  46. package/.docs/raw/docs/cloud/ai-sdk.mdx +292 -0
  47. package/.docs/raw/docs/cloud/authorization.mdx +178 -79
  48. package/.docs/raw/docs/cloud/{persistence/langgraph.mdx → langgraph.mdx} +2 -2
  49. package/.docs/raw/docs/cloud/overview.mdx +29 -39
  50. package/.docs/raw/docs/react-native/adapters.mdx +118 -0
  51. package/.docs/raw/docs/react-native/custom-backend.mdx +210 -0
  52. package/.docs/raw/docs/react-native/hooks.mdx +364 -0
  53. package/.docs/raw/docs/react-native/index.mdx +332 -0
  54. package/.docs/raw/docs/react-native/primitives.mdx +653 -0
  55. package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +7 -15
  56. package/.docs/raw/docs/runtimes/assistant-transport.mdx +103 -0
  57. package/.docs/raw/docs/runtimes/custom/external-store.mdx +25 -2
  58. package/.docs/raw/docs/runtimes/data-stream.mdx +1 -3
  59. package/.docs/raw/docs/runtimes/langgraph/index.mdx +113 -9
  60. package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +1 -4
  61. package/.docs/raw/docs/ui/attachment.mdx +4 -2
  62. package/.docs/raw/docs/ui/message-timing.mdx +92 -0
  63. package/.docs/raw/docs/ui/part-grouping.mdx +1 -1
  64. package/.docs/raw/docs/ui/reasoning.mdx +4 -4
  65. package/.docs/raw/docs/ui/scrollbar.mdx +2 -2
  66. package/.docs/raw/docs/ui/syntax-highlighting.mdx +55 -50
  67. package/.docs/raw/docs/ui/thread.mdx +16 -9
  68. package/dist/index.d.ts +1 -1
  69. package/dist/index.d.ts.map +1 -1
  70. package/package.json +3 -3
  71. package/src/tools/tests/integration.test.ts +2 -2
  72. package/src/tools/tests/json-parsing.test.ts +1 -1
  73. package/src/tools/tests/mcp-protocol.test.ts +1 -3
  74. package/.docs/raw/docs/cloud/persistence/ai-sdk.mdx +0 -108
@@ -260,7 +260,13 @@ export function MyRuntimeProvider({
260
260
  ```tsx
261
261
  "use client";
262
262
 
263
- import { useAssistantRuntime, useAssistantTool } from "@assistant-ui/react";
263
+ import {
264
+ useAssistantRuntime,
265
+ useAssistantTool,
266
+ useAui,
267
+ AuiProvider,
268
+ Suggestions,
269
+ } from "@assistant-ui/react";
264
270
  import { Thread } from "@/components/assistant-ui/thread";
265
271
  import { PlusIcon } from "lucide-react";
266
272
 
@@ -317,11 +323,33 @@ function NewThreadButton() {
317
323
  );
318
324
  }
319
325
 
326
+ function ThreadWithSuggestions() {
327
+ const aui = useAui({
328
+ suggestions: Suggestions([
329
+ {
330
+ title: "Run a web search",
331
+ label: "for recent AI news",
332
+ prompt: "Search the web for the latest AI news.",
333
+ },
334
+ {
335
+ title: "Show a browser alert",
336
+ label: "using the alert tool",
337
+ prompt: "Show me a browser alert saying hello!",
338
+ },
339
+ ]),
340
+ });
341
+ return (
342
+ <AuiProvider value={aui}>
343
+ <Thread />
344
+ </AuiProvider>
345
+ );
346
+ }
347
+
320
348
  export default function Home() {
321
349
  return (
322
350
  <main className="relative h-dvh">
323
351
  <NewThreadButton />
324
- <Thread />
352
+ <ThreadWithSuggestions />
325
353
  <BrowserAlertTool />
326
354
  </main>
327
355
  );
@@ -359,18 +387,6 @@ export default function Home() {
359
387
 
360
388
  ```
361
389
 
362
- ## lib/utils.ts
363
-
364
- ```typescript
365
- import { clsx, type ClassValue } from "clsx";
366
- import { twMerge } from "tailwind-merge";
367
-
368
- export function cn(...inputs: ClassValue[]) {
369
- return twMerge(clsx(inputs));
370
- }
371
-
372
- ```
373
-
374
390
  ## next.config.ts
375
391
 
376
392
  ```typescript
@@ -398,32 +414,27 @@ export default nextConfig;
398
414
  "start": "next start"
399
415
  },
400
416
  "dependencies": {
401
- "@ag-ui/client": "^0.0.44",
417
+ "@ag-ui/client": "^0.0.45",
402
418
  "@assistant-ui/react": "workspace:*",
403
419
  "@assistant-ui/react-ag-ui": "workspace:*",
404
420
  "@assistant-ui/react-markdown": "workspace:*",
405
421
  "@assistant-ui/ui": "workspace:*",
406
- "@radix-ui/react-avatar": "^1.1.11",
407
- "@radix-ui/react-collapsible": "^1.1.12",
408
- "@radix-ui/react-dialog": "^1.1.15",
409
- "@radix-ui/react-slot": "^1.2.4",
410
- "@radix-ui/react-tooltip": "^1.2.8",
411
422
  "class-variance-authority": "^0.7.1",
412
423
  "clsx": "^2.1.1",
413
- "lucide-react": "^0.563.0",
424
+ "lucide-react": "^0.575.0",
414
425
  "next": "^16.1.6",
415
426
  "react": "^19.2.4",
416
427
  "react-dom": "^19.2.4",
417
- "tailwind-merge": "^3.4.0"
428
+ "tailwind-merge": "^3.5.0"
418
429
  },
419
430
  "devDependencies": {
420
431
  "@assistant-ui/x-buildutils": "workspace:*",
421
- "@tailwindcss/postcss": "^4.1.18",
422
- "@types/node": "^25.2.1",
423
- "@types/react": "^19.2.13",
432
+ "@tailwindcss/postcss": "^4.2.1",
433
+ "@types/node": "^25.3.0",
434
+ "@types/react": "^19.2.14",
424
435
  "@types/react-dom": "^19.2.3",
425
436
  "postcss": "^8.5.6",
426
- "tailwindcss": "^4.1.18",
437
+ "tailwindcss": "^4.2.1",
427
438
  "tw-animate-css": "^1.4.0",
428
439
  "typescript": "^5.9.3"
429
440
  }
@@ -515,6 +526,7 @@ The included `server/agent.py` provides:
515
526
  "../../packages/ui/src/components/assistant-ui/*"
516
527
  ],
517
528
  "@/components/ui/*": ["../../packages/ui/src/components/ui/*"],
529
+ "@/lib/utils": ["../../packages/ui/src/lib/utils"],
518
530
  "@assistant-ui/ui/*": ["../../packages/ui/src/*"]
519
531
  }
520
532
  },
@@ -203,17 +203,43 @@ export default function RootLayout({
203
203
  "use client";
204
204
 
205
205
  import { Thread } from "@/components/assistant-ui/thread";
206
- import { AssistantRuntimeProvider } from "@assistant-ui/react";
206
+ import {
207
+ AssistantRuntimeProvider,
208
+ useAui,
209
+ AuiProvider,
210
+ Suggestions,
211
+ } from "@assistant-ui/react";
207
212
  import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
208
213
 
214
+ function ThreadWithSuggestions() {
215
+ const aui = useAui({
216
+ suggestions: Suggestions([
217
+ {
218
+ title: "What's the weather",
219
+ label: "in Tokyo right now?",
220
+ prompt: "What's the weather in Tokyo?",
221
+ },
222
+ {
223
+ title: "Tell me a fun fact",
224
+ label: "about any topic",
225
+ prompt: "Tell me a fun fact about space.",
226
+ },
227
+ ]),
228
+ });
229
+ return (
230
+ <AuiProvider value={aui}>
231
+ <Thread />
232
+ </AuiProvider>
233
+ );
234
+ }
235
+
209
236
  export default function Home() {
210
- // Using the new simplified useChatRuntime hook
211
237
  const runtime = useChatRuntime();
212
238
 
213
239
  return (
214
240
  <AssistantRuntimeProvider runtime={runtime}>
215
241
  <div className="h-full">
216
- <Thread />
242
+ <ThreadWithSuggestions />
217
243
  </div>
218
244
  </AssistantRuntimeProvider>
219
245
  );
@@ -251,18 +277,6 @@ export default function Home() {
251
277
 
252
278
  ```
253
279
 
254
- ## lib/utils.ts
255
-
256
- ```typescript
257
- import { clsx, type ClassValue } from "clsx";
258
- import { twMerge } from "tailwind-merge";
259
-
260
- export function cn(...inputs: ClassValue[]) {
261
- return twMerge(clsx(inputs));
262
- }
263
-
264
- ```
265
-
266
280
  ## next.config.js
267
281
 
268
282
  ```javascript
@@ -289,34 +303,29 @@ export default nextConfig;
289
303
  "start": "next start"
290
304
  },
291
305
  "dependencies": {
292
- "@ai-sdk/openai": "^3.0.25",
306
+ "@ai-sdk/openai": "^3.0.33",
293
307
  "@assistant-ui/react": "workspace:*",
294
308
  "@assistant-ui/react-ai-sdk": "workspace:*",
295
309
  "@assistant-ui/react-markdown": "workspace:*",
296
310
  "@assistant-ui/ui": "workspace:*",
297
- "@radix-ui/react-avatar": "^1.1.11",
298
- "@radix-ui/react-collapsible": "^1.1.12",
299
- "@radix-ui/react-dialog": "^1.1.15",
300
- "@radix-ui/react-slot": "^1.2.4",
301
- "@radix-ui/react-tooltip": "^1.2.8",
302
- "ai": "^6.0.73",
311
+ "ai": "^6.0.98",
303
312
  "class-variance-authority": "^0.7.1",
304
313
  "clsx": "^2.1.1",
305
- "lucide-react": "^0.563.0",
314
+ "lucide-react": "^0.575.0",
306
315
  "next": "^16.1.6",
307
316
  "react": "^19.2.4",
308
317
  "react-dom": "^19.2.4",
309
- "tailwind-merge": "^3.4.0",
318
+ "tailwind-merge": "^3.5.0",
310
319
  "zod": "^4.3.6"
311
320
  },
312
321
  "devDependencies": {
313
322
  "@assistant-ui/x-buildutils": "workspace:*",
314
- "@tailwindcss/postcss": "^4.1.18",
315
- "@types/node": "^25.2.1",
316
- "@types/react": "^19.2.13",
323
+ "@tailwindcss/postcss": "^4.2.1",
324
+ "@types/node": "^25.3.0",
325
+ "@types/react": "^19.2.14",
317
326
  "@types/react-dom": "^19.2.3",
318
327
  "postcss": "^8.5.6",
319
- "tailwindcss": "^4.1.18",
328
+ "tailwindcss": "^4.2.1",
320
329
  "tw-animate-css": "^1.4.0",
321
330
  "typescript": "^5.9.3"
322
331
  }
@@ -418,6 +427,7 @@ The API route at `/api/chat` uses the new `streamText` function from AI SDK v6 t
418
427
  "../../packages/ui/src/components/assistant-ui/*"
419
428
  ],
420
429
  "@/components/ui/*": ["../../packages/ui/src/components/ui/*"],
430
+ "@/lib/utils": ["../../packages/ui/src/lib/utils"],
421
431
  "@assistant-ui/ui/*": ["../../packages/ui/src/*"]
422
432
  }
423
433
  },
@@ -0,0 +1,467 @@
1
+ # Example: with-artifacts
2
+
3
+ ## app/api/chat/route.ts
4
+
5
+ ```typescript
6
+ import { openai } from "@ai-sdk/openai";
7
+ import {
8
+ streamText,
9
+ convertToModelMessages,
10
+ tool,
11
+ stepCountIs,
12
+ zodSchema,
13
+ } from "ai";
14
+ import type { UIMessage } from "ai";
15
+ import { z } from "zod";
16
+
17
+ export const maxDuration = 30;
18
+
19
+ export async function POST(req: Request) {
20
+ const { messages }: { messages: UIMessage[] } = await req.json();
21
+
22
+ const result = streamText({
23
+ model: openai("gpt-4o"),
24
+ system:
25
+ "You are a helpful assistant that can generate HTML code. When the user asks you to create any visual content, UI, or webpage, use the render_html tool to render it in the browser. Always use the render_html tool for HTML output rather than showing code in a code block.",
26
+ messages: await convertToModelMessages(messages),
27
+ stopWhen: stepCountIs(10),
28
+ tools: {
29
+ render_html: tool({
30
+ description:
31
+ "Render HTML code in the user's browser. Use this whenever the user asks for HTML, a webpage, a UI component, or any visual content.",
32
+ inputSchema: zodSchema(
33
+ z.object({
34
+ code: z
35
+ .string()
36
+ .describe(
37
+ "The complete HTML code to render, including inline CSS and JavaScript if needed.",
38
+ ),
39
+ }),
40
+ ),
41
+ execute: async () => {
42
+ return { success: true };
43
+ },
44
+ }),
45
+ },
46
+ });
47
+
48
+ return result.toUIMessageStreamResponse();
49
+ }
50
+
51
+ ```
52
+
53
+ ## app/globals.css
54
+
55
+ ```css
56
+ @import "tailwindcss";
57
+ @import "tw-animate-css";
58
+
59
+ @source "../../../packages/ui/src";
60
+
61
+ @custom-variant dark (&:is(.dark *));
62
+
63
+ @theme inline {
64
+ --radius-sm: calc(var(--radius) - 4px);
65
+ --radius-md: calc(var(--radius) - 2px);
66
+ --radius-lg: var(--radius);
67
+ --radius-xl: calc(var(--radius) + 4px);
68
+ --color-background: var(--background);
69
+ --color-foreground: var(--foreground);
70
+ --color-card: var(--card);
71
+ --color-card-foreground: var(--card-foreground);
72
+ --color-popover: var(--popover);
73
+ --color-popover-foreground: var(--popover-foreground);
74
+ --color-primary: var(--primary);
75
+ --color-primary-foreground: var(--primary-foreground);
76
+ --color-secondary: var(--secondary);
77
+ --color-secondary-foreground: var(--secondary-foreground);
78
+ --color-muted: var(--muted);
79
+ --color-muted-foreground: var(--muted-foreground);
80
+ --color-accent: var(--accent);
81
+ --color-accent-foreground: var(--accent-foreground);
82
+ --color-destructive: var(--destructive);
83
+ --color-border: var(--border);
84
+ --color-input: var(--input);
85
+ --color-ring: var(--ring);
86
+ --color-chart-1: var(--chart-1);
87
+ --color-chart-2: var(--chart-2);
88
+ --color-chart-3: var(--chart-3);
89
+ --color-chart-4: var(--chart-4);
90
+ --color-chart-5: var(--chart-5);
91
+ --color-sidebar: var(--sidebar);
92
+ --color-sidebar-foreground: var(--sidebar-foreground);
93
+ --color-sidebar-primary: var(--sidebar-primary);
94
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
95
+ --color-sidebar-accent: var(--sidebar-accent);
96
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
97
+ --color-sidebar-border: var(--sidebar-border);
98
+ --color-sidebar-ring: var(--sidebar-ring);
99
+ }
100
+
101
+ :root {
102
+ --radius: 0.625rem;
103
+ --background: oklch(1 0 0);
104
+ --foreground: oklch(0.141 0.005 285.823);
105
+ --card: oklch(1 0 0);
106
+ --card-foreground: oklch(0.141 0.005 285.823);
107
+ --popover: oklch(1 0 0);
108
+ --popover-foreground: oklch(0.141 0.005 285.823);
109
+ --primary: oklch(0.21 0.006 285.885);
110
+ --primary-foreground: oklch(0.985 0 0);
111
+ --secondary: oklch(0.967 0.001 286.375);
112
+ --secondary-foreground: oklch(0.21 0.006 285.885);
113
+ --muted: oklch(0.967 0.001 286.375);
114
+ --muted-foreground: oklch(0.552 0.016 285.938);
115
+ --accent: oklch(0.967 0.001 286.375);
116
+ --accent-foreground: oklch(0.21 0.006 285.885);
117
+ --destructive: oklch(0.577 0.245 27.325);
118
+ --border: oklch(0.92 0.004 286.32);
119
+ --input: oklch(0.92 0.004 286.32);
120
+ --ring: oklch(0.705 0.015 286.067);
121
+ --chart-1: oklch(0.646 0.222 41.116);
122
+ --chart-2: oklch(0.6 0.118 184.704);
123
+ --chart-3: oklch(0.398 0.07 227.392);
124
+ --chart-4: oklch(0.828 0.189 84.429);
125
+ --chart-5: oklch(0.769 0.188 70.08);
126
+ --sidebar: oklch(0.985 0 0);
127
+ --sidebar-foreground: oklch(0.141 0.005 285.823);
128
+ --sidebar-primary: oklch(0.21 0.006 285.885);
129
+ --sidebar-primary-foreground: oklch(0.985 0 0);
130
+ --sidebar-accent: oklch(0.967 0.001 286.375);
131
+ --sidebar-accent-foreground: oklch(0.21 0.006 285.885);
132
+ --sidebar-border: oklch(0.92 0.004 286.32);
133
+ --sidebar-ring: oklch(0.705 0.015 286.067);
134
+ }
135
+
136
+ .dark {
137
+ --background: oklch(0.141 0.005 285.823);
138
+ --foreground: oklch(0.985 0 0);
139
+ --card: oklch(0.21 0.006 285.885);
140
+ --card-foreground: oklch(0.985 0 0);
141
+ --popover: oklch(0.21 0.006 285.885);
142
+ --popover-foreground: oklch(0.985 0 0);
143
+ --primary: oklch(0.92 0.004 286.32);
144
+ --primary-foreground: oklch(0.21 0.006 285.885);
145
+ --secondary: oklch(0.274 0.006 286.033);
146
+ --secondary-foreground: oklch(0.985 0 0);
147
+ --muted: oklch(0.274 0.006 286.033);
148
+ --muted-foreground: oklch(0.705 0.015 286.067);
149
+ --accent: oklch(0.274 0.006 286.033);
150
+ --accent-foreground: oklch(0.985 0 0);
151
+ --destructive: oklch(0.704 0.191 22.216);
152
+ --border: oklch(1 0 0 / 10%);
153
+ --input: oklch(1 0 0 / 15%);
154
+ --ring: oklch(0.552 0.016 285.938);
155
+ --chart-1: oklch(0.488 0.243 264.376);
156
+ --chart-2: oklch(0.696 0.17 162.48);
157
+ --chart-3: oklch(0.769 0.188 70.08);
158
+ --chart-4: oklch(0.627 0.265 303.9);
159
+ --chart-5: oklch(0.645 0.246 16.439);
160
+ --sidebar: oklch(0.21 0.006 285.885);
161
+ --sidebar-foreground: oklch(0.985 0 0);
162
+ --sidebar-primary: oklch(0.488 0.243 264.376);
163
+ --sidebar-primary-foreground: oklch(0.985 0 0);
164
+ --sidebar-accent: oklch(0.274 0.006 286.033);
165
+ --sidebar-accent-foreground: oklch(0.985 0 0);
166
+ --sidebar-border: oklch(1 0 0 / 10%);
167
+ --sidebar-ring: oklch(0.552 0.016 285.938);
168
+ }
169
+
170
+ @layer base {
171
+ * {
172
+ @apply border-border outline-ring/50;
173
+ }
174
+ body {
175
+ @apply bg-background text-foreground;
176
+ }
177
+ }
178
+
179
+ ```
180
+
181
+ ## app/layout.tsx
182
+
183
+ ```tsx
184
+ import type { Metadata } from "next";
185
+ import "./globals.css";
186
+
187
+ export const metadata: Metadata = {
188
+ title: "assistant-ui Artifacts Example",
189
+ description: "Example using assistant-ui with HTML artifact rendering",
190
+ };
191
+
192
+ export default function RootLayout({
193
+ children,
194
+ }: Readonly<{
195
+ children: React.ReactNode;
196
+ }>) {
197
+ return (
198
+ <html lang="en">
199
+ <body className="h-dvh">{children}</body>
200
+ </html>
201
+ );
202
+ }
203
+
204
+ ```
205
+
206
+ ## app/page.tsx
207
+
208
+ ```tsx
209
+ "use client";
210
+
211
+ import { Thread } from "@/components/assistant-ui/thread";
212
+ import {
213
+ AssistantRuntimeProvider,
214
+ makeAssistantTool,
215
+ useAui,
216
+ useAuiState,
217
+ AuiProvider,
218
+ Suggestions,
219
+ } from "@assistant-ui/react";
220
+ import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
221
+ import type { ToolCallMessagePart } from "@assistant-ui/react";
222
+ import { TerminalIcon, CodeIcon, EyeIcon } from "lucide-react";
223
+ import { useState } from "react";
224
+ import { z } from "zod";
225
+
226
+ const RenderHTMLTool = makeAssistantTool({
227
+ toolName: "render_html",
228
+ description:
229
+ "Whenever the user asks for HTML code, call this function. The user will see the HTML code rendered in their browser.",
230
+ parameters: z.object({
231
+ code: z.string(),
232
+ }),
233
+ execute: async () => {
234
+ return {};
235
+ },
236
+ render: () => {
237
+ return (
238
+ <div className="my-2 inline-flex items-center gap-2 rounded-full border bg-primary px-4 py-2 text-primary-foreground">
239
+ <TerminalIcon className="size-4" />
240
+ render_html(&#123; code: &quot;...&quot; &#125;)
241
+ </div>
242
+ );
243
+ },
244
+ });
245
+
246
+ function ArtifactsView() {
247
+ const [tab, setTab] = useState<"source" | "preview">("source");
248
+
249
+ const lastToolCall = useAuiState((s) => {
250
+ const messages = s.thread.messages;
251
+ return messages
252
+ .flatMap((m) =>
253
+ m.content.filter(
254
+ (c): c is ToolCallMessagePart =>
255
+ c.type === "tool-call" && c.toolName === "render_html",
256
+ ),
257
+ )
258
+ .at(-1);
259
+ });
260
+
261
+ const code = lastToolCall?.args["code"] as string | undefined;
262
+ const isComplete = lastToolCall?.result !== undefined;
263
+
264
+ if (!code) return null;
265
+
266
+ return (
267
+ <div className="flex flex-grow basis-full justify-stretch p-3">
268
+ <div className="flex h-full w-full flex-col overflow-hidden rounded-lg border">
269
+ <div className="flex border-b">
270
+ <button
271
+ onClick={() => setTab("source")}
272
+ className={`inline-flex flex-1 items-center justify-center gap-2 px-4 py-2.5 font-medium text-sm transition-colors ${
273
+ tab === "source"
274
+ ? "bg-background text-foreground"
275
+ : "text-muted-foreground hover:text-foreground"
276
+ }`}
277
+ >
278
+ <CodeIcon className="size-4" />
279
+ Source Code
280
+ </button>
281
+ <button
282
+ onClick={() => isComplete && setTab("preview")}
283
+ disabled={!isComplete}
284
+ className={`inline-flex flex-1 items-center justify-center gap-2 px-4 py-2.5 font-medium text-sm transition-colors ${
285
+ !isComplete
286
+ ? "cursor-not-allowed opacity-50"
287
+ : tab === "preview"
288
+ ? "bg-background text-foreground"
289
+ : "text-muted-foreground hover:text-foreground"
290
+ }`}
291
+ >
292
+ <EyeIcon className="size-4" />
293
+ Preview
294
+ </button>
295
+ </div>
296
+ {tab === "source" || !isComplete ? (
297
+ <div className="h-full overflow-y-auto whitespace-pre-line break-words px-4 py-2 font-mono text-sm">
298
+ {code}
299
+ </div>
300
+ ) : (
301
+ <div className="flex h-full flex-grow px-4 py-2">
302
+ <iframe
303
+ className="h-full w-full"
304
+ title="Artifact Preview"
305
+ srcDoc={code}
306
+ />
307
+ </div>
308
+ )}
309
+ </div>
310
+ </div>
311
+ );
312
+ }
313
+
314
+ function ThreadWithSuggestions() {
315
+ const aui = useAui({
316
+ suggestions: Suggestions([
317
+ {
318
+ title: "Build a landing page",
319
+ label: "with modern styling",
320
+ prompt:
321
+ "Build a beautiful landing page for a coffee shop with modern CSS.",
322
+ },
323
+ {
324
+ title: "Create a calculator",
325
+ label: "with HTML and JavaScript",
326
+ prompt:
327
+ "Create a calculator app with HTML, CSS, and JavaScript that supports basic arithmetic.",
328
+ },
329
+ ]),
330
+ });
331
+ return (
332
+ <AuiProvider value={aui}>
333
+ <Thread />
334
+ </AuiProvider>
335
+ );
336
+ }
337
+
338
+ export default function Home() {
339
+ const runtime = useChatRuntime();
340
+
341
+ return (
342
+ <AssistantRuntimeProvider runtime={runtime}>
343
+ <main className="flex h-full justify-stretch">
344
+ <div className="flex-grow basis-full">
345
+ <ThreadWithSuggestions />
346
+ </div>
347
+ <RenderHTMLTool />
348
+ <ArtifactsView />
349
+ </main>
350
+ </AssistantRuntimeProvider>
351
+ );
352
+ }
353
+
354
+ ```
355
+
356
+ ## components.json
357
+
358
+ ```json
359
+ {
360
+ "$schema": "https://ui.shadcn.com/schema.json",
361
+ "style": "new-york",
362
+ "rsc": true,
363
+ "tsx": true,
364
+ "tailwind": {
365
+ "config": "",
366
+ "css": "app/globals.css",
367
+ "baseColor": "zinc",
368
+ "cssVariables": true,
369
+ "prefix": ""
370
+ },
371
+ "aliases": {
372
+ "components": "@/components",
373
+ "utils": "@/lib/utils",
374
+ "ui": "@/components/ui",
375
+ "lib": "@/lib",
376
+ "hooks": "@/hooks"
377
+ },
378
+ "iconLibrary": "lucide",
379
+ "registries": {
380
+ "@assistant-ui": "https://r.assistant-ui.com/{name}.json"
381
+ }
382
+ }
383
+
384
+ ```
385
+
386
+ ## next.config.js
387
+
388
+ ```javascript
389
+ /** @type {import('next').NextConfig} */
390
+ const nextConfig = {
391
+ transpilePackages: [
392
+ "@assistant-ui/react",
393
+ "@assistant-ui/react-ai-sdk",
394
+ "@assistant-ui/react-markdown",
395
+ ],
396
+ };
397
+
398
+ export default nextConfig;
399
+
400
+ ```
401
+
402
+ ## package.json
403
+
404
+ ```json
405
+ {
406
+ "name": "with-artifacts",
407
+ "version": "0.0.0",
408
+ "private": true,
409
+ "type": "module",
410
+ "scripts": {
411
+ "dev": "next dev",
412
+ "build": "next build",
413
+ "start": "next start"
414
+ },
415
+ "dependencies": {
416
+ "@ai-sdk/openai": "^3.0.33",
417
+ "@assistant-ui/react": "workspace:*",
418
+ "@assistant-ui/react-ai-sdk": "workspace:*",
419
+ "@assistant-ui/react-markdown": "workspace:*",
420
+ "@assistant-ui/ui": "workspace:*",
421
+ "ai": "^6.0.98",
422
+ "class-variance-authority": "^0.7.1",
423
+ "clsx": "^2.1.1",
424
+ "lucide-react": "^0.575.0",
425
+ "next": "^16.1.6",
426
+ "react": "^19.2.4",
427
+ "react-dom": "^19.2.4",
428
+ "tailwind-merge": "^3.5.0",
429
+ "zod": "^4.3.6"
430
+ },
431
+ "devDependencies": {
432
+ "@assistant-ui/x-buildutils": "workspace:*",
433
+ "@tailwindcss/postcss": "^4.2.1",
434
+ "@types/node": "^25.3.0",
435
+ "@types/react": "^19.2.14",
436
+ "@types/react-dom": "^19.2.3",
437
+ "postcss": "^8.5.6",
438
+ "tailwindcss": "^4.2.1",
439
+ "tw-animate-css": "^1.4.0",
440
+ "typescript": "^5.9.3"
441
+ }
442
+ }
443
+
444
+ ```
445
+
446
+ ## tsconfig.json
447
+
448
+ ```json
449
+ {
450
+ "extends": "@assistant-ui/x-buildutils/ts/next",
451
+ "compilerOptions": {
452
+ "paths": {
453
+ "@/*": ["./*"],
454
+ "@/components/assistant-ui/*": [
455
+ "../../packages/ui/src/components/assistant-ui/*"
456
+ ],
457
+ "@/components/ui/*": ["../../packages/ui/src/components/ui/*"],
458
+ "@/lib/utils": ["../../packages/ui/src/lib/utils"],
459
+ "@assistant-ui/ui/*": ["../../packages/ui/src/*"]
460
+ }
461
+ },
462
+ "include": ["**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
463
+ "exclude": ["node_modules"]
464
+ }
465
+
466
+ ```
467
+