@assistant-ui/mcp-docs-server 0.1.19 → 0.1.21

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 (108) hide show
  1. package/.docs/organized/code-examples/with-ag-ui.md +172 -1633
  2. package/.docs/organized/code-examples/with-ai-sdk-v6.md +42 -1640
  3. package/.docs/organized/code-examples/with-assistant-transport.md +40 -1743
  4. package/.docs/organized/code-examples/with-cloud.md +71 -1745
  5. package/.docs/organized/code-examples/with-custom-thread-list.md +87 -1723
  6. package/.docs/organized/code-examples/with-elevenlabs-scribe.md +70 -1637
  7. package/.docs/organized/code-examples/with-external-store.md +67 -1624
  8. package/.docs/organized/code-examples/with-ffmpeg.md +71 -1629
  9. package/.docs/organized/code-examples/with-langgraph.md +95 -1893
  10. package/.docs/organized/code-examples/with-parent-id-grouping.md +57 -1654
  11. package/.docs/organized/code-examples/with-react-hook-form.md +220 -2163
  12. package/.docs/organized/code-examples/with-react-router.md +66 -1318
  13. package/.docs/organized/code-examples/with-store.md +31 -31
  14. package/.docs/organized/code-examples/with-tanstack.md +77 -861
  15. package/.docs/organized/code-examples/with-tap-runtime.md +812 -0
  16. package/.docs/raw/docs/(docs)/cli.mdx +66 -0
  17. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool-ui.mdx +0 -1
  18. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool.mdx +0 -1
  19. package/.docs/raw/docs/(docs)/copilots/model-context.mdx +4 -4
  20. package/.docs/raw/docs/(docs)/copilots/motivation.mdx +3 -3
  21. package/.docs/raw/docs/(docs)/devtools.mdx +0 -1
  22. package/.docs/raw/docs/(docs)/guides/attachments.mdx +2 -3
  23. package/.docs/raw/docs/(docs)/guides/context-api.mdx +117 -117
  24. package/.docs/raw/docs/(docs)/guides/suggestions.mdx +296 -0
  25. package/.docs/raw/docs/(docs)/guides/tools.mdx +336 -513
  26. package/.docs/raw/docs/(docs)/index.mdx +33 -410
  27. package/.docs/raw/docs/(docs)/installation.mdx +450 -0
  28. package/.docs/raw/docs/(docs)/llm.mdx +209 -0
  29. package/.docs/raw/docs/(reference)/api-reference/context-providers/assistant-runtime-provider.mdx +0 -1
  30. package/.docs/raw/docs/(reference)/api-reference/context-providers/text-message-part-provider.mdx +0 -1
  31. package/.docs/raw/docs/(reference)/api-reference/integrations/react-data-stream.mdx +48 -3
  32. package/.docs/raw/docs/(reference)/api-reference/integrations/react-hook-form.mdx +0 -1
  33. package/.docs/raw/docs/(reference)/api-reference/integrations/vercel-ai-sdk.mdx +0 -1
  34. package/.docs/raw/docs/(reference)/api-reference/overview.mdx +9 -3
  35. package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar-more.mdx +20 -52
  36. package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar.mdx +16 -39
  37. package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +49 -50
  38. package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-modal.mdx +3 -11
  39. package/.docs/raw/docs/(reference)/api-reference/primitives/attachment.mdx +0 -3
  40. package/.docs/raw/docs/(reference)/api-reference/primitives/branch-picker.mdx +0 -1
  41. package/.docs/raw/docs/(reference)/api-reference/primitives/composer.mdx +5 -16
  42. package/.docs/raw/docs/(reference)/api-reference/primitives/composition.mdx +0 -1
  43. package/.docs/raw/docs/(reference)/api-reference/primitives/error.mdx +0 -1
  44. package/.docs/raw/docs/(reference)/api-reference/primitives/message-part.mdx +1 -2
  45. package/.docs/raw/docs/(reference)/api-reference/primitives/message.mdx +0 -1
  46. package/.docs/raw/docs/(reference)/api-reference/primitives/suggestion.mdx +152 -0
  47. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list-item-more.mdx +0 -1
  48. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list-item.mdx +1 -2
  49. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list.mdx +1 -2
  50. package/.docs/raw/docs/(reference)/api-reference/primitives/thread.mdx +28 -40
  51. package/.docs/raw/docs/(reference)/api-reference/runtimes/assistant-runtime.mdx +0 -1
  52. package/.docs/raw/docs/(reference)/api-reference/runtimes/attachment-runtime.mdx +1 -2
  53. package/.docs/raw/docs/(reference)/api-reference/runtimes/composer-runtime.mdx +2 -3
  54. package/.docs/raw/docs/(reference)/api-reference/runtimes/message-part-runtime.mdx +1 -2
  55. package/.docs/raw/docs/(reference)/api-reference/runtimes/message-runtime.mdx +1 -2
  56. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-item-runtime.mdx +0 -1
  57. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-runtime.mdx +0 -1
  58. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-runtime.mdx +1 -2
  59. package/.docs/raw/docs/(reference)/legacy/styled/assistant-modal.mdx +0 -1
  60. package/.docs/raw/docs/(reference)/legacy/styled/decomposition.mdx +5 -5
  61. package/.docs/raw/docs/(reference)/legacy/styled/markdown.mdx +0 -1
  62. package/.docs/raw/docs/(reference)/legacy/styled/thread.mdx +0 -1
  63. package/.docs/raw/docs/(reference)/migrations/v0-12.mdx +207 -33
  64. package/.docs/raw/docs/(reference)/react-compatibility.mdx +0 -1
  65. package/.docs/raw/docs/cloud/persistence/ai-sdk.mdx +0 -1
  66. package/.docs/raw/docs/cloud/persistence/langgraph.mdx +0 -1
  67. package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +0 -1
  68. package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +118 -0
  69. package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +198 -0
  70. package/.docs/raw/docs/runtimes/assistant-transport.mdx +3 -3
  71. package/.docs/raw/docs/runtimes/custom/custom-thread-list.mdx +5 -6
  72. package/.docs/raw/docs/runtimes/custom/external-store.mdx +9 -11
  73. package/.docs/raw/docs/runtimes/custom/local.mdx +43 -36
  74. package/.docs/raw/docs/runtimes/data-stream.mdx +35 -3
  75. package/.docs/raw/docs/runtimes/langgraph/index.mdx +1 -2
  76. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +0 -1
  77. package/.docs/raw/docs/runtimes/langserve.mdx +0 -1
  78. package/.docs/raw/docs/runtimes/mastra/full-stack-integration.mdx +0 -1
  79. package/.docs/raw/docs/runtimes/mastra/separate-server-integration.mdx +0 -1
  80. package/.docs/raw/docs/ui/accordion.mdx +259 -0
  81. package/.docs/raw/docs/ui/assistant-modal.mdx +1 -3
  82. package/.docs/raw/docs/ui/assistant-sidebar.mdx +1 -3
  83. package/.docs/raw/docs/ui/attachment.mdx +0 -2
  84. package/.docs/raw/docs/ui/badge.mdx +138 -0
  85. package/.docs/raw/docs/ui/diff-viewer.mdx +279 -0
  86. package/.docs/raw/docs/ui/file.mdx +152 -0
  87. package/.docs/raw/docs/ui/image.mdx +100 -0
  88. package/.docs/raw/docs/ui/markdown.mdx +0 -1
  89. package/.docs/raw/docs/ui/mermaid.mdx +0 -1
  90. package/.docs/raw/docs/ui/model-selector.mdx +224 -0
  91. package/.docs/raw/docs/ui/part-grouping.mdx +4 -5
  92. package/.docs/raw/docs/ui/reasoning.mdx +6 -5
  93. package/.docs/raw/docs/ui/scrollbar.mdx +26 -9
  94. package/.docs/raw/docs/ui/select.mdx +245 -0
  95. package/.docs/raw/docs/ui/sources.mdx +6 -5
  96. package/.docs/raw/docs/ui/streamdown.mdx +348 -0
  97. package/.docs/raw/docs/ui/syntax-highlighting.mdx +8 -63
  98. package/.docs/raw/docs/ui/tabs.mdx +259 -0
  99. package/.docs/raw/docs/ui/thread-list.mdx +98 -16
  100. package/.docs/raw/docs/ui/thread.mdx +57 -73
  101. package/.docs/raw/docs/ui/tool-fallback.mdx +0 -1
  102. package/.docs/raw/docs/ui/tool-group.mdx +1 -3
  103. package/README.md +3 -3
  104. package/package.json +4 -4
  105. package/src/tools/tests/examples.test.ts +1 -1
  106. package/.docs/raw/docs/(docs)/about-assistantui.mdx +0 -54
  107. package/.docs/raw/docs/(docs)/mcp-docs-server.mdx +0 -321
  108. package/.docs/raw/docs/runtimes/ai-sdk/use-chat.mdx +0 -219
