@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.
@@ -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
- import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs";
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 hover:bg-accent/50 cursor-pointer transition-colors"
440
+ asChild
441
+ >
442
+ {children}
443
+ </DialogTrigger>
444
+ <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">
445
+ <DialogTitle className="aui-sr-only sr-only">
446
+ Image Attachment Preview
447
+ </DialogTitle>
448
+ <div className="aui-attachment-preview bg-background relative mx-auto flex max-h-[80dvh] w-full items-center justify-center overflow-hidden">
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 text-muted-foreground size-8" />
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 bg-muted size-14 cursor-pointer overflow-hidden rounded-[14px] border 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 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"
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 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"
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-zinc-900 px-4 py-2 text-sm font-semibold text-white">
406
- <span className="lowercase [&>span]:text-xs">{language}</span>
623
+ <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">
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 font-extrabold tracking-tight last:mb-0",
658
+ "aui-md-h1 mb-8 scroll-m-20 text-4xl font-extrabold 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 font-semibold tracking-tight first:mt-0 last:mb-0",
667
+ "aui-md-h2 mt-8 mb-4 scroll-m-20 text-3xl font-semibold 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 font-semibold tracking-tight first:mt-0 last:mb-0",
676
+ "aui-md-h3 mt-6 mb-4 scroll-m-20 text-2xl font-semibold 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 font-semibold tracking-tight first:mt-0 last:mb-0",
685
+ "aui-md-h4 mt-6 mb-4 scroll-m-20 text-xl font-semibold 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 font-semibold first:mt-0 last:mb-0",
694
+ "aui-md-h5 my-4 text-lg font-semibold 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("my-4 font-semibold first:mt-0 last:mb-0", className)}
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("mt-5 mb-5 leading-7 first:mt-0 last:mb-0", className)}
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
- "text-primary font-medium underline underline-offset-4",
721
+ "aui-md-a text-primary font-medium 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 [&[align=center]]:text-center [&[align=right]]:text-right",
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 [&[align=center]]:text-center [&[align=right]]:text-right",
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 && "bg-muted rounded border font-semibold",
804
+ !isCodeBlock &&
805
+ "aui-md-inline-code bg-muted rounded border font-semibold",
579
806
  className,
580
807
  )}
581
808
  {...props}
