@assistant-ui/mcp-docs-server 0.1.15 → 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.
Files changed (55) hide show
  1. package/.docs/organized/code-examples/store-example.md +112 -38
  2. package/.docs/organized/code-examples/with-ag-ui.md +248 -184
  3. package/.docs/organized/code-examples/with-ai-sdk-v5.md +247 -196
  4. package/.docs/organized/code-examples/with-assistant-transport.md +192 -240
  5. package/.docs/organized/code-examples/with-cloud.md +275 -224
  6. package/.docs/organized/code-examples/with-custom-thread-list.md +1855 -0
  7. package/.docs/organized/code-examples/with-external-store.md +244 -178
  8. package/.docs/organized/code-examples/with-ffmpeg.md +253 -187
  9. package/.docs/organized/code-examples/with-langgraph.md +291 -240
  10. package/.docs/organized/code-examples/with-parent-id-grouping.md +241 -261
  11. package/.docs/organized/code-examples/with-react-hook-form.md +260 -194
  12. package/.docs/organized/code-examples/with-tanstack.md +1574 -0
  13. package/.docs/raw/blog/2024-07-29-hello/index.mdx +2 -2
  14. package/.docs/raw/docs/api-reference/overview.mdx +6 -6
  15. package/.docs/raw/docs/api-reference/primitives/ActionBar.mdx +85 -4
  16. package/.docs/raw/docs/api-reference/primitives/AssistantIf.mdx +200 -0
  17. package/.docs/raw/docs/api-reference/primitives/Composer.mdx +0 -20
  18. package/.docs/raw/docs/api-reference/primitives/Message.mdx +0 -45
  19. package/.docs/raw/docs/api-reference/primitives/Thread.mdx +0 -50
  20. package/.docs/raw/docs/cloud/persistence/ai-sdk.mdx +2 -3
  21. package/.docs/raw/docs/cloud/persistence/langgraph.mdx +2 -3
  22. package/.docs/raw/docs/devtools.mdx +2 -3
  23. package/.docs/raw/docs/getting-started.mdx +36 -1102
  24. package/.docs/raw/docs/guides/Attachments.mdx +3 -25
  25. package/.docs/raw/docs/guides/Branching.mdx +1 -1
  26. package/.docs/raw/docs/guides/Speech.mdx +1 -1
  27. package/.docs/raw/docs/guides/ToolUI.mdx +1 -1
  28. package/.docs/raw/docs/legacy/styled/AssistantModal.mdx +2 -3
  29. package/.docs/raw/docs/legacy/styled/Decomposition.mdx +6 -5
  30. package/.docs/raw/docs/legacy/styled/Markdown.mdx +2 -3
  31. package/.docs/raw/docs/legacy/styled/Thread.mdx +2 -3
  32. package/.docs/raw/docs/react-compatibility.mdx +2 -5
  33. package/.docs/raw/docs/runtimes/ai-sdk/use-chat.mdx +3 -4
  34. package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +3 -6
  35. package/.docs/raw/docs/runtimes/custom/external-store.mdx +2 -3
  36. package/.docs/raw/docs/runtimes/custom/local.mdx +11 -41
  37. package/.docs/raw/docs/runtimes/data-stream.mdx +15 -11
  38. package/.docs/raw/docs/runtimes/langgraph/index.mdx +3 -3
  39. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +1 -1
  40. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +2 -3
  41. package/.docs/raw/docs/runtimes/langserve.mdx +2 -3
  42. package/.docs/raw/docs/runtimes/mastra/full-stack-integration.mdx +2 -3
  43. package/.docs/raw/docs/runtimes/mastra/separate-server-integration.mdx +2 -3
  44. package/.docs/raw/docs/ui/AssistantModal.mdx +3 -25
  45. package/.docs/raw/docs/ui/AssistantSidebar.mdx +2 -24
  46. package/.docs/raw/docs/ui/Attachment.mdx +3 -25
  47. package/.docs/raw/docs/ui/Markdown.mdx +2 -24
  48. package/.docs/raw/docs/ui/Mermaid.mdx +2 -24
  49. package/.docs/raw/docs/ui/Reasoning.mdx +2 -24
  50. package/.docs/raw/docs/ui/Scrollbar.mdx +4 -6
  51. package/.docs/raw/docs/ui/SyntaxHighlighting.mdx +3 -47
  52. package/.docs/raw/docs/ui/Thread.mdx +38 -53
  53. package/.docs/raw/docs/ui/ThreadList.mdx +4 -47
  54. package/.docs/raw/docs/ui/ToolFallback.mdx +2 -24
  55. package/package.json +5 -6