@@ -18,6 +18,36 @@
18
18
 
19
19
  ```
20
20
 
21
+ ## components.json
22
+
23
+ ```json
24
+ {
25
+ "$schema": "https://ui.shadcn.com/schema.json",
26
+ "style": "new-york",
27
+ "rsc": false,
28
+ "tsx": true,
29
+ "tailwind": {
30
+ "config": "",
31
+ "css": "src/styles.css",
32
+ "baseColor": "zinc",
33
+ "cssVariables": true,
34
+ "prefix": ""
35
+ },
36
+ "aliases": {
37
+ "components": "@/components",
38
+ "utils": "@/lib/utils",
39
+ "ui": "@/components/ui",
40
+ "lib": "@/lib",
41
+ "hooks": "@/hooks"
42
+ },
43
+ "iconLibrary": "lucide",
44
+ "registries": {
45
+ "@assistant-ui": "https://r.assistant-ui.com/{name}.json"
46
+ }
47
+ }
48
+
49
+ ```
50
+
21
51
  ## package.json
22
52
 
23
53
  ```json
@@ -37,26 +67,26 @@
37
67
  "@radix-ui/react-slot": "^1.2.4",
38
68
  "@radix-ui/react-tooltip": "^1.2.8",
39
69
  "@tailwindcss/vite": "^4.1.18",
40
- "@tanstack/react-router": "^1.153.2",
41
- "@tanstack/react-start": "^1.154.0",
70
+ "@tanstack/react-router": "^1.158.0",
71
+ "@tanstack/react-start": "^1.158.0",
42
72
  "class-variance-authority": "^0.7.1",
43
73
  "clsx": "^2.1.1",
44
- "lucide-react": "^0.562.0",
45
- "nitro": "^3.0.1-alpha.1",
46
- "openai": "^6.16.0",
47
- "react": "^19.2.3",
48
- "react-dom": "^19.2.3",
74
+ "lucide-react": "^0.563.0",
75
+ "nitro": "^3.0.1-alpha.2",
76
+ "openai": "^6.17.0",
77
+ "react": "^19.2.4",
78
+ "react-dom": "^19.2.4",
49
79
  "remark-gfm": "^4.0.1",
50
80
  "tailwind-merge": "^3.4.0",
51
81
  "tailwindcss": "^4.1.18",
52
- "vite-tsconfig-paths": "^6.0.4"
82
+ "vite-tsconfig-paths": "^6.0.5"
53
83
  },