@@ -877,12 +1104,111 @@ const CircleStopIcon = () => {
877
1104
 
878
1105
  ```
879
1106
 
1107
+ ## components/assistant-ui/tool-fallback.tsx
1108
+
1109
+ ```tsx
1110
+ import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
1111
+ import {
1112
+ CheckIcon,
1113
+ ChevronDownIcon,
1114
+ ChevronUpIcon,
1115
+ XCircleIcon,
1116
+ } from "lucide-react";
1117
+ import { useState } from "react";
1118
+ import { Button } from "@/components/ui/button";
1119
+ import { cn } from "@/lib/utils";
1120
+
1121
+ export const ToolFallback: ToolCallMessagePartComponent = ({
1122
+ toolName,
1123
+ argsText,
1124
+ result,
1125
+ status,
1126
+ }) => {
1127
+ const [isCollapsed, setIsCollapsed] = useState(true);
1128
+
1129
+ const isCancelled =
1130
+ status?.type === "incomplete" && status.reason === "cancelled";
1131
+ const cancelledReason =
1132
+ isCancelled && status.error
1133
+ ? typeof status.error === "string"
1134
+ ? status.error
1135
+ : JSON.stringify(status.error)
1136
+ : null;
1137
+
1138
+ return (
1139
+ <div
1140
+ className={cn(
1141
+ "aui-tool-fallback-root mb-4 flex w-full flex-col gap-3 rounded-lg border py-3",
1142
+ isCancelled && "border-muted-foreground/30 bg-muted/30",
1143
+ )}
1144
+ >
1145
+ <div className="aui-tool-fallback-header flex items-center gap-2 px-4">
1146
+ {isCancelled ? (
1147
+ <XCircleIcon className="aui-tool-fallback-icon text-muted-foreground size-4" />
1148
+ ) : (
1149
+ <CheckIcon className="aui-tool-fallback-icon size-4" />
1150
+ )}
1151
+ <p
1152
+ className={cn(
1153
+ "aui-tool-fallback-title grow",
1154
+ isCancelled && "text-muted-foreground line-through",
1155
+ )}
1156
+ >
1157
+ {isCancelled ? "Cancelled tool: " : "Used tool: "}
1158
+ <b>{toolName}</b>
1159
+ </p>
1160
+ <Button onClick={() => setIsCollapsed(!isCollapsed)}>
1161
+ {isCollapsed ? <ChevronUpIcon /> : <ChevronDownIcon />}
1162
+ </Button>
1163
+ </div>
1164
+ {!isCollapsed && (
1165
+ <div className="aui-tool-fallback-content flex flex-col gap-2 border-t pt-2">
1166
+ {cancelledReason && (
1167
+ <div className="aui-tool-fallback-cancelled-root px-4">
1168
+ <p className="aui-tool-fallback-cancelled-header text-muted-foreground font-semibold">
1169
+ Cancelled reason:
1170
+ </p>
1171
+ <p className="aui-tool-fallback-cancelled-reason text-muted-foreground">
1172
+ {cancelledReason}
1173
+ </p>
1174
+ </div>
1175
+ )}
1176
+ <div
1177
+ className={cn(
1178
+ "aui-tool-fallback-args-root px-4",
1179
+ isCancelled && "opacity-60",
1180
+ )}
1181
+ >
1182
+ <pre className="aui-tool-fallback-args-value whitespace-pre-wrap">
1183
+ {argsText}
1184
+ </pre>
1185
+ </div>
1186
+ {!isCancelled && result !== undefined && (
1187
+ <div className="aui-tool-fallback-result-root border-t border-dashed px-4 pt-2">
1188
+ <p className="aui-tool-fallback-result-header font-semibold">
1189
+ Result:
1190
+ </p>
1191
+ <pre className="aui-tool-fallback-result-content whitespace-pre-wrap">
1192
+ {typeof result === "string"
1193
+ ? result
1194
+ : JSON.stringify(result, null, 2)}
1195
+ </pre>
1196
+ </div>
1197
+ )}
1198
+ </div>
1199
+ )}
1200
+ </div>
1201
+ );
1202
+ };
1203
+
1204
+ ```
1205
+
880
1206
  ## components/assistant-ui/tooltip-icon-button.tsx
881
1207
 
882
1208
  ```tsx
883
1209
  "use client";
884
1210
 
885
- import { ComponentPropsWithoutRef, forwardRef } from "react";
1211
+ import { ComponentPropsWithRef, forwardRef } from "react";
886
1212
  import { Slottable } from "@radix-ui/react-slot";
887
1213
 
888
1214
  import {
@@ -893,7 +1219,7 @@ import {
893
1219
  import { Button } from "@/components/ui/button";
894
1220
  import { cn } from "@/lib/utils";
895
1221
 
896
- export type TooltipIconButtonProps = ComponentPropsWithoutRef<typeof Button> & {
1222
+ export type TooltipIconButtonProps = ComponentPropsWithRef<typeof Button> & {
897
1223
  tooltip: string;
898
1224
  side?: "top" | "bottom" | "left" | "right";
899
1225
  };
@@ -909,11 +1235,11 @@ export const TooltipIconButton = forwardRef<
909
1235
  variant="ghost"
910
1236
  size="icon"
911
1237
  {...rest}
912
- className={cn("size-6 p-1", className)}
1238
+ className={cn("aui-button-icon size-6 p-1", className)}
913
1239
  ref={ref}
914
1240
  >
915
1241
  <Slottable>{children}</Slottable>
916
- <span className="sr-only">{tooltip}</span>
1242
+ <span className="aui-sr-only sr-only">{tooltip}</span>
917
1243
  </Button>
918
1244
  </TooltipTrigger>
919
1245
  <TooltipContent side={side}>{tooltip}</TooltipContent>
@@ -1074,6 +1400,62 @@ export const SignupForm: FC = () => {
1074
1400
 
1075
1401
  ```
1076
1402
 
1403
+ ## components/ui/avatar.tsx
1404
+
1405
+ ```tsx
1406
+ "use client";
1407
+
1408
+ import * as React from "react";
1409
+ import * as AvatarPrimitive from "@radix-ui/react-avatar";
1410
+
1411
+ import { cn } from "@/lib/utils";
1412
+
1413
+ const Avatar = React.forwardRef<
1414
+ React.ElementRef<typeof AvatarPrimitive.Root>,
1415
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
1416
+ >(({ className, ...props }, ref) => (
1417
+ <AvatarPrimitive.Root
1418
+ ref={ref}
1419
+ className={cn(
1420
+ "relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
1421
+ className,
1422
+ )}
1423
+ {...props}
1424
+ />
1425
+ ));
1426
+ Avatar.displayName = AvatarPrimitive.Root.displayName;
1427
+
1428
+ const AvatarImage = React.forwardRef<
1429
+ React.ElementRef<typeof AvatarPrimitive.Image>,
1430
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
1431
+ >(({ className, ...props }, ref) => (
1432
+ <AvatarPrimitive.Image
1433
+ ref={ref}
1434
+ className={cn("aspect-square h-full w-full", className)}
1435
+ {...props}
1436
+ />
1437
+ ));
1438
+ AvatarImage.displayName = AvatarPrimitive.Image.displayName;
1439
+
1440
+ const AvatarFallback = React.forwardRef<
1441
+ React.ElementRef<typeof AvatarPrimitive.Fallback>,
1442
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
1443
+ >(({ className, ...props }, ref) => (
1444
+ <AvatarPrimitive.Fallback
1445
+ ref={ref}
1446
+ className={cn(
1447
+ "bg-muted flex h-full w-full items-center justify-center rounded-full",
1448
+ className,
1449
+ )}
1450
+ {...props}
1451
+ />
1452
+ ));
1453
+ AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
1454
+
1455
+ export { Avatar, AvatarImage, AvatarFallback };
1456
+
1457
+ ```
1458
+
1077
1459
  ## components/ui/button.tsx
1078
1460
 
1079
1461
  ```tsx
@@ -1139,6 +1521,147 @@ export { Button, buttonVariants };
1139
1521
 
1140
1522
  ```
1141
1523
 
1524
+ ## components/ui/dialog.tsx
1525
+
1526
+ ```tsx
1527
+ "use client";
1528
+
1529
+ import * as React from "react";
1530
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
1531
+ import { XIcon } from "lucide-react";
1532
+
1533
+ import { cn } from "@/lib/utils";
1534
+
1535
+ function Dialog({
1536
+ ...props
1537
+ }: React.ComponentProps<typeof DialogPrimitive.Root>) {
1538
+ return <DialogPrimitive.Root data-slot="dialog" {...props} />;
1539
+ }
1540
+
1541
+ function DialogTrigger({
1542
+ ...props
1543
+ }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
1544
+ return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
1545
+ }
1546
+
1547
+ function DialogPortal({
1548
+ ...props
1549
+ }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
1550
+ return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
1551
+ }
1552
+
1553
+ function DialogClose({
1554
+ ...props
1555
+ }: React.ComponentProps<typeof DialogPrimitive.Close>) {
1556
+ return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
1557
+ }
1558
+
1559
+ function DialogOverlay({
1560
+ className,
1561
+ ...props
1562
+ }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
1563
+ return (
1564
+ <DialogPrimitive.Overlay
1565
+ data-slot="dialog-overlay"
1566
+ className={cn(
1567
+ "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",
1568
+ className,
1569
+ )}
1570
+ {...props}
1571
+ />
1572
+ );
1573
+ }
1574
+
1575
+ function DialogContent({
1576
+ className,
1577
+ children,
1578
+ ...props
1579
+ }: React.ComponentProps<typeof DialogPrimitive.Content>) {
1580
+ return (
1581
+ <DialogPortal data-slot="dialog-portal">
1582
+ <DialogOverlay />
1583
+ <DialogPrimitive.Content
1584
+ data-slot="dialog-content"
1585
+ className={cn(
1586
+ "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",
1587
+ className,
1588
+ )}
1589
+ {...props}
1590
+ >
1591
+ {children}
1592
+ <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">
1593
+ <XIcon />
1594
+ <span className="sr-only">Close</span>
1595
+ </DialogPrimitive.Close>
1596
+ </DialogPrimitive.Content>
1597
+ </DialogPortal>
1598
+ );
1599
+ }
1600
+
1601
+ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
1602
+ return (
1603
+ <div
1604
+ data-slot="dialog-header"
1605
+ className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
1606
+ {...props}
1607
+ />
1608
+ );
1609
+ }
1610
+
1611
+ function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
1612
+ return (
1613
+ <div
1614
+ data-slot="dialog-footer"
1615
+ className={cn(
1616
+ "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
1617
+ className,
1618
+ )}
1619
+ {...props}
1620
+ />
1621
+ );
1622
+ }
1623
+
1624
+ function DialogTitle({
1625
+ className,
1626
+ ...props
1627
+ }: React.ComponentProps<typeof DialogPrimitive.Title>) {
1628
+ return (
1629
+ <DialogPrimitive.Title
1630
+ data-slot="dialog-title"
1631
+ className={cn("text-lg leading-none font-semibold", className)}
1632
+ {...props}
1633
+ />
1634
+ );
1635
+ }
1636
+
1637
+ function DialogDescription({
1638
+ className,
1639
+ ...props
1640
+ }: React.ComponentProps<typeof DialogPrimitive.Description>) {
1641
+ return (
1642
+ <DialogPrimitive.Description
1643
+ data-slot="dialog-description"
1644
+ className={cn("text-muted-foreground text-sm", className)}
1645
+ {...props}
1646
+ />
1647
+ );
1648
+ }
1649
+
1650
+ export {
1651
+ Dialog,
1652
+ DialogClose,
1653
+ DialogContent,
1654
+ DialogDescription,
1655
+ DialogFooter,
1656
+ DialogHeader,
1657
+ DialogOverlay,
1658
+ DialogPortal,
1659
+ DialogTitle,
1660
+ DialogTrigger,
1661
+ };
1662
+
1663
+ ```
1664
+
1142
1665
  ## components/ui/form.tsx
1143
1666
 
1144
1667
  ```tsx
@@ -1601,18 +2124,6 @@ export function cn(...inputs: ClassValue[]) {
1601
2124
 
1602
2125
  ```
1603
2126
 
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
2127
  ## next.config.ts
1617
2128
 
1618
2129
  ```typescript
@@ -1640,25 +2151,26 @@ export default nextConfig;
1640
2151
  "lint": "eslint ."
1641
2152
  },
1642
2153
  "dependencies": {
1643
- "@ai-sdk/openai": "^2.0.68",
2154
+ "@ai-sdk/openai": "^2.0.73",
1644
2155
  "@assistant-ui/react": "workspace:*",
1645
2156
  "@assistant-ui/react-ai-sdk": "workspace:*",
1646
2157
  "@assistant-ui/react-hook-form": "workspace:*",
1647
2158
  "@assistant-ui/react-markdown": "workspace:*",
1648
2159
  "@hookform/resolvers": "^5.2.2",
1649
- "@radix-ui/react-avatar": "^1.1.11",
2160
+ "@radix-ui/react-avatar": "^1.1.4",
2161
+ "@radix-ui/react-dialog": "^1.1.7",
1650
2162
  "@radix-ui/react-icons": "^1.3.2",
1651
2163
  "@radix-ui/react-label": "^2.1.8",
1652
2164
  "@radix-ui/react-slot": "^1.2.4",
1653
2165
  "@radix-ui/react-tabs": "^1.1.13",
1654
2166
  "@radix-ui/react-tooltip": "^1.2.8",
1655
2167
  "@react-hook/media-query": "^1.1.1",
1656
- "ai": "^5.0.93",
2168
+ "ai": "^5.0.102",
1657
2169
  "class-variance-authority": "^0.7.1",
1658
2170
  "clsx": "^2.1.1",
1659
- "json-schema-to-zod": "^2.6.1",
1660
- "lucide-react": "^0.554.0",
1661
- "next": "16.0.3",
2171
+ "lucide-react": "^0.555.0",
2172
+ "motion": "^11.18.2",
2173
+ "next": "16.0.4",
1662
2174
  "react": "19.2.0",
1663
2175
  "react-dom": "19.2.0",
1664
2176
  "react-hook-form": "^7.66.1",
@@ -1666,7 +2178,7 @@ export default nextConfig;
1666
2178
  "remark-gfm": "^4.0.1",
1667
2179
  "tailwind-merge": "^3.4.0",
1668
2180
  "tw-animate-css": "^1.4.0",
1669
- "zod": "^4.1.12",
2181
+ "zod": "^4.1.13",
1670
2182
  "zustand": "^5.0.8"
1671
2183
  },
1672
2184
  "devDependencies": {