@assistant-ui/mcp-docs-server 0.1.14 → 0.1.15

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.
@@ -426,7 +426,6 @@ export default function Home() {
426
426
  setLastFile(lastAttachment.file!);
427
427
  }, [attachments]);
428
428
 
429
- console.log(lastFile);
430
429
  return (
431
430
  <div className="flex h-full flex-col">
432
431
  <div className="border-b">
@@ -472,6 +471,247 @@ export default function Home() {
472
471
 
473
472
  ```
474
473
 
474
+ ## components/assistant-ui/attachment.tsx
475
+
476
+ ```tsx
477
+ "use client";
478
+
479
+ import { PropsWithChildren, useEffect, useState, type FC } from "react";
480
+ import Image from "next/image";
481
+ import { XIcon, PlusIcon, FileText } from "lucide-react";
482
+ import {
483
+ AttachmentPrimitive,
484
+ ComposerPrimitive,
485
+ MessagePrimitive,
486
+ useAssistantState,
487
+ useAssistantApi,
488
+ } from "@assistant-ui/react";
489
+ import { useShallow } from "zustand/shallow";
490
+ import {
491
+ Tooltip,
492
+ TooltipContent,
493
+ TooltipTrigger,
494
+ } from "@/components/ui/tooltip";
495
+ import {
496
+ Dialog,
497
+ DialogTitle,
498
+ DialogContent,
499
+ DialogTrigger,
500
+ } from "@/components/ui/dialog";
501
+ import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
502
+ import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
503
+ import { cn } from "@/lib/utils";
504
+
505
+ const useFileSrc = (file: File | undefined) => {
506
+ const [src, setSrc] = useState<string | undefined>(undefined);
507
+
508
+ useEffect(() => {
509
+ if (!file) {
510
+ setSrc(undefined);
511
+ return;
512
+ }
513
+
514
+ const objectUrl = URL.createObjectURL(file);
515
+ setSrc(objectUrl);
516
+
517
+ return () => {
518
+ URL.revokeObjectURL(objectUrl);
519
+ };
520
+ }, [file]);
521
+
522
+ return src;
523
+ };
524
+
525
+ const useAttachmentSrc = () => {
526
+ const { file, src } = useAssistantState(
527
+ useShallow(({ attachment }): { file?: File; src?: string } => {
528
+ if (attachment.type !== "image") return {};
529
+ if (attachment.file) return { file: attachment.file };
530
+ const src = attachment.content?.filter((c) => c.type === "image")[0]
531
+ ?.image;
532
+ if (!src) return {};
533
+ return { src };
534
+ }),
535
+ );
536
+
537
+ return useFileSrc(file) ?? src;
538
+ };
539
+
540
+ type AttachmentPreviewProps = {
541
+ src: string;
542
+ };
543
+
544
+ const AttachmentPreview: FC<AttachmentPreviewProps> = ({ src }) => {
545
+ const [isLoaded, setIsLoaded] = useState(false);
546
+ return (
547
+ <Image
548
+ src={src}
549
+ alt="Image Preview"
550
+ width={1}
551
+ height={1}
552
+ className={
553
+ isLoaded
554
+ ? "aui-attachment-preview-image-loaded block h-auto max-h-[80vh] w-auto max-w-full object-contain"
555
+ : "aui-attachment-preview-image-loading hidden"
556
+ }
557
+ onLoadingComplete={() => setIsLoaded(true)}
558
+ priority={false}
559
+ />
560
+ );
561
+ };
562
+
563
+ const AttachmentPreviewDialog: FC<PropsWithChildren> = ({ children }) => {
564
+ const src = useAttachmentSrc();
565
+
566
+ if (!src) return children;
567
+
568
+ return (
569
+ <Dialog>
570
+ <DialogTrigger
571
+ className="aui-attachment-preview-trigger hover:bg-accent/50 cursor-pointer transition-colors"
572
+ asChild
573
+ >
574
+ {children}
575
+ </DialogTrigger>
576
+ <DialogContent className="aui-attachment-preview-dialog-content [&_svg]:text-background [&>button]:bg-foreground/60 [&>button]:hover:[&_svg]:text-destructive p-2 sm:max-w-3xl [&>button]:rounded-full [&>button]:p-1 [&>button]:opacity-100 [&>button]:!ring-0">
577
+ <DialogTitle className="aui-sr-only sr-only">
578
+ Image Attachment Preview
579
+ </DialogTitle>
580
+ <div className="aui-attachment-preview bg-background relative mx-auto flex max-h-[80dvh] w-full items-center justify-center overflow-hidden">
581
+ <AttachmentPreview src={src} />
582
+ </div>
583
+ </DialogContent>
584
+ </Dialog>
585
+ );
586
+ };
587
+
588
+ const AttachmentThumb: FC = () => {
589
+ const isImage = useAssistantState(
590
+ ({ attachment }) => attachment.type === "image",
591
+ );
592
+ const src = useAttachmentSrc();
593
+
594
+ return (
595
+ <Avatar className="aui-attachment-tile-avatar h-full w-full rounded-none">
596
+ <AvatarImage
597
+ src={src}
598
+ alt="Attachment preview"
599
+ className="aui-attachment-tile-image object-cover"
600
+ />
601
+ <AvatarFallback delayMs={isImage ? 200 : 0}>
602
+ <FileText className="aui-attachment-tile-fallback-icon text-muted-foreground size-8" />
603
+ </AvatarFallback>
604
+ </Avatar>
605
+ );
606
+ };
607
+
608
+ const AttachmentUI: FC = () => {
609
+ const api = useAssistantApi();
610
+ const isComposer = api.attachment.source === "composer";
611
+
612
+ const isImage = useAssistantState(
613
+ ({ attachment }) => attachment.type === "image",
614
+ );
615
+ const typeLabel = useAssistantState(({ attachment }) => {
616
+ const type = attachment.type;
617
+ switch (type) {
618
+ case "image":
619
+ return "Image";
620
+ case "document":
621
+ return "Document";
622
+ case "file":
623
+ return "File";
624
+ default:
625
+ const _exhaustiveCheck: never = type;
626
+ throw new Error(`Unknown attachment type: ${_exhaustiveCheck}`);
627
+ }
628
+ });
629
+
630
+ return (
631
+ <Tooltip>
632
+ <AttachmentPrimitive.Root
633
+ className={cn(
634
+ "aui-attachment-root relative",
635
+ isImage &&
636
+ "aui-attachment-root-composer only:[&>#attachment-tile]:size-24",
637
+ )}
638
+ >
639
+ <AttachmentPreviewDialog>
640
+ <TooltipTrigger asChild>
641
+ <div
642
+ className={cn(
643
+ "aui-attachment-tile bg-muted size-14 cursor-pointer overflow-hidden rounded-[14px] border transition-opacity hover:opacity-75",
644
+ isComposer &&
645
+ "aui-attachment-tile-composer border-foreground/20",
646
+ )}
647
+ role="button"
648
+ id="attachment-tile"
649
+ aria-label={`${typeLabel} attachment`}
650
+ >
651
+ <AttachmentThumb />
652
+ </div>
653
+ </TooltipTrigger>
654
+ </AttachmentPreviewDialog>
655
+ {isComposer && <AttachmentRemove />}
656
+ </AttachmentPrimitive.Root>
657
+ <TooltipContent side="top">
658
+ <AttachmentPrimitive.Name />
659
+ </TooltipContent>
660
+ </Tooltip>
661
+ );
662
+ };
663
+
664
+ const AttachmentRemove: FC = () => {
665
+ return (
666
+ <AttachmentPrimitive.Remove asChild>
667
+ <TooltipIconButton
668
+ tooltip="Remove file"
669
+ className="aui-attachment-tile-remove text-muted-foreground hover:[&_svg]:text-destructive absolute top-1.5 right-1.5 size-3.5 rounded-full bg-white opacity-100 shadow-sm hover:!bg-white [&_svg]:text-black"
670
+ side="top"
671
+ >
672
+ <XIcon className="aui-attachment-remove-icon size-3 dark:stroke-[2.5px]" />
673
+ </TooltipIconButton>
674
+ </AttachmentPrimitive.Remove>
675
+ );
676
+ };
677
+
678
+ export const UserMessageAttachments: FC = () => {
679
+ return (
680
+ <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">
681
+ <MessagePrimitive.Attachments components={{ Attachment: AttachmentUI }} />
682
+ </div>
683
+ );
684
+ };
685
+
686
+ export const ComposerAttachments: FC = () => {
687
+ return (
688
+ <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">
689
+ <ComposerPrimitive.Attachments
690
+ components={{ Attachment: AttachmentUI }}
691
+ />
692
+ </div>
693
+ );
694
+ };
695
+
696
+ export const ComposerAddAttachment: FC = () => {
697
+ return (
698
+ <ComposerPrimitive.AddAttachment asChild>
699
+ <TooltipIconButton
700
+ tooltip="Add Attachment"
701
+ side="bottom"
702
+ variant="ghost"
703
+ size="icon"
704
+ className="aui-composer-add-attachment hover:bg-muted-foreground/15 dark:border-muted-foreground/15 dark:hover:bg-muted-foreground/30 size-[34px] rounded-full p-1 text-xs font-semibold"
705
+ aria-label="Add Attachment"
706
+ >
707
+ <PlusIcon className="aui-attachment-add-icon size-5 stroke-[1.5px]" />
708
+ </TooltipIconButton>
709
+ </ComposerPrimitive.AddAttachment>
710
+ );
711
+ };
712
+
713
+ ```
714
+
475
715
  ## components/assistant-ui/markdown-text.tsx
476
716
 
477
717
  ```tsx
@@ -480,13 +720,13 @@ export default function Home() {
480
720
  import "@assistant-ui/react-markdown/styles/dot.css";
481
721
 
482
722
  import {
483
- CodeHeaderProps,
723
+ type CodeHeaderProps,
484
724
  MarkdownTextPrimitive,
485
725
  unstable_memoizeMarkdownComponents as memoizeMarkdownComponents,
486
726
  useIsMarkdownCodeBlock,
487
727
  } from "@assistant-ui/react-markdown";
488
728
  import remarkGfm from "remark-gfm";
489
- import { FC, memo, useState } from "react";
729
+ import { type FC, memo, useState } from "react";
490
730
  import { CheckIcon, CopyIcon } from "lucide-react";
491
731
 
492
732
  import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
@@ -512,8 +752,10 @@ const CodeHeader: FC<CodeHeaderProps> = ({ language, code }) => {
512
752
  };
513
753
 
514
754
  return (
515
- <div className="flex items-center justify-between gap-4 rounded-t-lg bg-zinc-900 px-4 py-2 text-sm font-semibold text-white">
516
- <span className="lowercase [&>span]:text-xs">{language}</span>
755
+ <div className="aui-code-header-root bg-muted-foreground/15 text-foreground dark:bg-muted-foreground/20 mt-4 flex items-center justify-between gap-4 rounded-t-lg px-4 py-2 text-sm font-semibold">
756
+ <span className="aui-code-header-language lowercase [&>span]:text-xs">
757
+ {language}
758
+ </span>
517
759
  <TooltipIconButton tooltip="Copy" onClick={onCopy}>
518
760
  {!isCopied && <CopyIcon />}
519
761
  {isCopied && <CheckIcon />}
@@ -545,7 +787,7 @@ const defaultComponents = memoizeMarkdownComponents({
545
787
  h1: ({ className, ...props }) => (
546
788
  <h1
547
789
  className={cn(
548
- "mb-8 scroll-m-20 text-4xl font-extrabold tracking-tight last:mb-0",
790
+ "aui-md-h1 mb-8 scroll-m-20 text-4xl font-extrabold tracking-tight last:mb-0",
549
791
  className,
550
792
  )}
551
793
  {...props}
@@ -554,7 +796,7 @@ const defaultComponents = memoizeMarkdownComponents({
554
796
  h2: ({ className, ...props }) => (
555
797
  <h2
556
798
  className={cn(
557
- "mt-8 mb-4 scroll-m-20 text-3xl font-semibold tracking-tight first:mt-0 last:mb-0",
799
+ "aui-md-h2 mt-8 mb-4 scroll-m-20 text-3xl font-semibold tracking-tight first:mt-0 last:mb-0",
558
800
  className,
559
801
  )}
560
802
  {...props}
@@ -563,7 +805,7 @@ const defaultComponents = memoizeMarkdownComponents({
563
805
  h3: ({ className, ...props }) => (
564
806
  <h3
565
807
  className={cn(
566
- "mt-6 mb-4 scroll-m-20 text-2xl font-semibold tracking-tight first:mt-0 last:mb-0",
808
+ "aui-md-h3 mt-6 mb-4 scroll-m-20 text-2xl font-semibold tracking-tight first:mt-0 last:mb-0",
567
809
  className,
568
810
  )}
569
811
  {...props}
@@ -572,7 +814,7 @@ const defaultComponents = memoizeMarkdownComponents({
572
814
  h4: ({ className, ...props }) => (
573
815
  <h4
574
816
  className={cn(
575
- "mt-6 mb-4 scroll-m-20 text-xl font-semibold tracking-tight first:mt-0 last:mb-0",
817
+ "aui-md-h4 mt-6 mb-4 scroll-m-20 text-xl font-semibold tracking-tight first:mt-0 last:mb-0",
576
818
  className,
577
819
  )}
578
820
  {...props}
@@ -581,7 +823,7 @@ const defaultComponents = memoizeMarkdownComponents({
581
823
  h5: ({ className, ...props }) => (
582
824
  <h5
583
825
  className={cn(
584
- "my-4 text-lg font-semibold first:mt-0 last:mb-0",
826
+ "aui-md-h5 my-4 text-lg font-semibold first:mt-0 last:mb-0",
585
827
  className,
586
828
  )}
587
829
  {...props}
@@ -589,20 +831,26 @@ const defaultComponents = memoizeMarkdownComponents({
589
831
  ),
590
832
  h6: ({ className, ...props }) => (
591
833
  <h6
592
- className={cn("my-4 font-semibold first:mt-0 last:mb-0", className)}
834
+ className={cn(
835
+ "aui-md-h6 my-4 font-semibold first:mt-0 last:mb-0",
836
+ className,
837
+ )}
593
838
  {...props}
594
839
  />
595
840
  ),
596
841
  p: ({ className, ...props }) => (
597
842
  <p
598
- className={cn("mt-5 mb-5 leading-7 first:mt-0 last:mb-0", className)}
843
+ className={cn(
844
+ "aui-md-p mt-5 mb-5 leading-7 first:mt-0 last:mb-0",
845
+ className,
846
+ )}
599
847
  {...props}
600
848
  />
601
849
  ),
602
850
  a: ({ className, ...props }) => (
603
851
  <a
604
852
  className={cn(
605
- "text-primary font-medium underline underline-offset-4",
853
+ "aui-md-a text-primary font-medium underline underline-offset-4",
606
854
  className,
607
855
  )}
608
856
  {...props}
@@ -610,29 +858,29 @@ const defaultComponents = memoizeMarkdownComponents({
610
858
  ),
611
859
  blockquote: ({ className, ...props }) => (
612
860
  <blockquote
613
- className={cn("border-l-2 pl-6 italic", className)}
861
+ className={cn("aui-md-blockquote border-l-2 pl-6 italic", className)}
614
862
  {...props}
615
863
  />
616
864
  ),
617
865
  ul: ({ className, ...props }) => (
618
866
  <ul
619
- className={cn("my-5 ml-6 list-disc [&>li]:mt-2", className)}
867
+ className={cn("aui-md-ul my-5 ml-6 list-disc [&>li]:mt-2", className)}
620
868
  {...props}
621
869
  />
622
870
  ),
623
871
  ol: ({ className, ...props }) => (
624
872
  <ol
625
- className={cn("my-5 ml-6 list-decimal [&>li]:mt-2", className)}
873
+ className={cn("aui-md-ol my-5 ml-6 list-decimal [&>li]:mt-2", className)}
626
874
  {...props}
627
875
  />
628
876
  ),
629
877
  hr: ({ className, ...props }) => (
630
- <hr className={cn("my-5 border-b", className)} {...props} />
878
+ <hr className={cn("aui-md-hr my-5 border-b", className)} {...props} />
631
879
  ),
632
880
  table: ({ className, ...props }) => (
633
881
  <table
634
882
  className={cn(
635
- "my-5 w-full border-separate border-spacing-0 overflow-y-auto",
883
+ "aui-md-table my-5 w-full border-separate border-spacing-0 overflow-y-auto",
636
884
  className,
637
885
  )}
638
886
  {...props}
@@ -641,7 +889,7 @@ const defaultComponents = memoizeMarkdownComponents({
641
889
  th: ({ className, ...props }) => (
642
890
  <th
643
891
  className={cn(
644
- "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",
892
+ "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",
645
893
  className,
646
894
  )}
647
895
  {...props}
@@ -650,7 +898,7 @@ const defaultComponents = memoizeMarkdownComponents({
650
898
  td: ({ className, ...props }) => (
651
899
  <td
652
900
  className={cn(
653
- "border-b border-l px-4 py-2 text-left last:border-r [&[align=center]]:text-center [&[align=right]]:text-right",
901
+ "aui-md-td border-b border-l px-4 py-2 text-left last:border-r [&[align=center]]:text-center [&[align=right]]:text-right",
654
902
  className,
655
903
  )}
656
904
  {...props}
@@ -659,7 +907,7 @@ const defaultComponents = memoizeMarkdownComponents({
659
907
  tr: ({ className, ...props }) => (
660
908
  <tr
661
909
  className={cn(
662
- "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",
910
+ "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",
663
911
  className,
664
912
  )}
665
913
  {...props}
@@ -667,14 +915,14 @@ const defaultComponents = memoizeMarkdownComponents({
667
915
  ),
668
916
  sup: ({ className, ...props }) => (
669
917
  <sup
670
- className={cn("[&>a]:text-xs [&>a]:no-underline", className)}
918
+ className={cn("aui-md-sup [&>a]:text-xs [&>a]:no-underline", className)}
671
919
  {...props}
672
920
  />
673
921
  ),
674
922
  pre: ({ className, ...props }) => (
675
923
  <pre
676
924
  className={cn(
677
- "overflow-x-auto rounded-b-lg bg-black p-4 text-white",
925
+ "aui-md-pre overflow-x-auto !rounded-t-none rounded-b-lg bg-black p-4 text-white",
678
926
  className,
679
927
  )}
680
928
  {...props}
@@ -685,7 +933,8 @@ const defaultComponents = memoizeMarkdownComponents({
685
933
  return (
686
934
  <code
687
935
  className={cn(
688
- !isCodeBlock && "bg-muted rounded border font-semibold",
936
+ !isCodeBlock &&
937
+ "aui-md-inline-code bg-muted rounded border font-semibold",
689
938
  className,
690
939
  )}
691
940
  {...props}
@@ -987,12 +1236,111 @@ const CircleStopIcon = () => {
987
1236
 
988
1237
  ```
989
1238
 
1239
+ ## components/assistant-ui/tool-fallback.tsx
1240
+
1241
+ ```tsx
1242
+ import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
1243
+ import {
1244
+ CheckIcon,
1245
+ ChevronDownIcon,
1246
+ ChevronUpIcon,
1247
+ XCircleIcon,
1248
+ } from "lucide-react";
1249
+ import { useState } from "react";
1250
+ import { Button } from "@/components/ui/button";
1251
+ import { cn } from "@/lib/utils";
1252
+
1253
+ export const ToolFallback: ToolCallMessagePartComponent = ({
1254
+ toolName,
1255
+ argsText,
1256
+ result,
1257
+ status,
1258
+ }) => {
1259
+ const [isCollapsed, setIsCollapsed] = useState(true);
1260
+
1261
+ const isCancelled =
1262
+ status?.type === "incomplete" && status.reason === "cancelled";
1263
+ const cancelledReason =
1264
+ isCancelled && status.error
1265
+ ? typeof status.error === "string"
1266
+ ? status.error
1267
+ : JSON.stringify(status.error)
1268
+ : null;
1269
+
1270
+ return (
1271
+ <div
1272
+ className={cn(
1273
+ "aui-tool-fallback-root mb-4 flex w-full flex-col gap-3 rounded-lg border py-3",
1274
+ isCancelled && "border-muted-foreground/30 bg-muted/30",
1275
+ )}
1276
+ >
1277
+ <div className="aui-tool-fallback-header flex items-center gap-2 px-4">
1278
+ {isCancelled ? (
1279
+ <XCircleIcon className="aui-tool-fallback-icon text-muted-foreground size-4" />
1280
+ ) : (
1281
+ <CheckIcon className="aui-tool-fallback-icon size-4" />
1282
+ )}
1283
+ <p
1284
+ className={cn(
1285
+ "aui-tool-fallback-title grow",
1286
+ isCancelled && "text-muted-foreground line-through",
1287
+ )}
1288
+ >
1289
+ {isCancelled ? "Cancelled tool: " : "Used tool: "}
1290
+ <b>{toolName}</b>
1291
+ </p>
1292
+ <Button onClick={() => setIsCollapsed(!isCollapsed)}>
1293
+ {isCollapsed ? <ChevronUpIcon /> : <ChevronDownIcon />}
1294
+ </Button>
1295
+ </div>
1296
+ {!isCollapsed && (
1297
+ <div className="aui-tool-fallback-content flex flex-col gap-2 border-t pt-2">
1298
+ {cancelledReason && (
1299
+ <div className="aui-tool-fallback-cancelled-root px-4">
1300
+ <p className="aui-tool-fallback-cancelled-header text-muted-foreground font-semibold">
1301
+ Cancelled reason:
1302
+ </p>
1303
+ <p className="aui-tool-fallback-cancelled-reason text-muted-foreground">
1304
+ {cancelledReason}
1305
+ </p>
1306
+ </div>
1307
+ )}
1308
+ <div
1309
+ className={cn(
1310
+ "aui-tool-fallback-args-root px-4",
1311
+ isCancelled && "opacity-60",
1312
+ )}
1313
+ >
1314
+ <pre className="aui-tool-fallback-args-value whitespace-pre-wrap">
1315
+ {argsText}
1316
+ </pre>
1317
+ </div>
1318
+ {!isCancelled && result !== undefined && (
1319
+ <div className="aui-tool-fallback-result-root border-t border-dashed px-4 pt-2">
1320
+ <p className="aui-tool-fallback-result-header font-semibold">
1321
+ Result:
1322
+ </p>
1323
+ <pre className="aui-tool-fallback-result-content whitespace-pre-wrap">
1324
+ {typeof result === "string"
1325
+ ? result
1326
+ : JSON.stringify(result, null, 2)}
1327
+ </pre>
1328
+ </div>
1329
+ )}
1330
+ </div>
1331
+ )}
1332
+ </div>
1333
+ );
1334
+ };
1335
+
1336
+ ```
1337
+
990
1338
  ## components/assistant-ui/tooltip-icon-button.tsx
991
1339
 
992
1340
  ```tsx
993
1341
  "use client";
994
1342
 
995
- import { ComponentPropsWithoutRef, forwardRef } from "react";
1343
+ import { ComponentPropsWithRef, forwardRef } from "react";
996
1344
  import { Slottable } from "@radix-ui/react-slot";
997
1345
 
998
1346
  import {
@@ -1003,7 +1351,7 @@ import {
1003
1351
  import { Button } from "@/components/ui/button";
1004
1352
  import { cn } from "@/lib/utils";
1005
1353
 
1006
- export type TooltipIconButtonProps = ComponentPropsWithoutRef<typeof Button> & {
1354
+ export type TooltipIconButtonProps = ComponentPropsWithRef<typeof Button> & {
1007
1355
  tooltip: string;
1008
1356
  side?: "top" | "bottom" | "left" | "right";
1009
1357
  };
@@ -1019,11 +1367,11 @@ export const TooltipIconButton = forwardRef<
1019
1367
  variant="ghost"
1020
1368
  size="icon"
1021
1369
  {...rest}
1022
- className={cn("size-6 p-1", className)}
1370
+ className={cn("aui-button-icon size-6 p-1", className)}
1023
1371
  ref={ref}
1024
1372
  >
1025
1373
  <Slottable>{children}</Slottable>
1026
- <span className="sr-only">{tooltip}</span>
1374
+ <span className="aui-sr-only sr-only">{tooltip}</span>
1027
1375
  </Button>
1028
1376
  </TooltipTrigger>
1029
1377
  <TooltipContent side={side}>{tooltip}</TooltipContent>
@@ -1035,6 +1383,62 @@ TooltipIconButton.displayName = "TooltipIconButton";
1035
1383
 
1036
1384
  ```
1037
1385
 
1386
+ ## components/ui/avatar.tsx
1387
+
1388
+ ```tsx
1389
+ "use client";
1390
+
1391
+ import * as React from "react";
1392
+ import * as AvatarPrimitive from "@radix-ui/react-avatar";
1393
+
1394
+ import { cn } from "@/lib/utils";
1395
+
1396
+ const Avatar = React.forwardRef<
1397
+ React.ElementRef<typeof AvatarPrimitive.Root>,
1398
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
1399
+ >(({ className, ...props }, ref) => (
1400
+ <AvatarPrimitive.Root
1401
+ ref={ref}
1402
+ className={cn(
1403
+ "relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
1404
+ className,
1405
+ )}
1406
+ {...props}
1407
+ />
1408
+ ));
1409
+ Avatar.displayName = AvatarPrimitive.Root.displayName;
1410
+
1411
+ const AvatarImage = React.forwardRef<
1412
+ React.ElementRef<typeof AvatarPrimitive.Image>,
1413
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
1414
+ >(({ className, ...props }, ref) => (
1415
+ <AvatarPrimitive.Image
1416
+ ref={ref}
1417
+ className={cn("aspect-square h-full w-full", className)}
1418
+ {...props}
1419
+ />
1420
+ ));
1421
+ AvatarImage.displayName = AvatarPrimitive.Image.displayName;
1422
+
1423
+ const AvatarFallback = React.forwardRef<
1424
+ React.ElementRef<typeof AvatarPrimitive.Fallback>,
1425
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
1426
+ >(({ className, ...props }, ref) => (
1427
+ <AvatarPrimitive.Fallback
1428
+ ref={ref}
1429
+ className={cn(
1430
+ "bg-muted flex h-full w-full items-center justify-center rounded-full",
1431
+ className,
1432
+ )}
1433
+ {...props}
1434
+ />
1435
+ ));
1436
+ AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
1437
+
1438
+ export { Avatar, AvatarImage, AvatarFallback };
1439
+
1440
+ ```
1441
+
1038
1442
  ## components/ui/button.tsx
1039
1443
 
1040
1444
  ```tsx
@@ -1102,6 +1506,147 @@ export { Button, buttonVariants };
1102
1506
 
1103
1507
  ```
1104
1508
 
1509
+ ## components/ui/dialog.tsx
1510
+
1511
+ ```tsx
1512
+ "use client";
1513
+
1514
+ import * as React from "react";
1515
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
1516
+ import { XIcon } from "lucide-react";
1517
+
1518
+ import { cn } from "@/lib/utils";
1519
+
1520
+ function Dialog({
1521
+ ...props
1522
+ }: React.ComponentProps<typeof DialogPrimitive.Root>) {
1523
+ return <DialogPrimitive.Root data-slot="dialog" {...props} />;
1524
+ }
1525
+
1526
+ function DialogTrigger({
1527
+ ...props
1528
+ }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
1529
+ return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
1530
+ }
1531
+
1532
+ function DialogPortal({
1533
+ ...props
1534
+ }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
1535
+ return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
1536
+ }
1537
+
1538
+ function DialogClose({
1539
+ ...props
1540
+ }: React.ComponentProps<typeof DialogPrimitive.Close>) {
1541
+ return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
1542
+ }
1543
+
1544
+ function DialogOverlay({
1545
+ className,
1546
+ ...props
1547
+ }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
1548
+ return (
1549
+ <DialogPrimitive.Overlay
1550
+ data-slot="dialog-overlay"
1551
+ className={cn(
1552
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80",
1553
+ className,
1554
+ )}
1555
+ {...props}
1556
+ />
1557
+ );
1558
+ }
1559
+
1560
+ function DialogContent({
1561
+ className,
1562
+ children,
1563
+ ...props
1564
+ }: React.ComponentProps<typeof DialogPrimitive.Content>) {
1565
+ return (
1566
+ <DialogPortal data-slot="dialog-portal">
1567
+ <DialogOverlay />
1568
+ <DialogPrimitive.Content
1569
+ data-slot="dialog-content"
1570
+ className={cn(
1571
+ "bg-background data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in 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 p-6 shadow-lg duration-200 sm:max-w-lg",
1572
+ className,
1573
+ )}
1574
+ {...props}
1575
+ >
1576
+ {children}
1577
+ <DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4">
1578
+ <XIcon />
1579
+ <span className="sr-only">Close</span>
1580
+ </DialogPrimitive.Close>
1581
+ </DialogPrimitive.Content>
1582
+ </DialogPortal>
1583
+ );
1584
+ }
1585
+
1586
+ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
1587
+ return (
1588
+ <div
1589
+ data-slot="dialog-header"
1590
+ className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
1591
+ {...props}
1592
+ />
1593
+ );
1594
+ }
1595
+
1596
+ function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
1597
+ return (
1598
+ <div
1599
+ data-slot="dialog-footer"
1600
+ className={cn(
1601
+ "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
1602
+ className,
1603
+ )}
1604
+ {...props}
1605
+ />
1606
+ );
1607
+ }
1608
+
1609
+ function DialogTitle({
1610
+ className,
1611
+ ...props
1612
+ }: React.ComponentProps<typeof DialogPrimitive.Title>) {
1613
+ return (
1614
+ <DialogPrimitive.Title
1615
+ data-slot="dialog-title"
1616
+ className={cn("text-lg leading-none font-semibold", className)}
1617
+ {...props}
1618
+ />
1619
+ );
1620
+ }
1621
+
1622
+ function DialogDescription({
1623
+ className,
1624
+ ...props
1625
+ }: React.ComponentProps<typeof DialogPrimitive.Description>) {
1626
+ return (
1627
+ <DialogPrimitive.Description
1628
+ data-slot="dialog-description"
1629
+ className={cn("text-muted-foreground text-sm", className)}
1630
+ {...props}
1631
+ />
1632
+ );
1633
+ }
1634
+
1635
+ export {
1636
+ Dialog,
1637
+ DialogClose,
1638
+ DialogContent,
1639
+ DialogDescription,
1640
+ DialogFooter,
1641
+ DialogHeader,
1642
+ DialogOverlay,
1643
+ DialogPortal,
1644
+ DialogTitle,
1645
+ DialogTrigger,
1646
+ };
1647
+
1648
+ ```
1649
+
1105
1650
  ## components/ui/tooltip.tsx
1106
1651
 
1107
1652
  ```tsx
@@ -1181,18 +1726,6 @@ export function cn(...inputs: ClassValue[]) {
1181
1726
 
1182
1727
  ```
1183
1728
 
1184
- ## next-env.d.ts
1185
-
1186
- ```typescript
1187
- /// <reference types="next" />
1188
- /// <reference types="next/image-types/global" />
1189
- import "./.next/types/routes.d.ts";
1190
-
1191
- // NOTE: This file should not be edited
1192
- // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
1193
-
1194
- ```
1195
-
1196
1729
  ## next.config.ts
1197
1730
 
1198
1731
  ```typescript
@@ -1220,7 +1753,7 @@ export default nextConfig;
1220
1753
  "lint": "eslint ."
1221
1754
  },
1222
1755
  "dependencies": {
1223
- "@ai-sdk/openai": "^2.0.68",
1756
+ "@ai-sdk/openai": "^2.0.73",
1224
1757
  "@assistant-ui/react": "workspace:*",
1225
1758
  "@assistant-ui/react-ai-sdk": "workspace:*",
1226
1759
  "@assistant-ui/react-hook-form": "workspace:*",
@@ -1228,19 +1761,20 @@ export default nextConfig;
1228
1761
  "@ffmpeg/ffmpeg": "^0.12.15",
1229
1762
  "@ffmpeg/util": "^0.12.2",
1230
1763
  "@hookform/resolvers": "^5.2.2",
1231
- "@radix-ui/react-avatar": "^1.1.11",
1764
+ "@radix-ui/react-avatar": "^1.1.4",
1765
+ "@radix-ui/react-dialog": "^1.1.7",
1232
1766
  "@radix-ui/react-icons": "^1.3.2",
1233
1767
  "@radix-ui/react-label": "^2.1.8",
1234
1768
  "@radix-ui/react-slot": "^1.2.4",
1235
1769
  "@radix-ui/react-tabs": "^1.1.13",
1236
1770
  "@radix-ui/react-tooltip": "^1.2.8",
1237
1771
  "@react-hook/media-query": "^1.1.1",
1238
- "ai": "^5.0.93",
1772
+ "ai": "^5.0.102",
1239
1773
  "class-variance-authority": "^0.7.1",
1240
1774
  "clsx": "^2.1.1",
1241
- "json-schema-to-zod": "^2.6.1",
1242
- "lucide-react": "^0.554.0",
1243
- "next": "16.0.3",
1775
+ "lucide-react": "^0.555.0",
1776
+ "motion": "^11.18.2",
1777
+ "next": "16.0.4",
1244
1778
  "react": "19.2.0",
1245
1779
  "react-dom": "19.2.0",
1246
1780
  "react-hook-form": "^7.66.1",
@@ -1248,7 +1782,7 @@ export default nextConfig;
1248
1782
  "remark-gfm": "^4.0.1",
1249
1783
  "tailwind-merge": "^3.4.0",
1250
1784
  "tw-animate-css": "^1.4.0",
1251
- "zod": "^4.1.12",
1785
+ "zod": "^4.1.13",
1252
1786
  "zustand": "^5.0.8"
1253
1787
  },
1254
1788
  "devDependencies": {