54
84
  "devDependencies": {
55
85
  "@assistant-ui/x-buildutils": "workspace:*",
56
- "@types/node": "^25.0.9",
57
- "@types/react": "^19.2.9",
86
+ "@types/node": "^25.2.0",
87
+ "@types/react": "^19.2.10",
58
88
  "@types/react-dom": "^19.2.3",
59
- "@vitejs/plugin-react": "^5.1.2",
89
+ "@vitejs/plugin-react": "^5.1.3",
60
90
  "typescript": "^5.9.3",
61
91
  "vite": "^7.3.1"
62
92
  }
@@ -64,741 +94,48 @@
64
94
 
65
95
  ```
66
96
 
67
- ## src/components/assistant-ui/markdown-text.tsx
97
+ ## README.md
68
98
 
69
- ```tsx
70
- import "@assistant-ui/react-markdown/styles/dot.css";
99
+ ```markdown
100
+ # TanStack Start Integration
71
101
 
72
- import {
73
- type CodeHeaderProps,
74
- MarkdownTextPrimitive,
75
- unstable_memoizeMarkdownComponents as memoizeMarkdownComponents,
76
- useIsMarkdownCodeBlock,
77
- } from "@assistant-ui/react-markdown";
78
- import remarkGfm from "remark-gfm";
79
- import { type FC, memo, useState } from "react";
80
- import { CheckIcon, CopyIcon } from "lucide-react";
81
-
82
- import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
83
- import { cn } from "@/lib/utils";
84
-
85
- const MarkdownTextImpl = () => {
86
- return (
87
- <MarkdownTextPrimitive
88
- remarkPlugins={[remarkGfm]}
89
- className="aui-md"
90
- components={defaultComponents}
91
- />
92
- );
93
- };
102
+ This example demonstrates how to use assistant-ui with TanStack Start (TanStack Router + Vite).
94
103
 
95
- export const MarkdownText = memo(MarkdownTextImpl);
104
+ ## Quick Start
96
105
 
97
- const CodeHeader: FC<CodeHeaderProps> = ({ language, code }) => {
98
- const { isCopied, copyToClipboard } = useCopyToClipboard();
99
- const onCopy = () => {
100
- if (!code || isCopied) return;
101
- copyToClipboard(code);
102
- };
103
-
104
- return (
105
- <div className="aui-code-header-root mt-4 flex items-center justify-between gap-4 rounded-t-lg bg-muted-foreground/15 px-4 py-2 font-semibold text-foreground text-sm dark:bg-muted-foreground/20">
106
- <span className="aui-code-header-language lowercase [&>span]:text-xs">
107
- {language}
108
- </span>
109
- <TooltipIconButton tooltip="Copy" onClick={onCopy}>
110
- {!isCopied && <CopyIcon />}
111
- {isCopied && <CheckIcon />}
112
- </TooltipIconButton>
113
- </div>
114
- );
115
- };
116
-
117
- const useCopyToClipboard = ({
118
- copiedDuration = 3000,
119
- }: {
120
- copiedDuration?: number;
121
- } = {}) => {
122
- const [isCopied, setIsCopied] = useState<boolean>(false);
123
-
124
- const copyToClipboard = (value: string) => {
125
- if (!value) return;
126
-
127
- navigator.clipboard.writeText(value).then(() => {
128
- setIsCopied(true);
129
- setTimeout(() => setIsCopied(false), copiedDuration);
130
- });
131
- };
132
-
133
- return { isCopied, copyToClipboard };
134
- };
135
-
136
- const defaultComponents = memoizeMarkdownComponents({
137
- h1: ({ className, ...props }) => (
138
- <h1
139
- className={cn(
140
- "aui-md-h1 mb-8 scroll-m-20 font-extrabold text-4xl tracking-tight last:mb-0",
141
- className,
142
- )}
143
- {...props}
144
- />
145
- ),
146
- h2: ({ className, ...props }) => (
147
- <h2
148
- className={cn(
149
- "aui-md-h2 mt-8 mb-4 scroll-m-20 font-semibold text-3xl tracking-tight first:mt-0 last:mb-0",
150
- className,
151
- )}
152
- {...props}
153
- />
154
- ),
155
- h3: ({ className, ...props }) => (
156
- <h3
157
- className={cn(
158
- "aui-md-h3 mt-6 mb-4 scroll-m-20 font-semibold text-2xl tracking-tight first:mt-0 last:mb-0",
159
- className,
160
- )}
161
- {...props}
162
- />
163
- ),
164
- h4: ({ className, ...props }) => (
165
- <h4
166
- className={cn(
167
- "aui-md-h4 mt-6 mb-4 scroll-m-20 font-semibold text-xl tracking-tight first:mt-0 last:mb-0",
168
- className,
169
- )}
170
- {...props}
171
- />
172
- ),
173
- h5: ({ className, ...props }) => (
174
- <h5
175
- className={cn(
176
- "aui-md-h5 my-4 font-semibold text-lg first:mt-0 last:mb-0",
177
- className,
178
- )}
179
- {...props}
180
- />
181
- ),
182
- h6: ({ className, ...props }) => (
183
- <h6
184
- className={cn(
185
- "aui-md-h6 my-4 font-semibold first:mt-0 last:mb-0",
186
- className,
187
- )}
188
- {...props}
189
- />
190
- ),
191
- p: ({ className, ...props }) => (
192
- <p
193
- className={cn(
194
- "aui-md-p mt-5 mb-5 leading-7 first:mt-0 last:mb-0",
195
- className,
196
- )}
197
- {...props}
198
- />
199
- ),
200
- a: ({ className, ...props }) => (
201
- <a
202
- className={cn(
203
- "aui-md-a font-medium text-primary underline underline-offset-4",
204
- className,
205
- )}
206
- {...props}
207
- />
208
- ),
209
- blockquote: ({ className, ...props }) => (
210
- <blockquote
211
- className={cn("aui-md-blockquote border-l-2 pl-6 italic", className)}
212
- {...props}
213
- />
214
- ),
215
- ul: ({ className, ...props }) => (
216
- <ul
217
- className={cn("aui-md-ul my-5 ml-6 list-disc [&>li]:mt-2", className)}
218
- {...props}
219
- />
220
- ),
221
- ol: ({ className, ...props }) => (
222
- <ol
223
- className={cn("aui-md-ol my-5 ml-6 list-decimal [&>li]:mt-2", className)}
224
- {...props}
225
- />
226
- ),
227
- hr: ({ className, ...props }) => (
228
- <hr className={cn("aui-md-hr my-5 border-b", className)} {...props} />
229
- ),
230
- table: ({ className, ...props }) => (
231
- <table
232
- className={cn(
233
- "aui-md-table my-5 w-full border-separate border-spacing-0 overflow-y-auto",
234
- className,
235
- )}
236
- {...props}
237
- />
238
- ),
239
- th: ({ className, ...props }) => (
240
- <th
241
- className={cn(
242
- "aui-md-th bg-muted px-4 py-2 text-left font-bold first:rounded-tl-lg last:rounded-tr-lg [[align=center]]:text-center [[align=right]]:text-right",
243
- className,
244
- )}
245
- {...props}
246
- />
247
- ),
248
- td: ({ className, ...props }) => (
249
- <td
250
- className={cn(
251
- "aui-md-td border-b border-l px-4 py-2 text-left last:border-r [[align=center]]:text-center [[align=right]]:text-right",
252
- className,
253
- )}
254
- {...props}
255
- />
256
- ),
257
- tr: ({ className, ...props }) => (
258
- <tr
259
- className={cn(
260
- "aui-md-tr m-0 border-b p-0 first:border-t [&:last-child>td:first-child]:rounded-bl-lg [&:last-child>td:last-child]:rounded-br-lg",
261
- className,
262
- )}
263
- {...props}
264
- />
265
- ),
266
- sup: ({ className, ...props }) => (
267
- <sup
268
- className={cn("aui-md-sup [&>a]:text-xs [&>a]:no-underline", className)}
269
- {...props}
270
- />
271
- ),
272
- pre: ({ className, ...props }) => (
273
- <pre
274
- className={cn(
275
- "aui-md-pre overflow-x-auto rounded-t-none! rounded-b-lg bg-black p-4 text-white",
276
- className,
277
- )}
278
- {...props}
279
- />
280
- ),
281
- code: function Code({ className, ...props }) {
282
- const isCodeBlock = useIsMarkdownCodeBlock();
283
- return (
284
- <code
285
- className={cn(
286
- !isCodeBlock &&
287
- "aui-md-inline-code rounded border bg-muted font-semibold",
288
- className,
289
- )}
290
- {...props}
291
- />
292
- );
293
- },
294
- CodeHeader,
295
- });
106
+ ### Using CLI (Recommended)
296
107
 
108
+ ```bash
109
+ npx assistant-ui@latest create my-app --example with-tanstack
110
+ cd my-app
297
111
  ```
298
112
 
299
- ## src/components/assistant-ui/thread.tsx
300
-
301
- ```tsx
302
- import {
303
- ArrowDownIcon,
304
- ArrowUpIcon,
305
- CheckIcon,
306
- ChevronLeftIcon,
307
- ChevronRightIcon,
308
- CopyIcon,
309
- PencilIcon,
310
- RefreshCwIcon,
311
- Square,
312
- } from "lucide-react";
313
-
314
- import {
315
- ActionBarPrimitive,
316
- AssistantIf,
317
- BranchPickerPrimitive,
318
- ComposerPrimitive,
319
- ErrorPrimitive,
320
- MessagePrimitive,
321
- ThreadPrimitive,
322
- } from "@assistant-ui/react";
323
-
324
- import type { FC } from "react";
113
+ ### Environment Variables
325
114
 