@@ -432,16 +432,16 @@ const AttachmentPreviewDialog: FC<PropsWithChildren> = ({ children }) => {
432
432
  return (
433
433
  <Dialog>
434
434
  <DialogTrigger
435
- className="aui-attachment-preview-trigger hover:bg-accent/50 cursor-pointer transition-colors"
435
+ className="aui-attachment-preview-trigger cursor-pointer transition-colors hover:bg-accent/50"
436
436
  asChild
437
437
  >
438
438
  {children}
439
439
  </DialogTrigger>
440
- <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">
440
+ <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">
441
441
  <DialogTitle className="aui-sr-only sr-only">
442
442
  Image Attachment Preview
443
443
  </DialogTitle>
444
- <div className="aui-attachment-preview bg-background relative mx-auto flex max-h-[80dvh] w-full items-center justify-center overflow-hidden">
444
+ <div className="aui-attachment-preview relative mx-auto flex max-h-[80dvh] w-full items-center justify-center overflow-hidden bg-background">
445
445
  <AttachmentPreview src={src} />
446
446
  </div>
447
447
  </DialogContent>
@@ -463,7 +463,7 @@ const AttachmentThumb: FC = () => {
463
463
  className="aui-attachment-tile-image object-cover"
464
464
  />
465
465
  <AvatarFallback delayMs={isImage ? 200 : 0}>
466
- <FileText className="aui-attachment-tile-fallback-icon text-muted-foreground size-8" />
466
+ <FileText className="aui-attachment-tile-fallback-icon size-8 text-muted-foreground" />
467
467
  </AvatarFallback>
468
468
  </Avatar>
469
469
  );
@@ -504,7 +504,7 @@ const AttachmentUI: FC = () => {
504
504
  <TooltipTrigger asChild>
505
505
  <div
506
506
  className={cn(
507
- "aui-attachment-tile bg-muted size-14 cursor-pointer overflow-hidden rounded-[14px] border transition-opacity hover:opacity-75",
507
+ "aui-attachment-tile size-14 cursor-pointer overflow-hidden rounded-[14px] border bg-muted transition-opacity hover:opacity-75",
508
508
  isComposer &&
509
509
  "aui-attachment-tile-composer border-foreground/20",
510
510
  )}
@@ -530,7 +530,7 @@ const AttachmentRemove: FC = () => {
530
530
  <AttachmentPrimitive.Remove asChild>
531
531
  <TooltipIconButton
532
532
  tooltip="Remove file"
533
- 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"
533
+ 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"
534
534
  side="top"
535
535
  >
536
536
  <XIcon className="aui-attachment-remove-icon size-3 dark:stroke-[2.5px]" />
@@ -565,7 +565,7 @@ export const ComposerAddAttachment: FC = () => {
565
565
  side="bottom"
566
566
  variant="ghost"
567
567
  size="icon"
568
- 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"
568
+ 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"
569
569
  aria-label="Add Attachment"
570
570
  >
571
571
  <PlusIcon className="aui-attachment-add-icon size-5 stroke-[1.5px]" />
@@ -616,7 +616,7 @@ const CodeHeader: FC<CodeHeaderProps> = ({ language, code }) => {
616
616
  };
617
617
 
618
618
  return (
619
- <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">
619
+ <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">
620
620
  <span className="aui-code-header-language lowercase [&>span]:text-xs">
621
621
  {language}
622
622
  </span>
@@ -651,7 +651,7 @@ const defaultComponents = memoizeMarkdownComponents({
651
651
  h1: ({ className, ...props }) => (
652
652
  <h1
653
653
  className={cn(
654
- "aui-md-h1 mb-8 scroll-m-20 text-4xl font-extrabold tracking-tight last:mb-0",
654
+ "aui-md-h1 mb-8 scroll-m-20 font-extrabold text-4xl tracking-tight last:mb-0",
655
655
  className,
656
656
  )}
657
657
  {...props}
@@ -660,7 +660,7 @@ const defaultComponents = memoizeMarkdownComponents({
660
660
  h2: ({ className, ...props }) => (
661
661
  <h2
662
662
  className={cn(
663
- "aui-md-h2 mt-8 mb-4 scroll-m-20 text-3xl font-semibold tracking-tight first:mt-0 last:mb-0",
663
+ "aui-md-h2 mt-8 mb-4 scroll-m-20 font-semibold text-3xl tracking-tight first:mt-0 last:mb-0",
664
664
  className,
665
665
  )}
666
666
  {...props}
@@ -669,7 +669,7 @@ const defaultComponents = memoizeMarkdownComponents({
669
669
  h3: ({ className, ...props }) => (
670
670
  <h3
671
671
  className={cn(
672
- "aui-md-h3 mt-6 mb-4 scroll-m-20 text-2xl font-semibold tracking-tight first:mt-0 last:mb-0",
672
+ "aui-md-h3 mt-6 mb-4 scroll-m-20 font-semibold text-2xl tracking-tight first:mt-0 last:mb-0",
673
673
  className,
674
674
  )}
675
675
  {...props}
@@ -678,7 +678,7 @@ const defaultComponents = memoizeMarkdownComponents({
678
678
  h4: ({ className, ...props }) => (
679
679
  <h4
680
680
  className={cn(
681
- "aui-md-h4 mt-6 mb-4 scroll-m-20 text-xl font-semibold tracking-tight first:mt-0 last:mb-0",
681
+ "aui-md-h4 mt-6 mb-4 scroll-m-20 font-semibold text-xl tracking-tight first:mt-0 last:mb-0",
682
682
  className,
683
683
  )}
684
684
  {...props}
@@ -687,7 +687,7 @@ const defaultComponents = memoizeMarkdownComponents({
687
687
  h5: ({ className, ...props }) => (
688
688
  <h5
689
689
  className={cn(
690
- "aui-md-h5 my-4 text-lg font-semibold first:mt-0 last:mb-0",
690
+ "aui-md-h5 my-4 font-semibold text-lg first:mt-0 last:mb-0",
691
691
  className,
692
692
  )}
693
693
  {...props}
@@ -714,7 +714,7 @@ const defaultComponents = memoizeMarkdownComponents({
714
714
  a: ({ className, ...props }) => (
715
715
  <a
716
716
  className={cn(
717
- "aui-md-a text-primary font-medium underline underline-offset-4",
717
+ "aui-md-a font-medium text-primary underline underline-offset-4",
718
718
  className,
719
719
  )}
720
720
  {...props}
@@ -753,7 +753,7 @@ const defaultComponents = memoizeMarkdownComponents({
753
753
  th: ({ className, ...props }) => (
754
754
  <th
755
755
  className={cn(
756
- "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",
756
+ "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",
757
757
  className,
758
758
  )}
759
759
  {...props}
@@ -762,7 +762,7 @@ const defaultComponents = memoizeMarkdownComponents({
762
762
  td: ({ className, ...props }) => (
763
763
  <td
764
764
  className={cn(
765
- "aui-md-td border-b border-l px-4 py-2 text-left last:border-r [&[align=center]]:text-center [&[align=right]]:text-right",
765
+ "aui-md-td border-b border-l px-4 py-2 text-left last:border-r [[align=center]]:text-center [[align=right]]:text-right",
766
766
  className,
767
767
  )}
768
768
  {...props}
@@ -786,7 +786,7 @@ const defaultComponents = memoizeMarkdownComponents({
786
786
  pre: ({ className, ...props }) => (
787
787
  <pre
788
788
  className={cn(
789
- "aui-md-pre overflow-x-auto !rounded-t-none rounded-b-lg bg-black p-4 text-white",
789
+ "aui-md-pre overflow-x-auto rounded-t-none! rounded-b-lg bg-black p-4 text-white",
790
790
  className,
791
791
  )}
792
792
  {...props}
@@ -798,7 +798,7 @@ const defaultComponents = memoizeMarkdownComponents({
798
798
  <code
799
799
  className={cn(
800
800
  !isCodeBlock &&
801
- "aui-md-inline-code bg-muted rounded border font-semibold",
801
+ "aui-md-inline-code rounded border bg-muted font-semibold",
802
802
  className,
803
803
  )}
804
804
  {...props}
@@ -813,23 +813,27 @@ const defaultComponents = memoizeMarkdownComponents({
813
813
  ## components/assistant-ui/thread-list.tsx
814
814
 
815
815
  ```tsx
816
- import type { FC } from "react";
816
+ import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
817
+ import { Button } from "@/components/ui/button";
818
+ import { Skeleton } from "@/components/ui/skeleton";
817
819
  import {
820
+ AssistantIf,
818
821
  ThreadListItemPrimitive,
819
822
  ThreadListPrimitive,
820
- useAssistantState,
821
823
  } from "@assistant-ui/react";
822
824
  import { ArchiveIcon, PlusIcon } from "lucide-react";
823
-
824
- import { Button } from "@/components/ui/button";
825
- import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
826
- import { Skeleton } from "@/components/ui/skeleton";
825
+ import type { FC } from "react";
827
826
 
828
827
  export const ThreadList: FC = () => {
829
828
  return (
830
- <ThreadListPrimitive.Root className="aui-root aui-thread-list-root flex flex-col items-stretch gap-1.5">
829
+ <ThreadListPrimitive.Root className="aui-root aui-thread-list-root flex flex-col gap-1">
831
830
  <ThreadListNew />
832
- <ThreadListItems />
831
+ <AssistantIf condition={({ threads }) => threads.isLoading}>
832
+ <ThreadListSkeleton />
833
+ </AssistantIf>
834
+ <AssistantIf condition={({ threads }) => !threads.isLoading}>
835
+ <ThreadListPrimitive.Items components={{ ThreadListItem }} />
836
+ </AssistantIf>
833
837
  </ThreadListPrimitive.Root>
834
838
  );
835
839
  };
@@ -838,72 +842,53 @@ const ThreadListNew: FC = () => {
838
842
  return (
839
843
  <ThreadListPrimitive.New asChild>
840
844
  <Button
841
- className="aui-thread-list-new hover:bg-muted data-active:bg-muted flex items-center justify-start gap-1 rounded-lg px-2.5 py-2 text-start"
842
- variant="ghost"
845
+ variant="outline"
846
+ className="aui-thread-list-new h-9 justify-start gap-2 rounded-lg px-3 text-sm hover:bg-muted data-active:bg-muted"
843
847
  >
844
- <PlusIcon />
848
+ <PlusIcon className="size-4" />
845
849
  New Thread
846
850
  </Button>
847
851
  </ThreadListPrimitive.New>
848
852
  );
849
853
  };
850
854
 
851
- const ThreadListItems: FC = () => {
852
- const isLoading = useAssistantState(({ threads }) => threads.isLoading);
853
-
854
- if (isLoading) {
855
- return <ThreadListSkeleton />;
856
- }
857
-
858
- return <ThreadListPrimitive.Items components={{ ThreadListItem }} />;
859
- };
860
-
861
855
  const ThreadListSkeleton: FC = () => {
862
856
  return (
863
- <>
857
+ <div className="flex flex-col gap-1">
864
858
  {Array.from({ length: 5 }, (_, i) => (
865
859
  <div
866
860
  key={i}
867
861
  role="status"
868
862
  aria-label="Loading threads"
869
- aria-live="polite"
870
- className="aui-thread-list-skeleton-wrapper flex items-center gap-2 rounded-md px-3 py-2"
863
+ className="aui-thread-list-skeleton-wrapper flex h-9 items-center px-3"
871
864
  >
872
- <Skeleton className="aui-thread-list-skeleton h-[22px] flex-grow" />
865
+ <Skeleton className="aui-thread-list-skeleton h-4 w-full" />
873
866
  </div>
874
867
  ))}
875
- </>
868
+ </div>
876
869
  );
877
870
  };
878
871
 
879
872
  const ThreadListItem: FC = () => {
880
873
  return (
881
- <ThreadListItemPrimitive.Root className="aui-thread-list-item hover:bg-muted focus-visible:bg-muted focus-visible:ring-ring data-active:bg-muted flex items-center gap-2 rounded-lg transition-all focus-visible:ring-2 focus-visible:outline-none">
882
- <ThreadListItemPrimitive.Trigger className="aui-thread-list-item-trigger flex-grow px-3 py-2 text-start">
883
- <ThreadListItemTitle />
874
+ <ThreadListItemPrimitive.Root className="aui-thread-list-item group flex h-9 items-center rounded-lg transition-colors hover:bg-muted focus-visible:bg-muted focus-visible:outline-none data-active:bg-muted">
875
+ <ThreadListItemPrimitive.Trigger className="aui-thread-list-item-trigger flex h-full flex-1 items-center truncate px-3 text-start text-sm">
876
+ <ThreadListItemPrimitive.Title fallback="New Chat" />
884
877
  </ThreadListItemPrimitive.Trigger>
885
878
  <ThreadListItemArchive />
886
879
  </ThreadListItemPrimitive.Root>
887
880
  );
888
881
  };
889
882
 
890
- const ThreadListItemTitle: FC = () => {
891
- return (
892
- <span className="aui-thread-list-item-title text-sm">
893
- <ThreadListItemPrimitive.Title fallback="New Chat" />
894
- </span>
895
- );
896
- };
897
-
898
883
  const ThreadListItemArchive: FC = () => {
899
884
  return (
900
885
  <ThreadListItemPrimitive.Archive asChild>
901
886
  <TooltipIconButton
902
- className="aui-thread-list-item-archive text-foreground hover:text-primary mr-3 ml-auto size-4 p-0"
903
887
  variant="ghost"
904
888
  tooltip="Archive thread"
889
+ className="aui-thread-list-item-archive mr-2 size-7 p-0 opacity-0 transition-opacity group-hover:opacity-100"
905
890
  >
906
- <ArchiveIcon />
891
+ <ArchiveIcon className="size-4" />
907
892
  </TooltipIconButton>
908
893
  </ThreadListItemPrimitive.Archive>
909
894
  );
@@ -914,57 +899,67 @@ const ThreadListItemArchive: FC = () => {
914
899
  ## components/assistant-ui/thread.tsx
915
900
 
916
901
  ```tsx
902
+ import {
903
+ ComposerAddAttachment,
904
+ ComposerAttachments,
905
+ UserMessageAttachments,
906
+ } from "@/components/assistant-ui/attachment";
907
+ import { MarkdownText } from "@/components/assistant-ui/markdown-text";
908
+ import { ToolFallback } from "@/components/assistant-ui/tool-fallback";
909
+ import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
910
+ import { Button } from "@/components/ui/button";
911
+ import { cn } from "@/lib/utils";
917
912
  import {
918
913
  ActionBarPrimitive,
914
+ AssistantIf,
919
915
  BranchPickerPrimitive,
920
916
  ComposerPrimitive,
917
+ ErrorPrimitive,
921
918
  MessagePrimitive,
922
919
  ThreadPrimitive,
923
920
  } from "@assistant-ui/react";
924
- import type { FC } from "react";
925
921
  import {
926
922
  ArrowDownIcon,
923
+ ArrowUpIcon,
927
924
  CheckIcon,
928
925
  ChevronLeftIcon,
929
926
  ChevronRightIcon,
930
927
  CopyIcon,
928
+ DownloadIcon,
931
929
  PencilIcon,
932
930
  RefreshCwIcon,
933
- SendHorizontalIcon,
931
+ SquareIcon,
934
932
  } from "lucide-react";
935
- import { cn } from "@/lib/utils";
936
-
937
- import { Button } from "@/components/ui/button";
938
- import { MarkdownText } from "@/components/assistant-ui/markdown-text";
939
- import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
933
+ import type { FC } from "react";
940
934
 
941
935
  export const Thread: FC = () => {
942
936
  return (
943
937
  <ThreadPrimitive.Root
944
- className="bg-background box-border flex h-full flex-col overflow-hidden"
938
+ className="aui-root aui-thread-root @container flex h-full flex-col bg-background"
945
939
  style={{
946
- ["--thread-max-width" as string]: "42rem",
940
+ ["--thread-max-width" as string]: "44rem",
947
941
  }}
948
942
  >
949
- <ThreadPrimitive.Viewport className="flex h-full flex-col items-center overflow-y-scroll scroll-smooth bg-inherit px-4 pt-8">
950
- <ThreadWelcome />
943
+ <ThreadPrimitive.Viewport
944
+ turnAnchor="top"
945
+ className="aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-smooth px-4 pt-4"
946
+ >
947
+ <AssistantIf condition={({ thread }) => thread.isEmpty}>
948
+ <ThreadWelcome />
949
+ </AssistantIf>
951
950
 
952
951
  <ThreadPrimitive.Messages
953
952
  components={{
954
- UserMessage: UserMessage,
955
- EditComposer: EditComposer,
956
- AssistantMessage: AssistantMessage,
953
+ UserMessage,
954
+ EditComposer,
955
+ AssistantMessage,
957
956
  }}
958
957
  />
959
958
 
960
- <ThreadPrimitive.If empty={false}>
961
- <div className="min-h-8 flex-grow" />
962
- </ThreadPrimitive.If>
963
-
964
- <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">
959
+ <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">
965
960
  <ThreadScrollToBottom />
966
961
  <Composer />
967
- </div>
962
+ </ThreadPrimitive.ViewportFooter>
968
963
  </ThreadPrimitive.Viewport>
969
964
  </ThreadPrimitive.Root>
970
965
  );
@@ -976,7 +971,7 @@ const ThreadScrollToBottom: FC = () => {
976
971
  <TooltipIconButton
977
972
  tooltip="Scroll to bottom"
978
973
  variant="outline"
979
- className="absolute -top-8 rounded-full disabled:invisible"
974
+ 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"
980
975
  >
981
976
  <ArrowDownIcon />
982
977
  </TooltipIconButton>
@@ -986,175 +981,247 @@ const ThreadScrollToBottom: FC = () => {
986
981
 
987
982
  const ThreadWelcome: FC = () => {
988
983
  return (
989
- <ThreadPrimitive.Empty>
990
- <div className="flex w-full max-w-[var(--thread-max-width)] flex-grow flex-col">
991
- <div className="flex w-full flex-grow flex-col items-center justify-center">
992
- <p className="mt-4 font-medium">How can I help you today?</p>
984
+ <div className="aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col">
985
+ <div className="aui-thread-welcome-center flex w-full grow flex-col items-center justify-center">
986
+ <div className="aui-thread-welcome-message flex size-full flex-col justify-center px-4">
987
+ <h1 className="aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in font-semibold text-2xl duration-200">
988
+ Hello there!
989
+ </h1>
990
+ <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">
991
+ How can I help you today?
992
+ </p>
993
993
  </div>
994
- <ThreadWelcomeSuggestions />
995
994
  </div>
996
- </ThreadPrimitive.Empty>
995
+ <ThreadSuggestions />
996
+ </div>
997
997
  );
998
998
  };
999
999
 
1000
- const ThreadWelcomeSuggestions: FC = () => {
1000
+ const SUGGESTIONS = [
1001
+ {
1002
+ title: "What's the weather",
1003
+ label: "in San Francisco?",
1004
+ prompt: "What's the weather in San Francisco?",
1005
+ },
1006
+ {
1007
+ title: "Explain React hooks",
1008
+ label: "like useState and useEffect",
1009
+ prompt: "Explain React hooks like useState and useEffect",
1010
+ },
1011
+ ] as const;
1012
+
1013
+ const ThreadSuggestions: FC = () => {
1001
1014
  return (
1002
- <div className="mt-3 flex w-full items-stretch justify-center gap-4">
1003
- <ThreadPrimitive.Suggestion
1004
- className="hover:bg-muted/80 flex max-w-sm grow basis-0 flex-col items-center justify-center rounded-lg border p-3 transition-colors ease-in"
1005
- prompt="What is the weather in Tokyo?"
1006
- method="replace"
1007
- autoSend
1008
- >
1009
- <span className="line-clamp-2 text-sm font-semibold text-ellipsis">
1010
- What is the weather in Tokyo?
1011
- </span>
1012
- </ThreadPrimitive.Suggestion>
1013
- <ThreadPrimitive.Suggestion
1014
- className="hover:bg-muted/80 flex max-w-sm grow basis-0 flex-col items-center justify-center rounded-lg border p-3 transition-colors ease-in"
1015
- prompt="What is assistant-ui?"
1016
- method="replace"
1017
- autoSend
1018
- >
1019
- <span className="line-clamp-2 text-sm font-semibold text-ellipsis">
1020
- What is assistant-ui?
1021
- </span>
1022
- </ThreadPrimitive.Suggestion>
1015
+ <div className="aui-thread-welcome-suggestions grid w-full @md:grid-cols-2 gap-2 pb-4">
1016
+ {SUGGESTIONS.map((suggestion, index) => (
1017
+ <div
1018
+ key={suggestion.prompt}
1019
+ 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"
1020
+ style={{ animationDelay: `${100 + index * 50}ms` }}
1021
+ >
1022
+ <ThreadPrimitive.Suggestion prompt={suggestion.prompt} send asChild>
1023
+ <Button
1024
+ variant="ghost"
1025
+ 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"
1026
+ aria-label={suggestion.prompt}
1027
+ >
1028
+ <span className="aui-thread-welcome-suggestion-text-1 font-medium">
1029
+ {suggestion.title}
1030
+ </span>
1031
+ <span className="aui-thread-welcome-suggestion-text-2 text-muted-foreground">
1032
+ {suggestion.label}
1033
+ </span>
1034
+ </Button>
1035
+ </ThreadPrimitive.Suggestion>
1036
+ </div>
1037
+ ))}
1023
1038
  </div>
1024
1039
  );
1025
1040
  };
1026
1041
 
1027
1042
  const Composer: FC = () => {
1028
1043
  return (
1029
- <ComposerPrimitive.Root className="focus-within:border-ring/20 flex w-full flex-wrap items-end rounded-lg border bg-inherit px-2.5 shadow-sm transition-colors ease-in">
1030
- <ComposerPrimitive.Input
1031
- rows={1}
1032
- autoFocus
1033
- placeholder="Write a message..."
1034
- className="placeholder:text-muted-foreground max-h-40 flex-grow resize-none border-none bg-transparent px-2 py-4 text-sm outline-none focus:ring-0 disabled:cursor-not-allowed"
1035
- />
1036
- <ComposerAction />
1044
+ <ComposerPrimitive.Root className="aui-composer-root relative flex w-full flex-col">
1045
+ <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">
1046
+ <ComposerAttachments />
1047
+ <ComposerPrimitive.Input
1048
+ placeholder="Send a message..."
1049
+ 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"
1050
+ rows={1}
1051
+ autoFocus
1052
+ aria-label="Message input"
1053
+ />
1054
+ <ComposerAction />
1055
+ </ComposerPrimitive.AttachmentDropzone>
1037
1056
  </ComposerPrimitive.Root>
1038
1057
  );
1039
1058
  };
1040
1059
 
1041
1060
  const ComposerAction: FC = () => {
1042
1061
  return (
1043
- <>
1044
- <ThreadPrimitive.If running={false}>
1062
+ <div className="aui-composer-action-wrapper relative mx-2 mb-2 flex items-center justify-between">
1063
+ <ComposerAddAttachment />
1064
+
1065
+ <AssistantIf condition={({ thread }) => !thread.isRunning}>
1045
1066
  <ComposerPrimitive.Send asChild>
1046
1067
  <TooltipIconButton
1047
- tooltip="Send"
1068
+ tooltip="Send message"
1069
+ side="bottom"
1070
+ type="submit"
1048
1071
  variant="default"
1049
- className="my-2.5 size-8 p-2 transition-opacity ease-in"
1072
+ size="icon"
1073
+ className="aui-composer-send size-8 rounded-full"
1074
+ aria-label="Send message"
1050
1075
  >
1051
- <SendHorizontalIcon />
1076
+ <ArrowUpIcon className="aui-composer-send-icon size-4" />
1052
1077
  </TooltipIconButton>
1053
1078
  </ComposerPrimitive.Send>
1054
- </ThreadPrimitive.If>
1055
- <ThreadPrimitive.If running>
1079
+ </AssistantIf>
1080
+
1081
+ <AssistantIf condition={({ thread }) => thread.isRunning}>
1056
1082
  <ComposerPrimitive.Cancel asChild>
1057
- <TooltipIconButton
1058
- tooltip="Cancel"
1083
+ <Button
1084
+ type="button"
1059
1085
  variant="default"
1060
- className="my-2.5 size-8 p-2 transition-opacity ease-in"
1086
+ size="icon"
1087
+ className="aui-composer-cancel size-8 rounded-full"
1088
+ aria-label="Stop generating"
1061
1089
  >
1062
- <CircleStopIcon />
1063
- </TooltipIconButton>
1090
+ <SquareIcon className="aui-composer-cancel-icon size-3 fill-current" />
1091
+ </Button>
1064
1092
  </ComposerPrimitive.Cancel>
1065
- </ThreadPrimitive.If>
1066
- </>
1093
+ </AssistantIf>
1094
+ </div>
1067
1095
  );
1068
1096
  };
1069
1097
 
1070
- const UserMessage: FC = () => {
1098
+ const MessageError: FC = () => {
1071
1099
  return (
1072
- <MessagePrimitive.Root className="grid w-full max-w-[var(--thread-max-width)] auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] gap-y-2 py-4 [&:where(>*)]:col-start-2">
1073
- <UserActionBar />
1100
+ <MessagePrimitive.Error>
1101
+ <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">
1102
+ <ErrorPrimitive.Message className="aui-message-error-message line-clamp-2" />
1103
+ </ErrorPrimitive.Root>
1104
+ </MessagePrimitive.Error>
1105
+ );
1106
+ };
1074
1107
 
1075
- <div className="bg-muted text-foreground col-start-2 row-start-2 max-w-[calc(var(--thread-max-width)*0.8)] rounded-3xl px-5 py-2.5 break-words">
1076
- <MessagePrimitive.Parts />
1108
+ const AssistantMessage: FC = () => {
1109
+ return (
1110
+ <MessagePrimitive.Root
1111
+ 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"
1112
+ data-role="assistant"
1113
+ >
1114
+ <div className="aui-assistant-message-content wrap-break-word px-2 text-foreground leading-relaxed">
1115
+ <MessagePrimitive.Parts
1116
+ components={{
1117
+ Text: MarkdownText,
1118
+ tools: { Fallback: ToolFallback },
1119
+ }}
1120
+ />
1121
+ <MessageError />
1077
1122
  </div>
1078
1123
 
1079
- <BranchPicker className="col-span-full col-start-1 row-start-3 -mr-1 justify-end" />
1124
+ <div className="aui-assistant-message-footer mt-1 ml-2 flex">
1125
+ <BranchPicker />
1126
+ <AssistantActionBar />
1127
+ </div>
1080
1128
  </MessagePrimitive.Root>
1081
1129
  );
1082
1130
  };
1083
1131
 
1084
- const UserActionBar: FC = () => {
1132
+ const AssistantActionBar: FC = () => {
1085
1133
  return (
1086
1134
  <ActionBarPrimitive.Root
1087
1135
  hideWhenRunning
1088
1136
  autohide="not-last"
1089
- className="col-start-1 row-start-2 mt-2.5 mr-3 flex flex-col items-end"
1137
+ autohideFloat="single-branch"
1138
+ 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"
1090
1139
  >
1091
- <ActionBarPrimitive.Edit asChild>
1092
- <TooltipIconButton tooltip="Edit">
1093
- <PencilIcon />
1140
+ <ActionBarPrimitive.Copy asChild>
1141
+ <TooltipIconButton tooltip="Copy">
1142
+ <AssistantIf condition={({ message }) => message.isCopied}>
1143
+ <CheckIcon />
1144
+ </AssistantIf>
1145
+ <AssistantIf condition={({ message }) => !message.isCopied}>
1146
+ <CopyIcon />
1147
+ </AssistantIf>
1094
1148
  </TooltipIconButton>
1095
- </ActionBarPrimitive.Edit>
1149
+ </ActionBarPrimitive.Copy>
1150
+ <ActionBarPrimitive.ExportMarkdown asChild>
1151
+ <TooltipIconButton tooltip="Export as Markdown">
1152
+ <DownloadIcon />
1153
+ </TooltipIconButton>
1154
+ </ActionBarPrimitive.ExportMarkdown>
1155
+ <ActionBarPrimitive.Reload asChild>
1156
+ <TooltipIconButton tooltip="Refresh">
1157
+ <RefreshCwIcon />
1158
+ </TooltipIconButton>
1159
+ </ActionBarPrimitive.Reload>
1096
1160
  </ActionBarPrimitive.Root>
1097
1161
  );
1098
1162
  };
1099
1163
 
1100
- const EditComposer: FC = () => {
1164
+ const UserMessage: FC = () => {
1101
1165
  return (
1102
- <ComposerPrimitive.Root className="bg-muted my-4 flex w-full max-w-[var(--thread-max-width)] flex-col gap-2 rounded-xl">
1103
- <ComposerPrimitive.Input className="text-foreground flex h-8 w-full resize-none bg-transparent p-4 pb-0 outline-none" />
1104
-
1105
- <div className="mx-3 mb-3 flex items-center justify-center gap-2 self-end">
1106
- <ComposerPrimitive.Cancel asChild>
1107
- <Button variant="ghost">Cancel</Button>
1108
- </ComposerPrimitive.Cancel>
1109
- <ComposerPrimitive.Send asChild>
1110
- <Button>Send</Button>
1111
- </ComposerPrimitive.Send>
1112
- </div>
1113
- </ComposerPrimitive.Root>
1114
- );
1115
- };
1166
+ <MessagePrimitive.Root
1167
+ 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"
1168
+ data-role="user"
1169
+ >
1170
+ <UserMessageAttachments />
1116
1171
 
1117
- const AssistantMessage: FC = () => {
1118
- return (
1119
- <MessagePrimitive.Root className="relative grid w-full max-w-[var(--thread-max-width)] grid-cols-[auto_auto_1fr] grid-rows-[auto_1fr] py-4">
1120
- <div className="text-foreground col-span-2 col-start-2 row-start-1 my-1.5 max-w-[calc(var(--thread-max-width)*0.8)] leading-7 break-words">
1121
- <MessagePrimitive.Parts components={{ Text: MarkdownText }} />
1172
+ <div className="aui-user-message-content-wrapper relative col-start-2 min-w-0">
1173
+ <div className="aui-user-message-content wrap-break-word rounded-2xl bg-muted px-4 py-2.5 text-foreground">
1174
+ <MessagePrimitive.Parts />
1175
+ </div>
1176
+ <div className="aui-user-action-bar-wrapper -translate-x-full -translate-y-1/2 absolute top-1/2 left-0 pr-2">
1177
+ <UserActionBar />
1178
+ </div>
1122
1179
  </div>
1123
1180
 
1124
- <AssistantActionBar />
1125
-
1126
- <BranchPicker className="col-start-2 row-start-2 mr-2 -ml-2" />
1181
+ <BranchPicker className="aui-user-branch-picker -mr-1 col-span-full col-start-1 row-start-3 justify-end" />
1127
1182
  </MessagePrimitive.Root>
1128
1183
  );
1129
1184
  };
1130
1185
 
1131
- const AssistantActionBar: FC = () => {
1186
+ const UserActionBar: FC = () => {
1132
1187
  return (
1133
1188
  <ActionBarPrimitive.Root
1134
1189
  hideWhenRunning
1135
1190
  autohide="not-last"
1136
- autohideFloat="single-branch"
1137
- 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"
1191
+ className="aui-user-action-bar-root flex flex-col items-end"
1138
1192
  >
1139
- <ActionBarPrimitive.Copy asChild>
1140
- <TooltipIconButton tooltip="Copy">
1141
- <MessagePrimitive.If copied>
1142
- <CheckIcon />
1143
- </MessagePrimitive.If>
1144
- <MessagePrimitive.If copied={false}>
1145
- <CopyIcon />
1146
- </MessagePrimitive.If>
1147
- </TooltipIconButton>
1148
- </ActionBarPrimitive.Copy>
1149
- <ActionBarPrimitive.Reload asChild>
1150
- <TooltipIconButton tooltip="Refresh">
1151
- <RefreshCwIcon />
1193
+ <ActionBarPrimitive.Edit asChild>
1194
+ <TooltipIconButton tooltip="Edit" className="aui-user-action-edit p-4">
1195
+ <PencilIcon />
1152
1196
  </TooltipIconButton>
1153
- </ActionBarPrimitive.Reload>
1197
+ </ActionBarPrimitive.Edit>
1154
1198
  </ActionBarPrimitive.Root>
1155
1199
  );
1156
1200
  };
1157
1201
 
1202
+ const EditComposer: FC = () => {
1203
+ return (
1204
+ <MessagePrimitive.Root className="aui-edit-composer-wrapper mx-auto flex w-full max-w-(--thread-max-width) flex-col px-2 py-3">
1205
+ <ComposerPrimitive.Root className="aui-edit-composer-root ml-auto flex w-full max-w-[85%] flex-col rounded-2xl bg-muted">
1206
+ <ComposerPrimitive.Input
1207
+ className="aui-edit-composer-input min-h-14 w-full resize-none bg-transparent p-4 text-foreground text-sm outline-none"
1208
+ autoFocus
1209
+ />
1210
+ <div className="aui-edit-composer-footer mx-3 mb-3 flex items-center gap-2 self-end">
1211
+ <ComposerPrimitive.Cancel asChild>
1212
+ <Button variant="ghost" size="sm">
1213
+ Cancel
1214
+ </Button>
1215
+ </ComposerPrimitive.Cancel>
1216
+ <ComposerPrimitive.Send asChild>
1217
+ <Button size="sm">Update</Button>
1218
+ </ComposerPrimitive.Send>
1219
+ </div>
1220
+ </ComposerPrimitive.Root>
1221
+ </MessagePrimitive.Root>
1222
+ );
1223
+ };
1224
+
1158
1225
  const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
1159
1226
  className,
1160
1227
  ...rest
@@ -1163,7 +1230,7 @@ const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
1163
1230
  <BranchPickerPrimitive.Root
1164
1231
  hideWhenSingleBranch
1165
1232
  className={cn(
1166
- "text-muted-foreground inline-flex items-center text-xs",
1233
+ "aui-branch-picker-root -ml-2 mr-2 inline-flex items-center text-muted-foreground text-xs",
1167
1234
  className,
1168
1235
  )}
1169
1236
  {...rest}
@@ -1173,7 +1240,7 @@ const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
1173
1240
  <ChevronLeftIcon />
1174
1241
  </TooltipIconButton>
1175
1242
  </BranchPickerPrimitive.Previous>
1176
- <span className="font-medium">
1243
+ <span className="aui-branch-picker-state font-medium">
1177
1244
  <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
1178
1245
  </span>
1179
1246
  <BranchPickerPrimitive.Next asChild>
@@ -1185,20 +1252,6 @@ const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
1185
1252
  );
1186
1253
  };
1187
1254
 
1188
- const CircleStopIcon = () => {
1189
- return (
1190
- <svg
1191
- xmlns="http://www.w3.org/2000/svg"
1192
- viewBox="0 0 16 16"
1193
- fill="currentColor"
1194
- width="16"
1195
- height="16"
1196
- >
1197
- <rect width="10" height="10" x="3" y="3" rx="2" />
1198
- </svg>
1199
- );
1200
- };
1201
-
1202
1255
  ```
1203
1256
 
1204
1257
  ## components/assistant-ui/tool-fallback.tsx
@@ -1241,7 +1294,7 @@ export const ToolFallback: ToolCallMessagePartComponent = ({
1241
1294
  >
1242
1295
  <div className="aui-tool-fallback-header flex items-center gap-2 px-4">
1243
1296
  {isCancelled ? (
1244
- <XCircleIcon className="aui-tool-fallback-icon text-muted-foreground size-4" />
1297
+ <XCircleIcon className="aui-tool-fallback-icon size-4 text-muted-foreground" />
1245
1298
  ) : (
1246
1299
  <CheckIcon className="aui-tool-fallback-icon size-4" />
1247
1300
  )}
@@ -1262,7 +1315,7 @@ export const ToolFallback: ToolCallMessagePartComponent = ({
1262
1315
  <div className="aui-tool-fallback-content flex flex-col gap-2 border-t pt-2">
1263
1316
  {cancelledReason && (
1264
1317
  <div className="aui-tool-fallback-cancelled-root px-4">
1265
- <p className="aui-tool-fallback-cancelled-header text-muted-foreground font-semibold">
1318
+ <p className="aui-tool-fallback-cancelled-header font-semibold text-muted-foreground">
1266
1319
  Cancelled reason:
1267
1320
  </p>
1268
1321
  <p className="aui-tool-fallback-cancelled-reason text-muted-foreground">
@@ -1382,17 +1435,17 @@ export function PriceSnapshot({
1382
1435
  return (
1383
1436
  <Card className="mx-auto w-full max-w-md">
1384
1437
  <CardHeader>
1385
- <CardTitle className="text-2xl font-bold">{ticker}</CardTitle>
1438
+ <CardTitle className="font-bold text-2xl">{ticker}</CardTitle>
1386
1439
  </CardHeader>
1387
1440
  <CardContent>
1388
1441
  <div className="grid grid-cols-2 gap-4">
1389
1442
  <div className="col-span-2">
1390
- <p className="text-3xl font-semibold">${price?.toFixed(2)}</p>
1443
+ <p className="font-semibold text-3xl">${price?.toFixed(2)}</p>
1391
1444
  </div>
1392
1445
  <div>
1393
1446
  <p className="text-muted-foreground text-sm">Day Change</p>
1394
1447
  <p
1395
- className={`flex items-center text-lg font-medium ${changeColor}`}
1448
+ className={`flex items-center font-medium text-lg ${changeColor}`}
1396
1449
  >
1397
1450
  <ArrowIcon className="mr-1 h-4 w-4" />$
1398
1451
  {Math.abs(day_change)?.toFixed(2)} (
@@ -1401,7 +1454,7 @@ export function PriceSnapshot({
1401
1454
  </div>
1402
1455
  <div>
1403
1456
  <p className="text-muted-foreground text-sm">Last Updated</p>
1404
- <p className="text-lg font-medium">
1457
+ <p className="font-medium text-lg">
1405
1458
  {new Date(time).toLocaleTimeString()}
1406
1459
  </p>
1407
1460
  </div>
@@ -1530,13 +1583,13 @@ export function TransactionConfirmationFinal(props: TransactionConfirmation) {
1530
1583
  <Card className="mx-auto w-full max-w-md">
1531
1584
  <CardHeader className="text-center">
1532
1585
  <CheckCircle className="mx-auto mb-4 h-16 w-16 text-green-500" />
1533
- <CardTitle className="text-2xl font-bold text-green-700">
1586
+ <CardTitle className="font-bold text-2xl text-green-700">
1534
1587
  Transaction Confirmed
1535
1588
  </CardTitle>
1536
1589
  </CardHeader>
1537
1590
  <CardContent className="space-y-4">
1538
1591
  <div className="rounded-md border border-green-200 bg-green-50 p-4">
1539
- <h3 className="mb-2 text-lg font-semibold text-green-800">
1592
+ <h3 className="mb-2 font-semibold text-green-800 text-lg">
1540
1593
  Purchase Summary
1541
1594
  </h3>
1542
1595
  <div className="grid grid-cols-2 gap-2 text-sm">
@@ -1551,12 +1604,12 @@ export function TransactionConfirmationFinal(props: TransactionConfirmation) {
1551
1604
  </div>
1552
1605
  </div>
1553
1606
  <div className="rounded-md border border-green-300 bg-green-100 p-4">
1554
- <p className="text-lg font-semibold text-green-800">Total Cost:</p>
1555
- <p className="text-2xl font-bold text-green-900">
1607
+ <p className="font-semibold text-green-800 text-lg">Total Cost:</p>
1608
+ <p className="font-bold text-2xl text-green-900">
1556
1609
  ${(quantity * maxPurchasePrice)?.toFixed(2)}
1557
1610
  </p>
1558
1611
  </div>
1559
- <p className="text-center text-sm text-green-600">
1612
+ <p className="text-center text-green-600 text-sm">
1560
1613
  Your purchase of {quantity} shares of {companyName} ({ticker}) has
1561
1614
  been successfully processed.
1562
1615
  </p>
@@ -1597,26 +1650,26 @@ export function TransactionConfirmationPending(props: TransactionConfirmation) {
1597
1650
  return (
1598
1651
  <Card className="mx-auto w-full max-w-md">
1599
1652
  <CardHeader>
1600
- <CardTitle className="text-2xl font-bold">
1653
+ <CardTitle className="font-bold text-2xl">
1601
1654
  Confirm Transaction
1602
1655
  </CardTitle>
1603
1656
  </CardHeader>
1604
1657
  <CardContent className="space-y-4">
1605
1658
  <div className="grid grid-cols-2 gap-2">
1606
- <p className="text-muted-foreground text-sm font-medium">Ticker:</p>
1607
- <p className="text-sm font-bold">{ticker}</p>
1608
- <p className="text-muted-foreground text-sm font-medium">Company:</p>
1659
+ <p className="font-medium text-muted-foreground text-sm">Ticker:</p>
1660
+ <p className="font-bold text-sm">{ticker}</p>
1661
+ <p className="font-medium text-muted-foreground text-sm">Company:</p>
1609
1662
  <p className="text-sm">{companyName}</p>
1610
- <p className="text-muted-foreground text-sm font-medium">Quantity:</p>
1663
+ <p className="font-medium text-muted-foreground text-sm">Quantity:</p>
1611
1664
  <p className="text-sm">{quantity} shares</p>
1612
- <p className="text-muted-foreground text-sm font-medium">
1665
+ <p className="font-medium text-muted-foreground text-sm">
1613
1666
  Max Purchase Price:
1614
1667
  </p>
1615
1668
  <p className="text-sm">${maxPurchasePrice?.toFixed(2)}</p>
1616
1669
  </div>
1617
- <div className="bg-muted rounded-md p-3">
1618
- <p className="text-sm font-medium">Total Maximum Cost:</p>
1619
- <p className="text-lg font-bold">
1670
+ <div className="rounded-md bg-muted p-3">
1671
+ <p className="font-medium text-sm">Total Maximum Cost:</p>
1672
+ <p className="font-bold text-lg">
1620
1673
  ${(quantity * maxPurchasePrice)?.toFixed(2)}
1621
1674
  </p>
1622
1675
  </div>
@@ -1643,7 +1696,7 @@ export function TransactionConfirmationPending(props: TransactionConfirmation) {
1643
1696
  import { ToolCallMessagePartComponent } from "@assistant-ui/react";
1644
1697
  import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
1645
1698
  import { useState } from "react";
1646
- import { Button } from "../ui/button";
1699
+ import { Button } from "@/components/ui/button";
1647
1700
 
1648
1701
  export const ToolFallback: ToolCallMessagePartComponent = ({
1649
1702
  toolName,
@@ -1730,7 +1783,7 @@ const AvatarFallback = React.forwardRef<
1730
1783
  <AvatarPrimitive.Fallback
1731
1784
  ref={ref}
1732
1785
  className={cn(
1733
- "bg-muted flex h-full w-full items-center justify-center rounded-full",
1786
+ "flex h-full w-full items-center justify-center rounded-full bg-muted",
1734
1787
  className,
1735
1788
  )}
1736
1789
  {...props}
@@ -1752,7 +1805,7 @@ import { cva, type VariantProps } from "class-variance-authority";
1752
1805
  import { cn } from "@/lib/utils";
1753
1806
 
1754
1807
  const buttonVariants = cva(
1755
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
1808
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md font-medium text-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
1756
1809
  {
1757
1810
  variants: {
1758
1811
  variant: {
@@ -1819,7 +1872,7 @@ const Card = React.forwardRef<
1819
1872
  <div
1820
1873
  ref={ref}
1821
1874
  className={cn(
1822
- "bg-card text-card-foreground rounded-xl border shadow",
1875
+ "rounded-xl border bg-card text-card-foreground shadow",
1823
1876
  className,
1824
1877
  )}
1825
1878
  {...props}
@@ -1845,7 +1898,7 @@ const CardTitle = React.forwardRef<
1845
1898
  >(({ className, ...props }, ref) => (
1846
1899
  <div
1847
1900
  ref={ref}
1848
- className={cn("leading-none font-semibold tracking-tight", className)}
1901
+ className={cn("font-semibold leading-none tracking-tight", className)}
1849
1902
  {...props}
1850
1903
  />
1851
1904
  ));
@@ -1937,7 +1990,7 @@ function DialogOverlay({
1937
1990
  <DialogPrimitive.Overlay
1938
1991
  data-slot="dialog-overlay"
1939
1992
  className={cn(
1940
- "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",
1993
+ "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",
1941
1994
  className,
1942
1995
  )}
1943
1996
  {...props}
@@ -1956,13 +2009,13 @@ function DialogContent({
1956
2009
  <DialogPrimitive.Content
1957
2010
  data-slot="dialog-content"
1958
2011
  className={cn(
1959
- "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",
2012
+ "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",
1960
2013
  className,
1961
2014
  )}
1962
2015
  {...props}
1963
2016
  >
1964
2017
  {children}
1965
- <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">
2018
+ <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">
1966
2019
  <XIcon />
1967
2020
  <span className="sr-only">Close</span>
1968
2021
  </DialogPrimitive.Close>
@@ -2001,7 +2054,7 @@ function DialogTitle({
2001
2054
  return (
2002
2055
  <DialogPrimitive.Title
2003
2056
  data-slot="dialog-title"
2004
- className={cn("text-lg leading-none font-semibold", className)}
2057
+ className={cn("font-semibold text-lg leading-none", className)}
2005
2058
  {...props}
2006
2059
  />
2007
2060
  );
@@ -2044,7 +2097,7 @@ function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
2044
2097
  return (
2045
2098
  <div
2046
2099
  data-slot="skeleton"
2047
- className={cn("bg-accent animate-pulse rounded-md", className)}
2100
+ className={cn("animate-pulse rounded-md bg-accent", className)}
2048
2101
  {...props}
2049
2102
  />
2050
2103
  );
@@ -2105,13 +2158,13 @@ function TooltipContent({
2105
2158
  data-slot="tooltip-content"
2106
2159
  sideOffset={sideOffset}
2107
2160
  className={cn(
2108
- "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out 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) rounded-md px-3 py-1.5 text-xs text-balance",
2161
+ "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",
2109
2162
  className,
2110
2163
  )}
2111
2164
  {...props}
2112
2165
  >
2113
2166
  {children}
2114
- <TooltipPrimitive.Arrow className="bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
2167
+ <TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-primary fill-primary" />
2115
2168
  </TooltipPrimitive.Content>
2116
2169
  </TooltipPrimitive.Portal>
2117
2170
  );
@@ -2240,32 +2293,30 @@ export default nextConfig;
2240
2293
  "scripts": {
2241
2294
  "dev": "next dev --turbo",
2242
2295
  "build": "next build",
2243
- "start": "next start",
2244
- "lint": "eslint ."
2296
+ "start": "next start"
2245
2297
  },
2246
2298
  "dependencies": {
2247
2299
  "@assistant-ui/react": "workspace:*",
2248
2300
  "@assistant-ui/react-langgraph": "workspace:*",
2249
2301
  "@assistant-ui/react-markdown": "workspace:*",
2250
- "@langchain/langgraph-sdk": "^1.0.2",
2251
- "@radix-ui/react-avatar": "^1.1.4",
2252
- "@radix-ui/react-dialog": "^1.1.7",
2302
+ "@langchain/langgraph-sdk": "^1.2.0",
2303
+ "@radix-ui/react-avatar": "^1.1.11",
2304
+ "@radix-ui/react-dialog": "^1.1.15",
2253
2305
  "@radix-ui/react-slot": "^1.2.4",
2254
2306
  "@radix-ui/react-tooltip": "^1.2.8",
2255
2307
  "class-variance-authority": "^0.7.1",
2256
2308
  "clsx": "^2.1.1",
2257
2309
  "js-cookie": "^3.0.5",
2258
- "jsonwebtoken": "^9.0.2",
2259
- "lucide-react": "^0.555.0",
2260
- "motion": "^11.18.2",
2310
+ "jsonwebtoken": "^9.0.3",
2311
+ "lucide-react": "^0.556.0",
2261
2312
  "nanoid": "5.1.6",
2262
- "next": "16.0.4",
2263
- "react": "19.2.0",
2264
- "react-dom": "19.2.0",
2313
+ "next": "16.0.7",
2314
+ "react": "19.2.1",
2315
+ "react-dom": "19.2.1",
2265
2316
  "remark-gfm": "^4.0.1",
2266
2317
  "tailwind-merge": "^3.4.0",
2267
2318
  "tw-animate-css": "^1.4.0",
2268
- "zustand": "^5.0.8"
2319
+ "zustand": "^5.0.9"
2269
2320
  },
2270
2321
  "devDependencies": {
2271
2322
  "@assistant-ui/x-buildutils": "workspace:*",