@assistant-ui/mcp-docs-server 0.1.14 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.docs/organized/code-examples/store-example.md +628 -0
- package/.docs/organized/code-examples/with-ag-ui.md +792 -178
- package/.docs/organized/code-examples/with-ai-sdk-v5.md +762 -209
- package/.docs/organized/code-examples/with-assistant-transport.md +707 -254
- package/.docs/organized/code-examples/with-cloud.md +848 -202
- package/.docs/organized/code-examples/with-custom-thread-list.md +1855 -0
- package/.docs/organized/code-examples/with-external-store.md +788 -172
- package/.docs/organized/code-examples/with-ffmpeg.md +796 -196
- package/.docs/organized/code-examples/with-langgraph.md +864 -230
- package/.docs/organized/code-examples/with-parent-id-grouping.md +785 -255
- package/.docs/organized/code-examples/with-react-hook-form.md +804 -226
- package/.docs/organized/code-examples/with-tanstack.md +1574 -0
- package/.docs/raw/blog/2024-07-29-hello/index.mdx +2 -3
- package/.docs/raw/docs/api-reference/overview.mdx +6 -6
- package/.docs/raw/docs/api-reference/primitives/ActionBar.mdx +85 -4
- package/.docs/raw/docs/api-reference/primitives/AssistantIf.mdx +200 -0
- package/.docs/raw/docs/api-reference/primitives/Composer.mdx +0 -20
- package/.docs/raw/docs/api-reference/primitives/Message.mdx +0 -45
- package/.docs/raw/docs/api-reference/primitives/Thread.mdx +0 -50
- package/.docs/raw/docs/cli.mdx +396 -0
- package/.docs/raw/docs/cloud/persistence/ai-sdk.mdx +2 -3
- package/.docs/raw/docs/cloud/persistence/langgraph.mdx +2 -3
- package/.docs/raw/docs/devtools.mdx +2 -3
- package/.docs/raw/docs/getting-started.mdx +37 -1109
- package/.docs/raw/docs/guides/Attachments.mdx +3 -25
- package/.docs/raw/docs/guides/Branching.mdx +1 -1
- package/.docs/raw/docs/guides/Speech.mdx +1 -1
- package/.docs/raw/docs/guides/ToolUI.mdx +1 -1
- package/.docs/raw/docs/legacy/styled/AssistantModal.mdx +2 -3
- package/.docs/raw/docs/legacy/styled/Decomposition.mdx +6 -5
- package/.docs/raw/docs/legacy/styled/Markdown.mdx +2 -3
- package/.docs/raw/docs/legacy/styled/Thread.mdx +2 -3
- package/.docs/raw/docs/react-compatibility.mdx +2 -5
- package/.docs/raw/docs/runtimes/ai-sdk/use-chat.mdx +3 -4
- package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +3 -6
- package/.docs/raw/docs/runtimes/assistant-transport.mdx +891 -0
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +2 -3
- package/.docs/raw/docs/runtimes/custom/local.mdx +11 -41
- package/.docs/raw/docs/runtimes/data-stream.mdx +15 -11
- package/.docs/raw/docs/runtimes/langgraph/index.mdx +4 -4
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +1 -1
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +2 -3
- package/.docs/raw/docs/runtimes/langserve.mdx +2 -3
- package/.docs/raw/docs/runtimes/mastra/full-stack-integration.mdx +2 -3
- package/.docs/raw/docs/runtimes/mastra/separate-server-integration.mdx +2 -3
- package/.docs/raw/docs/ui/AssistantModal.mdx +3 -25
- package/.docs/raw/docs/ui/AssistantSidebar.mdx +2 -24
- package/.docs/raw/docs/ui/Attachment.mdx +3 -25
- package/.docs/raw/docs/ui/Markdown.mdx +2 -24
- package/.docs/raw/docs/ui/Mermaid.mdx +2 -24
- package/.docs/raw/docs/ui/Reasoning.mdx +2 -24
- package/.docs/raw/docs/ui/Scrollbar.mdx +4 -6
- package/.docs/raw/docs/ui/SyntaxHighlighting.mdx +3 -47
- package/.docs/raw/docs/ui/Thread.mdx +38 -53
- package/.docs/raw/docs/ui/ThreadList.mdx +4 -47
- package/.docs/raw/docs/ui/ToolFallback.mdx +2 -24
- package/package.json +15 -8
|
@@ -6,6 +6,7 @@ import { Step, Steps } from "fumadocs-ui/components/steps";
|
|
|
6
6
|
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
|
|
7
7
|
import { Callout } from "fumadocs-ui/components/callout";
|
|
8
8
|
import { Card, Cards } from "fumadocs-ui/components/card";
|
|
9
|
+
import { InstallCommand } from "@/components/docs/install-command";
|
|
9
10
|
|
|
10
11
|
## Start with a new project
|
|
11
12
|
|
|
@@ -77,1068 +78,7 @@ npm run dev
|
|
|
77
78
|
|
|
78
79
|
### Add assistant-ui
|
|
79
80
|
|
|
80
|
-
<
|
|
81
|
-
<Tab>
|
|
82
|
-
|
|
83
|
-
```sh npm2yarn
|
|
84
|
-
npx assistant-ui add thread thread-list
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
</Tab>
|
|
88
|
-
<Tab>
|
|
89
|
-
<Steps>
|
|
90
|
-
<Step>
|
|
91
|
-
|
|
92
|
-
Add the following packages:
|
|
93
|
-
|
|
94
|
-
```sh
|
|
95
|
-
npm install \
|
|
96
|
-
@assistant-ui/react \
|
|
97
|
-
@assistant-ui/react-markdown \
|
|
98
|
-
@assistant-ui/styles \
|
|
99
|
-
@radix-ui/react-avatar \
|
|
100
|
-
@radix-ui/react-dialog \
|
|
101
|
-
@radix-ui/react-slot \
|
|
102
|
-
@radix-ui/react-tooltip \
|
|
103
|
-
class-variance-authority \
|
|
104
|
-
clsx \
|
|
105
|
-
lucide-react \
|
|
106
|
-
motion \
|
|
107
|
-
remark-gfm \
|
|
108
|
-
zustand
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
</Step>
|
|
112
|
-
|
|
113
|
-
<Step>
|
|
114
|
-
|
|
115
|
-
Copy the following components into your project:
|
|
116
|
-
|
|
117
|
-
```tsx title="components/ui/button.tsx"
|
|
118
|
-
import * as React from "react";
|
|
119
|
-
import { Slot } from "@radix-ui/react-slot";
|
|
120
|
-
import { cva, type VariantProps } from "class-variance-authority";
|
|
121
|
-
|
|
122
|
-
import { cn } from "@/lib/utils";
|
|
123
|
-
|
|
124
|
-
const buttonVariants = cva("aui-button", {
|
|
125
|
-
variants: {
|
|
126
|
-
variant: {
|
|
127
|
-
default: "aui-button-primary",
|
|
128
|
-
outline: "aui-button-outline",
|
|
129
|
-
ghost: "aui-button-ghost",
|
|
130
|
-
},
|
|
131
|
-
size: {
|
|
132
|
-
default: "aui-button-medium",
|
|
133
|
-
icon: "aui-button-icon",
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
defaultVariants: {
|
|
137
|
-
variant: "default",
|
|
138
|
-
size: "default",
|
|
139
|
-
},
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
function Button({
|
|
143
|
-
className,
|
|
144
|
-
variant,
|
|
145
|
-
size,
|
|
146
|
-
asChild = false,
|
|
147
|
-
...props
|
|
148
|
-
}: React.ComponentProps<"button"> &
|
|
149
|
-
VariantProps<typeof buttonVariants> & {
|
|
150
|
-
asChild?: boolean;
|
|
151
|
-
}) {
|
|
152
|
-
const Comp = asChild ? Slot : "button";
|
|
153
|
-
|
|
154
|
-
return (
|
|
155
|
-
<Comp
|
|
156
|
-
data-slot="button"
|
|
157
|
-
className={cn(buttonVariants({ variant, size, className }))}
|
|
158
|
-
{...props}
|
|
159
|
-
/>
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export { Button, buttonVariants };
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
```tsx title="components/ui/tooltip.tsx"
|
|
167
|
-
"use client";
|
|
168
|
-
|
|
169
|
-
import * as React from "react";
|
|
170
|
-
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
171
|
-
|
|
172
|
-
import { cn } from "@/lib/utils";
|
|
173
|
-
|
|
174
|
-
const TooltipProvider = TooltipPrimitive.Provider;
|
|
175
|
-
|
|
176
|
-
const Tooltip = TooltipPrimitive.Root;
|
|
177
|
-
|
|
178
|
-
const TooltipTrigger = TooltipPrimitive.Trigger;
|
|
179
|
-
|
|
180
|
-
const TooltipContent = React.forwardRef<
|
|
181
|
-
React.ElementRef<typeof TooltipPrimitive.Content>,
|
|
182
|
-
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
|
|
183
|
-
>(({ className, sideOffset = 4, ...props }, ref) => (
|
|
184
|
-
<TooltipPrimitive.Portal>
|
|
185
|
-
<TooltipPrimitive.Content
|
|
186
|
-
ref={ref}
|
|
187
|
-
sideOffset={sideOffset}
|
|
188
|
-
className={cn("aui-tooltip-content", className)}
|
|
189
|
-
{...props}
|
|
190
|
-
/>
|
|
191
|
-
</TooltipPrimitive.Portal>
|
|
192
|
-
));
|
|
193
|
-
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
194
|
-
|
|
195
|
-
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
```tsx title="components/assistant-ui/thread.tsx"
|
|
199
|
-
import {
|
|
200
|
-
ArrowDownIcon,
|
|
201
|
-
ArrowUpIcon,
|
|
202
|
-
CheckIcon,
|
|
203
|
-
ChevronLeftIcon,
|
|
204
|
-
ChevronRightIcon,
|
|
205
|
-
CopyIcon,
|
|
206
|
-
PencilIcon,
|
|
207
|
-
RefreshCwIcon,
|
|
208
|
-
Square,
|
|
209
|
-
} from "lucide-react";
|
|
210
|
-
|
|
211
|
-
import {
|
|
212
|
-
ActionBarPrimitive,
|
|
213
|
-
BranchPickerPrimitive,
|
|
214
|
-
ComposerPrimitive,
|
|
215
|
-
ErrorPrimitive,
|
|
216
|
-
MessagePrimitive,
|
|
217
|
-
ThreadPrimitive,
|
|
218
|
-
} from "@assistant-ui/react";
|
|
219
|
-
|
|
220
|
-
import type { FC } from "react";
|
|
221
|
-
import { LazyMotion, MotionConfig, domAnimation } from "motion/react";
|
|
222
|
-
import * as m from "motion/react-m";
|
|
223
|
-
|
|
224
|
-
import { Button } from "@/components/ui/button";
|
|
225
|
-
import { MarkdownText } from "@/components/assistant-ui/markdown-text";
|
|
226
|
-
import { ToolFallback } from "@/components/assistant-ui/tool-fallback";
|
|
227
|
-
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
228
|
-
import {
|
|
229
|
-
ComposerAddAttachment,
|
|
230
|
-
ComposerAttachments,
|
|
231
|
-
UserMessageAttachments,
|
|
232
|
-
} from "@/components/assistant-ui/attachment";
|
|
233
|
-
|
|
234
|
-
import { cn } from "@/lib/utils";
|
|
235
|
-
|
|
236
|
-
export const Thread: FC = () => {
|
|
237
|
-
return (
|
|
238
|
-
<LazyMotion features={domAnimation}>
|
|
239
|
-
<MotionConfig reducedMotion="user">
|
|
240
|
-
<ThreadPrimitive.Root
|
|
241
|
-
className="aui-root aui-thread-root"
|
|
242
|
-
style={{
|
|
243
|
-
["--thread-max-width" as string]: "44rem",
|
|
244
|
-
}}
|
|
245
|
-
>
|
|
246
|
-
<ThreadPrimitive.Viewport className="aui-thread-viewport">
|
|
247
|
-
<ThreadPrimitive.If empty>
|
|
248
|
-
<ThreadWelcome />
|
|
249
|
-
</ThreadPrimitive.If>
|
|
250
|
-
|
|
251
|
-
<ThreadPrimitive.Messages
|
|
252
|
-
components={{
|
|
253
|
-
UserMessage,
|
|
254
|
-
EditComposer,
|
|
255
|
-
AssistantMessage,
|
|
256
|
-
}}
|
|
257
|
-
/>
|
|
258
|
-
|
|
259
|
-
<ThreadPrimitive.If empty={false}>
|
|
260
|
-
<div className="aui-thread-viewport-spacer" />
|
|
261
|
-
</ThreadPrimitive.If>
|
|
262
|
-
|
|
263
|
-
<Composer />
|
|
264
|
-
</ThreadPrimitive.Viewport>
|
|
265
|
-
</ThreadPrimitive.Root>
|
|
266
|
-
</MotionConfig>
|
|
267
|
-
</LazyMotion>
|
|
268
|
-
);
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
const ThreadScrollToBottom: FC = () => {
|
|
272
|
-
return (
|
|
273
|
-
<ThreadPrimitive.ScrollToBottom asChild>
|
|
274
|
-
<TooltipIconButton
|
|
275
|
-
tooltip="Scroll to bottom"
|
|
276
|
-
variant="outline"
|
|
277
|
-
className="aui-thread-scroll-to-bottom"
|
|
278
|
-
>
|
|
279
|
-
<ArrowDownIcon />
|
|
280
|
-
</TooltipIconButton>
|
|
281
|
-
</ThreadPrimitive.ScrollToBottom>
|
|
282
|
-
);
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
const ThreadWelcome: FC = () => {
|
|
286
|
-
return (
|
|
287
|
-
<div className="aui-thread-welcome-root">
|
|
288
|
-
<div className="aui-thread-welcome-center">
|
|
289
|
-
<div className="aui-thread-welcome-message">
|
|
290
|
-
<m.div
|
|
291
|
-
initial={{ opacity: 0, y: 10 }}
|
|
292
|
-
animate={{ opacity: 1, y: 0 }}
|
|
293
|
-
exit={{ opacity: 0, y: 10 }}
|
|
294
|
-
className="aui-thread-welcome-message-motion-1"
|
|
295
|
-
>
|
|
296
|
-
Hello there!
|
|
297
|
-
</m.div>
|
|
298
|
-
<m.div
|
|
299
|
-
initial={{ opacity: 0, y: 10 }}
|
|
300
|
-
animate={{ opacity: 1, y: 0 }}
|
|
301
|
-
exit={{ opacity: 0, y: 10 }}
|
|
302
|
-
transition={{ delay: 0.1 }}
|
|
303
|
-
className="aui-thread-welcome-message-motion-2"
|
|
304
|
-
>
|
|
305
|
-
How can I help you today?
|
|
306
|
-
</m.div>
|
|
307
|
-
</div>
|
|
308
|
-
</div>
|
|
309
|
-
<ThreadSuggestions />
|
|
310
|
-
</div>
|
|
311
|
-
);
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
const ThreadSuggestions: FC = () => {
|
|
315
|
-
return (
|
|
316
|
-
<div className="aui-thread-welcome-suggestions">
|
|
317
|
-
{[
|
|
318
|
-
{
|
|
319
|
-
title: "What's the weather",
|
|
320
|
-
label: "in San Francisco?",
|
|
321
|
-
action: "What's the weather in San Francisco?",
|
|
322
|
-
},
|
|
323
|
-
{
|
|
324
|
-
title: "Explain React hooks",
|
|
325
|
-
label: "like useState and useEffect",
|
|
326
|
-
action: "Explain React hooks like useState and useEffect",
|
|
327
|
-
},
|
|
328
|
-
{
|
|
329
|
-
title: "Write a SQL query",
|
|
330
|
-
label: "to find top customers",
|
|
331
|
-
action: "Write a SQL query to find top customers",
|
|
332
|
-
},
|
|
333
|
-
{
|
|
334
|
-
title: "Create a meal plan",
|
|
335
|
-
label: "for healthy weight loss",
|
|
336
|
-
action: "Create a meal plan for healthy weight loss",
|
|
337
|
-
},
|
|
338
|
-
].map((suggestedAction, index) => (
|
|
339
|
-
<m.div
|
|
340
|
-
initial={{ opacity: 0, y: 20 }}
|
|
341
|
-
animate={{ opacity: 1, y: 0 }}
|
|
342
|
-
exit={{ opacity: 0, y: 20 }}
|
|
343
|
-
transition={{ delay: 0.05 * index }}
|
|
344
|
-
key={`suggested-action-${suggestedAction.title}-${index}`}
|
|
345
|
-
className="aui-thread-welcome-suggestion-display"
|
|
346
|
-
>
|
|
347
|
-
<ThreadPrimitive.Suggestion
|
|
348
|
-
prompt={suggestedAction.action}
|
|
349
|
-
send
|
|
350
|
-
asChild
|
|
351
|
-
>
|
|
352
|
-
<Button
|
|
353
|
-
variant="ghost"
|
|
354
|
-
className="aui-thread-welcome-suggestion"
|
|
355
|
-
aria-label={suggestedAction.action}
|
|
356
|
-
>
|
|
357
|
-
<span className="aui-thread-welcome-suggestion-text-1">
|
|
358
|
-
{suggestedAction.title}
|
|
359
|
-
</span>
|
|
360
|
-
<span className="aui-thread-welcome-suggestion-text-2">
|
|
361
|
-
{suggestedAction.label}
|
|
362
|
-
</span>
|
|
363
|
-
</Button>
|
|
364
|
-
</ThreadPrimitive.Suggestion>
|
|
365
|
-
</m.div>
|
|
366
|
-
))}
|
|
367
|
-
</div>
|
|
368
|
-
);
|
|
369
|
-
};
|
|
370
|
-
|
|
371
|
-
const Composer: FC = () => {
|
|
372
|
-
return (
|
|
373
|
-
<div className="aui-composer-wrapper">
|
|
374
|
-
<ThreadScrollToBottom />
|
|
375
|
-
<ComposerPrimitive.Root className="aui-composer-root">
|
|
376
|
-
<ComposerAttachments />
|
|
377
|
-
<ComposerPrimitive.Input
|
|
378
|
-
placeholder="Send a message..."
|
|
379
|
-
className="aui-composer-input"
|
|
380
|
-
rows={1}
|
|
381
|
-
autoFocus
|
|
382
|
-
aria-label="Message input"
|
|
383
|
-
/>
|
|
384
|
-
<ComposerAction />
|
|
385
|
-
</ComposerPrimitive.Root>
|
|
386
|
-
</div>
|
|
387
|
-
);
|
|
388
|
-
};
|
|
389
|
-
|
|
390
|
-
const ComposerAction: FC = () => {
|
|
391
|
-
return (
|
|
392
|
-
<div className="aui-composer-action-wrapper">
|
|
393
|
-
<ComposerAddAttachment />
|
|
394
|
-
|
|
395
|
-
<ThreadPrimitive.If running={false}>
|
|
396
|
-
<ComposerPrimitive.Send asChild>
|
|
397
|
-
<TooltipIconButton
|
|
398
|
-
tooltip="Send message"
|
|
399
|
-
side="bottom"
|
|
400
|
-
type="submit"
|
|
401
|
-
variant="default"
|
|
402
|
-
size="icon"
|
|
403
|
-
className="aui-composer-send"
|
|
404
|
-
aria-label="Send message"
|
|
405
|
-
>
|
|
406
|
-
<ArrowUpIcon className="aui-composer-send-icon" />
|
|
407
|
-
</TooltipIconButton>
|
|
408
|
-
</ComposerPrimitive.Send>
|
|
409
|
-
</ThreadPrimitive.If>
|
|
410
|
-
|
|
411
|
-
<ThreadPrimitive.If running>
|
|
412
|
-
<ComposerPrimitive.Cancel asChild>
|
|
413
|
-
<Button
|
|
414
|
-
type="button"
|
|
415
|
-
variant="default"
|
|
416
|
-
size="icon"
|
|
417
|
-
className="aui-composer-cancel"
|
|
418
|
-
aria-label="Stop generating"
|
|
419
|
-
>
|
|
420
|
-
<Square className="aui-composer-cancel-icon" />
|
|
421
|
-
</Button>
|
|
422
|
-
</ComposerPrimitive.Cancel>
|
|
423
|
-
</ThreadPrimitive.If>
|
|
424
|
-
</div>
|
|
425
|
-
);
|
|
426
|
-
};
|
|
427
|
-
|
|
428
|
-
const MessageError: FC = () => {
|
|
429
|
-
return (
|
|
430
|
-
<MessagePrimitive.Error>
|
|
431
|
-
<ErrorPrimitive.Root className="aui-message-error-root">
|
|
432
|
-
<ErrorPrimitive.Message className="aui-message-error-message" />
|
|
433
|
-
</ErrorPrimitive.Root>
|
|
434
|
-
</MessagePrimitive.Error>
|
|
435
|
-
);
|
|
436
|
-
};
|
|
437
|
-
|
|
438
|
-
const AssistantMessage: FC = () => {
|
|
439
|
-
return (
|
|
440
|
-
<MessagePrimitive.Root asChild>
|
|
441
|
-
<div
|
|
442
|
-
className="aui-assistant-message-root"
|
|
443
|
-
data-role="assistant"
|
|
444
|
-
>
|
|
445
|
-
<div className="aui-assistant-message-content">
|
|
446
|
-
<MessagePrimitive.Parts
|
|
447
|
-
components={{
|
|
448
|
-
Text: MarkdownText,
|
|
449
|
-
tools: { Fallback: ToolFallback },
|
|
450
|
-
}}
|
|
451
|
-
/>
|
|
452
|
-
<MessageError />
|
|
453
|
-
</div>
|
|
454
|
-
|
|
455
|
-
<div className="aui-assistant-message-footer">
|
|
456
|
-
<BranchPicker />
|
|
457
|
-
<AssistantActionBar />
|
|
458
|
-
</div>
|
|
459
|
-
</div>
|
|
460
|
-
</MessagePrimitive.Root>
|
|
461
|
-
);
|
|
462
|
-
};
|
|
463
|
-
|
|
464
|
-
const AssistantActionBar: FC = () => {
|
|
465
|
-
return (
|
|
466
|
-
<ActionBarPrimitive.Root
|
|
467
|
-
hideWhenRunning
|
|
468
|
-
autohide="not-last"
|
|
469
|
-
autohideFloat="single-branch"
|
|
470
|
-
className="aui-assistant-action-bar-root"
|
|
471
|
-
>
|
|
472
|
-
<ActionBarPrimitive.Copy asChild>
|
|
473
|
-
<TooltipIconButton tooltip="Copy">
|
|
474
|
-
<MessagePrimitive.If copied>
|
|
475
|
-
<CheckIcon />
|
|
476
|
-
</MessagePrimitive.If>
|
|
477
|
-
<MessagePrimitive.If copied={false}>
|
|
478
|
-
<CopyIcon />
|
|
479
|
-
</MessagePrimitive.If>
|
|
480
|
-
</TooltipIconButton>
|
|
481
|
-
</ActionBarPrimitive.Copy>
|
|
482
|
-
<ActionBarPrimitive.Reload asChild>
|
|
483
|
-
<TooltipIconButton tooltip="Refresh">
|
|
484
|
-
<RefreshCwIcon />
|
|
485
|
-
</TooltipIconButton>
|
|
486
|
-
</ActionBarPrimitive.Reload>
|
|
487
|
-
</ActionBarPrimitive.Root>
|
|
488
|
-
);
|
|
489
|
-
};
|
|
490
|
-
|
|
491
|
-
const UserMessage: FC = () => {
|
|
492
|
-
return (
|
|
493
|
-
<MessagePrimitive.Root asChild>
|
|
494
|
-
<div
|
|
495
|
-
className="aui-user-message-root"
|
|
496
|
-
data-role="user"
|
|
497
|
-
>
|
|
498
|
-
<UserMessageAttachments />
|
|
499
|
-
|
|
500
|
-
<div className="aui-user-message-content-wrapper">
|
|
501
|
-
<div className="aui-user-message-content">
|
|
502
|
-
<MessagePrimitive.Parts />
|
|
503
|
-
</div>
|
|
504
|
-
<div className="aui-user-action-bar-wrapper">
|
|
505
|
-
<UserActionBar />
|
|
506
|
-
</div>
|
|
507
|
-
</div>
|
|
508
|
-
|
|
509
|
-
<BranchPicker className="aui-user-branch-picker" />
|
|
510
|
-
</div>
|
|
511
|
-
</MessagePrimitive.Root>
|
|
512
|
-
);
|
|
513
|
-
};
|
|
514
|
-
|
|
515
|
-
const UserActionBar: FC = () => {
|
|
516
|
-
return (
|
|
517
|
-
<ActionBarPrimitive.Root
|
|
518
|
-
hideWhenRunning
|
|
519
|
-
autohide="not-last"
|
|
520
|
-
className="aui-user-action-bar-root"
|
|
521
|
-
>
|
|
522
|
-
<ActionBarPrimitive.Edit asChild>
|
|
523
|
-
<TooltipIconButton tooltip="Edit" className="aui-user-action-edit">
|
|
524
|
-
<PencilIcon />
|
|
525
|
-
</TooltipIconButton>
|
|
526
|
-
</ActionBarPrimitive.Edit>
|
|
527
|
-
</ActionBarPrimitive.Root>
|
|
528
|
-
);
|
|
529
|
-
};
|
|
530
|
-
|
|
531
|
-
const EditComposer: FC = () => {
|
|
532
|
-
return (
|
|
533
|
-
<div className="aui-edit-composer-wrapper">
|
|
534
|
-
<ComposerPrimitive.Root className="aui-edit-composer-root">
|
|
535
|
-
<ComposerPrimitive.Input
|
|
536
|
-
className="aui-edit-composer-input"
|
|
537
|
-
autoFocus
|
|
538
|
-
/>
|
|
539
|
-
|
|
540
|
-
<div className="aui-edit-composer-footer">
|
|
541
|
-
<ComposerPrimitive.Cancel asChild>
|
|
542
|
-
<Button variant="ghost" size="sm" aria-label="Cancel edit">
|
|
543
|
-
Cancel
|
|
544
|
-
</Button>
|
|
545
|
-
</ComposerPrimitive.Cancel>
|
|
546
|
-
<ComposerPrimitive.Send asChild>
|
|
547
|
-
<Button size="sm" aria-label="Update message">
|
|
548
|
-
Update
|
|
549
|
-
</Button>
|
|
550
|
-
</ComposerPrimitive.Send>
|
|
551
|
-
</div>
|
|
552
|
-
</ComposerPrimitive.Root>
|
|
553
|
-
</div>
|
|
554
|
-
);
|
|
555
|
-
};
|
|
556
|
-
|
|
557
|
-
const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
|
|
558
|
-
className,
|
|
559
|
-
...rest
|
|
560
|
-
}) => {
|
|
561
|
-
return (
|
|
562
|
-
<BranchPickerPrimitive.Root
|
|
563
|
-
hideWhenSingleBranch
|
|
564
|
-
className={cn("aui-branch-picker-root", className)}
|
|
565
|
-
{...rest}
|
|
566
|
-
>
|
|
567
|
-
<BranchPickerPrimitive.Previous asChild>
|
|
568
|
-
<TooltipIconButton tooltip="Previous">
|
|
569
|
-
<ChevronLeftIcon />
|
|
570
|
-
</TooltipIconButton>
|
|
571
|
-
</BranchPickerPrimitive.Previous>
|
|
572
|
-
<span className="aui-branch-picker-state">
|
|
573
|
-
<BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
|
|
574
|
-
</span>
|
|
575
|
-
<BranchPickerPrimitive.Next asChild>
|
|
576
|
-
<TooltipIconButton tooltip="Next">
|
|
577
|
-
<ChevronRightIcon />
|
|
578
|
-
</TooltipIconButton>
|
|
579
|
-
</BranchPickerPrimitive.Next>
|
|
580
|
-
</BranchPickerPrimitive.Root>
|
|
581
|
-
);
|
|
582
|
-
};
|
|
583
|
-
```
|
|
584
|
-
|
|
585
|
-
```tsx title="components/assistant-ui/attachment.tsx"
|
|
586
|
-
"use client";
|
|
587
|
-
|
|
588
|
-
import { PropsWithChildren, useEffect, useState, type FC } from "react";
|
|
589
|
-
import Image from "next/image";
|
|
590
|
-
import { XIcon, PlusIcon, FileText } from "lucide-react";
|
|
591
|
-
import {
|
|
592
|
-
AttachmentPrimitive,
|
|
593
|
-
ComposerPrimitive,
|
|
594
|
-
MessagePrimitive,
|
|
595
|
-
useAssistantState,
|
|
596
|
-
useAssistantApi,
|
|
597
|
-
} from "@assistant-ui/react";
|
|
598
|
-
import { useShallow } from "zustand/shallow";
|
|
599
|
-
import {
|
|
600
|
-
Tooltip,
|
|
601
|
-
TooltipContent,
|
|
602
|
-
TooltipTrigger,
|
|
603
|
-
} from "@/components/ui/tooltip";
|
|
604
|
-
import {
|
|
605
|
-
Dialog,
|
|
606
|
-
DialogTitle,
|
|
607
|
-
DialogContent,
|
|
608
|
-
DialogTrigger,
|
|
609
|
-
} from "@/components/ui/dialog";
|
|
610
|
-
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
|
|
611
|
-
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
612
|
-
import { cn } from "@/lib/utils";
|
|
613
|
-
|
|
614
|
-
const useFileSrc = (file: File | undefined) => {
|
|
615
|
-
const [src, setSrc] = useState<string | undefined>(undefined);
|
|
616
|
-
|
|
617
|
-
useEffect(() => {
|
|
618
|
-
if (!file) {
|
|
619
|
-
setSrc(undefined);
|
|
620
|
-
return;
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
const objectUrl = URL.createObjectURL(file);
|
|
624
|
-
setSrc(objectUrl);
|
|
625
|
-
|
|
626
|
-
return () => {
|
|
627
|
-
URL.revokeObjectURL(objectUrl);
|
|
628
|
-
};
|
|
629
|
-
}, [file]);
|
|
630
|
-
|
|
631
|
-
return src;
|
|
632
|
-
};
|
|
633
|
-
|
|
634
|
-
const useAttachmentSrc = () => {
|
|
635
|
-
const { file, src } = useAssistantState(
|
|
636
|
-
useShallow(({ attachment }): { file?: File; src?: string } => {
|
|
637
|
-
if (attachment.type !== "image") return {};
|
|
638
|
-
if (attachment.file) return { file: attachment.file };
|
|
639
|
-
const src = attachment.content?.filter((c) => c.type === "image")[0]
|
|
640
|
-
?.image;
|
|
641
|
-
if (!src) return {};
|
|
642
|
-
return { src };
|
|
643
|
-
}),
|
|
644
|
-
);
|
|
645
|
-
|
|
646
|
-
return useFileSrc(file) ?? src;
|
|
647
|
-
};
|
|
648
|
-
|
|
649
|
-
type AttachmentPreviewProps = {
|
|
650
|
-
src: string;
|
|
651
|
-
};
|
|
652
|
-
|
|
653
|
-
const AttachmentPreview: FC<AttachmentPreviewProps> = ({ src }) => {
|
|
654
|
-
const [isLoaded, setIsLoaded] = useState(false);
|
|
655
|
-
return (
|
|
656
|
-
<Image
|
|
657
|
-
src={src}
|
|
658
|
-
alt="Image Preview"
|
|
659
|
-
width={1}
|
|
660
|
-
height={1}
|
|
661
|
-
className={
|
|
662
|
-
isLoaded
|
|
663
|
-
? "aui-attachment-preview-image-loaded"
|
|
664
|
-
: "aui-attachment-preview-image-loading"
|
|
665
|
-
}
|
|
666
|
-
onLoadingComplete={() => setIsLoaded(true)}
|
|
667
|
-
priority={false}
|
|
668
|
-
/>
|
|
669
|
-
);
|
|
670
|
-
};
|
|
671
|
-
|
|
672
|
-
const AttachmentPreviewDialog: FC<PropsWithChildren> = ({ children }) => {
|
|
673
|
-
const src = useAttachmentSrc();
|
|
674
|
-
|
|
675
|
-
if (!src) return children;
|
|
676
|
-
|
|
677
|
-
return (
|
|
678
|
-
<Dialog>
|
|
679
|
-
<DialogTrigger className="aui-attachment-preview-trigger" asChild>
|
|
680
|
-
{children}
|
|
681
|
-
</DialogTrigger>
|
|
682
|
-
<DialogContent className="aui-attachment-preview-dialog-content">
|
|
683
|
-
<DialogTitle className="aui-sr-only">
|
|
684
|
-
Image Attachment Preview
|
|
685
|
-
</DialogTitle>
|
|
686
|
-
<div className="aui-attachment-preview">
|
|
687
|
-
<AttachmentPreview src={src} />
|
|
688
|
-
</div>
|
|
689
|
-
</DialogContent>
|
|
690
|
-
</Dialog>
|
|
691
|
-
);
|
|
692
|
-
};
|
|
693
|
-
|
|
694
|
-
const AttachmentThumb: FC = () => {
|
|
695
|
-
const isImage = useAssistantState(
|
|
696
|
-
({ attachment }) => attachment.type === "image",
|
|
697
|
-
);
|
|
698
|
-
const src = useAttachmentSrc();
|
|
699
|
-
|
|
700
|
-
return (
|
|
701
|
-
<Avatar className="aui-attachment-tile-avatar">
|
|
702
|
-
<AvatarImage
|
|
703
|
-
src={src}
|
|
704
|
-
alt="Attachment preview"
|
|
705
|
-
className="aui-attachment-tile-image"
|
|
706
|
-
/>
|
|
707
|
-
<AvatarFallback delayMs={isImage ? 200 : 0}>
|
|
708
|
-
<FileText className="aui-attachment-tile-fallback-icon" />
|
|
709
|
-
</AvatarFallback>
|
|
710
|
-
</Avatar>
|
|
711
|
-
);
|
|
712
|
-
};
|
|
713
|
-
|
|
714
|
-
const AttachmentUI: FC = () => {
|
|
715
|
-
const api = useAssistantApi();
|
|
716
|
-
const isComposer = api.attachment.source === "composer";
|
|
717
|
-
|
|
718
|
-
const isImage = useAssistantState(
|
|
719
|
-
({ attachment }) => attachment.type === "image",
|
|
720
|
-
);
|
|
721
|
-
const typeLabel = useAssistantState(({ attachment }) => {
|
|
722
|
-
const type = attachment.type;
|
|
723
|
-
switch (type) {
|
|
724
|
-
case "image":
|
|
725
|
-
return "Image";
|
|
726
|
-
case "document":
|
|
727
|
-
return "Document";
|
|
728
|
-
case "file":
|
|
729
|
-
return "File";
|
|
730
|
-
default:
|
|
731
|
-
const _exhaustiveCheck: never = type;
|
|
732
|
-
throw new Error(`Unknown attachment type: ${_exhaustiveCheck}`);
|
|
733
|
-
}
|
|
734
|
-
});
|
|
735
|
-
|
|
736
|
-
return (
|
|
737
|
-
<Tooltip>
|
|
738
|
-
<AttachmentPrimitive.Root
|
|
739
|
-
className={cn(
|
|
740
|
-
"aui-attachment-root",
|
|
741
|
-
isImage && "aui-attachment-root-composer",
|
|
742
|
-
)}
|
|
743
|
-
>
|
|
744
|
-
<AttachmentPreviewDialog>
|
|
745
|
-
<TooltipTrigger asChild>
|
|
746
|
-
<div
|
|
747
|
-
className={cn(
|
|
748
|
-
"aui-attachment-tile",
|
|
749
|
-
isComposer && "aui-attachment-tile-composer",
|
|
750
|
-
)}
|
|
751
|
-
role="button"
|
|
752
|
-
id="attachment-tile"
|
|
753
|
-
aria-label={`${typeLabel} attachment`}
|
|
754
|
-
>
|
|
755
|
-
<AttachmentThumb />
|
|
756
|
-
</div>
|
|
757
|
-
</TooltipTrigger>
|
|
758
|
-
</AttachmentPreviewDialog>
|
|
759
|
-
{isComposer && <AttachmentRemove />}
|
|
760
|
-
</AttachmentPrimitive.Root>
|
|
761
|
-
<TooltipContent side="top">
|
|
762
|
-
<AttachmentPrimitive.Name />
|
|
763
|
-
</TooltipContent>
|
|
764
|
-
</Tooltip>
|
|
765
|
-
);
|
|
766
|
-
};
|
|
767
|
-
|
|
768
|
-
const AttachmentRemove: FC = () => {
|
|
769
|
-
return (
|
|
770
|
-
<AttachmentPrimitive.Remove asChild>
|
|
771
|
-
<TooltipIconButton
|
|
772
|
-
tooltip="Remove file"
|
|
773
|
-
className="aui-attachment-tile-remove"
|
|
774
|
-
side="top"
|
|
775
|
-
>
|
|
776
|
-
<XIcon className="aui-attachment-remove-icon" />
|
|
777
|
-
</TooltipIconButton>
|
|
778
|
-
</AttachmentPrimitive.Remove>
|
|
779
|
-
);
|
|
780
|
-
};
|
|
781
|
-
|
|
782
|
-
export const UserMessageAttachments: FC = () => {
|
|
783
|
-
return (
|
|
784
|
-
<div className="aui-user-message-attachments-end">
|
|
785
|
-
<MessagePrimitive.Attachments components={{ Attachment: AttachmentUI }} />
|
|
786
|
-
</div>
|
|
787
|
-
);
|
|
788
|
-
};
|
|
789
|
-
|
|
790
|
-
export const ComposerAttachments: FC = () => {
|
|
791
|
-
return (
|
|
792
|
-
<div className="aui-composer-attachments">
|
|
793
|
-
<ComposerPrimitive.Attachments
|
|
794
|
-
components={{ Attachment: AttachmentUI }}
|
|
795
|
-
/>
|
|
796
|
-
</div>
|
|
797
|
-
);
|
|
798
|
-
};
|
|
799
|
-
|
|
800
|
-
export const ComposerAddAttachment: FC = () => {
|
|
801
|
-
return (
|
|
802
|
-
<ComposerPrimitive.AddAttachment asChild>
|
|
803
|
-
<TooltipIconButton
|
|
804
|
-
tooltip="Add Attachment"
|
|
805
|
-
side="bottom"
|
|
806
|
-
variant="ghost"
|
|
807
|
-
size="icon"
|
|
808
|
-
className="aui-composer-add-attachment"
|
|
809
|
-
aria-label="Add Attachment"
|
|
810
|
-
>
|
|
811
|
-
<PlusIcon className="aui-attachment-add-icon" />
|
|
812
|
-
</TooltipIconButton>
|
|
813
|
-
</ComposerPrimitive.AddAttachment>
|
|
814
|
-
);
|
|
815
|
-
};
|
|
816
|
-
```
|
|
817
|
-
|
|
818
|
-
```tsx title="components/assistant-ui/tool-fallback.tsx"
|
|
819
|
-
import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
|
|
820
|
-
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
|
|
821
|
-
import { useState } from "react";
|
|
822
|
-
import { Button } from "@/components/ui/button";
|
|
823
|
-
|
|
824
|
-
export const ToolFallback: ToolCallMessagePartComponent = ({
|
|
825
|
-
toolName,
|
|
826
|
-
argsText,
|
|
827
|
-
result,
|
|
828
|
-
}) => {
|
|
829
|
-
const [isCollapsed, setIsCollapsed] = useState(true);
|
|
830
|
-
return (
|
|
831
|
-
<div className="aui-tool-fallback-root">
|
|
832
|
-
<div className="aui-tool-fallback-header">
|
|
833
|
-
<CheckIcon className="aui-tool-fallback-icon" />
|
|
834
|
-
<p className="aui-tool-fallback-title">
|
|
835
|
-
Used tool: <b>{toolName}</b>
|
|
836
|
-
</p>
|
|
837
|
-
<Button onClick={() => setIsCollapsed(!isCollapsed)}>
|
|
838
|
-
{isCollapsed ? <ChevronUpIcon /> : <ChevronDownIcon />}
|
|
839
|
-
</Button>
|
|
840
|
-
</div>
|
|
841
|
-
{!isCollapsed && (
|
|
842
|
-
<div className="aui-tool-fallback-content">
|
|
843
|
-
<div className="aui-tool-fallback-args-root">
|
|
844
|
-
<pre className="aui-tool-fallback-args-value">
|
|
845
|
-
{argsText}
|
|
846
|
-
</pre>
|
|
847
|
-
</div>
|
|
848
|
-
{result !== undefined && (
|
|
849
|
-
<div className="aui-tool-fallback-result-root">
|
|
850
|
-
<p className="aui-tool-fallback-result-header">
|
|
851
|
-
Result:
|
|
852
|
-
</p>
|
|
853
|
-
<pre className="aui-tool-fallback-result-content">
|
|
854
|
-
{typeof result === "string"
|
|
855
|
-
? result
|
|
856
|
-
: JSON.stringify(result, null, 2)}
|
|
857
|
-
</pre>
|
|
858
|
-
</div>
|
|
859
|
-
)}
|
|
860
|
-
</div>
|
|
861
|
-
)}
|
|
862
|
-
</div>
|
|
863
|
-
);
|
|
864
|
-
};
|
|
865
|
-
```
|
|
866
|
-
|
|
867
|
-
```
|
|
868
|
-
|
|
869
|
-
```tsx title="components/assistant-ui/thread-list.tsx"
|
|
870
|
-
import type { FC } from "react";
|
|
871
|
-
import {
|
|
872
|
-
ThreadListItemPrimitive,
|
|
873
|
-
ThreadListPrimitive,
|
|
874
|
-
} from "@assistant-ui/react";
|
|
875
|
-
import { ArchiveIcon, PlusIcon } from "lucide-react";
|
|
876
|
-
|
|
877
|
-
import { Button } from "@/components/ui/button";
|
|
878
|
-
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
879
|
-
|
|
880
|
-
export const ThreadList: FC = () => {
|
|
881
|
-
return (
|
|
882
|
-
<ThreadListPrimitive.Root className="aui-root aui-thread-list-root">
|
|
883
|
-
<ThreadListNew />
|
|
884
|
-
<ThreadListItems />
|
|
885
|
-
</ThreadListPrimitive.Root>
|
|
886
|
-
);
|
|
887
|
-
};
|
|
888
|
-
|
|
889
|
-
const ThreadListNew: FC = () => {
|
|
890
|
-
return (
|
|
891
|
-
<ThreadListPrimitive.New asChild>
|
|
892
|
-
<Button className="aui-thread-list-new" variant="ghost">
|
|
893
|
-
<PlusIcon />
|
|
894
|
-
New Thread
|
|
895
|
-
</Button>
|
|
896
|
-
</ThreadListPrimitive.New>
|
|
897
|
-
);
|
|
898
|
-
};
|
|
899
|
-
|
|
900
|
-
const ThreadListItems: FC = () => {
|
|
901
|
-
return <ThreadListPrimitive.Items components={{ ThreadListItem }} />;
|
|
902
|
-
};
|
|
903
|
-
|
|
904
|
-
const ThreadListItem: FC = () => {
|
|
905
|
-
return (
|
|
906
|
-
<ThreadListItemPrimitive.Root className="aui-thread-list-item">
|
|
907
|
-
<ThreadListItemPrimitive.Trigger className="aui-thread-list-item-trigger">
|
|
908
|
-
<ThreadListItemTitle />
|
|
909
|
-
</ThreadListItemPrimitive.Trigger>
|
|
910
|
-
<ThreadListItemArchive />
|
|
911
|
-
</ThreadListItemPrimitive.Root>
|
|
912
|
-
);
|
|
913
|
-
};
|
|
914
|
-
|
|
915
|
-
const ThreadListItemTitle: FC = () => {
|
|
916
|
-
return (
|
|
917
|
-
<span className="aui-thread-list-item-title">
|
|
918
|
-
<ThreadListItemPrimitive.Title fallback="New Chat" />
|
|
919
|
-
</span>
|
|
920
|
-
);
|
|
921
|
-
};
|
|
922
|
-
|
|
923
|
-
const ThreadListItemArchive: FC = () => {
|
|
924
|
-
return (
|
|
925
|
-
<ThreadListItemPrimitive.Archive asChild>
|
|
926
|
-
<TooltipIconButton
|
|
927
|
-
className="aui-thread-list-item-archive"
|
|
928
|
-
variant="ghost"
|
|
929
|
-
tooltip="Archive thread"
|
|
930
|
-
>
|
|
931
|
-
<ArchiveIcon />
|
|
932
|
-
</TooltipIconButton>
|
|
933
|
-
</ThreadListItemPrimitive.Archive>
|
|
934
|
-
);
|
|
935
|
-
};
|
|
936
|
-
```
|
|
937
|
-
|
|
938
|
-
```tsx title="components/assistant-ui/markdown-text.tsx"
|
|
939
|
-
"use client";
|
|
940
|
-
|
|
941
|
-
import "@assistant-ui/react-markdown/styles/dot.css";
|
|
942
|
-
|
|
943
|
-
import {
|
|
944
|
-
type CodeHeaderProps,
|
|
945
|
-
MarkdownTextPrimitive,
|
|
946
|
-
unstable_memoizeMarkdownComponents as memoizeMarkdownComponents,
|
|
947
|
-
useIsMarkdownCodeBlock,
|
|
948
|
-
} from "@assistant-ui/react-markdown";
|
|
949
|
-
import remarkGfm from "remark-gfm";
|
|
950
|
-
import { type FC, memo, useState } from "react";
|
|
951
|
-
import { CheckIcon, CopyIcon } from "lucide-react";
|
|
952
|
-
|
|
953
|
-
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
954
|
-
import { cn } from "@/lib/utils";
|
|
955
|
-
|
|
956
|
-
const MarkdownTextImpl = () => {
|
|
957
|
-
return (
|
|
958
|
-
<MarkdownTextPrimitive
|
|
959
|
-
remarkPlugins={[remarkGfm]}
|
|
960
|
-
className="aui-md"
|
|
961
|
-
components={defaultComponents}
|
|
962
|
-
/>
|
|
963
|
-
);
|
|
964
|
-
};
|
|
965
|
-
|
|
966
|
-
export const MarkdownText = memo(MarkdownTextImpl);
|
|
967
|
-
|
|
968
|
-
const CodeHeader: FC<CodeHeaderProps> = ({ language, code }) => {
|
|
969
|
-
const { isCopied, copyToClipboard } = useCopyToClipboard();
|
|
970
|
-
const onCopy = () => {
|
|
971
|
-
if (!code || isCopied) return;
|
|
972
|
-
copyToClipboard(code);
|
|
973
|
-
};
|
|
974
|
-
|
|
975
|
-
return (
|
|
976
|
-
<div className="aui-code-header-root">
|
|
977
|
-
<span className="aui-code-header-language">{language}</span>
|
|
978
|
-
<TooltipIconButton tooltip="Copy" onClick={onCopy}>
|
|
979
|
-
{!isCopied && <CopyIcon />}
|
|
980
|
-
{isCopied && <CheckIcon />}
|
|
981
|
-
</TooltipIconButton>
|
|
982
|
-
</div>
|
|
983
|
-
);
|
|
984
|
-
};
|
|
985
|
-
|
|
986
|
-
const useCopyToClipboard = ({
|
|
987
|
-
copiedDuration = 3000,
|
|
988
|
-
}: {
|
|
989
|
-
copiedDuration?: number;
|
|
990
|
-
} = {}) => {
|
|
991
|
-
const [isCopied, setIsCopied] = useState<boolean>(false);
|
|
992
|
-
|
|
993
|
-
const copyToClipboard = (value: string) => {
|
|
994
|
-
if (!value) return;
|
|
995
|
-
|
|
996
|
-
navigator.clipboard.writeText(value).then(() => {
|
|
997
|
-
setIsCopied(true);
|
|
998
|
-
setTimeout(() => setIsCopied(false), copiedDuration);
|
|
999
|
-
});
|
|
1000
|
-
};
|
|
1001
|
-
|
|
1002
|
-
return { isCopied, copyToClipboard };
|
|
1003
|
-
};
|
|
1004
|
-
|
|
1005
|
-
const defaultComponents = memoizeMarkdownComponents({
|
|
1006
|
-
h1: ({ className, ...props }) => (
|
|
1007
|
-
<h1 className={cn("aui-md-h1", className)} {...props} />
|
|
1008
|
-
),
|
|
1009
|
-
h2: ({ className, ...props }) => (
|
|
1010
|
-
<h2 className={cn("aui-md-h2", className)} {...props} />
|
|
1011
|
-
),
|
|
1012
|
-
h3: ({ className, ...props }) => (
|
|
1013
|
-
<h3 className={cn("aui-md-h3", className)} {...props} />
|
|
1014
|
-
),
|
|
1015
|
-
h4: ({ className, ...props }) => (
|
|
1016
|
-
<h4 className={cn("aui-md-h4", className)} {...props} />
|
|
1017
|
-
),
|
|
1018
|
-
h5: ({ className, ...props }) => (
|
|
1019
|
-
<h5 className={cn("aui-md-h5", className)} {...props} />
|
|
1020
|
-
),
|
|
1021
|
-
h6: ({ className, ...props }) => (
|
|
1022
|
-
<h6 className={cn("aui-md-h6", className)} {...props} />
|
|
1023
|
-
),
|
|
1024
|
-
p: ({ className, ...props }) => (
|
|
1025
|
-
<p className={cn("aui-md-p", className)} {...props} />
|
|
1026
|
-
),
|
|
1027
|
-
a: ({ className, ...props }) => (
|
|
1028
|
-
<a className={cn("aui-md-a", className)} {...props} />
|
|
1029
|
-
),
|
|
1030
|
-
blockquote: ({ className, ...props }) => (
|
|
1031
|
-
<blockquote className={cn("aui-md-blockquote", className)} {...props} />
|
|
1032
|
-
),
|
|
1033
|
-
ul: ({ className, ...props }) => (
|
|
1034
|
-
<ul className={cn("aui-md-ul", className)} {...props} />
|
|
1035
|
-
),
|
|
1036
|
-
ol: ({ className, ...props }) => (
|
|
1037
|
-
<ol className={cn("aui-md-ol", className)} {...props} />
|
|
1038
|
-
),
|
|
1039
|
-
hr: ({ className, ...props }) => (
|
|
1040
|
-
<hr className={cn("aui-md-hr", className)} {...props} />
|
|
1041
|
-
),
|
|
1042
|
-
table: ({ className, ...props }) => (
|
|
1043
|
-
<table className={cn("aui-md-table", className)} {...props} />
|
|
1044
|
-
),
|
|
1045
|
-
th: ({ className, ...props }) => (
|
|
1046
|
-
<th className={cn("aui-md-th", className)} {...props} />
|
|
1047
|
-
),
|
|
1048
|
-
td: ({ className, ...props }) => (
|
|
1049
|
-
<td className={cn("aui-md-td", className)} {...props} />
|
|
1050
|
-
),
|
|
1051
|
-
tr: ({ className, ...props }) => (
|
|
1052
|
-
<tr className={cn("aui-md-tr", className)} {...props} />
|
|
1053
|
-
),
|
|
1054
|
-
sup: ({ className, ...props }) => (
|
|
1055
|
-
<sup className={cn("aui-md-sup", className)} {...props} />
|
|
1056
|
-
),
|
|
1057
|
-
pre: ({ className, ...props }) => (
|
|
1058
|
-
<pre className={cn("aui-md-pre", className)} {...props} />
|
|
1059
|
-
),
|
|
1060
|
-
code: function Code({ className, ...props }) {
|
|
1061
|
-
const isCodeBlock = useIsMarkdownCodeBlock();
|
|
1062
|
-
return (
|
|
1063
|
-
<code
|
|
1064
|
-
className={cn(!isCodeBlock && "aui-md-inline-code", className)}
|
|
1065
|
-
{...props}
|
|
1066
|
-
/>
|
|
1067
|
-
);
|
|
1068
|
-
},
|
|
1069
|
-
CodeHeader,
|
|
1070
|
-
});
|
|
1071
|
-
```
|
|
1072
|
-
|
|
1073
|
-
```tsx title="components/assistant-ui/tooltip-icon-button.tsx"
|
|
1074
|
-
"use client";
|
|
1075
|
-
|
|
1076
|
-
import { ComponentPropsWithRef, forwardRef } from "react";
|
|
1077
|
-
import { Slottable } from "@radix-ui/react-slot";
|
|
1078
|
-
|
|
1079
|
-
import {
|
|
1080
|
-
Tooltip,
|
|
1081
|
-
TooltipContent,
|
|
1082
|
-
TooltipTrigger,
|
|
1083
|
-
} from "@/components/ui/tooltip";
|
|
1084
|
-
import { Button } from "@/components/ui/button";
|
|
1085
|
-
import { cn } from "@/lib/utils";
|
|
1086
|
-
|
|
1087
|
-
export type TooltipIconButtonProps = ComponentPropsWithRef<typeof Button> & {
|
|
1088
|
-
tooltip: string;
|
|
1089
|
-
side?: "top" | "bottom" | "left" | "right";
|
|
1090
|
-
};
|
|
1091
|
-
|
|
1092
|
-
export const TooltipIconButton = forwardRef<
|
|
1093
|
-
HTMLButtonElement,
|
|
1094
|
-
TooltipIconButtonProps
|
|
1095
|
-
>(({ children, tooltip, side = "bottom", className, ...rest }, ref) => {
|
|
1096
|
-
return (
|
|
1097
|
-
<Tooltip>
|
|
1098
|
-
<TooltipTrigger asChild>
|
|
1099
|
-
<Button
|
|
1100
|
-
variant="ghost"
|
|
1101
|
-
size="icon"
|
|
1102
|
-
{...rest}
|
|
1103
|
-
className={cn("aui-button-icon", className)}
|
|
1104
|
-
ref={ref}
|
|
1105
|
-
>
|
|
1106
|
-
<Slottable>{children}</Slottable>
|
|
1107
|
-
<span className="aui-sr-only">{tooltip}</span>
|
|
1108
|
-
</Button>
|
|
1109
|
-
</TooltipTrigger>
|
|
1110
|
-
<TooltipContent side={side}>{tooltip}</TooltipContent>
|
|
1111
|
-
</Tooltip>
|
|
1112
|
-
);
|
|
1113
|
-
});
|
|
1114
|
-
|
|
1115
|
-
TooltipIconButton.displayName = "TooltipIconButton";
|
|
1116
|
-
```
|
|
1117
|
-
|
|
1118
|
-
```ts title="lib/utils.ts"
|
|
1119
|
-
import { type ClassValue, clsx } from "clsx";
|
|
1120
|
-
|
|
1121
|
-
export function cn(...inputs: ClassValue[]) {
|
|
1122
|
-
return clsx(inputs);
|
|
1123
|
-
}
|
|
1124
|
-
```
|
|
1125
|
-
|
|
1126
|
-
</Step>
|
|
1127
|
-
|
|
1128
|
-
<Step>
|
|
1129
|
-
The components above reference CSS class names like `aui-thread-root`, `aui-composer-input`, etc. These are normally replaced by our CLI with Tailwind class names, but in this case you'll use our pre-compiled CSS files without a need for Tailwind:
|
|
1130
|
-
|
|
1131
|
-
```ts
|
|
1132
|
-
import "@assistant-ui/styles/index.css";
|
|
1133
|
-
import "@assistant-ui/styles/markdown.css";
|
|
1134
|
-
// import "@assistant-ui/styles/modal.css"; // for future reference, only if you use our modal component
|
|
1135
|
-
```
|
|
1136
|
-
|
|
1137
|
-
</Step>
|
|
1138
|
-
</Steps>
|
|
1139
|
-
|
|
1140
|
-
</Tab>
|
|
1141
|
-
</Tabs>
|
|
81
|
+
<InstallCommand shadcn={["thread", "thread-list"]} manualSetupInstructions />
|
|
1142
82
|
|
|
1143
83
|
</Step>
|
|
1144
84
|
<Step>
|
|
@@ -1148,51 +88,39 @@ import "@assistant-ui/styles/markdown.css";
|
|
|
1148
88
|
Install provider SDK:
|
|
1149
89
|
|
|
1150
90
|
<Tabs groupId="provider" items={["OpenAI", "Anthropic", "Azure", "AWS", "Gemini", "GCP", "Groq", "Fireworks", "Cohere", "Ollama", "Chrome AI"]}>
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
npm
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
npm
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
```sh title="Terminal" tab="Cohere"
|
|
1185
|
-
npm install ai @assistant-ui/react-ai-sdk @ai-sdk/cohere
|
|
1186
|
-
```
|
|
1187
|
-
|
|
1188
|
-
```sh title="Terminal" tab="Ollama"
|
|
1189
|
-
npm install ai @assistant-ui/react-ai-sdk ollama-ai-provider
|
|
1190
|
-
```
|
|
1191
|
-
|
|
1192
|
-
```sh title="Terminal" tab="Chrome AI"
|
|
1193
|
-
npm install ai @assistant-ui/react-ai-sdk chrome-ai
|
|
1194
|
-
```
|
|
1195
|
-
|
|
91
|
+
<Tab>
|
|
92
|
+
<InstallCommand npm={["ai", "@assistant-ui/react-ai-sdk", "@ai-sdk/openai"]} />
|
|
93
|
+
</Tab>
|
|
94
|
+
<Tab>
|
|
95
|
+
<InstallCommand npm={["ai", "@assistant-ui/react-ai-sdk", "@ai-sdk/anthropic"]} />
|
|
96
|
+
</Tab>
|
|
97
|
+
<Tab>
|
|
98
|
+
<InstallCommand npm={["ai", "@assistant-ui/react-ai-sdk", "@ai-sdk/azure"]} />
|
|
99
|
+
</Tab>
|
|
100
|
+
<Tab>
|
|
101
|
+
<InstallCommand npm={["ai", "@assistant-ui/react-ai-sdk", "@ai-sdk/amazon-bedrock"]} />
|
|
102
|
+
</Tab>
|
|
103
|
+
<Tab>
|
|
104
|
+
<InstallCommand npm={["ai", "@assistant-ui/react-ai-sdk", "@ai-sdk/google"]} />
|
|
105
|
+
</Tab>
|
|
106
|
+
<Tab>
|
|
107
|
+
<InstallCommand npm={["ai", "@assistant-ui/react-ai-sdk", "@ai-sdk/google-vertex"]} />
|
|
108
|
+
</Tab>
|
|
109
|
+
<Tab>
|
|
110
|
+
<InstallCommand npm={["ai", "@assistant-ui/react-ai-sdk", "@ai-sdk/openai"]} />
|
|
111
|
+
</Tab>
|
|
112
|
+
<Tab>
|
|
113
|
+
<InstallCommand npm={["ai", "@assistant-ui/react-ai-sdk", "@ai-sdk/openai"]} />
|
|
114
|
+
</Tab>
|
|
115
|
+
<Tab>
|
|
116
|
+
<InstallCommand npm={["ai", "@assistant-ui/react-ai-sdk", "@ai-sdk/cohere"]} />
|
|
117
|
+
</Tab>
|
|
118
|
+
<Tab>
|
|
119
|
+
<InstallCommand npm={["ai", "@assistant-ui/react-ai-sdk", "ollama-ai-provider-v2"]} />
|
|
120
|
+
</Tab>
|
|
121
|
+
<Tab>
|
|
122
|
+
<InstallCommand npm={["ai", "@assistant-ui/react-ai-sdk", "chrome-ai"]} />
|
|
123
|
+
</Tab>
|
|
1196
124
|
</Tabs>
|
|
1197
125
|
|
|
1198
126
|
Add an API endpoint:
|
|
@@ -1353,7 +281,7 @@ export async function POST(req: Request) {
|
|
|
1353
281
|
```
|
|
1354
282
|
|
|
1355
283
|
```ts title="/app/api/chat/route.ts" tab="Ollama"
|
|
1356
|
-
import { ollama } from "ollama-ai-provider";
|
|
284
|
+
import { ollama } from "ollama-ai-provider-v2";
|
|
1357
285
|
import { convertToModelMessages, streamText } from "ai";
|
|
1358
286
|
|
|
1359
287
|
export const maxDuration = 30;
|
|
@@ -1476,7 +404,7 @@ const MyApp = () => {
|
|
|
1476
404
|
```
|
|
1477
405
|
|
|
1478
406
|
```tsx title="/app/page.tsx" tab="AssistantModal"
|
|
1479
|
-
// run `npx shadcn@latest add
|
|
407
|
+
// run `npx shadcn@latest add @assistant-ui/assistant-modal`
|
|
1480
408
|
|
|
1481
409
|
import { AssistantRuntimeProvider } from "@assistant-ui/react";
|
|
1482
410
|
import { useChatRuntime, AssistantChatTransport } from "@assistant-ui/react-ai-sdk";
|