326
- import { Button } from "@/components/ui/button";
327
- import { MarkdownText } from "@/components/assistant-ui/markdown-text";
328
- import { ToolFallback } from "@/components/assistant-ui/tool-fallback";
329
- import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
330
-
331
- import { cn } from "@/lib/utils";
332
-
333
- export const Thread: FC = () => {
334
- return (
335
- <ThreadPrimitive.Root
336
- className="aui-root aui-thread-root @container flex h-full flex-col bg-background"
337
- style={{
338
- ["--thread-max-width" as string]: "44rem",
339
- }}
340
- >
341
- <ThreadPrimitive.Viewport
342
- turnAnchor="top"
343
- className="aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-smooth px-4 pt-4"
344
- >
345
- <AssistantIf condition={({ thread }) => thread.isEmpty}>
346
- <ThreadWelcome />
347
- </AssistantIf>
348
-
349
- <ThreadPrimitive.Messages
350
- components={{
351
- UserMessage,
352
- EditComposer,
353
- AssistantMessage,
354
- }}
355
- />
356
-
357
- <ThreadPrimitive.ViewportFooter className="aui-thread-viewport-footer sticky bottom-0 mx-auto mt-4 flex w-full max-w-(--thread-max-width) flex-col gap-4 overflow-visible rounded-t-3xl bg-background pb-4 md:pb-6">
358
- <ThreadScrollToBottom />
359
- <Composer />
360
- </ThreadPrimitive.ViewportFooter>
361
- </ThreadPrimitive.Viewport>
362
- </ThreadPrimitive.Root>
363
- );
364
- };
365
-
366
- const ThreadScrollToBottom: FC = () => {
367
- return (
368
- <ThreadPrimitive.ScrollToBottom asChild>
369
- <TooltipIconButton
370
- tooltip="Scroll to bottom"
371
- variant="outline"
372
- className="aui-thread-scroll-to-bottom absolute -top-12 z-10 self-center rounded-full p-4 disabled:invisible dark:bg-background dark:hover:bg-accent"
373
- >
374
- <ArrowDownIcon />
375
- </TooltipIconButton>
376
- </ThreadPrimitive.ScrollToBottom>
377
- );
378
- };
379
-
380
- const ThreadWelcome: FC = () => {
381
- return (
382
- <div className="aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col">
383
- <div className="aui-thread-welcome-center flex w-full grow flex-col items-center justify-center">
384
- <div className="aui-thread-welcome-message flex size-full flex-col justify-center px-8">
385
- <div className="aui-thread-welcome-message-inner fade-in slide-in-from-bottom-2 animate-in font-semibold text-2xl duration-300 ease-out">
386
- Hello there!
387
- </div>
388
- <div className="aui-thread-welcome-message-inner fade-in slide-in-from-bottom-2 animate-in text-2xl text-muted-foreground/65 delay-100 duration-300 ease-out">
389
- How can I help you today?
390
- </div>
391
- </div>
392
- </div>
393
- <ThreadSuggestions />
394
- </div>
395
- );
396
- };
397
-
398
- const ThreadSuggestions: FC = () => {
399
- return (
400
- <div className="aui-thread-welcome-suggestions grid w-full @md:grid-cols-2 gap-2 pb-4">
401
- {[
402
- {
403
- title: "What's the weather",
404
- label: "in San Francisco?",
405
- action: "What's the weather in San Francisco?",
406
- },
407
- {
408
- title: "Explain React hooks",
409
- label: "like useState and useEffect",
410
- action: "Explain React hooks like useState and useEffect",
411
- },
412
- {
413
- title: "Write a SQL query",
414
- label: "to find top customers",
415
- action: "Write a SQL query to find top customers",
416
- },
417
- {
418
- title: "Create a meal plan",
419
- label: "for healthy weight loss",
420
- action: "Create a meal plan for healthy weight loss",
421
- },
422
- ].map((suggestedAction, index) => (
423
- <div
424
- key={`suggested-action-${suggestedAction.title}-${index}`}
425
- className="aui-thread-welcome-suggestion-display fade-in slide-in-from-bottom-4 @md:nth-[n+3]:block nth-[n+3]:hidden animate-in fill-mode-both duration-300 ease-out"
426
- style={{ animationDelay: `${index * 50}ms` }}
427
- >
428
- <ThreadPrimitive.Suggestion
429
- prompt={suggestedAction.action}
430
- send
431
- asChild
432
- >
433
- <Button
434
- variant="ghost"
435
- className="aui-thread-welcome-suggestion h-auto w-full flex-1 @md:flex-col flex-wrap items-start justify-start gap-1 rounded-3xl border px-5 py-4 text-left text-sm dark:hover:bg-accent/60"
436
- aria-label={suggestedAction.action}
437
- >
438
- <span className="aui-thread-welcome-suggestion-text-1 font-medium">
439
- {suggestedAction.title}
440
- </span>
441
- <span className="aui-thread-welcome-suggestion-text-2 text-muted-foreground">
442
- {suggestedAction.label}
443
- </span>
444
- </Button>
445
- </ThreadPrimitive.Suggestion>
446
- </div>
447
- ))}
448
- </div>
449
- );
450
- };
451
-
452
- const Composer: FC = () => {
453
- return (
454
- <ComposerPrimitive.Root className="aui-composer-root relative flex w-full flex-col">
455
- <div className="flex w-full flex-col rounded-3xl border border-input bg-background px-1 pt-2 shadow-xs outline-none transition-[color,box-shadow] has-[textarea:focus-visible]:border-ring has-[textarea:focus-visible]:ring-[3px] has-[textarea:focus-visible]:ring-ring/50 dark:bg-background">
456
- <ComposerPrimitive.Input
457
- placeholder="Send a message..."
458
- className="aui-composer-input mb-1 max-h-32 min-h-16 w-full resize-none bg-transparent px-3.5 pt-1.5 pb-3 text-base outline-none placeholder:text-muted-foreground focus-visible:ring-0"
459
- rows={1}
460
- autoFocus
461
- aria-label="Message input"
462
- />
463
- <ComposerAction />
464
- </div>
465
- </ComposerPrimitive.Root>
466
- );
467
- };
468
-
469
- const ComposerAction: FC = () => {
470
- return (
471
- <div className="aui-composer-action-wrapper relative mx-1 mt-2 mb-2 flex items-center justify-end">
472
- <AssistantIf condition={({ thread }) => !thread.isRunning}>
473
- <ComposerPrimitive.Send asChild>
474
- <TooltipIconButton
475
- tooltip="Send message"
476
- side="bottom"
477
- type="submit"
478
- variant="default"
479
- size="icon"
480
- className="aui-composer-send size-[34px] rounded-full p-1"
481
- aria-label="Send message"
482
- >
483
- <ArrowUpIcon className="aui-composer-send-icon size-5" />
484
- </TooltipIconButton>
485
- </ComposerPrimitive.Send>
486
- </AssistantIf>
487
-
488
- <AssistantIf condition={({ thread }) => thread.isRunning}>
489
- <ComposerPrimitive.Cancel asChild>
490
- <Button
491
- type="button"
492
- variant="default"
493
- size="icon"
494
- className="aui-composer-cancel size-[34px] rounded-full border border-muted-foreground/60 hover:bg-primary/75 dark:border-muted-foreground/90"
495
- aria-label="Stop generating"
496
- >
497
- <Square className="aui-composer-cancel-icon size-3.5 fill-white dark:fill-black" />
498
- </Button>
499
- </ComposerPrimitive.Cancel>
500
- </AssistantIf>
501
- </div>
502
- );
503
- };
504
-
505
- const MessageError: FC = () => {
506
- return (
507
- <MessagePrimitive.Error>
508
- <ErrorPrimitive.Root className="aui-message-error-root mt-2 rounded-md border border-destructive bg-destructive/10 p-3 text-destructive text-sm dark:bg-destructive/5 dark:text-red-200">
509
- <ErrorPrimitive.Message className="aui-message-error-message line-clamp-2" />
510
- </ErrorPrimitive.Root>
511
- </MessagePrimitive.Error>
512
- );
513
- };
514
-
515
- const AssistantMessage: FC = () => {
516
- return (
517
- <MessagePrimitive.Root
518
- className="aui-assistant-message-root fade-in slide-in-from-bottom-1 relative mx-auto w-full max-w-(--thread-max-width) animate-in py-4 duration-150 ease-out"
519
- data-role="assistant"
520
- >
521
- <div className="aui-assistant-message-content wrap-break-word mx-2 text-foreground leading-7">
522
- <MessagePrimitive.Parts
523
- components={{
524
- Text: MarkdownText,
525
- tools: { Fallback: ToolFallback },
526
- }}
527
- />
528
- <MessageError />
529
- </div>
530
-
531
- <div className="aui-assistant-message-footer mt-2 ml-2 flex">
532
- <BranchPicker />
533
- <AssistantActionBar />
534
- </div>
535
- </MessagePrimitive.Root>
536
- );
537
- };
538
-
539
- const AssistantActionBar: FC = () => {
540
- return (
541
- <ActionBarPrimitive.Root
542
- hideWhenRunning
543
- autohide="not-last"
544
- autohideFloat="single-branch"
545
- className="aui-assistant-action-bar-root col-start-3 row-start-2 -ml-1 flex gap-1 text-muted-foreground data-floating:absolute data-floating:rounded-md data-floating:border data-floating:bg-background data-floating:p-1 data-floating:shadow-sm"
546
- >
547
- <ActionBarPrimitive.Copy asChild>
548
- <TooltipIconButton tooltip="Copy">
549
- <AssistantIf condition={({ message }) => message.isCopied}>
550
- <CheckIcon />
551
- </AssistantIf>
552
- <AssistantIf condition={({ message }) => !message.isCopied}>
553
- <CopyIcon />
554
- </AssistantIf>
555
- </TooltipIconButton>
556
- </ActionBarPrimitive.Copy>
557
- <ActionBarPrimitive.Reload asChild>
558
- <TooltipIconButton tooltip="Refresh">
559
- <RefreshCwIcon />
560
- </TooltipIconButton>
561
- </ActionBarPrimitive.Reload>
562
- </ActionBarPrimitive.Root>
563
- );
564
- };
565
-
566
- const UserMessage: FC = () => {
567
- return (
568
- <MessagePrimitive.Root
569
- className="aui-user-message-root fade-in slide-in-from-bottom-1 mx-auto grid w-full max-w-(--thread-max-width) animate-in auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] content-start gap-y-2 px-2 py-4 duration-150 ease-out [&:where(>*)]:col-start-2"
570
- data-role="user"
571
- >
572
- <div className="aui-user-message-content-wrapper relative col-start-2 min-w-0">
573
- <div className="aui-user-message-content wrap-break-word rounded-3xl bg-muted px-5 py-2.5 text-foreground">
574
- <MessagePrimitive.Parts />
575
- </div>
576
- <div className="aui-user-action-bar-wrapper absolute top-1/2 left-0 -translate-x-full -translate-y-1/2 pr-2">
577
- <UserActionBar />
578
- </div>
579
- </div>
580
-
581
- <BranchPicker className="aui-user-branch-picker col-span-full col-start-1 row-start-3 -mr-1 justify-end" />
582
- </MessagePrimitive.Root>
583
- );
584
- };
585
-
586
- const UserActionBar: FC = () => {
587
- return (
588
- <ActionBarPrimitive.Root
589
- hideWhenRunning
590
- autohide="not-last"
591
- className="aui-user-action-bar-root flex flex-col items-end"
592
- >
593
- <ActionBarPrimitive.Edit asChild>
594
- <TooltipIconButton tooltip="Edit" className="aui-user-action-edit p-4">
595
- <PencilIcon />
596
- </TooltipIconButton>
597
- </ActionBarPrimitive.Edit>
598
- </ActionBarPrimitive.Root>
599
- );
600
- };
601
-
602
- const EditComposer: FC = () => {
603
- return (
604
- <MessagePrimitive.Root className="aui-edit-composer-wrapper mx-auto flex w-full max-w-(--thread-max-width) flex-col gap-4 px-2">
605
- <ComposerPrimitive.Root className="aui-edit-composer-root ml-auto flex w-full max-w-7/8 flex-col rounded-xl bg-muted">
606
- <ComposerPrimitive.Input
607
- className="aui-edit-composer-input flex min-h-[60px] w-full resize-none bg-transparent p-4 text-foreground outline-none"
608
- autoFocus
609
- />
610
-
611
- <div className="aui-edit-composer-footer mx-3 mb-3 flex items-center justify-center gap-2 self-end">
612
- <ComposerPrimitive.Cancel asChild>
613
- <Button variant="ghost" size="sm" aria-label="Cancel edit">
614
- Cancel
615
- </Button>
616
- </ComposerPrimitive.Cancel>
617
- <ComposerPrimitive.Send asChild>
618
- <Button size="sm" aria-label="Update message">
619
- Update
620
- </Button>
621
- </ComposerPrimitive.Send>
622
- </div>
623
- </ComposerPrimitive.Root>
624
- </MessagePrimitive.Root>
625
- );
626
- };
627
-
628
- const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
629
- className,
630
- ...rest
631
- }) => {
632
- return (
633
- <BranchPickerPrimitive.Root
634
- hideWhenSingleBranch
635
- className={cn(
636
- "aui-branch-picker-root mr-2 -ml-2 inline-flex items-center text-muted-foreground text-xs",
637
- className,
638
- )}
639
- {...rest}
640
- >
641
- <BranchPickerPrimitive.Previous asChild>
642
- <TooltipIconButton tooltip="Previous">
643
- <ChevronLeftIcon />
644
- </TooltipIconButton>
645
- </BranchPickerPrimitive.Previous>
646
- <span className="aui-branch-picker-state font-medium">
647
- <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
648
- </span>
649
- <BranchPickerPrimitive.Next asChild>
650
- <TooltipIconButton tooltip="Next">
651
- <ChevronRightIcon />
652
- </TooltipIconButton>
653
- </BranchPickerPrimitive.Next>
654
- </BranchPickerPrimitive.Root>
655
- );
656
- };
115
+ Create `.env`:
657
116
 
