@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
|
@@ -219,7 +219,7 @@ import Link from "next/link";
|
|
|
219
219
|
|
|
220
220
|
const SetFormFieldTool = () => {
|
|
221
221
|
return (
|
|
222
|
-
<p className="text-center font-
|
|
222
|
+
<p className="text-center font-bold font-mono text-blue-500 text-sm">
|
|
223
223
|
set_form_field(...)
|
|
224
224
|
</p>
|
|
225
225
|
);
|
|
@@ -227,7 +227,7 @@ const SetFormFieldTool = () => {
|
|
|
227
227
|
|
|
228
228
|
const SubmitFormTool = () => {
|
|
229
229
|
return (
|
|
230
|
-
<p className="text-center font-
|
|
230
|
+
<p className="text-center font-bold font-mono text-blue-500 text-sm">
|
|
231
231
|
submit_form(...)
|
|
232
232
|
</p>
|
|
233
233
|
);
|
|
@@ -260,7 +260,7 @@ export default function Home() {
|
|
|
260
260
|
<AssistantSidebar>
|
|
261
261
|
<div className="h-full overflow-y-scroll">
|
|
262
262
|
<main className="container py-8">
|
|
263
|
-
<h1 className="mb-2 text-2xl
|
|
263
|
+
<h1 className="mb-2 font-semibold text-2xl">
|
|
264
264
|
Simon's Hackathon
|
|
265
265
|
</h1>
|
|
266
266
|
<p>
|
|
@@ -316,39 +316,16 @@ export default function Home() {
|
|
|
316
316
|
## components/assistant-ui/assistant-sidebar.tsx
|
|
317
317
|
|
|
318
318
|
```tsx
|
|
319
|
-
"use client";
|
|
320
|
-
|
|
321
319
|
import {
|
|
322
320
|
ResizableHandle,
|
|
323
321
|
ResizablePanel,
|
|
324
322
|
ResizablePanelGroup,
|
|
325
323
|
} from "@/components/ui/resizable";
|
|
326
|
-
import { useMediaQuery } from "@react-hook/media-query";
|
|
327
324
|
import type { FC, PropsWithChildren } from "react";
|
|
328
|
-
|
|
325
|
+
|
|
329
326
|
import { Thread } from "@/components/assistant-ui/thread";
|
|
330
327
|
|
|
331
328
|
export const AssistantSidebar: FC<PropsWithChildren> = ({ children }) => {
|
|
332
|
-
const isSmall = useMediaQuery("(max-width: 768px)");
|
|
333
|
-
|
|
334
|
-
if (isSmall) {
|
|
335
|
-
return (
|
|
336
|
-
<Tabs
|
|
337
|
-
defaultValue="app"
|
|
338
|
-
className="mx-auto flex h-full max-w-[480px] flex-col px-4 pt-4"
|
|
339
|
-
>
|
|
340
|
-
<TabsList className="grid w-full grid-cols-2">
|
|
341
|
-
<TabsTrigger value="app">Form</TabsTrigger>
|
|
342
|
-
<TabsTrigger value="thread">Chat</TabsTrigger>
|
|
343
|
-
</TabsList>
|
|
344
|
-
<TabsContent value="app">{children}</TabsContent>
|
|
345
|
-
<TabsContent value="thread">
|
|
346
|
-
<Thread />
|
|
347
|
-
</TabsContent>
|
|
348
|
-
</Tabs>
|
|
349
|
-
);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
329
|
return (
|
|
353
330
|
<ResizablePanelGroup direction="horizontal">
|
|
354
331
|
<ResizablePanel>{children}</ResizablePanel>
|
|
@@ -362,6 +339,247 @@ export const AssistantSidebar: FC<PropsWithChildren> = ({ children }) => {
|
|
|
362
339
|
|
|
363
340
|
```
|
|
364
341
|
|
|
342
|
+
## components/assistant-ui/attachment.tsx
|
|
343
|
+
|
|
344
|
+
```tsx
|
|
345
|
+
"use client";
|
|
346
|
+
|
|
347
|
+
import { PropsWithChildren, useEffect, useState, type FC } from "react";
|
|
348
|
+
import Image from "next/image";
|
|
349
|
+
import { XIcon, PlusIcon, FileText } from "lucide-react";
|
|
350
|
+
import {
|
|
351
|
+
AttachmentPrimitive,
|
|
352
|
+
ComposerPrimitive,
|
|
353
|
+
MessagePrimitive,
|
|
354
|
+
useAssistantState,
|
|
355
|
+
useAssistantApi,
|
|
356
|
+
} from "@assistant-ui/react";
|
|
357
|
+
import { useShallow } from "zustand/shallow";
|
|
358
|
+
import {
|
|
359
|
+
Tooltip,
|
|
360
|
+
TooltipContent,
|
|
361
|
+
TooltipTrigger,
|
|
362
|
+
} from "@/components/ui/tooltip";
|
|
363
|
+
import {
|
|
364
|
+
Dialog,
|
|
365
|
+
DialogTitle,
|
|
366
|
+
DialogContent,
|
|
367
|
+
DialogTrigger,
|
|
368
|
+
} from "@/components/ui/dialog";
|
|
369
|
+
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
|
|
370
|
+
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
371
|
+
import { cn } from "@/lib/utils";
|
|
372
|
+
|
|
373
|
+
const useFileSrc = (file: File | undefined) => {
|
|
374
|
+
const [src, setSrc] = useState<string | undefined>(undefined);
|
|
375
|
+
|
|
376
|
+
useEffect(() => {
|
|
377
|
+
if (!file) {
|
|
378
|
+
setSrc(undefined);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const objectUrl = URL.createObjectURL(file);
|
|
383
|
+
setSrc(objectUrl);
|
|
384
|
+
|
|
385
|
+
return () => {
|
|
386
|
+
URL.revokeObjectURL(objectUrl);
|
|
387
|
+
};
|
|
388
|
+
}, [file]);
|
|
389
|
+
|
|
390
|
+
return src;
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
const useAttachmentSrc = () => {
|
|
394
|
+
const { file, src } = useAssistantState(
|
|
395
|
+
useShallow(({ attachment }): { file?: File; src?: string } => {
|
|
396
|
+
if (attachment.type !== "image") return {};
|
|
397
|
+
if (attachment.file) return { file: attachment.file };
|
|
398
|
+
const src = attachment.content?.filter((c) => c.type === "image")[0]
|
|
399
|
+
?.image;
|
|
400
|
+
if (!src) return {};
|
|
401
|
+
return { src };
|
|
402
|
+
}),
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
return useFileSrc(file) ?? src;
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
type AttachmentPreviewProps = {
|
|
409
|
+
src: string;
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
const AttachmentPreview: FC<AttachmentPreviewProps> = ({ src }) => {
|
|
413
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
414
|
+
return (
|
|
415
|
+
<Image
|
|
416
|
+
src={src}
|
|
417
|
+
alt="Image Preview"
|
|
418
|
+
width={1}
|
|
419
|
+
height={1}
|
|
420
|
+
className={
|
|
421
|
+
isLoaded
|
|
422
|
+
? "aui-attachment-preview-image-loaded block h-auto max-h-[80vh] w-auto max-w-full object-contain"
|
|
423
|
+
: "aui-attachment-preview-image-loading hidden"
|
|
424
|
+
}
|
|
425
|
+
onLoadingComplete={() => setIsLoaded(true)}
|
|
426
|
+
priority={false}
|
|
427
|
+
/>
|
|
428
|
+
);
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
const AttachmentPreviewDialog: FC<PropsWithChildren> = ({ children }) => {
|
|
432
|
+
const src = useAttachmentSrc();
|
|
433
|
+
|
|
434
|
+
if (!src) return children;
|
|
435
|
+
|
|
436
|
+
return (
|
|
437
|
+
<Dialog>
|
|
438
|
+
<DialogTrigger
|
|
439
|
+
className="aui-attachment-preview-trigger cursor-pointer transition-colors hover:bg-accent/50"
|
|
440
|
+
asChild
|
|
441
|
+
>
|
|
442
|
+
{children}
|
|
443
|
+
</DialogTrigger>
|
|
444
|
+
<DialogContent className="aui-attachment-preview-dialog-content p-2 sm:max-w-3xl [&>button]:rounded-full [&>button]:bg-foreground/60 [&>button]:p-1 [&>button]:opacity-100 [&>button]:ring-0! [&_svg]:text-background [&>button]:hover:[&_svg]:text-destructive">
|
|
445
|
+
<DialogTitle className="aui-sr-only sr-only">
|
|
446
|
+
Image Attachment Preview
|
|
447
|
+
</DialogTitle>
|
|
448
|
+
<div className="aui-attachment-preview relative mx-auto flex max-h-[80dvh] w-full items-center justify-center overflow-hidden bg-background">
|
|
449
|
+
<AttachmentPreview src={src} />
|
|
450
|
+
</div>
|
|
451
|
+
</DialogContent>
|
|
452
|
+
</Dialog>
|
|
453
|
+
);
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
const AttachmentThumb: FC = () => {
|
|
457
|
+
const isImage = useAssistantState(
|
|
458
|
+
({ attachment }) => attachment.type === "image",
|
|
459
|
+
);
|
|
460
|
+
const src = useAttachmentSrc();
|
|
461
|
+
|
|
462
|
+
return (
|
|
463
|
+
<Avatar className="aui-attachment-tile-avatar h-full w-full rounded-none">
|
|
464
|
+
<AvatarImage
|
|
465
|
+
src={src}
|
|
466
|
+
alt="Attachment preview"
|
|
467
|
+
className="aui-attachment-tile-image object-cover"
|
|
468
|
+
/>
|
|
469
|
+
<AvatarFallback delayMs={isImage ? 200 : 0}>
|
|
470
|
+
<FileText className="aui-attachment-tile-fallback-icon size-8 text-muted-foreground" />
|
|
471
|
+
</AvatarFallback>
|
|
472
|
+
</Avatar>
|
|
473
|
+
);
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
const AttachmentUI: FC = () => {
|
|
477
|
+
const api = useAssistantApi();
|
|
478
|
+
const isComposer = api.attachment.source === "composer";
|
|
479
|
+
|
|
480
|
+
const isImage = useAssistantState(
|
|
481
|
+
({ attachment }) => attachment.type === "image",
|
|
482
|
+
);
|
|
483
|
+
const typeLabel = useAssistantState(({ attachment }) => {
|
|
484
|
+
const type = attachment.type;
|
|
485
|
+
switch (type) {
|
|
486
|
+
case "image":
|
|
487
|
+
return "Image";
|
|
488
|
+
case "document":
|
|
489
|
+
return "Document";
|
|
490
|
+
case "file":
|
|
491
|
+
return "File";
|
|
492
|
+
default:
|
|
493
|
+
const _exhaustiveCheck: never = type;
|
|
494
|
+
throw new Error(`Unknown attachment type: ${_exhaustiveCheck}`);
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
return (
|
|
499
|
+
<Tooltip>
|
|
500
|
+
<AttachmentPrimitive.Root
|
|
501
|
+
className={cn(
|
|
502
|
+
"aui-attachment-root relative",
|
|
503
|
+
isImage &&
|
|
504
|
+
"aui-attachment-root-composer only:[&>#attachment-tile]:size-24",
|
|
505
|
+
)}
|
|
506
|
+
>
|
|
507
|
+
<AttachmentPreviewDialog>
|
|
508
|
+
<TooltipTrigger asChild>
|
|
509
|
+
<div
|
|
510
|
+
className={cn(
|
|
511
|
+
"aui-attachment-tile size-14 cursor-pointer overflow-hidden rounded-[14px] border bg-muted transition-opacity hover:opacity-75",
|
|
512
|
+
isComposer &&
|
|
513
|
+
"aui-attachment-tile-composer border-foreground/20",
|
|
514
|
+
)}
|
|
515
|
+
role="button"
|
|
516
|
+
id="attachment-tile"
|
|
517
|
+
aria-label={`${typeLabel} attachment`}
|
|
518
|
+
>
|
|
519
|
+
<AttachmentThumb />
|
|
520
|
+
</div>
|
|
521
|
+
</TooltipTrigger>
|
|
522
|
+
</AttachmentPreviewDialog>
|
|
523
|
+
{isComposer && <AttachmentRemove />}
|
|
524
|
+
</AttachmentPrimitive.Root>
|
|
525
|
+
<TooltipContent side="top">
|
|
526
|
+
<AttachmentPrimitive.Name />
|
|
527
|
+
</TooltipContent>
|
|
528
|
+
</Tooltip>
|
|
529
|
+
);
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
const AttachmentRemove: FC = () => {
|
|
533
|
+
return (
|
|
534
|
+
<AttachmentPrimitive.Remove asChild>
|
|
535
|
+
<TooltipIconButton
|
|
536
|
+
tooltip="Remove file"
|
|
537
|
+
className="aui-attachment-tile-remove absolute top-1.5 right-1.5 size-3.5 rounded-full bg-white text-muted-foreground opacity-100 shadow-sm hover:bg-white! [&_svg]:text-black hover:[&_svg]:text-destructive"
|
|
538
|
+
side="top"
|
|
539
|
+
>
|
|
540
|
+
<XIcon className="aui-attachment-remove-icon size-3 dark:stroke-[2.5px]" />
|
|
541
|
+
</TooltipIconButton>
|
|
542
|
+
</AttachmentPrimitive.Remove>
|
|
543
|
+
);
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
export const UserMessageAttachments: FC = () => {
|
|
547
|
+
return (
|
|
548
|
+
<div className="aui-user-message-attachments-end col-span-full col-start-1 row-start-1 flex w-full flex-row justify-end gap-2">
|
|
549
|
+
<MessagePrimitive.Attachments components={{ Attachment: AttachmentUI }} />
|
|
550
|
+
</div>
|
|
551
|
+
);
|
|
552
|
+
};
|
|
553
|
+
|
|
554
|
+
export const ComposerAttachments: FC = () => {
|
|
555
|
+
return (
|
|
556
|
+
<div className="aui-composer-attachments mb-2 flex w-full flex-row items-center gap-2 overflow-x-auto px-1.5 pt-0.5 pb-1 empty:hidden">
|
|
557
|
+
<ComposerPrimitive.Attachments
|
|
558
|
+
components={{ Attachment: AttachmentUI }}
|
|
559
|
+
/>
|
|
560
|
+
</div>
|
|
561
|
+
);
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
export const ComposerAddAttachment: FC = () => {
|
|
565
|
+
return (
|
|
566
|
+
<ComposerPrimitive.AddAttachment asChild>
|
|
567
|
+
<TooltipIconButton
|
|
568
|
+
tooltip="Add Attachment"
|
|
569
|
+
side="bottom"
|
|
570
|
+
variant="ghost"
|
|
571
|
+
size="icon"
|
|
572
|
+
className="aui-composer-add-attachment size-[34px] rounded-full p-1 font-semibold text-xs hover:bg-muted-foreground/15 dark:border-muted-foreground/15 dark:hover:bg-muted-foreground/30"
|
|
573
|
+
aria-label="Add Attachment"
|
|
574
|
+
>
|
|
575
|
+
<PlusIcon className="aui-attachment-add-icon size-5 stroke-[1.5px]" />
|
|
576
|
+
</TooltipIconButton>
|
|
577
|
+
</ComposerPrimitive.AddAttachment>
|
|
578
|
+
);
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
```
|
|
582
|
+
|
|
365
583
|
## components/assistant-ui/markdown-text.tsx
|
|
366
584
|
|
|
367
585
|
```tsx
|
|
@@ -370,13 +588,13 @@ export const AssistantSidebar: FC<PropsWithChildren> = ({ children }) => {
|
|
|
370
588
|
import "@assistant-ui/react-markdown/styles/dot.css";
|
|
371
589
|
|
|
372
590
|
import {
|
|
373
|
-
CodeHeaderProps,
|
|
591
|
+
type CodeHeaderProps,
|
|
374
592
|
MarkdownTextPrimitive,
|
|
375
593
|
unstable_memoizeMarkdownComponents as memoizeMarkdownComponents,
|
|
376
594
|
useIsMarkdownCodeBlock,
|
|
377
595
|
} from "@assistant-ui/react-markdown";
|
|
378
596
|
import remarkGfm from "remark-gfm";
|
|
379
|
-
import { FC, memo, useState } from "react";
|
|
597
|
+
import { type FC, memo, useState } from "react";
|
|
380
598
|
import { CheckIcon, CopyIcon } from "lucide-react";
|
|
381
599
|
|
|
382
600
|
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
@@ -402,8 +620,10 @@ const CodeHeader: FC<CodeHeaderProps> = ({ language, code }) => {
|
|
|
402
620
|
};
|
|
403
621
|
|
|
404
622
|
return (
|
|
405
|
-
<div className="flex items-center justify-between gap-4 rounded-t-lg bg-
|
|
406
|
-
<span className="lowercase [&>span]:text-xs">
|
|
623
|
+
<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">
|
|
624
|
+
<span className="aui-code-header-language lowercase [&>span]:text-xs">
|
|
625
|
+
{language}
|
|
626
|
+
</span>
|
|
407
627
|
<TooltipIconButton tooltip="Copy" onClick={onCopy}>
|
|
408
628
|
{!isCopied && <CopyIcon />}
|
|
409
629
|
{isCopied && <CheckIcon />}
|
|
@@ -435,7 +655,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
435
655
|
h1: ({ className, ...props }) => (
|
|
436
656
|
<h1
|
|
437
657
|
className={cn(
|
|
438
|
-
"mb-8 scroll-m-20 text-4xl
|
|
658
|
+
"aui-md-h1 mb-8 scroll-m-20 font-extrabold text-4xl tracking-tight last:mb-0",
|
|
439
659
|
className,
|
|
440
660
|
)}
|
|
441
661
|
{...props}
|
|
@@ -444,7 +664,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
444
664
|
h2: ({ className, ...props }) => (
|
|
445
665
|
<h2
|
|
446
666
|
className={cn(
|
|
447
|
-
"mt-8 mb-4 scroll-m-20 text-3xl
|
|
667
|
+
"aui-md-h2 mt-8 mb-4 scroll-m-20 font-semibold text-3xl tracking-tight first:mt-0 last:mb-0",
|
|
448
668
|
className,
|
|
449
669
|
)}
|
|
450
670
|
{...props}
|
|
@@ -453,7 +673,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
453
673
|
h3: ({ className, ...props }) => (
|
|
454
674
|
<h3
|
|
455
675
|
className={cn(
|
|
456
|
-
"mt-6 mb-4 scroll-m-20 text-2xl
|
|
676
|
+
"aui-md-h3 mt-6 mb-4 scroll-m-20 font-semibold text-2xl tracking-tight first:mt-0 last:mb-0",
|
|
457
677
|
className,
|
|
458
678
|
)}
|
|
459
679
|
{...props}
|
|
@@ -462,7 +682,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
462
682
|
h4: ({ className, ...props }) => (
|
|
463
683
|
<h4
|
|
464
684
|
className={cn(
|
|
465
|
-
"mt-6 mb-4 scroll-m-20 text-xl
|
|
685
|
+
"aui-md-h4 mt-6 mb-4 scroll-m-20 font-semibold text-xl tracking-tight first:mt-0 last:mb-0",
|
|
466
686
|
className,
|
|
467
687
|
)}
|
|
468
688
|
{...props}
|
|
@@ -471,7 +691,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
471
691
|
h5: ({ className, ...props }) => (
|
|
472
692
|
<h5
|
|
473
693
|
className={cn(
|
|
474
|
-
"my-4 text-lg
|
|
694
|
+
"aui-md-h5 my-4 font-semibold text-lg first:mt-0 last:mb-0",
|
|
475
695
|
className,
|
|
476
696
|
)}
|
|
477
697
|
{...props}
|
|
@@ -479,20 +699,26 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
479
699
|
),
|
|
480
700
|
h6: ({ className, ...props }) => (
|
|
481
701
|
<h6
|
|
482
|
-
className={cn(
|
|
702
|
+
className={cn(
|
|
703
|
+
"aui-md-h6 my-4 font-semibold first:mt-0 last:mb-0",
|
|
704
|
+
className,
|
|
705
|
+
)}
|
|
483
706
|
{...props}
|
|
484
707
|
/>
|
|
485
708
|
),
|
|
486
709
|
p: ({ className, ...props }) => (
|
|
487
710
|
<p
|
|
488
|
-
className={cn(
|
|
711
|
+
className={cn(
|
|
712
|
+
"aui-md-p mt-5 mb-5 leading-7 first:mt-0 last:mb-0",
|
|
713
|
+
className,
|
|
714
|
+
)}
|
|
489
715
|
{...props}
|
|
490
716
|
/>
|
|
491
717
|
),
|
|
492
718
|
a: ({ className, ...props }) => (
|
|
493
719
|
<a
|
|
494
720
|
className={cn(
|
|
495
|
-
"
|
|
721
|
+
"aui-md-a font-medium text-primary underline underline-offset-4",
|
|
496
722
|
className,
|
|
497
723
|
)}
|
|
498
724
|
{...props}
|
|
@@ -500,29 +726,29 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
500
726
|
),
|
|
501
727
|
blockquote: ({ className, ...props }) => (
|
|
502
728
|
<blockquote
|
|
503
|
-
className={cn("border-l-2 pl-6 italic", className)}
|
|
729
|
+
className={cn("aui-md-blockquote border-l-2 pl-6 italic", className)}
|
|
504
730
|
{...props}
|
|
505
731
|
/>
|
|
506
732
|
),
|
|
507
733
|
ul: ({ className, ...props }) => (
|
|
508
734
|
<ul
|
|
509
|
-
className={cn("my-5 ml-6 list-disc [&>li]:mt-2", className)}
|
|
735
|
+
className={cn("aui-md-ul my-5 ml-6 list-disc [&>li]:mt-2", className)}
|
|
510
736
|
{...props}
|
|
511
737
|
/>
|
|
512
738
|
),
|
|
513
739
|
ol: ({ className, ...props }) => (
|
|
514
740
|
<ol
|
|
515
|
-
className={cn("my-5 ml-6 list-decimal [&>li]:mt-2", className)}
|
|
741
|
+
className={cn("aui-md-ol my-5 ml-6 list-decimal [&>li]:mt-2", className)}
|
|
516
742
|
{...props}
|
|
517
743
|
/>
|
|
518
744
|
),
|
|
519
745
|
hr: ({ className, ...props }) => (
|
|
520
|
-
<hr className={cn("my-5 border-b", className)} {...props} />
|
|
746
|
+
<hr className={cn("aui-md-hr my-5 border-b", className)} {...props} />
|
|
521
747
|
),
|
|
522
748
|
table: ({ className, ...props }) => (
|
|
523
749
|
<table
|
|
524
750
|
className={cn(
|
|
525
|
-
"my-5 w-full border-separate border-spacing-0 overflow-y-auto",
|
|
751
|
+
"aui-md-table my-5 w-full border-separate border-spacing-0 overflow-y-auto",
|
|
526
752
|
className,
|
|
527
753
|
)}
|
|
528
754
|
{...props}
|
|
@@ -531,7 +757,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
531
757
|
th: ({ className, ...props }) => (
|
|
532
758
|
<th
|
|
533
759
|
className={cn(
|
|
534
|
-
"bg-muted px-4 py-2 text-left font-bold first:rounded-tl-lg last:rounded-tr-lg [
|
|
760
|
+
"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",
|
|
535
761
|
className,
|
|
536
762
|
)}
|
|
537
763
|
{...props}
|
|
@@ -540,7 +766,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
540
766
|
td: ({ className, ...props }) => (
|
|
541
767
|
<td
|
|
542
768
|
className={cn(
|
|
543
|
-
"border-b border-l px-4 py-2 text-left last:border-r [
|
|
769
|
+
"aui-md-td border-b border-l px-4 py-2 text-left last:border-r [[align=center]]:text-center [[align=right]]:text-right",
|
|
544
770
|
className,
|
|
545
771
|
)}
|
|
546
772
|
{...props}
|
|
@@ -549,7 +775,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
549
775
|
tr: ({ className, ...props }) => (
|
|
550
776
|
<tr
|
|
551
777
|
className={cn(
|
|
552
|
-
"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",
|
|
778
|
+
"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",
|
|
553
779
|
className,
|
|
554
780
|
)}
|
|
555
781
|
{...props}
|
|
@@ -557,14 +783,14 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
557
783
|
),
|
|
558
784
|
sup: ({ className, ...props }) => (
|
|
559
785
|
<sup
|
|
560
|
-
className={cn("[&>a]:text-xs [&>a]:no-underline", className)}
|
|
786
|
+
className={cn("aui-md-sup [&>a]:text-xs [&>a]:no-underline", className)}
|
|
561
787
|
{...props}
|
|
562
788
|
/>
|
|
563
789
|
),
|
|
564
790
|
pre: ({ className, ...props }) => (
|
|
565
791
|
<pre
|
|
566
792
|
className={cn(
|
|
567
|
-
"overflow-x-auto rounded-b-lg bg-black p-4 text-white",
|
|
793
|
+
"aui-md-pre overflow-x-auto rounded-t-none! rounded-b-lg bg-black p-4 text-white",
|
|
568
794
|
className,
|
|
569
795
|
)}
|
|
570
796
|
{...props}
|
|
@@ -575,7 +801,8 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
575
801
|
return (
|
|
576
802
|
<code
|
|
577
803
|
className={cn(
|
|
578
|
-
!isCodeBlock &&
|
|
804
|
+
!isCodeBlock &&
|
|
805
|
+
"aui-md-inline-code rounded border bg-muted font-semibold",
|
|
579
806
|
className,
|
|
580
807
|
)}
|
|
581
808
|
{...props}
|
|
@@ -590,57 +817,67 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
590
817
|
## components/assistant-ui/thread.tsx
|
|
591
818
|
|
|
592
819
|
```tsx
|
|
820
|
+
import {
|
|
821
|
+
ComposerAddAttachment,
|
|
822
|
+
ComposerAttachments,
|
|
823
|
+
UserMessageAttachments,
|
|
824
|
+
} from "@/components/assistant-ui/attachment";
|
|
825
|
+
import { MarkdownText } from "@/components/assistant-ui/markdown-text";
|
|
826
|
+
import { ToolFallback } from "@/components/assistant-ui/tool-fallback";
|
|
827
|
+
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
828
|
+
import { Button } from "@/components/ui/button";
|
|
829
|
+
import { cn } from "@/lib/utils";
|
|
593
830
|
import {
|
|
594
831
|
ActionBarPrimitive,
|
|
832
|
+
AssistantIf,
|
|
595
833
|
BranchPickerPrimitive,
|
|
596
834
|
ComposerPrimitive,
|
|
835
|
+
ErrorPrimitive,
|
|
597
836
|
MessagePrimitive,
|
|
598
837
|
ThreadPrimitive,
|
|
599
838
|
} from "@assistant-ui/react";
|
|
600
|
-
import type { FC } from "react";
|
|
601
839
|
import {
|
|
602
840
|
ArrowDownIcon,
|
|
841
|
+
ArrowUpIcon,
|
|
603
842
|
CheckIcon,
|
|
604
843
|
ChevronLeftIcon,
|
|
605
844
|
ChevronRightIcon,
|
|
606
845
|
CopyIcon,
|
|
846
|
+
DownloadIcon,
|
|
607
847
|
PencilIcon,
|
|
608
848
|
RefreshCwIcon,
|
|
609
|
-
|
|
849
|
+
SquareIcon,
|
|
610
850
|
} from "lucide-react";
|
|
611
|
-
import {
|
|
612
|
-
|
|
613
|
-
import { Button } from "@/components/ui/button";
|
|
614
|
-
import { MarkdownText } from "@/components/assistant-ui/markdown-text";
|
|
615
|
-
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
851
|
+
import type { FC } from "react";
|
|
616
852
|
|
|
617
853
|
export const Thread: FC = () => {
|
|
618
854
|
return (
|
|
619
855
|
<ThreadPrimitive.Root
|
|
620
|
-
className="
|
|
856
|
+
className="aui-root aui-thread-root @container flex h-full flex-col bg-background"
|
|
621
857
|
style={{
|
|
622
|
-
["--thread-max-width" as string]: "
|
|
858
|
+
["--thread-max-width" as string]: "44rem",
|
|
623
859
|
}}
|
|
624
860
|
>
|
|
625
|
-
<ThreadPrimitive.Viewport
|
|
626
|
-
|
|
861
|
+
<ThreadPrimitive.Viewport
|
|
862
|
+
turnAnchor="top"
|
|
863
|
+
className="aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-smooth px-4 pt-4"
|
|
864
|
+
>
|
|
865
|
+
<AssistantIf condition={({ thread }) => thread.isEmpty}>
|
|
866
|
+
<ThreadWelcome />
|
|
867
|
+
</AssistantIf>
|
|
627
868
|
|
|
628
869
|
<ThreadPrimitive.Messages
|
|
629
870
|
components={{
|
|
630
|
-
UserMessage
|
|
631
|
-
EditComposer
|
|
632
|
-
AssistantMessage
|
|
871
|
+
UserMessage,
|
|
872
|
+
EditComposer,
|
|
873
|
+
AssistantMessage,
|
|
633
874
|
}}
|
|
634
875
|
/>
|
|
635
876
|
|
|
636
|
-
<ThreadPrimitive.
|
|
637
|
-
<div className="min-h-8 flex-grow" />
|
|
638
|
-
</ThreadPrimitive.If>
|
|
639
|
-
|
|
640
|
-
<div className="sticky bottom-0 mt-3 flex w-full max-w-[var(--thread-max-width)] flex-col items-center justify-end rounded-t-lg bg-inherit pb-4">
|
|
877
|
+
<ThreadPrimitive.ViewportFooter className="aui-thread-viewport-footer sticky bottom-0 mx-auto mt-auto flex w-full max-w-(--thread-max-width) flex-col gap-4 overflow-visible rounded-t-3xl bg-background pb-4 md:pb-6">
|
|
641
878
|
<ThreadScrollToBottom />
|
|
642
879
|
<Composer />
|
|
643
|
-
</
|
|
880
|
+
</ThreadPrimitive.ViewportFooter>
|
|
644
881
|
</ThreadPrimitive.Viewport>
|
|
645
882
|
</ThreadPrimitive.Root>
|
|
646
883
|
);
|
|
@@ -652,7 +889,7 @@ const ThreadScrollToBottom: FC = () => {
|
|
|
652
889
|
<TooltipIconButton
|
|
653
890
|
tooltip="Scroll to bottom"
|
|
654
891
|
variant="outline"
|
|
655
|
-
className="
|
|
892
|
+
className="aui-thread-scroll-to-bottom -top-12 absolute z-10 self-center rounded-full p-4 disabled:invisible dark:bg-background dark:hover:bg-accent"
|
|
656
893
|
>
|
|
657
894
|
<ArrowDownIcon />
|
|
658
895
|
</TooltipIconButton>
|
|
@@ -662,175 +899,247 @@ const ThreadScrollToBottom: FC = () => {
|
|
|
662
899
|
|
|
663
900
|
const ThreadWelcome: FC = () => {
|
|
664
901
|
return (
|
|
665
|
-
<
|
|
666
|
-
<div className="
|
|
667
|
-
<div className="flex
|
|
668
|
-
<
|
|
902
|
+
<div className="aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col">
|
|
903
|
+
<div className="aui-thread-welcome-center flex w-full grow flex-col items-center justify-center">
|
|
904
|
+
<div className="aui-thread-welcome-message flex size-full flex-col justify-center px-4">
|
|
905
|
+
<h1 className="aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in font-semibold text-2xl duration-200">
|
|
906
|
+
Hello there!
|
|
907
|
+
</h1>
|
|
908
|
+
<p className="aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in text-muted-foreground text-xl delay-75 duration-200">
|
|
909
|
+
How can I help you today?
|
|
910
|
+
</p>
|
|
669
911
|
</div>
|
|
670
|
-
<ThreadWelcomeSuggestions />
|
|
671
912
|
</div>
|
|
672
|
-
|
|
913
|
+
<ThreadSuggestions />
|
|
914
|
+
</div>
|
|
673
915
|
);
|
|
674
916
|
};
|
|
675
917
|
|
|
676
|
-
const
|
|
918
|
+
const SUGGESTIONS = [
|
|
919
|
+
{
|
|
920
|
+
title: "What's the weather",
|
|
921
|
+
label: "in San Francisco?",
|
|
922
|
+
prompt: "What's the weather in San Francisco?",
|
|
923
|
+
},
|
|
924
|
+
{
|
|
925
|
+
title: "Explain React hooks",
|
|
926
|
+
label: "like useState and useEffect",
|
|
927
|
+
prompt: "Explain React hooks like useState and useEffect",
|
|
928
|
+
},
|
|
929
|
+
] as const;
|
|
930
|
+
|
|
931
|
+
const ThreadSuggestions: FC = () => {
|
|
677
932
|
return (
|
|
678
|
-
<div className="
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
933
|
+
<div className="aui-thread-welcome-suggestions grid w-full @md:grid-cols-2 gap-2 pb-4">
|
|
934
|
+
{SUGGESTIONS.map((suggestion, index) => (
|
|
935
|
+
<div
|
|
936
|
+
key={suggestion.prompt}
|
|
937
|
+
className="aui-thread-welcome-suggestion-display fade-in slide-in-from-bottom-2 @md:nth-[n+3]:block nth-[n+3]:hidden animate-in fill-mode-both duration-200"
|
|
938
|
+
style={{ animationDelay: `${100 + index * 50}ms` }}
|
|
939
|
+
>
|
|
940
|
+
<ThreadPrimitive.Suggestion prompt={suggestion.prompt} send asChild>
|
|
941
|
+
<Button
|
|
942
|
+
variant="ghost"
|
|
943
|
+
className="aui-thread-welcome-suggestion h-auto w-full @md:flex-col flex-wrap items-start justify-start gap-1 rounded-2xl border px-4 py-3 text-left text-sm transition-colors hover:bg-muted"
|
|
944
|
+
aria-label={suggestion.prompt}
|
|
945
|
+
>
|
|
946
|
+
<span className="aui-thread-welcome-suggestion-text-1 font-medium">
|
|
947
|
+
{suggestion.title}
|
|
948
|
+
</span>
|
|
949
|
+
<span className="aui-thread-welcome-suggestion-text-2 text-muted-foreground">
|
|
950
|
+
{suggestion.label}
|
|
951
|
+
</span>
|
|
952
|
+
</Button>
|
|
953
|
+
</ThreadPrimitive.Suggestion>
|
|
954
|
+
</div>
|
|
955
|
+
))}
|
|
699
956
|
</div>
|
|
700
957
|
);
|
|
701
958
|
};
|
|
702
959
|
|
|
703
960
|
const Composer: FC = () => {
|
|
704
961
|
return (
|
|
705
|
-
<ComposerPrimitive.Root className="
|
|
706
|
-
<ComposerPrimitive.
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
962
|
+
<ComposerPrimitive.Root className="aui-composer-root relative flex w-full flex-col">
|
|
963
|
+
<ComposerPrimitive.AttachmentDropzone className="aui-composer-attachment-dropzone flex w-full flex-col rounded-2xl border border-input bg-background px-1 pt-2 outline-none transition-shadow has-[textarea:focus-visible]:border-ring has-[textarea:focus-visible]:ring-2 has-[textarea:focus-visible]:ring-ring/20 data-[dragging=true]:border-ring data-[dragging=true]:border-dashed data-[dragging=true]:bg-accent/50">
|
|
964
|
+
<ComposerAttachments />
|
|
965
|
+
<ComposerPrimitive.Input
|
|
966
|
+
placeholder="Send a message..."
|
|
967
|
+
className="aui-composer-input mb-1 max-h-32 min-h-14 w-full resize-none bg-transparent px-4 pt-2 pb-3 text-sm outline-none placeholder:text-muted-foreground focus-visible:ring-0"
|
|
968
|
+
rows={1}
|
|
969
|
+
autoFocus
|
|
970
|
+
aria-label="Message input"
|
|
971
|
+
/>
|
|
972
|
+
<ComposerAction />
|
|
973
|
+
</ComposerPrimitive.AttachmentDropzone>
|
|
713
974
|
</ComposerPrimitive.Root>
|
|
714
975
|
);
|
|
715
976
|
};
|
|
716
977
|
|
|
717
978
|
const ComposerAction: FC = () => {
|
|
718
979
|
return (
|
|
719
|
-
|
|
720
|
-
<
|
|
980
|
+
<div className="aui-composer-action-wrapper relative mx-2 mb-2 flex items-center justify-between">
|
|
981
|
+
<ComposerAddAttachment />
|
|
982
|
+
|
|
983
|
+
<AssistantIf condition={({ thread }) => !thread.isRunning}>
|
|
721
984
|
<ComposerPrimitive.Send asChild>
|
|
722
985
|
<TooltipIconButton
|
|
723
|
-
tooltip="Send"
|
|
986
|
+
tooltip="Send message"
|
|
987
|
+
side="bottom"
|
|
988
|
+
type="submit"
|
|
724
989
|
variant="default"
|
|
725
|
-
|
|
990
|
+
size="icon"
|
|
991
|
+
className="aui-composer-send size-8 rounded-full"
|
|
992
|
+
aria-label="Send message"
|
|
726
993
|
>
|
|
727
|
-
<
|
|
994
|
+
<ArrowUpIcon className="aui-composer-send-icon size-4" />
|
|
728
995
|
</TooltipIconButton>
|
|
729
996
|
</ComposerPrimitive.Send>
|
|
730
|
-
</
|
|
731
|
-
|
|
997
|
+
</AssistantIf>
|
|
998
|
+
|
|
999
|
+
<AssistantIf condition={({ thread }) => thread.isRunning}>
|
|
732
1000
|
<ComposerPrimitive.Cancel asChild>
|
|
733
|
-
<
|
|
734
|
-
|
|
1001
|
+
<Button
|
|
1002
|
+
type="button"
|
|
735
1003
|
variant="default"
|
|
736
|
-
|
|
1004
|
+
size="icon"
|
|
1005
|
+
className="aui-composer-cancel size-8 rounded-full"
|
|
1006
|
+
aria-label="Stop generating"
|
|
737
1007
|
>
|
|
738
|
-
<
|
|
739
|
-
</
|
|
1008
|
+
<SquareIcon className="aui-composer-cancel-icon size-3 fill-current" />
|
|
1009
|
+
</Button>
|
|
740
1010
|
</ComposerPrimitive.Cancel>
|
|
741
|
-
</
|
|
742
|
-
|
|
1011
|
+
</AssistantIf>
|
|
1012
|
+
</div>
|
|
743
1013
|
);
|
|
744
1014
|
};
|
|
745
1015
|
|
|
746
|
-
const
|
|
1016
|
+
const MessageError: FC = () => {
|
|
747
1017
|
return (
|
|
748
|
-
<MessagePrimitive.
|
|
749
|
-
<
|
|
1018
|
+
<MessagePrimitive.Error>
|
|
1019
|
+
<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">
|
|
1020
|
+
<ErrorPrimitive.Message className="aui-message-error-message line-clamp-2" />
|
|
1021
|
+
</ErrorPrimitive.Root>
|
|
1022
|
+
</MessagePrimitive.Error>
|
|
1023
|
+
);
|
|
1024
|
+
};
|
|
750
1025
|
|
|
751
|
-
|
|
752
|
-
|
|
1026
|
+
const AssistantMessage: FC = () => {
|
|
1027
|
+
return (
|
|
1028
|
+
<MessagePrimitive.Root
|
|
1029
|
+
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-3 duration-150"
|
|
1030
|
+
data-role="assistant"
|
|
1031
|
+
>
|
|
1032
|
+
<div className="aui-assistant-message-content wrap-break-word px-2 text-foreground leading-relaxed">
|
|
1033
|
+
<MessagePrimitive.Parts
|
|
1034
|
+
components={{
|
|
1035
|
+
Text: MarkdownText,
|
|
1036
|
+
tools: { Fallback: ToolFallback },
|
|
1037
|
+
}}
|
|
1038
|
+
/>
|
|
1039
|
+
<MessageError />
|
|
753
1040
|
</div>
|
|
754
1041
|
|
|
755
|
-
<
|
|
1042
|
+
<div className="aui-assistant-message-footer mt-1 ml-2 flex">
|
|
1043
|
+
<BranchPicker />
|
|
1044
|
+
<AssistantActionBar />
|
|
1045
|
+
</div>
|
|
756
1046
|
</MessagePrimitive.Root>
|
|
757
1047
|
);
|
|
758
1048
|
};
|
|
759
1049
|
|
|
760
|
-
const
|
|
1050
|
+
const AssistantActionBar: FC = () => {
|
|
761
1051
|
return (
|
|
762
1052
|
<ActionBarPrimitive.Root
|
|
763
1053
|
hideWhenRunning
|
|
764
1054
|
autohide="not-last"
|
|
765
|
-
|
|
1055
|
+
autohideFloat="single-branch"
|
|
1056
|
+
className="aui-assistant-action-bar-root -ml-1 col-start-3 row-start-2 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"
|
|
766
1057
|
>
|
|
767
|
-
<ActionBarPrimitive.
|
|
768
|
-
<TooltipIconButton tooltip="
|
|
769
|
-
<
|
|
1058
|
+
<ActionBarPrimitive.Copy asChild>
|
|
1059
|
+
<TooltipIconButton tooltip="Copy">
|
|
1060
|
+
<AssistantIf condition={({ message }) => message.isCopied}>
|
|
1061
|
+
<CheckIcon />
|
|
1062
|
+
</AssistantIf>
|
|
1063
|
+
<AssistantIf condition={({ message }) => !message.isCopied}>
|
|
1064
|
+
<CopyIcon />
|
|
1065
|
+
</AssistantIf>
|
|
770
1066
|
</TooltipIconButton>
|
|
771
|
-
</ActionBarPrimitive.
|
|
1067
|
+
</ActionBarPrimitive.Copy>
|
|
1068
|
+
<ActionBarPrimitive.ExportMarkdown asChild>
|
|
1069
|
+
<TooltipIconButton tooltip="Export as Markdown">
|
|
1070
|
+
<DownloadIcon />
|
|
1071
|
+
</TooltipIconButton>
|
|
1072
|
+
</ActionBarPrimitive.ExportMarkdown>
|
|
1073
|
+
<ActionBarPrimitive.Reload asChild>
|
|
1074
|
+
<TooltipIconButton tooltip="Refresh">
|
|
1075
|
+
<RefreshCwIcon />
|
|
1076
|
+
</TooltipIconButton>
|
|
1077
|
+
</ActionBarPrimitive.Reload>
|
|
772
1078
|
</ActionBarPrimitive.Root>
|
|
773
1079
|
);
|
|
774
1080
|
};
|
|
775
1081
|
|
|
776
|
-
const
|
|
1082
|
+
const UserMessage: FC = () => {
|
|
777
1083
|
return (
|
|
778
|
-
<
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
<Button variant="ghost">Cancel</Button>
|
|
784
|
-
</ComposerPrimitive.Cancel>
|
|
785
|
-
<ComposerPrimitive.Send asChild>
|
|
786
|
-
<Button>Send</Button>
|
|
787
|
-
</ComposerPrimitive.Send>
|
|
788
|
-
</div>
|
|
789
|
-
</ComposerPrimitive.Root>
|
|
790
|
-
);
|
|
791
|
-
};
|
|
1084
|
+
<MessagePrimitive.Root
|
|
1085
|
+
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-3 duration-150 [&:where(>*)]:col-start-2"
|
|
1086
|
+
data-role="user"
|
|
1087
|
+
>
|
|
1088
|
+
<UserMessageAttachments />
|
|
792
1089
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
<
|
|
1090
|
+
<div className="aui-user-message-content-wrapper relative col-start-2 min-w-0">
|
|
1091
|
+
<div className="aui-user-message-content wrap-break-word rounded-2xl bg-muted px-4 py-2.5 text-foreground">
|
|
1092
|
+
<MessagePrimitive.Parts />
|
|
1093
|
+
</div>
|
|
1094
|
+
<div className="aui-user-action-bar-wrapper -translate-x-full -translate-y-1/2 absolute top-1/2 left-0 pr-2">
|
|
1095
|
+
<UserActionBar />
|
|
1096
|
+
</div>
|
|
798
1097
|
</div>
|
|
799
1098
|
|
|
800
|
-
<
|
|
801
|
-
|
|
802
|
-
<BranchPicker className="col-start-2 row-start-2 mr-2 -ml-2" />
|
|
1099
|
+
<BranchPicker className="aui-user-branch-picker -mr-1 col-span-full col-start-1 row-start-3 justify-end" />
|
|
803
1100
|
</MessagePrimitive.Root>
|
|
804
1101
|
);
|
|
805
1102
|
};
|
|
806
1103
|
|
|
807
|
-
const
|
|
1104
|
+
const UserActionBar: FC = () => {
|
|
808
1105
|
return (
|
|
809
1106
|
<ActionBarPrimitive.Root
|
|
810
1107
|
hideWhenRunning
|
|
811
1108
|
autohide="not-last"
|
|
812
|
-
|
|
813
|
-
className="text-muted-foreground data-[floating]:bg-background col-start-3 row-start-2 -ml-1 flex gap-1 data-[floating]:absolute data-[floating]:rounded-md data-[floating]:border data-[floating]:p-1 data-[floating]:shadow-sm"
|
|
1109
|
+
className="aui-user-action-bar-root flex flex-col items-end"
|
|
814
1110
|
>
|
|
815
|
-
<ActionBarPrimitive.
|
|
816
|
-
<TooltipIconButton tooltip="
|
|
817
|
-
<
|
|
818
|
-
<CheckIcon />
|
|
819
|
-
</MessagePrimitive.If>
|
|
820
|
-
<MessagePrimitive.If copied={false}>
|
|
821
|
-
<CopyIcon />
|
|
822
|
-
</MessagePrimitive.If>
|
|
823
|
-
</TooltipIconButton>
|
|
824
|
-
</ActionBarPrimitive.Copy>
|
|
825
|
-
<ActionBarPrimitive.Reload asChild>
|
|
826
|
-
<TooltipIconButton tooltip="Refresh">
|
|
827
|
-
<RefreshCwIcon />
|
|
1111
|
+
<ActionBarPrimitive.Edit asChild>
|
|
1112
|
+
<TooltipIconButton tooltip="Edit" className="aui-user-action-edit p-4">
|
|
1113
|
+
<PencilIcon />
|
|
828
1114
|
</TooltipIconButton>
|
|
829
|
-
</ActionBarPrimitive.
|
|
1115
|
+
</ActionBarPrimitive.Edit>
|
|
830
1116
|
</ActionBarPrimitive.Root>
|
|
831
1117
|
);
|
|
832
1118
|
};
|
|
833
1119
|
|
|
1120
|
+
const EditComposer: FC = () => {
|
|
1121
|
+
return (
|
|
1122
|
+
<MessagePrimitive.Root className="aui-edit-composer-wrapper mx-auto flex w-full max-w-(--thread-max-width) flex-col px-2 py-3">
|
|
1123
|
+
<ComposerPrimitive.Root className="aui-edit-composer-root ml-auto flex w-full max-w-[85%] flex-col rounded-2xl bg-muted">
|
|
1124
|
+
<ComposerPrimitive.Input
|
|
1125
|
+
className="aui-edit-composer-input min-h-14 w-full resize-none bg-transparent p-4 text-foreground text-sm outline-none"
|
|
1126
|
+
autoFocus
|
|
1127
|
+
/>
|
|
1128
|
+
<div className="aui-edit-composer-footer mx-3 mb-3 flex items-center gap-2 self-end">
|
|
1129
|
+
<ComposerPrimitive.Cancel asChild>
|
|
1130
|
+
<Button variant="ghost" size="sm">
|
|
1131
|
+
Cancel
|
|
1132
|
+
</Button>
|
|
1133
|
+
</ComposerPrimitive.Cancel>
|
|
1134
|
+
<ComposerPrimitive.Send asChild>
|
|
1135
|
+
<Button size="sm">Update</Button>
|
|
1136
|
+
</ComposerPrimitive.Send>
|
|
1137
|
+
</div>
|
|
1138
|
+
</ComposerPrimitive.Root>
|
|
1139
|
+
</MessagePrimitive.Root>
|
|
1140
|
+
);
|
|
1141
|
+
};
|
|
1142
|
+
|
|
834
1143
|
const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
|
|
835
1144
|
className,
|
|
836
1145
|
...rest
|
|
@@ -839,7 +1148,7 @@ const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
|
|
|
839
1148
|
<BranchPickerPrimitive.Root
|
|
840
1149
|
hideWhenSingleBranch
|
|
841
1150
|
className={cn(
|
|
842
|
-
"
|
|
1151
|
+
"aui-branch-picker-root -ml-2 mr-2 inline-flex items-center text-muted-foreground text-xs",
|
|
843
1152
|
className,
|
|
844
1153
|
)}
|
|
845
1154
|
{...rest}
|
|
@@ -849,7 +1158,7 @@ const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
|
|
|
849
1158
|
<ChevronLeftIcon />
|
|
850
1159
|
</TooltipIconButton>
|
|
851
1160
|
</BranchPickerPrimitive.Previous>
|
|
852
|
-
<span className="font-medium">
|
|
1161
|
+
<span className="aui-branch-picker-state font-medium">
|
|
853
1162
|
<BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
|
|
854
1163
|
</span>
|
|
855
1164
|
<BranchPickerPrimitive.Next asChild>
|
|
@@ -861,17 +1170,102 @@ const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
|
|
|
861
1170
|
);
|
|
862
1171
|
};
|
|
863
1172
|
|
|
864
|
-
|
|
1173
|
+
```
|
|
1174
|
+
|
|
1175
|
+
## components/assistant-ui/tool-fallback.tsx
|
|
1176
|
+
|
|
1177
|
+
```tsx
|
|
1178
|
+
import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
|
|
1179
|
+
import {
|
|
1180
|
+
CheckIcon,
|
|
1181
|
+
ChevronDownIcon,
|
|
1182
|
+
ChevronUpIcon,
|
|
1183
|
+
XCircleIcon,
|
|
1184
|
+
} from "lucide-react";
|
|
1185
|
+
import { useState } from "react";
|
|
1186
|
+
import { Button } from "@/components/ui/button";
|
|
1187
|
+
import { cn } from "@/lib/utils";
|
|
1188
|
+
|
|
1189
|
+
export const ToolFallback: ToolCallMessagePartComponent = ({
|
|
1190
|
+
toolName,
|
|
1191
|
+
argsText,
|
|
1192
|
+
result,
|
|
1193
|
+
status,
|
|
1194
|
+
}) => {
|
|
1195
|
+
const [isCollapsed, setIsCollapsed] = useState(true);
|
|
1196
|
+
|
|
1197
|
+
const isCancelled =
|
|
1198
|
+
status?.type === "incomplete" && status.reason === "cancelled";
|
|
1199
|
+
const cancelledReason =
|
|
1200
|
+
isCancelled && status.error
|
|
1201
|
+
? typeof status.error === "string"
|
|
1202
|
+
? status.error
|
|
1203
|
+
: JSON.stringify(status.error)
|
|
1204
|
+
: null;
|
|
1205
|
+
|
|
865
1206
|
return (
|
|
866
|
-
<
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
height="16"
|
|
1207
|
+
<div
|
|
1208
|
+
className={cn(
|
|
1209
|
+
"aui-tool-fallback-root mb-4 flex w-full flex-col gap-3 rounded-lg border py-3",
|
|
1210
|
+
isCancelled && "border-muted-foreground/30 bg-muted/30",
|
|
1211
|
+
)}
|
|
872
1212
|
>
|
|
873
|
-
<
|
|
874
|
-
|
|
1213
|
+
<div className="aui-tool-fallback-header flex items-center gap-2 px-4">
|
|
1214
|
+
{isCancelled ? (
|
|
1215
|
+
<XCircleIcon className="aui-tool-fallback-icon size-4 text-muted-foreground" />
|
|
1216
|
+
) : (
|
|
1217
|
+
<CheckIcon className="aui-tool-fallback-icon size-4" />
|
|
1218
|
+
)}
|
|
1219
|
+
<p
|
|
1220
|
+
className={cn(
|
|
1221
|
+
"aui-tool-fallback-title grow",
|
|
1222
|
+
isCancelled && "text-muted-foreground line-through",
|
|
1223
|
+
)}
|
|
1224
|
+
>
|
|
1225
|
+
{isCancelled ? "Cancelled tool: " : "Used tool: "}
|
|
1226
|
+
<b>{toolName}</b>
|
|
1227
|
+
</p>
|
|
1228
|
+
<Button onClick={() => setIsCollapsed(!isCollapsed)}>
|
|
1229
|
+
{isCollapsed ? <ChevronUpIcon /> : <ChevronDownIcon />}
|
|
1230
|
+
</Button>
|
|
1231
|
+
</div>
|
|
1232
|
+
{!isCollapsed && (
|
|
1233
|
+
<div className="aui-tool-fallback-content flex flex-col gap-2 border-t pt-2">
|
|
1234
|
+
{cancelledReason && (
|
|
1235
|
+
<div className="aui-tool-fallback-cancelled-root px-4">
|
|
1236
|
+
<p className="aui-tool-fallback-cancelled-header font-semibold text-muted-foreground">
|
|
1237
|
+
Cancelled reason:
|
|
1238
|
+
</p>
|
|
1239
|
+
<p className="aui-tool-fallback-cancelled-reason text-muted-foreground">
|
|
1240
|
+
{cancelledReason}
|
|
1241
|
+
</p>
|
|
1242
|
+
</div>
|
|
1243
|
+
)}
|
|
1244
|
+
<div
|
|
1245
|
+
className={cn(
|
|
1246
|
+
"aui-tool-fallback-args-root px-4",
|
|
1247
|
+
isCancelled && "opacity-60",
|
|
1248
|
+
)}
|
|
1249
|
+
>
|
|
1250
|
+
<pre className="aui-tool-fallback-args-value whitespace-pre-wrap">
|
|
1251
|
+
{argsText}
|
|
1252
|
+
</pre>
|
|
1253
|
+
</div>
|
|
1254
|
+
{!isCancelled && result !== undefined && (
|
|
1255
|
+
<div className="aui-tool-fallback-result-root border-t border-dashed px-4 pt-2">
|
|
1256
|
+
<p className="aui-tool-fallback-result-header font-semibold">
|
|
1257
|
+
Result:
|
|
1258
|
+
</p>
|
|
1259
|
+
<pre className="aui-tool-fallback-result-content whitespace-pre-wrap">
|
|
1260
|
+
{typeof result === "string"
|
|
1261
|
+
? result
|
|
1262
|
+
: JSON.stringify(result, null, 2)}
|
|
1263
|
+
</pre>
|
|
1264
|
+
</div>
|
|
1265
|
+
)}
|
|
1266
|
+
</div>
|
|
1267
|
+
)}
|
|
1268
|
+
</div>
|
|
875
1269
|
);
|
|
876
1270
|
};
|
|
877
1271
|
|
|
@@ -882,7 +1276,7 @@ const CircleStopIcon = () => {
|
|
|
882
1276
|
```tsx
|
|
883
1277
|
"use client";
|
|
884
1278
|
|
|
885
|
-
import {
|
|
1279
|
+
import { ComponentPropsWithRef, forwardRef } from "react";
|
|
886
1280
|
import { Slottable } from "@radix-ui/react-slot";
|
|
887
1281
|
|
|
888
1282
|
import {
|
|
@@ -893,7 +1287,7 @@ import {
|
|
|
893
1287
|
import { Button } from "@/components/ui/button";
|
|
894
1288
|
import { cn } from "@/lib/utils";
|
|
895
1289
|
|
|
896
|
-
export type TooltipIconButtonProps =
|
|
1290
|
+
export type TooltipIconButtonProps = ComponentPropsWithRef<typeof Button> & {
|
|
897
1291
|
tooltip: string;
|
|
898
1292
|
side?: "top" | "bottom" | "left" | "right";
|
|
899
1293
|
};
|
|
@@ -909,11 +1303,11 @@ export const TooltipIconButton = forwardRef<
|
|
|
909
1303
|
variant="ghost"
|
|
910
1304
|
size="icon"
|
|
911
1305
|
{...rest}
|
|
912
|
-
className={cn("size-6 p-1", className)}
|
|
1306
|
+
className={cn("aui-button-icon size-6 p-1", className)}
|
|
913
1307
|
ref={ref}
|
|
914
1308
|
>
|
|
915
1309
|
<Slottable>{children}</Slottable>
|
|
916
|
-
<span className="sr-only">{tooltip}</span>
|
|
1310
|
+
<span className="aui-sr-only sr-only">{tooltip}</span>
|
|
917
1311
|
</Button>
|
|
918
1312
|
</TooltipTrigger>
|
|
919
1313
|
<TooltipContent side={side}>{tooltip}</TooltipContent>
|
|
@@ -1074,6 +1468,62 @@ export const SignupForm: FC = () => {
|
|
|
1074
1468
|
|
|
1075
1469
|
```
|
|
1076
1470
|
|
|
1471
|
+
## components/ui/avatar.tsx
|
|
1472
|
+
|
|
1473
|
+
```tsx
|
|
1474
|
+
"use client";
|
|
1475
|
+
|
|
1476
|
+
import * as React from "react";
|
|
1477
|
+
import * as AvatarPrimitive from "@radix-ui/react-avatar";
|
|
1478
|
+
|
|
1479
|
+
import { cn } from "@/lib/utils";
|
|
1480
|
+
|
|
1481
|
+
const Avatar = React.forwardRef<
|
|
1482
|
+
React.ElementRef<typeof AvatarPrimitive.Root>,
|
|
1483
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
|
|
1484
|
+
>(({ className, ...props }, ref) => (
|
|
1485
|
+
<AvatarPrimitive.Root
|
|
1486
|
+
ref={ref}
|
|
1487
|
+
className={cn(
|
|
1488
|
+
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
|
|
1489
|
+
className,
|
|
1490
|
+
)}
|
|
1491
|
+
{...props}
|
|
1492
|
+
/>
|
|
1493
|
+
));
|
|
1494
|
+
Avatar.displayName = AvatarPrimitive.Root.displayName;
|
|
1495
|
+
|
|
1496
|
+
const AvatarImage = React.forwardRef<
|
|
1497
|
+
React.ElementRef<typeof AvatarPrimitive.Image>,
|
|
1498
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
|
|
1499
|
+
>(({ className, ...props }, ref) => (
|
|
1500
|
+
<AvatarPrimitive.Image
|
|
1501
|
+
ref={ref}
|
|
1502
|
+
className={cn("aspect-square h-full w-full", className)}
|
|
1503
|
+
{...props}
|
|
1504
|
+
/>
|
|
1505
|
+
));
|
|
1506
|
+
AvatarImage.displayName = AvatarPrimitive.Image.displayName;
|
|
1507
|
+
|
|
1508
|
+
const AvatarFallback = React.forwardRef<
|
|
1509
|
+
React.ElementRef<typeof AvatarPrimitive.Fallback>,
|
|
1510
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
|
|
1511
|
+
>(({ className, ...props }, ref) => (
|
|
1512
|
+
<AvatarPrimitive.Fallback
|
|
1513
|
+
ref={ref}
|
|
1514
|
+
className={cn(
|
|
1515
|
+
"flex h-full w-full items-center justify-center rounded-full bg-muted",
|
|
1516
|
+
className,
|
|
1517
|
+
)}
|
|
1518
|
+
{...props}
|
|
1519
|
+
/>
|
|
1520
|
+
));
|
|
1521
|
+
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
|
|
1522
|
+
|
|
1523
|
+
export { Avatar, AvatarImage, AvatarFallback };
|
|
1524
|
+
|
|
1525
|
+
```
|
|
1526
|
+
|
|
1077
1527
|
## components/ui/button.tsx
|
|
1078
1528
|
|
|
1079
1529
|
```tsx
|
|
@@ -1084,16 +1534,16 @@ import { cva, type VariantProps } from "class-variance-authority";
|
|
|
1084
1534
|
import { cn } from "@/lib/utils";
|
|
1085
1535
|
|
|
1086
1536
|
const buttonVariants = cva(
|
|
1087
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm
|
|
1537
|
+
"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",
|
|
1088
1538
|
{
|
|
1089
1539
|
variants: {
|
|
1090
1540
|
variant: {
|
|
1091
1541
|
default:
|
|
1092
1542
|
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
|
1093
1543
|
destructive:
|
|
1094
|
-
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40
|
|
1544
|
+
"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",
|
|
1095
1545
|
outline:
|
|
1096
|
-
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:
|
|
1546
|
+
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
|
|
1097
1547
|
secondary:
|
|
1098
1548
|
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
|
1099
1549
|
ghost:
|
|
@@ -1102,7 +1552,7 @@ const buttonVariants = cva(
|
|
|
1102
1552
|
},
|
|
1103
1553
|
size: {
|
|
1104
1554
|
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
1105
|
-
sm: "h-8
|
|
1555
|
+
sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
|
|
1106
1556
|
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
1107
1557
|
icon: "size-9",
|
|
1108
1558
|
},
|
|
@@ -1139,6 +1589,147 @@ export { Button, buttonVariants };
|
|
|
1139
1589
|
|
|
1140
1590
|
```
|
|
1141
1591
|
|
|
1592
|
+
## components/ui/dialog.tsx
|
|
1593
|
+
|
|
1594
|
+
```tsx
|
|
1595
|
+
"use client";
|
|
1596
|
+
|
|
1597
|
+
import * as React from "react";
|
|
1598
|
+
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
1599
|
+
import { XIcon } from "lucide-react";
|
|
1600
|
+
|
|
1601
|
+
import { cn } from "@/lib/utils";
|
|
1602
|
+
|
|
1603
|
+
function Dialog({
|
|
1604
|
+
...props
|
|
1605
|
+
}: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
|
1606
|
+
return <DialogPrimitive.Root data-slot="dialog" {...props} />;
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
function DialogTrigger({
|
|
1610
|
+
...props
|
|
1611
|
+
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
1612
|
+
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
function DialogPortal({
|
|
1616
|
+
...props
|
|
1617
|
+
}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
|
1618
|
+
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
function DialogClose({
|
|
1622
|
+
...props
|
|
1623
|
+
}: React.ComponentProps<typeof DialogPrimitive.Close>) {
|
|
1624
|
+
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
function DialogOverlay({
|
|
1628
|
+
className,
|
|
1629
|
+
...props
|
|
1630
|
+
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
1631
|
+
return (
|
|
1632
|
+
<DialogPrimitive.Overlay
|
|
1633
|
+
data-slot="dialog-overlay"
|
|
1634
|
+
className={cn(
|
|
1635
|
+
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80 data-[state=closed]:animate-out data-[state=open]:animate-in",
|
|
1636
|
+
className,
|
|
1637
|
+
)}
|
|
1638
|
+
{...props}
|
|
1639
|
+
/>
|
|
1640
|
+
);
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
function DialogContent({
|
|
1644
|
+
className,
|
|
1645
|
+
children,
|
|
1646
|
+
...props
|
|
1647
|
+
}: React.ComponentProps<typeof DialogPrimitive.Content>) {
|
|
1648
|
+
return (
|
|
1649
|
+
<DialogPortal data-slot="dialog-portal">
|
|
1650
|
+
<DialogOverlay />
|
|
1651
|
+
<DialogPrimitive.Content
|
|
1652
|
+
data-slot="dialog-content"
|
|
1653
|
+
className={cn(
|
|
1654
|
+
"data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in sm:max-w-lg",
|
|
1655
|
+
className,
|
|
1656
|
+
)}
|
|
1657
|
+
{...props}
|
|
1658
|
+
>
|
|
1659
|
+
{children}
|
|
1660
|
+
<DialogPrimitive.Close className="absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0">
|
|
1661
|
+
<XIcon />
|
|
1662
|
+
<span className="sr-only">Close</span>
|
|
1663
|
+
</DialogPrimitive.Close>
|
|
1664
|
+
</DialogPrimitive.Content>
|
|
1665
|
+
</DialogPortal>
|
|
1666
|
+
);
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
1670
|
+
return (
|
|
1671
|
+
<div
|
|
1672
|
+
data-slot="dialog-header"
|
|
1673
|
+
className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
|
|
1674
|
+
{...props}
|
|
1675
|
+
/>
|
|
1676
|
+
);
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
1680
|
+
return (
|
|
1681
|
+
<div
|
|
1682
|
+
data-slot="dialog-footer"
|
|
1683
|
+
className={cn(
|
|
1684
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
1685
|
+
className,
|
|
1686
|
+
)}
|
|
1687
|
+
{...props}
|
|
1688
|
+
/>
|
|
1689
|
+
);
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
function DialogTitle({
|
|
1693
|
+
className,
|
|
1694
|
+
...props
|
|
1695
|
+
}: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
1696
|
+
return (
|
|
1697
|
+
<DialogPrimitive.Title
|
|
1698
|
+
data-slot="dialog-title"
|
|
1699
|
+
className={cn("font-semibold text-lg leading-none", className)}
|
|
1700
|
+
{...props}
|
|
1701
|
+
/>
|
|
1702
|
+
);
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
function DialogDescription({
|
|
1706
|
+
className,
|
|
1707
|
+
...props
|
|
1708
|
+
}: React.ComponentProps<typeof DialogPrimitive.Description>) {
|
|
1709
|
+
return (
|
|
1710
|
+
<DialogPrimitive.Description
|
|
1711
|
+
data-slot="dialog-description"
|
|
1712
|
+
className={cn("text-muted-foreground text-sm", className)}
|
|
1713
|
+
{...props}
|
|
1714
|
+
/>
|
|
1715
|
+
);
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
export {
|
|
1719
|
+
Dialog,
|
|
1720
|
+
DialogClose,
|
|
1721
|
+
DialogContent,
|
|
1722
|
+
DialogDescription,
|
|
1723
|
+
DialogFooter,
|
|
1724
|
+
DialogHeader,
|
|
1725
|
+
DialogOverlay,
|
|
1726
|
+
DialogPortal,
|
|
1727
|
+
DialogTitle,
|
|
1728
|
+
DialogTrigger,
|
|
1729
|
+
};
|
|
1730
|
+
|
|
1731
|
+
```
|
|
1732
|
+
|
|
1142
1733
|
## components/ui/form.tsx
|
|
1143
1734
|
|
|
1144
1735
|
```tsx
|
|
@@ -1326,9 +1917,9 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
|
|
|
1326
1917
|
type={type}
|
|
1327
1918
|
data-slot="input"
|
|
1328
1919
|
className={cn(
|
|
1329
|
-
"
|
|
1330
|
-
"focus-visible:border-ring focus-visible:ring-
|
|
1331
|
-
"aria-invalid:
|
|
1920
|
+
"flex h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs outline-none transition-[color,box-shadow] selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:font-medium file:text-foreground file:text-sm placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30",
|
|
1921
|
+
"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
1922
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
|
|
1332
1923
|
className,
|
|
1333
1924
|
)}
|
|
1334
1925
|
{...props}
|
|
@@ -1358,7 +1949,7 @@ function Label({
|
|
|
1358
1949
|
<LabelPrimitive.Root
|
|
1359
1950
|
data-slot="label"
|
|
1360
1951
|
className={cn(
|
|
1361
|
-
"flex items-center gap-2 text-sm leading-none
|
|
1952
|
+
"flex select-none items-center gap-2 font-medium text-sm leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-50 group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50",
|
|
1362
1953
|
className,
|
|
1363
1954
|
)}
|
|
1364
1955
|
{...props}
|
|
@@ -1414,13 +2005,13 @@ function ResizableHandle({
|
|
|
1414
2005
|
<ResizablePrimitive.PanelResizeHandle
|
|
1415
2006
|
data-slot="resizable-handle"
|
|
1416
2007
|
className={cn(
|
|
1417
|
-
"
|
|
2008
|
+
"after:-translate-x-1/2 data-[panel-group-direction=vertical]:after:-translate-y-1/2 relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90",
|
|
1418
2009
|
className,
|
|
1419
2010
|
)}
|
|
1420
2011
|
{...props}
|
|
1421
2012
|
>
|
|
1422
2013
|
{withHandle && (
|
|
1423
|
-
<div className="
|
|
2014
|
+
<div className="z-10 flex h-4 w-3 items-center justify-center rounded-xs border bg-border">
|
|
1424
2015
|
<GripVerticalIcon className="size-2.5" />
|
|
1425
2016
|
</div>
|
|
1426
2017
|
)}
|
|
@@ -1463,7 +2054,7 @@ function TabsList({
|
|
|
1463
2054
|
<TabsPrimitive.List
|
|
1464
2055
|
data-slot="tabs-list"
|
|
1465
2056
|
className={cn(
|
|
1466
|
-
"
|
|
2057
|
+
"inline-flex h-9 w-fit items-center justify-center rounded-lg bg-muted p-[3px] text-muted-foreground",
|
|
1467
2058
|
className,
|
|
1468
2059
|
)}
|
|
1469
2060
|
{...props}
|
|
@@ -1479,7 +2070,7 @@ function TabsTrigger({
|
|
|
1479
2070
|
<TabsPrimitive.Trigger
|
|
1480
2071
|
data-slot="tabs-trigger"
|
|
1481
2072
|
className={cn(
|
|
1482
|
-
"
|
|
2073
|
+
"inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 whitespace-nowrap rounded-md border border-transparent px-2 py-1 font-medium text-foreground text-sm transition-[color,box-shadow] focus-visible:border-ring focus-visible:outline-1 focus-visible:outline-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:shadow-sm dark:text-muted-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 dark:data-[state=active]:text-foreground [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
1483
2074
|
className,
|
|
1484
2075
|
)}
|
|
1485
2076
|
{...props}
|
|
@@ -1555,13 +2146,13 @@ function TooltipContent({
|
|
|
1555
2146
|
data-slot="tooltip-content"
|
|
1556
2147
|
sideOffset={sideOffset}
|
|
1557
2148
|
className={cn(
|
|
1558
|
-
"
|
|
2149
|
+
"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",
|
|
1559
2150
|
className,
|
|
1560
2151
|
)}
|
|
1561
2152
|
{...props}
|
|
1562
2153
|
>
|
|
1563
2154
|
{children}
|
|
1564
|
-
<TooltipPrimitive.Arrow className="
|
|
2155
|
+
<TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-primary fill-primary" />
|
|
1565
2156
|
</TooltipPrimitive.Content>
|
|
1566
2157
|
</TooltipPrimitive.Portal>
|
|
1567
2158
|
);
|
|
@@ -1601,18 +2192,6 @@ export function cn(...inputs: ClassValue[]) {
|
|
|
1601
2192
|
|
|
1602
2193
|
```
|
|
1603
2194
|
|
|
1604
|
-
## next-env.d.ts
|
|
1605
|
-
|
|
1606
|
-
```typescript
|
|
1607
|
-
/// <reference types="next" />
|
|
1608
|
-
/// <reference types="next/image-types/global" />
|
|
1609
|
-
import "./.next/types/routes.d.ts";
|
|
1610
|
-
|
|
1611
|
-
// NOTE: This file should not be edited
|
|
1612
|
-
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
|
1613
|
-
|
|
1614
|
-
```
|
|
1615
|
-
|
|
1616
2195
|
## next.config.ts
|
|
1617
2196
|
|
|
1618
2197
|
```typescript
|
|
@@ -1636,38 +2215,37 @@ export default nextConfig;
|
|
|
1636
2215
|
"scripts": {
|
|
1637
2216
|
"dev": "next dev --turbo",
|
|
1638
2217
|
"build": "next build",
|
|
1639
|
-
"start": "next start"
|
|
1640
|
-
"lint": "eslint ."
|
|
2218
|
+
"start": "next start"
|
|
1641
2219
|
},
|
|
1642
2220
|
"dependencies": {
|
|
1643
|
-
"@ai-sdk/openai": "^2.0.
|
|
2221
|
+
"@ai-sdk/openai": "^2.0.77",
|
|
1644
2222
|
"@assistant-ui/react": "workspace:*",
|
|
1645
2223
|
"@assistant-ui/react-ai-sdk": "workspace:*",
|
|
1646
2224
|
"@assistant-ui/react-hook-form": "workspace:*",
|
|
1647
2225
|
"@assistant-ui/react-markdown": "workspace:*",
|
|
1648
2226
|
"@hookform/resolvers": "^5.2.2",
|
|
1649
2227
|
"@radix-ui/react-avatar": "^1.1.11",
|
|
2228
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
1650
2229
|
"@radix-ui/react-icons": "^1.3.2",
|
|
1651
2230
|
"@radix-ui/react-label": "^2.1.8",
|
|
1652
2231
|
"@radix-ui/react-slot": "^1.2.4",
|
|
1653
2232
|
"@radix-ui/react-tabs": "^1.1.13",
|
|
1654
2233
|
"@radix-ui/react-tooltip": "^1.2.8",
|
|
1655
2234
|
"@react-hook/media-query": "^1.1.1",
|
|
1656
|
-
"ai": "^5.0.
|
|
2235
|
+
"ai": "^5.0.107",
|
|
1657
2236
|
"class-variance-authority": "^0.7.1",
|
|
1658
2237
|
"clsx": "^2.1.1",
|
|
1659
|
-
"
|
|
1660
|
-
"
|
|
1661
|
-
"
|
|
1662
|
-
"react": "19.2.
|
|
1663
|
-
"react-
|
|
1664
|
-
"react-hook-form": "^7.66.1",
|
|
2238
|
+
"lucide-react": "^0.556.0",
|
|
2239
|
+
"next": "16.0.7",
|
|
2240
|
+
"react": "19.2.1",
|
|
2241
|
+
"react-dom": "19.2.1",
|
|
2242
|
+
"react-hook-form": "^7.68.0",
|
|
1665
2243
|
"react-resizable-panels": "^3.0.6",
|
|
1666
2244
|
"remark-gfm": "^4.0.1",
|
|
1667
2245
|
"tailwind-merge": "^3.4.0",
|
|
1668
2246
|
"tw-animate-css": "^1.4.0",
|
|
1669
|
-
"zod": "^4.1.
|
|
1670
|
-
"zustand": "^5.0.
|
|
2247
|
+
"zod": "^4.1.13",
|
|
2248
|
+
"zustand": "^5.0.9"
|
|
1671
2249
|
},
|
|
1672
2250
|
"devDependencies": {
|
|
1673
2251
|
"@assistant-ui/x-buildutils": "workspace:*",
|