117
+ ```
118
+ OPENAI_API_KEY=sk-...
658
119
  ```
659
120
 
660
- ## src/components/assistant-ui/tool-fallback.tsx
661
-
662
- ```tsx
663
- import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
664
- import {
665
- CheckIcon,
666
- ChevronDownIcon,
667
- ChevronUpIcon,
668
- XCircleIcon,
669
- } from "lucide-react";
670
- import { useState } from "react";
671
- import { Button } from "@/components/ui/button";
672
- import { cn } from "@/lib/utils";
673
-
674
- export const ToolFallback: ToolCallMessagePartComponent = ({
675
- toolName,
676
- argsText,
677
- result,
678
- status,
679
- }) => {
680
- const [isCollapsed, setIsCollapsed] = useState(true);
681
-
682
- const isCancelled =
683
- status?.type === "incomplete" && status.reason === "cancelled";
684
- const cancelledReason =
685
- isCancelled && status.error
686
- ? typeof status.error === "string"
687
- ? status.error
688
- : JSON.stringify(status.error)
689
- : null;
690
-
691
- return (
692
- <div
693
- className={cn(
694
- "aui-tool-fallback-root mb-4 flex w-full flex-col gap-3 rounded-lg border py-3",
695
- isCancelled && "border-muted-foreground/30 bg-muted/30",
696
- )}
697
- >
698
- <div className="aui-tool-fallback-header flex items-center gap-2 px-4">
699
- {isCancelled ? (
700
- <XCircleIcon className="aui-tool-fallback-icon size-4 text-muted-foreground" />
701
- ) : (
702
- <CheckIcon className="aui-tool-fallback-icon size-4" />
703
- )}
704
- <p
705
- className={cn(
706
- "aui-tool-fallback-title grow",
707
- isCancelled && "text-muted-foreground line-through",
708
- )}
709
- >
710
- {isCancelled ? "Cancelled tool: " : "Used tool: "}
711
- <b>{toolName}</b>
712
- </p>
713
- <Button onClick={() => setIsCollapsed(!isCollapsed)}>
714
- {isCollapsed ? <ChevronUpIcon /> : <ChevronDownIcon />}
715
- </Button>
716
- </div>
717
- {!isCollapsed && (
718
- <div className="aui-tool-fallback-content flex flex-col gap-2 border-t pt-2">
719
- {cancelledReason && (
720
- <div className="aui-tool-fallback-cancelled-root px-4">
721
- <p className="aui-tool-fallback-cancelled-header font-semibold text-muted-foreground">
722
- Cancelled reason:
723
- </p>
724
- <p className="aui-tool-fallback-cancelled-reason text-muted-foreground">
725
- {cancelledReason}
726
- </p>
727
- </div>
728
- )}
729
- <div
730
- className={cn(
731
- "aui-tool-fallback-args-root px-4",
732
- isCancelled && "opacity-60",
733
- )}
734
- >
735
- <pre className="aui-tool-fallback-args-value whitespace-pre-wrap">
736
- {argsText}
737
- </pre>
738
- </div>
739
- {!isCancelled && result !== undefined && (
740
- <div className="aui-tool-fallback-result-root border-t border-dashed px-4 pt-2">
741
- <p className="aui-tool-fallback-result-header font-semibold">
742
- Result:
743
- </p>
744
- <pre className="aui-tool-fallback-result-content whitespace-pre-wrap">
745
- {typeof result === "string"
746
- ? result
747
- : JSON.stringify(result, null, 2)}
748
- </pre>
749
- </div>
750
- )}
751
- </div>
752
- )}
753
- </div>
754
- );
755
- };
121
+ ### Run
756
122
 
123
+ ```bash
124
+ npm install
125
+ npm run dev
757
126
  ```
758
127
 
759
- ## src/components/assistant-ui/tooltip-icon-button.tsx
128
+ ## Features
760
129
 
761
- ```tsx
762
- import { ComponentPropsWithRef, forwardRef } from "react";
763
- import { Slottable } from "@radix-ui/react-slot";
130
+ - TanStack Start (TanStack Router + Vite)
131
+ - Full-stack React with server functions
132
+ - OpenAI streaming chat
133
+ - Markdown message rendering
764
134
 
765
- import {
766
- Tooltip,
767
- TooltipContent,
768
- TooltipTrigger,
769
- } from "@/components/ui/tooltip";
770
- import { Button } from "@/components/ui/button";
771
- import { cn } from "@/lib/utils";
772
-
773
- export type TooltipIconButtonProps = ComponentPropsWithRef<typeof Button> & {
774
- tooltip: string;
775
- side?: "top" | "bottom" | "left" | "right";
776
- };
135
+ ## Related Documentation
777
136
 
778
- export const TooltipIconButton = forwardRef<
779
- HTMLButtonElement,
780
- TooltipIconButtonProps
781
- >(({ children, tooltip, side = "bottom", className, ...rest }, ref) => {
782
- return (
783
- <Tooltip>
784
- <TooltipTrigger asChild>
785
- <Button
786
- variant="ghost"
787
- size="icon"
788
- {...rest}
789
- className={cn("aui-button-icon size-6 p-1", className)}
790
- ref={ref}
791
- >
792
- <Slottable>{children}</Slottable>
793
- <span className="aui-sr-only sr-only">{tooltip}</span>
794
- </Button>
795
- </TooltipTrigger>
796
- <TooltipContent side={side}>{tooltip}</TooltipContent>
797
- </Tooltip>
798
- );
799
- });
800
-
801
- TooltipIconButton.displayName = "TooltipIconButton";
137
+ - [assistant-ui Documentation](https://www.assistant-ui.com/docs)
138
+ - [TanStack Start Documentation](https://tanstack.com/start)
802
139
 
803
140
  ```
804
141
 
@@ -912,136 +249,6 @@ export function MyRuntimeProvider({
912
249
 
913
250
  ```
914
251
 
915
- ## src/components/ui/button.tsx
916
-
917
- ```tsx
918
- import * as React from "react";
919
- import { Slot } from "@radix-ui/react-slot";
920
- import { cva, type VariantProps } from "class-variance-authority";
921
-
922
- import { cn } from "@/lib/utils";
923
-
924
- const buttonVariants = cva(
925
- "inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md font-medium text-sm outline-none transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
926
- {
927
- variants: {
928
- variant: {
929
- default:
930
- "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
931
- destructive:
932
- "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
933
- outline:
934
- "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
935
- secondary:
936
- "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
937
- ghost:
938
- "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
939
- link: "text-primary underline-offset-4 hover:underline",
940
- },
941
- size: {
942
- default: "h-9 px-4 py-2 has-[>svg]:px-3",
943
- sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
944
- lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
945
- icon: "size-9",
946
- },
947
- },
948
- defaultVariants: {
949
- variant: "default",
950
- size: "default",
951
- },
952
- },
953
- );
954
-
955
- function Button({
956
- className,
957
- variant,
958
- size,
959
- asChild = false,
960
- ...props
961
- }: React.ComponentProps<"button"> &
962
- VariantProps<typeof buttonVariants> & {
963
- asChild?: boolean;
964
- }) {
965
- const Comp = asChild ? Slot : "button";
966
-
967
- return (
968
- <Comp
969
- data-slot="button"
970
- className={cn(buttonVariants({ variant, size, className }))}
971
- {...props}
972
- />
973
- );
974
- }
975
-
976
- export { Button, buttonVariants };
977
-
978
- ```
979
-
980
- ## src/components/ui/tooltip.tsx
981
-
982
- ```tsx
983
- import * as React from "react";
984
- import * as TooltipPrimitive from "@radix-ui/react-tooltip";
985
-
986
- import { cn } from "@/lib/utils";
987
-
988
- function TooltipProvider({
989
- delayDuration = 0,
990
- ...props
991
- }: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
992
- return (
993
- <TooltipPrimitive.Provider
994
- data-slot="tooltip-provider"
995
- delayDuration={delayDuration}
996
- {...props}
997
- />
998
- );
999
- }
1000
-
1001
- function Tooltip({
1002
- ...props
1003
- }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
1004
- return (
1005
- <TooltipProvider>
1006
- <TooltipPrimitive.Root data-slot="tooltip" {...props} />
1007
- </TooltipProvider>
1008
- );
1009
- }
1010
-
1011
- function TooltipTrigger({
1012
- ...props
1013
- }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
1014
- return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
1015
- }
1016
-
1017
- function TooltipContent({
1018
- className,
1019
- sideOffset = 0,
1020
- children,
1021
- ...props
1022
- }: React.ComponentProps<typeof TooltipPrimitive.Content>) {
1023
- return (
1024
- <TooltipPrimitive.Portal>
1025
- <TooltipPrimitive.Content
1026
- data-slot="tooltip-content"
1027
- sideOffset={sideOffset}
1028
- className={cn(
1029
- "fade-in-0 zoom-in-95 data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) animate-in text-balance rounded-md bg-primary px-3 py-1.5 text-primary-foreground text-xs data-[state=closed]:animate-out",
1030
- className,
1031
- )}
1032
- {...props}
1033
- >
1034
- {children}
1035
- <TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-primary fill-primary" />
1036
- </TooltipPrimitive.Content>
1037
- </TooltipPrimitive.Portal>
1038
- );
1039
- }
1040
-
1041
- export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
1042
-
1043
- ```
1044
-
1045
252
  ## src/lib/utils.ts
1046
253
 
1047
254
  ```typescript
@@ -1262,6 +469,8 @@ export const chatStream = createServerFn({ method: "POST" })
1262
469
  ```css
1263
470
  @import "tailwindcss";
1264
471
 
472
+ @source "../../../packages/ui/src";
473
+
1265
474
  @custom-variant dark (&:is(.dark *));
1266
475
 
1267
476
  @theme inline {
@@ -1520,7 +729,14 @@ export const chatStream = createServerFn({ method: "POST" })
1520
729
  "extends": "@assistant-ui/x-buildutils/ts/base",
1521
730
  "compilerOptions": {
1522
731
  "types": ["vite/client"],
1523
- "paths": { "@/*": ["./src/*"] }
732
+ "paths": {
733
+ "@/*": ["./src/*"],
734
+ "@/components/assistant-ui/*": [
735
+ "../../packages/ui/src/components/assistant-ui/*"
736
+ ],
737
+ "@/components/ui/*": ["../../packages/ui/src/components/ui/*"],
738
+ "@assistant-ui/ui/*": ["../../packages/ui/src/*"]
739
+ }
1524
740
  },
1525
741
  "include": ["**/*.ts", "**/*.tsx"],
1526
742
  "exclude": ["node_modules"]
@@ -1546,7 +762,7 @@ const config = defineConfig({
1546
762
  },
1547
763
  }),
1548
764
  viteTsConfigPaths({
1549
- projects: ["./tsconfig.json"],
765
+ projects: ["./tsconfig.json", "../../packages/ui/tsconfig.json"],
1550
766
  }),
1551
767
  tailwindcss(),
1552
768
  tanstackStart(),