@assistant-ui/mcp-docs-server 0.1.14 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.docs/organized/code-examples/store-example.md +628 -0
- package/.docs/organized/code-examples/with-ag-ui.md +792 -178
- package/.docs/organized/code-examples/with-ai-sdk-v5.md +762 -209
- package/.docs/organized/code-examples/with-assistant-transport.md +707 -254
- package/.docs/organized/code-examples/with-cloud.md +848 -202
- package/.docs/organized/code-examples/with-custom-thread-list.md +1855 -0
- package/.docs/organized/code-examples/with-external-store.md +788 -172
- package/.docs/organized/code-examples/with-ffmpeg.md +796 -196
- package/.docs/organized/code-examples/with-langgraph.md +864 -230
- package/.docs/organized/code-examples/with-parent-id-grouping.md +785 -255
- package/.docs/organized/code-examples/with-react-hook-form.md +804 -226
- package/.docs/organized/code-examples/with-tanstack.md +1574 -0
- package/.docs/raw/blog/2024-07-29-hello/index.mdx +2 -3
- package/.docs/raw/docs/api-reference/overview.mdx +6 -6
- package/.docs/raw/docs/api-reference/primitives/ActionBar.mdx +85 -4
- package/.docs/raw/docs/api-reference/primitives/AssistantIf.mdx +200 -0
- package/.docs/raw/docs/api-reference/primitives/Composer.mdx +0 -20
- package/.docs/raw/docs/api-reference/primitives/Message.mdx +0 -45
- package/.docs/raw/docs/api-reference/primitives/Thread.mdx +0 -50
- package/.docs/raw/docs/cli.mdx +396 -0
- package/.docs/raw/docs/cloud/persistence/ai-sdk.mdx +2 -3
- package/.docs/raw/docs/cloud/persistence/langgraph.mdx +2 -3
- package/.docs/raw/docs/devtools.mdx +2 -3
- package/.docs/raw/docs/getting-started.mdx +37 -1109
- package/.docs/raw/docs/guides/Attachments.mdx +3 -25
- package/.docs/raw/docs/guides/Branching.mdx +1 -1
- package/.docs/raw/docs/guides/Speech.mdx +1 -1
- package/.docs/raw/docs/guides/ToolUI.mdx +1 -1
- package/.docs/raw/docs/legacy/styled/AssistantModal.mdx +2 -3
- package/.docs/raw/docs/legacy/styled/Decomposition.mdx +6 -5
- package/.docs/raw/docs/legacy/styled/Markdown.mdx +2 -3
- package/.docs/raw/docs/legacy/styled/Thread.mdx +2 -3
- package/.docs/raw/docs/react-compatibility.mdx +2 -5
- package/.docs/raw/docs/runtimes/ai-sdk/use-chat.mdx +3 -4
- package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +3 -6
- package/.docs/raw/docs/runtimes/assistant-transport.mdx +891 -0
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +2 -3
- package/.docs/raw/docs/runtimes/custom/local.mdx +11 -41
- package/.docs/raw/docs/runtimes/data-stream.mdx +15 -11
- package/.docs/raw/docs/runtimes/langgraph/index.mdx +4 -4
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +1 -1
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +2 -3
- package/.docs/raw/docs/runtimes/langserve.mdx +2 -3
- package/.docs/raw/docs/runtimes/mastra/full-stack-integration.mdx +2 -3
- package/.docs/raw/docs/runtimes/mastra/separate-server-integration.mdx +2 -3
- package/.docs/raw/docs/ui/AssistantModal.mdx +3 -25
- package/.docs/raw/docs/ui/AssistantSidebar.mdx +2 -24
- package/.docs/raw/docs/ui/Attachment.mdx +3 -25
- package/.docs/raw/docs/ui/Markdown.mdx +2 -24
- package/.docs/raw/docs/ui/Mermaid.mdx +2 -24
- package/.docs/raw/docs/ui/Reasoning.mdx +2 -24
- package/.docs/raw/docs/ui/Scrollbar.mdx +4 -6
- package/.docs/raw/docs/ui/SyntaxHighlighting.mdx +3 -47
- package/.docs/raw/docs/ui/Thread.mdx +38 -53
- package/.docs/raw/docs/ui/ThreadList.mdx +4 -47
- package/.docs/raw/docs/ui/ToolFallback.mdx +2 -24
- package/package.json +15 -8
|
@@ -335,6 +335,247 @@ export default function Home() {
|
|
|
335
335
|
|
|
336
336
|
```
|
|
337
337
|
|
|
338
|
+
## components/assistant-ui/attachment.tsx
|
|
339
|
+
|
|
340
|
+
```tsx
|
|
341
|
+
"use client";
|
|
342
|
+
|
|
343
|
+
import { PropsWithChildren, useEffect, useState, type FC } from "react";
|
|
344
|
+
import Image from "next/image";
|
|
345
|
+
import { XIcon, PlusIcon, FileText } from "lucide-react";
|
|
346
|
+
import {
|
|
347
|
+
AttachmentPrimitive,
|
|
348
|
+
ComposerPrimitive,
|
|
349
|
+
MessagePrimitive,
|
|
350
|
+
useAssistantState,
|
|
351
|
+
useAssistantApi,
|
|
352
|
+
} from "@assistant-ui/react";
|
|
353
|
+
import { useShallow } from "zustand/shallow";
|
|
354
|
+
import {
|
|
355
|
+
Tooltip,
|
|
356
|
+
TooltipContent,
|
|
357
|
+
TooltipTrigger,
|
|
358
|
+
} from "@/components/ui/tooltip";
|
|
359
|
+
import {
|
|
360
|
+
Dialog,
|
|
361
|
+
DialogTitle,
|
|
362
|
+
DialogContent,
|
|
363
|
+
DialogTrigger,
|
|
364
|
+
} from "@/components/ui/dialog";
|
|
365
|
+
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
|
|
366
|
+
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
367
|
+
import { cn } from "@/lib/utils";
|
|
368
|
+
|
|
369
|
+
const useFileSrc = (file: File | undefined) => {
|
|
370
|
+
const [src, setSrc] = useState<string | undefined>(undefined);
|
|
371
|
+
|
|
372
|
+
useEffect(() => {
|
|
373
|
+
if (!file) {
|
|
374
|
+
setSrc(undefined);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const objectUrl = URL.createObjectURL(file);
|
|
379
|
+
setSrc(objectUrl);
|
|
380
|
+
|
|
381
|
+
return () => {
|
|
382
|
+
URL.revokeObjectURL(objectUrl);
|
|
383
|
+
};
|
|
384
|
+
}, [file]);
|
|
385
|
+
|
|
386
|
+
return src;
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
const useAttachmentSrc = () => {
|
|
390
|
+
const { file, src } = useAssistantState(
|
|
391
|
+
useShallow(({ attachment }): { file?: File; src?: string } => {
|
|
392
|
+
if (attachment.type !== "image") return {};
|
|
393
|
+
if (attachment.file) return { file: attachment.file };
|
|
394
|
+
const src = attachment.content?.filter((c) => c.type === "image")[0]
|
|
395
|
+
?.image;
|
|
396
|
+
if (!src) return {};
|
|
397
|
+
return { src };
|
|
398
|
+
}),
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
return useFileSrc(file) ?? src;
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
type AttachmentPreviewProps = {
|
|
405
|
+
src: string;
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
const AttachmentPreview: FC<AttachmentPreviewProps> = ({ src }) => {
|
|
409
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
410
|
+
return (
|
|
411
|
+
<Image
|
|
412
|
+
src={src}
|
|
413
|
+
alt="Image Preview"
|
|
414
|
+
width={1}
|
|
415
|
+
height={1}
|
|
416
|
+
className={
|
|
417
|
+
isLoaded
|
|
418
|
+
? "aui-attachment-preview-image-loaded block h-auto max-h-[80vh] w-auto max-w-full object-contain"
|
|
419
|
+
: "aui-attachment-preview-image-loading hidden"
|
|
420
|
+
}
|
|
421
|
+
onLoadingComplete={() => setIsLoaded(true)}
|
|
422
|
+
priority={false}
|
|
423
|
+
/>
|
|
424
|
+
);
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
const AttachmentPreviewDialog: FC<PropsWithChildren> = ({ children }) => {
|
|
428
|
+
const src = useAttachmentSrc();
|
|
429
|
+
|
|
430
|
+
if (!src) return children;
|
|
431
|
+
|
|
432
|
+
return (
|
|
433
|
+
<Dialog>
|
|
434
|
+
<DialogTrigger
|
|
435
|
+
className="aui-attachment-preview-trigger cursor-pointer transition-colors hover:bg-accent/50"
|
|
436
|
+
asChild
|
|
437
|
+
>
|
|
438
|
+
{children}
|
|
439
|
+
</DialogTrigger>
|
|
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
|
+
<DialogTitle className="aui-sr-only sr-only">
|
|
442
|
+
Image Attachment Preview
|
|
443
|
+
</DialogTitle>
|
|
444
|
+
<div className="aui-attachment-preview relative mx-auto flex max-h-[80dvh] w-full items-center justify-center overflow-hidden bg-background">
|
|
445
|
+
<AttachmentPreview src={src} />
|
|
446
|
+
</div>
|
|
447
|
+
</DialogContent>
|
|
448
|
+
</Dialog>
|
|
449
|
+
);
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
const AttachmentThumb: FC = () => {
|
|
453
|
+
const isImage = useAssistantState(
|
|
454
|
+
({ attachment }) => attachment.type === "image",
|
|
455
|
+
);
|
|
456
|
+
const src = useAttachmentSrc();
|
|
457
|
+
|
|
458
|
+
return (
|
|
459
|
+
<Avatar className="aui-attachment-tile-avatar h-full w-full rounded-none">
|
|
460
|
+
<AvatarImage
|
|
461
|
+
src={src}
|
|
462
|
+
alt="Attachment preview"
|
|
463
|
+
className="aui-attachment-tile-image object-cover"
|
|
464
|
+
/>
|
|
465
|
+
<AvatarFallback delayMs={isImage ? 200 : 0}>
|
|
466
|
+
<FileText className="aui-attachment-tile-fallback-icon size-8 text-muted-foreground" />
|
|
467
|
+
</AvatarFallback>
|
|
468
|
+
</Avatar>
|
|
469
|
+
);
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
const AttachmentUI: FC = () => {
|
|
473
|
+
const api = useAssistantApi();
|
|
474
|
+
const isComposer = api.attachment.source === "composer";
|
|
475
|
+
|
|
476
|
+
const isImage = useAssistantState(
|
|
477
|
+
({ attachment }) => attachment.type === "image",
|
|
478
|
+
);
|
|
479
|
+
const typeLabel = useAssistantState(({ attachment }) => {
|
|
480
|
+
const type = attachment.type;
|
|
481
|
+
switch (type) {
|
|
482
|
+
case "image":
|
|
483
|
+
return "Image";
|
|
484
|
+
case "document":
|
|
485
|
+
return "Document";
|
|
486
|
+
case "file":
|
|
487
|
+
return "File";
|
|
488
|
+
default:
|
|
489
|
+
const _exhaustiveCheck: never = type;
|
|
490
|
+
throw new Error(`Unknown attachment type: ${_exhaustiveCheck}`);
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
return (
|
|
495
|
+
<Tooltip>
|
|
496
|
+
<AttachmentPrimitive.Root
|
|
497
|
+
className={cn(
|
|
498
|
+
"aui-attachment-root relative",
|
|
499
|
+
isImage &&
|
|
500
|
+
"aui-attachment-root-composer only:[&>#attachment-tile]:size-24",
|
|
501
|
+
)}
|
|
502
|
+
>
|
|
503
|
+
<AttachmentPreviewDialog>
|
|
504
|
+
<TooltipTrigger asChild>
|
|
505
|
+
<div
|
|
506
|
+
className={cn(
|
|
507
|
+
"aui-attachment-tile size-14 cursor-pointer overflow-hidden rounded-[14px] border bg-muted transition-opacity hover:opacity-75",
|
|
508
|
+
isComposer &&
|
|
509
|
+
"aui-attachment-tile-composer border-foreground/20",
|
|
510
|
+
)}
|
|
511
|
+
role="button"
|
|
512
|
+
id="attachment-tile"
|
|
513
|
+
aria-label={`${typeLabel} attachment`}
|
|
514
|
+
>
|
|
515
|
+
<AttachmentThumb />
|
|
516
|
+
</div>
|
|
517
|
+
</TooltipTrigger>
|
|
518
|
+
</AttachmentPreviewDialog>
|
|
519
|
+
{isComposer && <AttachmentRemove />}
|
|
520
|
+
</AttachmentPrimitive.Root>
|
|
521
|
+
<TooltipContent side="top">
|
|
522
|
+
<AttachmentPrimitive.Name />
|
|
523
|
+
</TooltipContent>
|
|
524
|
+
</Tooltip>
|
|
525
|
+
);
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
const AttachmentRemove: FC = () => {
|
|
529
|
+
return (
|
|
530
|
+
<AttachmentPrimitive.Remove asChild>
|
|
531
|
+
<TooltipIconButton
|
|
532
|
+
tooltip="Remove file"
|
|
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
|
+
side="top"
|
|
535
|
+
>
|
|
536
|
+
<XIcon className="aui-attachment-remove-icon size-3 dark:stroke-[2.5px]" />
|
|
537
|
+
</TooltipIconButton>
|
|
538
|
+
</AttachmentPrimitive.Remove>
|
|
539
|
+
);
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
export const UserMessageAttachments: FC = () => {
|
|
543
|
+
return (
|
|
544
|
+
<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">
|
|
545
|
+
<MessagePrimitive.Attachments components={{ Attachment: AttachmentUI }} />
|
|
546
|
+
</div>
|
|
547
|
+
);
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
export const ComposerAttachments: FC = () => {
|
|
551
|
+
return (
|
|
552
|
+
<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">
|
|
553
|
+
<ComposerPrimitive.Attachments
|
|
554
|
+
components={{ Attachment: AttachmentUI }}
|
|
555
|
+
/>
|
|
556
|
+
</div>
|
|
557
|
+
);
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
export const ComposerAddAttachment: FC = () => {
|
|
561
|
+
return (
|
|
562
|
+
<ComposerPrimitive.AddAttachment asChild>
|
|
563
|
+
<TooltipIconButton
|
|
564
|
+
tooltip="Add Attachment"
|
|
565
|
+
side="bottom"
|
|
566
|
+
variant="ghost"
|
|
567
|
+
size="icon"
|
|
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
|
+
aria-label="Add Attachment"
|
|
570
|
+
>
|
|
571
|
+
<PlusIcon className="aui-attachment-add-icon size-5 stroke-[1.5px]" />
|
|
572
|
+
</TooltipIconButton>
|
|
573
|
+
</ComposerPrimitive.AddAttachment>
|
|
574
|
+
);
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
```
|
|
578
|
+
|
|
338
579
|
## components/assistant-ui/markdown-text.tsx
|
|
339
580
|
|
|
340
581
|
```tsx
|
|
@@ -343,13 +584,13 @@ export default function Home() {
|
|
|
343
584
|
import "@assistant-ui/react-markdown/styles/dot.css";
|
|
344
585
|
|
|
345
586
|
import {
|
|
346
|
-
CodeHeaderProps,
|
|
587
|
+
type CodeHeaderProps,
|
|
347
588
|
MarkdownTextPrimitive,
|
|
348
589
|
unstable_memoizeMarkdownComponents as memoizeMarkdownComponents,
|
|
349
590
|
useIsMarkdownCodeBlock,
|
|
350
591
|
} from "@assistant-ui/react-markdown";
|
|
351
592
|
import remarkGfm from "remark-gfm";
|
|
352
|
-
import { FC, memo, useState } from "react";
|
|
593
|
+
import { type FC, memo, useState } from "react";
|
|
353
594
|
import { CheckIcon, CopyIcon } from "lucide-react";
|
|
354
595
|
|
|
355
596
|
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
@@ -375,8 +616,10 @@ const CodeHeader: FC<CodeHeaderProps> = ({ language, code }) => {
|
|
|
375
616
|
};
|
|
376
617
|
|
|
377
618
|
return (
|
|
378
|
-
<div className="flex items-center justify-between gap-4 rounded-t-lg bg-
|
|
379
|
-
<span className="lowercase [&>span]:text-xs">
|
|
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
|
+
<span className="aui-code-header-language lowercase [&>span]:text-xs">
|
|
621
|
+
{language}
|
|
622
|
+
</span>
|
|
380
623
|
<TooltipIconButton tooltip="Copy" onClick={onCopy}>
|
|
381
624
|
{!isCopied && <CopyIcon />}
|
|
382
625
|
{isCopied && <CheckIcon />}
|
|
@@ -408,7 +651,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
408
651
|
h1: ({ className, ...props }) => (
|
|
409
652
|
<h1
|
|
410
653
|
className={cn(
|
|
411
|
-
"mb-8 scroll-m-20 text-4xl
|
|
654
|
+
"aui-md-h1 mb-8 scroll-m-20 font-extrabold text-4xl tracking-tight last:mb-0",
|
|
412
655
|
className,
|
|
413
656
|
)}
|
|
414
657
|
{...props}
|
|
@@ -417,7 +660,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
417
660
|
h2: ({ className, ...props }) => (
|
|
418
661
|
<h2
|
|
419
662
|
className={cn(
|
|
420
|
-
"mt-8 mb-4 scroll-m-20 text-3xl
|
|
663
|
+
"aui-md-h2 mt-8 mb-4 scroll-m-20 font-semibold text-3xl tracking-tight first:mt-0 last:mb-0",
|
|
421
664
|
className,
|
|
422
665
|
)}
|
|
423
666
|
{...props}
|
|
@@ -426,7 +669,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
426
669
|
h3: ({ className, ...props }) => (
|
|
427
670
|
<h3
|
|
428
671
|
className={cn(
|
|
429
|
-
"mt-6 mb-4 scroll-m-20 text-2xl
|
|
672
|
+
"aui-md-h3 mt-6 mb-4 scroll-m-20 font-semibold text-2xl tracking-tight first:mt-0 last:mb-0",
|
|
430
673
|
className,
|
|
431
674
|
)}
|
|
432
675
|
{...props}
|
|
@@ -435,7 +678,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
435
678
|
h4: ({ className, ...props }) => (
|
|
436
679
|
<h4
|
|
437
680
|
className={cn(
|
|
438
|
-
"mt-6 mb-4 scroll-m-20 text-xl
|
|
681
|
+
"aui-md-h4 mt-6 mb-4 scroll-m-20 font-semibold text-xl tracking-tight first:mt-0 last:mb-0",
|
|
439
682
|
className,
|
|
440
683
|
)}
|
|
441
684
|
{...props}
|
|
@@ -444,7 +687,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
444
687
|
h5: ({ className, ...props }) => (
|
|
445
688
|
<h5
|
|
446
689
|
className={cn(
|
|
447
|
-
"my-4 text-lg
|
|
690
|
+
"aui-md-h5 my-4 font-semibold text-lg first:mt-0 last:mb-0",
|
|
448
691
|
className,
|
|
449
692
|
)}
|
|
450
693
|
{...props}
|
|
@@ -452,20 +695,26 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
452
695
|
),
|
|
453
696
|
h6: ({ className, ...props }) => (
|
|
454
697
|
<h6
|
|
455
|
-
className={cn(
|
|
698
|
+
className={cn(
|
|
699
|
+
"aui-md-h6 my-4 font-semibold first:mt-0 last:mb-0",
|
|
700
|
+
className,
|
|
701
|
+
)}
|
|
456
702
|
{...props}
|
|
457
703
|
/>
|
|
458
704
|
),
|
|
459
705
|
p: ({ className, ...props }) => (
|
|
460
706
|
<p
|
|
461
|
-
className={cn(
|
|
707
|
+
className={cn(
|
|
708
|
+
"aui-md-p mt-5 mb-5 leading-7 first:mt-0 last:mb-0",
|
|
709
|
+
className,
|
|
710
|
+
)}
|
|
462
711
|
{...props}
|
|
463
712
|
/>
|
|
464
713
|
),
|
|
465
714
|
a: ({ className, ...props }) => (
|
|
466
715
|
<a
|
|
467
716
|
className={cn(
|
|
468
|
-
"
|
|
717
|
+
"aui-md-a font-medium text-primary underline underline-offset-4",
|
|
469
718
|
className,
|
|
470
719
|
)}
|
|
471
720
|
{...props}
|
|
@@ -473,29 +722,29 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
473
722
|
),
|
|
474
723
|
blockquote: ({ className, ...props }) => (
|
|
475
724
|
<blockquote
|
|
476
|
-
className={cn("border-l-2 pl-6 italic", className)}
|
|
725
|
+
className={cn("aui-md-blockquote border-l-2 pl-6 italic", className)}
|
|
477
726
|
{...props}
|
|
478
727
|
/>
|
|
479
728
|
),
|
|
480
729
|
ul: ({ className, ...props }) => (
|
|
481
730
|
<ul
|
|
482
|
-
className={cn("my-5 ml-6 list-disc [&>li]:mt-2", className)}
|
|
731
|
+
className={cn("aui-md-ul my-5 ml-6 list-disc [&>li]:mt-2", className)}
|
|
483
732
|
{...props}
|
|
484
733
|
/>
|
|
485
734
|
),
|
|
486
735
|
ol: ({ className, ...props }) => (
|
|
487
736
|
<ol
|
|
488
|
-
className={cn("my-5 ml-6 list-decimal [&>li]:mt-2", className)}
|
|
737
|
+
className={cn("aui-md-ol my-5 ml-6 list-decimal [&>li]:mt-2", className)}
|
|
489
738
|
{...props}
|
|
490
739
|
/>
|
|
491
740
|
),
|
|
492
741
|
hr: ({ className, ...props }) => (
|
|
493
|
-
<hr className={cn("my-5 border-b", className)} {...props} />
|
|
742
|
+
<hr className={cn("aui-md-hr my-5 border-b", className)} {...props} />
|
|
494
743
|
),
|
|
495
744
|
table: ({ className, ...props }) => (
|
|
496
745
|
<table
|
|
497
746
|
className={cn(
|
|
498
|
-
"my-5 w-full border-separate border-spacing-0 overflow-y-auto",
|
|
747
|
+
"aui-md-table my-5 w-full border-separate border-spacing-0 overflow-y-auto",
|
|
499
748
|
className,
|
|
500
749
|
)}
|
|
501
750
|
{...props}
|
|
@@ -504,7 +753,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
504
753
|
th: ({ className, ...props }) => (
|
|
505
754
|
<th
|
|
506
755
|
className={cn(
|
|
507
|
-
"bg-muted px-4 py-2 text-left font-bold first:rounded-tl-lg last:rounded-tr-lg [
|
|
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",
|
|
508
757
|
className,
|
|
509
758
|
)}
|
|
510
759
|
{...props}
|
|
@@ -513,7 +762,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
513
762
|
td: ({ className, ...props }) => (
|
|
514
763
|
<td
|
|
515
764
|
className={cn(
|
|
516
|
-
"border-b border-l px-4 py-2 text-left last:border-r [
|
|
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",
|
|
517
766
|
className,
|
|
518
767
|
)}
|
|
519
768
|
{...props}
|
|
@@ -522,7 +771,7 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
522
771
|
tr: ({ className, ...props }) => (
|
|
523
772
|
<tr
|
|
524
773
|
className={cn(
|
|
525
|
-
"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",
|
|
774
|
+
"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",
|
|
526
775
|
className,
|
|
527
776
|
)}
|
|
528
777
|
{...props}
|
|
@@ -530,14 +779,14 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
530
779
|
),
|
|
531
780
|
sup: ({ className, ...props }) => (
|
|
532
781
|
<sup
|
|
533
|
-
className={cn("[&>a]:text-xs [&>a]:no-underline", className)}
|
|
782
|
+
className={cn("aui-md-sup [&>a]:text-xs [&>a]:no-underline", className)}
|
|
534
783
|
{...props}
|
|
535
784
|
/>
|
|
536
785
|
),
|
|
537
786
|
pre: ({ className, ...props }) => (
|
|
538
787
|
<pre
|
|
539
788
|
className={cn(
|
|
540
|
-
"overflow-x-auto 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",
|
|
541
790
|
className,
|
|
542
791
|
)}
|
|
543
792
|
{...props}
|
|
@@ -548,7 +797,8 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
548
797
|
return (
|
|
549
798
|
<code
|
|
550
799
|
className={cn(
|
|
551
|
-
!isCodeBlock &&
|
|
800
|
+
!isCodeBlock &&
|
|
801
|
+
"aui-md-inline-code rounded border bg-muted font-semibold",
|
|
552
802
|
className,
|
|
553
803
|
)}
|
|
554
804
|
{...props}
|
|
@@ -563,21 +813,27 @@ const defaultComponents = memoizeMarkdownComponents({
|
|
|
563
813
|
## components/assistant-ui/thread-list.tsx
|
|
564
814
|
|
|
565
815
|
```tsx
|
|
566
|
-
import
|
|
816
|
+
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
817
|
+
import { Button } from "@/components/ui/button";
|
|
818
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
567
819
|
import {
|
|
820
|
+
AssistantIf,
|
|
568
821
|
ThreadListItemPrimitive,
|
|
569
822
|
ThreadListPrimitive,
|
|
570
823
|
} from "@assistant-ui/react";
|
|
571
824
|
import { ArchiveIcon, PlusIcon } from "lucide-react";
|
|
572
|
-
|
|
573
|
-
import { Button } from "@/components/ui/button";
|
|
574
|
-
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
825
|
+
import type { FC } from "react";
|
|
575
826
|
|
|
576
827
|
export const ThreadList: FC = () => {
|
|
577
828
|
return (
|
|
578
|
-
<ThreadListPrimitive.Root className="flex flex-col
|
|
829
|
+
<ThreadListPrimitive.Root className="aui-root aui-thread-list-root flex flex-col gap-1">
|
|
579
830
|
<ThreadListNew />
|
|
580
|
-
<
|
|
831
|
+
<AssistantIf condition={({ threads }) => threads.isLoading}>
|
|
832
|
+
<ThreadListSkeleton />
|
|
833
|
+
</AssistantIf>
|
|
834
|
+
<AssistantIf condition={({ threads }) => !threads.isLoading}>
|
|
835
|
+
<ThreadListPrimitive.Items components={{ ThreadListItem }} />
|
|
836
|
+
</AssistantIf>
|
|
581
837
|
</ThreadListPrimitive.Root>
|
|
582
838
|
);
|
|
583
839
|
};
|
|
@@ -586,48 +842,53 @@ const ThreadListNew: FC = () => {
|
|
|
586
842
|
return (
|
|
587
843
|
<ThreadListPrimitive.New asChild>
|
|
588
844
|
<Button
|
|
589
|
-
|
|
590
|
-
|
|
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"
|
|
591
847
|
>
|
|
592
|
-
<PlusIcon />
|
|
848
|
+
<PlusIcon className="size-4" />
|
|
593
849
|
New Thread
|
|
594
850
|
</Button>
|
|
595
851
|
</ThreadListPrimitive.New>
|
|
596
852
|
);
|
|
597
853
|
};
|
|
598
854
|
|
|
599
|
-
const
|
|
600
|
-
return
|
|
855
|
+
const ThreadListSkeleton: FC = () => {
|
|
856
|
+
return (
|
|
857
|
+
<div className="flex flex-col gap-1">
|
|
858
|
+
{Array.from({ length: 5 }, (_, i) => (
|
|
859
|
+
<div
|
|
860
|
+
key={i}
|
|
861
|
+
role="status"
|
|
862
|
+
aria-label="Loading threads"
|
|
863
|
+
className="aui-thread-list-skeleton-wrapper flex h-9 items-center px-3"
|
|
864
|
+
>
|
|
865
|
+
<Skeleton className="aui-thread-list-skeleton h-4 w-full" />
|
|
866
|
+
</div>
|
|
867
|
+
))}
|
|
868
|
+
</div>
|
|
869
|
+
);
|
|
601
870
|
};
|
|
602
871
|
|
|
603
872
|
const ThreadListItem: FC = () => {
|
|
604
873
|
return (
|
|
605
|
-
<ThreadListItemPrimitive.Root className="
|
|
606
|
-
<ThreadListItemPrimitive.Trigger className="flex-
|
|
607
|
-
<
|
|
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" />
|
|
608
877
|
</ThreadListItemPrimitive.Trigger>
|
|
609
878
|
<ThreadListItemArchive />
|
|
610
879
|
</ThreadListItemPrimitive.Root>
|
|
611
880
|
);
|
|
612
881
|
};
|
|
613
882
|
|
|
614
|
-
const ThreadListItemTitle: FC = () => {
|
|
615
|
-
return (
|
|
616
|
-
<p className="text-sm">
|
|
617
|
-
<ThreadListItemPrimitive.Title fallback="New Chat" />
|
|
618
|
-
</p>
|
|
619
|
-
);
|
|
620
|
-
};
|
|
621
|
-
|
|
622
883
|
const ThreadListItemArchive: FC = () => {
|
|
623
884
|
return (
|
|
624
885
|
<ThreadListItemPrimitive.Archive asChild>
|
|
625
886
|
<TooltipIconButton
|
|
626
|
-
className="hover:text-primary text-foreground mr-3 ml-auto size-4 p-0"
|
|
627
887
|
variant="ghost"
|
|
628
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"
|
|
629
890
|
>
|
|
630
|
-
<ArchiveIcon />
|
|
891
|
+
<ArchiveIcon className="size-4" />
|
|
631
892
|
</TooltipIconButton>
|
|
632
893
|
</ThreadListItemPrimitive.Archive>
|
|
633
894
|
);
|
|
@@ -638,57 +899,67 @@ const ThreadListItemArchive: FC = () => {
|
|
|
638
899
|
## components/assistant-ui/thread.tsx
|
|
639
900
|
|
|
640
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";
|
|
641
912
|
import {
|
|
642
913
|
ActionBarPrimitive,
|
|
914
|
+
AssistantIf,
|
|
643
915
|
BranchPickerPrimitive,
|
|
644
916
|
ComposerPrimitive,
|
|
917
|
+
ErrorPrimitive,
|
|
645
918
|
MessagePrimitive,
|
|
646
919
|
ThreadPrimitive,
|
|
647
920
|
} from "@assistant-ui/react";
|
|
648
|
-
import type { FC } from "react";
|
|
649
921
|
import {
|
|
650
922
|
ArrowDownIcon,
|
|
923
|
+
ArrowUpIcon,
|
|
651
924
|
CheckIcon,
|
|
652
925
|
ChevronLeftIcon,
|
|
653
926
|
ChevronRightIcon,
|
|
654
927
|
CopyIcon,
|
|
928
|
+
DownloadIcon,
|
|
655
929
|
PencilIcon,
|
|
656
930
|
RefreshCwIcon,
|
|
657
|
-
|
|
931
|
+
SquareIcon,
|
|
658
932
|
} from "lucide-react";
|
|
659
|
-
import {
|
|
660
|
-
|
|
661
|
-
import { Button } from "@/components/ui/button";
|
|
662
|
-
import { MarkdownText } from "@/components/assistant-ui/markdown-text";
|
|
663
|
-
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
933
|
+
import type { FC } from "react";
|
|
664
934
|
|
|
665
935
|
export const Thread: FC = () => {
|
|
666
936
|
return (
|
|
667
937
|
<ThreadPrimitive.Root
|
|
668
|
-
className="
|
|
938
|
+
className="aui-root aui-thread-root @container flex h-full flex-col bg-background"
|
|
669
939
|
style={{
|
|
670
|
-
["--thread-max-width" as string]: "
|
|
940
|
+
["--thread-max-width" as string]: "44rem",
|
|
671
941
|
}}
|
|
672
942
|
>
|
|
673
|
-
<ThreadPrimitive.Viewport
|
|
674
|
-
|
|
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>
|
|
675
950
|
|
|
676
951
|
<ThreadPrimitive.Messages
|
|
677
952
|
components={{
|
|
678
|
-
UserMessage
|
|
679
|
-
EditComposer
|
|
680
|
-
AssistantMessage
|
|
953
|
+
UserMessage,
|
|
954
|
+
EditComposer,
|
|
955
|
+
AssistantMessage,
|
|
681
956
|
}}
|
|
682
957
|
/>
|
|
683
958
|
|
|
684
|
-
<ThreadPrimitive.
|
|
685
|
-
<div className="min-h-8 flex-grow" />
|
|
686
|
-
</ThreadPrimitive.If>
|
|
687
|
-
|
|
688
|
-
<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">
|
|
689
960
|
<ThreadScrollToBottom />
|
|
690
961
|
<Composer />
|
|
691
|
-
</
|
|
962
|
+
</ThreadPrimitive.ViewportFooter>
|
|
692
963
|
</ThreadPrimitive.Viewport>
|
|
693
964
|
</ThreadPrimitive.Root>
|
|
694
965
|
);
|
|
@@ -700,7 +971,7 @@ const ThreadScrollToBottom: FC = () => {
|
|
|
700
971
|
<TooltipIconButton
|
|
701
972
|
tooltip="Scroll to bottom"
|
|
702
973
|
variant="outline"
|
|
703
|
-
className="
|
|
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"
|
|
704
975
|
>
|
|
705
976
|
<ArrowDownIcon />
|
|
706
977
|
</TooltipIconButton>
|
|
@@ -710,175 +981,247 @@ const ThreadScrollToBottom: FC = () => {
|
|
|
710
981
|
|
|
711
982
|
const ThreadWelcome: FC = () => {
|
|
712
983
|
return (
|
|
713
|
-
<
|
|
714
|
-
<div className="
|
|
715
|
-
<div className="flex
|
|
716
|
-
<
|
|
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>
|
|
717
993
|
</div>
|
|
718
|
-
<ThreadWelcomeSuggestions />
|
|
719
994
|
</div>
|
|
720
|
-
|
|
995
|
+
<ThreadSuggestions />
|
|
996
|
+
</div>
|
|
721
997
|
);
|
|
722
998
|
};
|
|
723
999
|
|
|
724
|
-
const
|
|
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 = () => {
|
|
725
1014
|
return (
|
|
726
|
-
<div className="
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
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
|
+
))}
|
|
747
1038
|
</div>
|
|
748
1039
|
);
|
|
749
1040
|
};
|
|
750
1041
|
|
|
751
1042
|
const Composer: FC = () => {
|
|
752
1043
|
return (
|
|
753
|
-
<ComposerPrimitive.Root className="
|
|
754
|
-
<ComposerPrimitive.
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
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>
|
|
761
1056
|
</ComposerPrimitive.Root>
|
|
762
1057
|
);
|
|
763
1058
|
};
|
|
764
1059
|
|
|
765
1060
|
const ComposerAction: FC = () => {
|
|
766
1061
|
return (
|
|
767
|
-
|
|
768
|
-
<
|
|
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}>
|
|
769
1066
|
<ComposerPrimitive.Send asChild>
|
|
770
1067
|
<TooltipIconButton
|
|
771
|
-
tooltip="Send"
|
|
1068
|
+
tooltip="Send message"
|
|
1069
|
+
side="bottom"
|
|
1070
|
+
type="submit"
|
|
772
1071
|
variant="default"
|
|
773
|
-
|
|
1072
|
+
size="icon"
|
|
1073
|
+
className="aui-composer-send size-8 rounded-full"
|
|
1074
|
+
aria-label="Send message"
|
|
774
1075
|
>
|
|
775
|
-
<
|
|
1076
|
+
<ArrowUpIcon className="aui-composer-send-icon size-4" />
|
|
776
1077
|
</TooltipIconButton>
|
|
777
1078
|
</ComposerPrimitive.Send>
|
|
778
|
-
</
|
|
779
|
-
|
|
1079
|
+
</AssistantIf>
|
|
1080
|
+
|
|
1081
|
+
<AssistantIf condition={({ thread }) => thread.isRunning}>
|
|
780
1082
|
<ComposerPrimitive.Cancel asChild>
|
|
781
|
-
<
|
|
782
|
-
|
|
1083
|
+
<Button
|
|
1084
|
+
type="button"
|
|
783
1085
|
variant="default"
|
|
784
|
-
|
|
1086
|
+
size="icon"
|
|
1087
|
+
className="aui-composer-cancel size-8 rounded-full"
|
|
1088
|
+
aria-label="Stop generating"
|
|
785
1089
|
>
|
|
786
|
-
<
|
|
787
|
-
</
|
|
1090
|
+
<SquareIcon className="aui-composer-cancel-icon size-3 fill-current" />
|
|
1091
|
+
</Button>
|
|
788
1092
|
</ComposerPrimitive.Cancel>
|
|
789
|
-
</
|
|
790
|
-
|
|
1093
|
+
</AssistantIf>
|
|
1094
|
+
</div>
|
|
791
1095
|
);
|
|
792
1096
|
};
|
|
793
1097
|
|
|
794
|
-
const
|
|
1098
|
+
const MessageError: FC = () => {
|
|
795
1099
|
return (
|
|
796
|
-
<MessagePrimitive.
|
|
797
|
-
<
|
|
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
|
+
};
|
|
798
1107
|
|
|
799
|
-
|
|
800
|
-
|
|
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 />
|
|
801
1122
|
</div>
|
|
802
1123
|
|
|
803
|
-
<
|
|
1124
|
+
<div className="aui-assistant-message-footer mt-1 ml-2 flex">
|
|
1125
|
+
<BranchPicker />
|
|
1126
|
+
<AssistantActionBar />
|
|
1127
|
+
</div>
|
|
804
1128
|
</MessagePrimitive.Root>
|
|
805
1129
|
);
|
|
806
1130
|
};
|
|
807
1131
|
|
|
808
|
-
const
|
|
1132
|
+
const AssistantActionBar: FC = () => {
|
|
809
1133
|
return (
|
|
810
1134
|
<ActionBarPrimitive.Root
|
|
811
1135
|
hideWhenRunning
|
|
812
1136
|
autohide="not-last"
|
|
813
|
-
|
|
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"
|
|
814
1139
|
>
|
|
815
|
-
<ActionBarPrimitive.
|
|
816
|
-
<TooltipIconButton tooltip="
|
|
817
|
-
<
|
|
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>
|
|
818
1148
|
</TooltipIconButton>
|
|
819
|
-
</ActionBarPrimitive.
|
|
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>
|
|
820
1160
|
</ActionBarPrimitive.Root>
|
|
821
1161
|
);
|
|
822
1162
|
};
|
|
823
1163
|
|
|
824
|
-
const
|
|
1164
|
+
const UserMessage: FC = () => {
|
|
825
1165
|
return (
|
|
826
|
-
<
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
<Button variant="ghost">Cancel</Button>
|
|
832
|
-
</ComposerPrimitive.Cancel>
|
|
833
|
-
<ComposerPrimitive.Send asChild>
|
|
834
|
-
<Button>Send</Button>
|
|
835
|
-
</ComposerPrimitive.Send>
|
|
836
|
-
</div>
|
|
837
|
-
</ComposerPrimitive.Root>
|
|
838
|
-
);
|
|
839
|
-
};
|
|
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 />
|
|
840
1171
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
<
|
|
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>
|
|
846
1179
|
</div>
|
|
847
1180
|
|
|
848
|
-
<
|
|
849
|
-
|
|
850
|
-
<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" />
|
|
851
1182
|
</MessagePrimitive.Root>
|
|
852
1183
|
);
|
|
853
1184
|
};
|
|
854
1185
|
|
|
855
|
-
const
|
|
1186
|
+
const UserActionBar: FC = () => {
|
|
856
1187
|
return (
|
|
857
1188
|
<ActionBarPrimitive.Root
|
|
858
1189
|
hideWhenRunning
|
|
859
1190
|
autohide="not-last"
|
|
860
|
-
|
|
861
|
-
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"
|
|
862
1192
|
>
|
|
863
|
-
<ActionBarPrimitive.
|
|
864
|
-
<TooltipIconButton tooltip="
|
|
865
|
-
<
|
|
866
|
-
<CheckIcon />
|
|
867
|
-
</MessagePrimitive.If>
|
|
868
|
-
<MessagePrimitive.If copied={false}>
|
|
869
|
-
<CopyIcon />
|
|
870
|
-
</MessagePrimitive.If>
|
|
871
|
-
</TooltipIconButton>
|
|
872
|
-
</ActionBarPrimitive.Copy>
|
|
873
|
-
<ActionBarPrimitive.Reload asChild>
|
|
874
|
-
<TooltipIconButton tooltip="Refresh">
|
|
875
|
-
<RefreshCwIcon />
|
|
1193
|
+
<ActionBarPrimitive.Edit asChild>
|
|
1194
|
+
<TooltipIconButton tooltip="Edit" className="aui-user-action-edit p-4">
|
|
1195
|
+
<PencilIcon />
|
|
876
1196
|
</TooltipIconButton>
|
|
877
|
-
</ActionBarPrimitive.
|
|
1197
|
+
</ActionBarPrimitive.Edit>
|
|
878
1198
|
</ActionBarPrimitive.Root>
|
|
879
1199
|
);
|
|
880
1200
|
};
|
|
881
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
|
+
|
|
882
1225
|
const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
|
|
883
1226
|
className,
|
|
884
1227
|
...rest
|
|
@@ -887,7 +1230,7 @@ const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
|
|
|
887
1230
|
<BranchPickerPrimitive.Root
|
|
888
1231
|
hideWhenSingleBranch
|
|
889
1232
|
className={cn(
|
|
890
|
-
"
|
|
1233
|
+
"aui-branch-picker-root -ml-2 mr-2 inline-flex items-center text-muted-foreground text-xs",
|
|
891
1234
|
className,
|
|
892
1235
|
)}
|
|
893
1236
|
{...rest}
|
|
@@ -897,7 +1240,7 @@ const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
|
|
|
897
1240
|
<ChevronLeftIcon />
|
|
898
1241
|
</TooltipIconButton>
|
|
899
1242
|
</BranchPickerPrimitive.Previous>
|
|
900
|
-
<span className="font-medium">
|
|
1243
|
+
<span className="aui-branch-picker-state font-medium">
|
|
901
1244
|
<BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
|
|
902
1245
|
</span>
|
|
903
1246
|
<BranchPickerPrimitive.Next asChild>
|
|
@@ -909,17 +1252,102 @@ const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
|
|
|
909
1252
|
);
|
|
910
1253
|
};
|
|
911
1254
|
|
|
912
|
-
|
|
1255
|
+
```
|
|
1256
|
+
|
|
1257
|
+
## components/assistant-ui/tool-fallback.tsx
|
|
1258
|
+
|
|
1259
|
+
```tsx
|
|
1260
|
+
import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
|
|
1261
|
+
import {
|
|
1262
|
+
CheckIcon,
|
|
1263
|
+
ChevronDownIcon,
|
|
1264
|
+
ChevronUpIcon,
|
|
1265
|
+
XCircleIcon,
|
|
1266
|
+
} from "lucide-react";
|
|
1267
|
+
import { useState } from "react";
|
|
1268
|
+
import { Button } from "@/components/ui/button";
|
|
1269
|
+
import { cn } from "@/lib/utils";
|
|
1270
|
+
|
|
1271
|
+
export const ToolFallback: ToolCallMessagePartComponent = ({
|
|
1272
|
+
toolName,
|
|
1273
|
+
argsText,
|
|
1274
|
+
result,
|
|
1275
|
+
status,
|
|
1276
|
+
}) => {
|
|
1277
|
+
const [isCollapsed, setIsCollapsed] = useState(true);
|
|
1278
|
+
|
|
1279
|
+
const isCancelled =
|
|
1280
|
+
status?.type === "incomplete" && status.reason === "cancelled";
|
|
1281
|
+
const cancelledReason =
|
|
1282
|
+
isCancelled && status.error
|
|
1283
|
+
? typeof status.error === "string"
|
|
1284
|
+
? status.error
|
|
1285
|
+
: JSON.stringify(status.error)
|
|
1286
|
+
: null;
|
|
1287
|
+
|
|
913
1288
|
return (
|
|
914
|
-
<
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
height="16"
|
|
1289
|
+
<div
|
|
1290
|
+
className={cn(
|
|
1291
|
+
"aui-tool-fallback-root mb-4 flex w-full flex-col gap-3 rounded-lg border py-3",
|
|
1292
|
+
isCancelled && "border-muted-foreground/30 bg-muted/30",
|
|
1293
|
+
)}
|
|
920
1294
|
>
|
|
921
|
-
<
|
|
922
|
-
|
|
1295
|
+
<div className="aui-tool-fallback-header flex items-center gap-2 px-4">
|
|
1296
|
+
{isCancelled ? (
|
|
1297
|
+
<XCircleIcon className="aui-tool-fallback-icon size-4 text-muted-foreground" />
|
|
1298
|
+
) : (
|
|
1299
|
+
<CheckIcon className="aui-tool-fallback-icon size-4" />
|
|
1300
|
+
)}
|
|
1301
|
+
<p
|
|
1302
|
+
className={cn(
|
|
1303
|
+
"aui-tool-fallback-title grow",
|
|
1304
|
+
isCancelled && "text-muted-foreground line-through",
|
|
1305
|
+
)}
|
|
1306
|
+
>
|
|
1307
|
+
{isCancelled ? "Cancelled tool: " : "Used tool: "}
|
|
1308
|
+
<b>{toolName}</b>
|
|
1309
|
+
</p>
|
|
1310
|
+
<Button onClick={() => setIsCollapsed(!isCollapsed)}>
|
|
1311
|
+
{isCollapsed ? <ChevronUpIcon /> : <ChevronDownIcon />}
|
|
1312
|
+
</Button>
|
|
1313
|
+
</div>
|
|
1314
|
+
{!isCollapsed && (
|
|
1315
|
+
<div className="aui-tool-fallback-content flex flex-col gap-2 border-t pt-2">
|
|
1316
|
+
{cancelledReason && (
|
|
1317
|
+
<div className="aui-tool-fallback-cancelled-root px-4">
|
|
1318
|
+
<p className="aui-tool-fallback-cancelled-header font-semibold text-muted-foreground">
|
|
1319
|
+
Cancelled reason:
|
|
1320
|
+
</p>
|
|
1321
|
+
<p className="aui-tool-fallback-cancelled-reason text-muted-foreground">
|
|
1322
|
+
{cancelledReason}
|
|
1323
|
+
</p>
|
|
1324
|
+
</div>
|
|
1325
|
+
)}
|
|
1326
|
+
<div
|
|
1327
|
+
className={cn(
|
|
1328
|
+
"aui-tool-fallback-args-root px-4",
|
|
1329
|
+
isCancelled && "opacity-60",
|
|
1330
|
+
)}
|
|
1331
|
+
>
|
|
1332
|
+
<pre className="aui-tool-fallback-args-value whitespace-pre-wrap">
|
|
1333
|
+
{argsText}
|
|
1334
|
+
</pre>
|
|
1335
|
+
</div>
|
|
1336
|
+
{!isCancelled && result !== undefined && (
|
|
1337
|
+
<div className="aui-tool-fallback-result-root border-t border-dashed px-4 pt-2">
|
|
1338
|
+
<p className="aui-tool-fallback-result-header font-semibold">
|
|
1339
|
+
Result:
|
|
1340
|
+
</p>
|
|
1341
|
+
<pre className="aui-tool-fallback-result-content whitespace-pre-wrap">
|
|
1342
|
+
{typeof result === "string"
|
|
1343
|
+
? result
|
|
1344
|
+
: JSON.stringify(result, null, 2)}
|
|
1345
|
+
</pre>
|
|
1346
|
+
</div>
|
|
1347
|
+
)}
|
|
1348
|
+
</div>
|
|
1349
|
+
)}
|
|
1350
|
+
</div>
|
|
923
1351
|
);
|
|
924
1352
|
};
|
|
925
1353
|
|
|
@@ -930,7 +1358,7 @@ const CircleStopIcon = () => {
|
|
|
930
1358
|
```tsx
|
|
931
1359
|
"use client";
|
|
932
1360
|
|
|
933
|
-
import {
|
|
1361
|
+
import { ComponentPropsWithRef, forwardRef } from "react";
|
|
934
1362
|
import { Slottable } from "@radix-ui/react-slot";
|
|
935
1363
|
|
|
936
1364
|
import {
|
|
@@ -941,7 +1369,7 @@ import {
|
|
|
941
1369
|
import { Button } from "@/components/ui/button";
|
|
942
1370
|
import { cn } from "@/lib/utils";
|
|
943
1371
|
|
|
944
|
-
export type TooltipIconButtonProps =
|
|
1372
|
+
export type TooltipIconButtonProps = ComponentPropsWithRef<typeof Button> & {
|
|
945
1373
|
tooltip: string;
|
|
946
1374
|
side?: "top" | "bottom" | "left" | "right";
|
|
947
1375
|
};
|
|
@@ -957,11 +1385,11 @@ export const TooltipIconButton = forwardRef<
|
|
|
957
1385
|
variant="ghost"
|
|
958
1386
|
size="icon"
|
|
959
1387
|
{...rest}
|
|
960
|
-
className={cn("size-6 p-1", className)}
|
|
1388
|
+
className={cn("aui-button-icon size-6 p-1", className)}
|
|
961
1389
|
ref={ref}
|
|
962
1390
|
>
|
|
963
1391
|
<Slottable>{children}</Slottable>
|
|
964
|
-
<span className="sr-only">{tooltip}</span>
|
|
1392
|
+
<span className="aui-sr-only sr-only">{tooltip}</span>
|
|
965
1393
|
</Button>
|
|
966
1394
|
</TooltipTrigger>
|
|
967
1395
|
<TooltipContent side={side}>{tooltip}</TooltipContent>
|
|
@@ -1007,17 +1435,17 @@ export function PriceSnapshot({
|
|
|
1007
1435
|
return (
|
|
1008
1436
|
<Card className="mx-auto w-full max-w-md">
|
|
1009
1437
|
<CardHeader>
|
|
1010
|
-
<CardTitle className="text-2xl
|
|
1438
|
+
<CardTitle className="font-bold text-2xl">{ticker}</CardTitle>
|
|
1011
1439
|
</CardHeader>
|
|
1012
1440
|
<CardContent>
|
|
1013
1441
|
<div className="grid grid-cols-2 gap-4">
|
|
1014
1442
|
<div className="col-span-2">
|
|
1015
|
-
<p className="text-3xl
|
|
1443
|
+
<p className="font-semibold text-3xl">${price?.toFixed(2)}</p>
|
|
1016
1444
|
</div>
|
|
1017
1445
|
<div>
|
|
1018
1446
|
<p className="text-muted-foreground text-sm">Day Change</p>
|
|
1019
1447
|
<p
|
|
1020
|
-
className={`flex items-center text-lg
|
|
1448
|
+
className={`flex items-center font-medium text-lg ${changeColor}`}
|
|
1021
1449
|
>
|
|
1022
1450
|
<ArrowIcon className="mr-1 h-4 w-4" />$
|
|
1023
1451
|
{Math.abs(day_change)?.toFixed(2)} (
|
|
@@ -1026,7 +1454,7 @@ export function PriceSnapshot({
|
|
|
1026
1454
|
</div>
|
|
1027
1455
|
<div>
|
|
1028
1456
|
<p className="text-muted-foreground text-sm">Last Updated</p>
|
|
1029
|
-
<p className="text-lg
|
|
1457
|
+
<p className="font-medium text-lg">
|
|
1030
1458
|
{new Date(time).toLocaleTimeString()}
|
|
1031
1459
|
</p>
|
|
1032
1460
|
</div>
|
|
@@ -1155,13 +1583,13 @@ export function TransactionConfirmationFinal(props: TransactionConfirmation) {
|
|
|
1155
1583
|
<Card className="mx-auto w-full max-w-md">
|
|
1156
1584
|
<CardHeader className="text-center">
|
|
1157
1585
|
<CheckCircle className="mx-auto mb-4 h-16 w-16 text-green-500" />
|
|
1158
|
-
<CardTitle className="
|
|
1586
|
+
<CardTitle className="font-bold text-2xl text-green-700">
|
|
1159
1587
|
Transaction Confirmed
|
|
1160
1588
|
</CardTitle>
|
|
1161
1589
|
</CardHeader>
|
|
1162
1590
|
<CardContent className="space-y-4">
|
|
1163
1591
|
<div className="rounded-md border border-green-200 bg-green-50 p-4">
|
|
1164
|
-
<h3 className="mb-2
|
|
1592
|
+
<h3 className="mb-2 font-semibold text-green-800 text-lg">
|
|
1165
1593
|
Purchase Summary
|
|
1166
1594
|
</h3>
|
|
1167
1595
|
<div className="grid grid-cols-2 gap-2 text-sm">
|
|
@@ -1176,12 +1604,12 @@ export function TransactionConfirmationFinal(props: TransactionConfirmation) {
|
|
|
1176
1604
|
</div>
|
|
1177
1605
|
</div>
|
|
1178
1606
|
<div className="rounded-md border border-green-300 bg-green-100 p-4">
|
|
1179
|
-
<p className="
|
|
1180
|
-
<p className="
|
|
1607
|
+
<p className="font-semibold text-green-800 text-lg">Total Cost:</p>
|
|
1608
|
+
<p className="font-bold text-2xl text-green-900">
|
|
1181
1609
|
${(quantity * maxPurchasePrice)?.toFixed(2)}
|
|
1182
1610
|
</p>
|
|
1183
1611
|
</div>
|
|
1184
|
-
<p className="text-center text-
|
|
1612
|
+
<p className="text-center text-green-600 text-sm">
|
|
1185
1613
|
Your purchase of {quantity} shares of {companyName} ({ticker}) has
|
|
1186
1614
|
been successfully processed.
|
|
1187
1615
|
</p>
|
|
@@ -1222,26 +1650,26 @@ export function TransactionConfirmationPending(props: TransactionConfirmation) {
|
|
|
1222
1650
|
return (
|
|
1223
1651
|
<Card className="mx-auto w-full max-w-md">
|
|
1224
1652
|
<CardHeader>
|
|
1225
|
-
<CardTitle className="text-2xl
|
|
1653
|
+
<CardTitle className="font-bold text-2xl">
|
|
1226
1654
|
Confirm Transaction
|
|
1227
1655
|
</CardTitle>
|
|
1228
1656
|
</CardHeader>
|
|
1229
1657
|
<CardContent className="space-y-4">
|
|
1230
1658
|
<div className="grid grid-cols-2 gap-2">
|
|
1231
|
-
<p className="text-muted-foreground text-sm
|
|
1232
|
-
<p className="text-sm
|
|
1233
|
-
<p className="text-muted-foreground text-sm
|
|
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>
|
|
1234
1662
|
<p className="text-sm">{companyName}</p>
|
|
1235
|
-
<p className="text-muted-foreground text-sm
|
|
1663
|
+
<p className="font-medium text-muted-foreground text-sm">Quantity:</p>
|
|
1236
1664
|
<p className="text-sm">{quantity} shares</p>
|
|
1237
|
-
<p className="text-muted-foreground text-sm
|
|
1665
|
+
<p className="font-medium text-muted-foreground text-sm">
|
|
1238
1666
|
Max Purchase Price:
|
|
1239
1667
|
</p>
|
|
1240
1668
|
<p className="text-sm">${maxPurchasePrice?.toFixed(2)}</p>
|
|
1241
1669
|
</div>
|
|
1242
|
-
<div className="bg-muted
|
|
1243
|
-
<p className="text-sm
|
|
1244
|
-
<p className="text-lg
|
|
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">
|
|
1245
1673
|
${(quantity * maxPurchasePrice)?.toFixed(2)}
|
|
1246
1674
|
</p>
|
|
1247
1675
|
</div>
|
|
@@ -1268,7 +1696,7 @@ export function TransactionConfirmationPending(props: TransactionConfirmation) {
|
|
|
1268
1696
|
import { ToolCallMessagePartComponent } from "@assistant-ui/react";
|
|
1269
1697
|
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
|
|
1270
1698
|
import { useState } from "react";
|
|
1271
|
-
import { Button } from "
|
|
1699
|
+
import { Button } from "@/components/ui/button";
|
|
1272
1700
|
|
|
1273
1701
|
export const ToolFallback: ToolCallMessagePartComponent = ({
|
|
1274
1702
|
toolName,
|
|
@@ -1311,6 +1739,62 @@ export const ToolFallback: ToolCallMessagePartComponent = ({
|
|
|
1311
1739
|
|
|
1312
1740
|
```
|
|
1313
1741
|
|
|
1742
|
+
## components/ui/avatar.tsx
|
|
1743
|
+
|
|
1744
|
+
```tsx
|
|
1745
|
+
"use client";
|
|
1746
|
+
|
|
1747
|
+
import * as React from "react";
|
|
1748
|
+
import * as AvatarPrimitive from "@radix-ui/react-avatar";
|
|
1749
|
+
|
|
1750
|
+
import { cn } from "@/lib/utils";
|
|
1751
|
+
|
|
1752
|
+
const Avatar = React.forwardRef<
|
|
1753
|
+
React.ElementRef<typeof AvatarPrimitive.Root>,
|
|
1754
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
|
|
1755
|
+
>(({ className, ...props }, ref) => (
|
|
1756
|
+
<AvatarPrimitive.Root
|
|
1757
|
+
ref={ref}
|
|
1758
|
+
className={cn(
|
|
1759
|
+
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
|
|
1760
|
+
className,
|
|
1761
|
+
)}
|
|
1762
|
+
{...props}
|
|
1763
|
+
/>
|
|
1764
|
+
));
|
|
1765
|
+
Avatar.displayName = AvatarPrimitive.Root.displayName;
|
|
1766
|
+
|
|
1767
|
+
const AvatarImage = React.forwardRef<
|
|
1768
|
+
React.ElementRef<typeof AvatarPrimitive.Image>,
|
|
1769
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
|
|
1770
|
+
>(({ className, ...props }, ref) => (
|
|
1771
|
+
<AvatarPrimitive.Image
|
|
1772
|
+
ref={ref}
|
|
1773
|
+
className={cn("aspect-square h-full w-full", className)}
|
|
1774
|
+
{...props}
|
|
1775
|
+
/>
|
|
1776
|
+
));
|
|
1777
|
+
AvatarImage.displayName = AvatarPrimitive.Image.displayName;
|
|
1778
|
+
|
|
1779
|
+
const AvatarFallback = React.forwardRef<
|
|
1780
|
+
React.ElementRef<typeof AvatarPrimitive.Fallback>,
|
|
1781
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
|
|
1782
|
+
>(({ className, ...props }, ref) => (
|
|
1783
|
+
<AvatarPrimitive.Fallback
|
|
1784
|
+
ref={ref}
|
|
1785
|
+
className={cn(
|
|
1786
|
+
"flex h-full w-full items-center justify-center rounded-full bg-muted",
|
|
1787
|
+
className,
|
|
1788
|
+
)}
|
|
1789
|
+
{...props}
|
|
1790
|
+
/>
|
|
1791
|
+
));
|
|
1792
|
+
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
|
|
1793
|
+
|
|
1794
|
+
export { Avatar, AvatarImage, AvatarFallback };
|
|
1795
|
+
|
|
1796
|
+
```
|
|
1797
|
+
|
|
1314
1798
|
## components/ui/button.tsx
|
|
1315
1799
|
|
|
1316
1800
|
```tsx
|
|
@@ -1321,7 +1805,7 @@ import { cva, type VariantProps } from "class-variance-authority";
|
|
|
1321
1805
|
import { cn } from "@/lib/utils";
|
|
1322
1806
|
|
|
1323
1807
|
const buttonVariants = cva(
|
|
1324
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm
|
|
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",
|
|
1325
1809
|
{
|
|
1326
1810
|
variants: {
|
|
1327
1811
|
variant: {
|
|
@@ -1388,7 +1872,7 @@ const Card = React.forwardRef<
|
|
|
1388
1872
|
<div
|
|
1389
1873
|
ref={ref}
|
|
1390
1874
|
className={cn(
|
|
1391
|
-
"bg-card text-card-foreground
|
|
1875
|
+
"rounded-xl border bg-card text-card-foreground shadow",
|
|
1392
1876
|
className,
|
|
1393
1877
|
)}
|
|
1394
1878
|
{...props}
|
|
@@ -1414,7 +1898,7 @@ const CardTitle = React.forwardRef<
|
|
|
1414
1898
|
>(({ className, ...props }, ref) => (
|
|
1415
1899
|
<div
|
|
1416
1900
|
ref={ref}
|
|
1417
|
-
className={cn("leading-none
|
|
1901
|
+
className={cn("font-semibold leading-none tracking-tight", className)}
|
|
1418
1902
|
{...props}
|
|
1419
1903
|
/>
|
|
1420
1904
|
));
|
|
@@ -1463,6 +1947,166 @@ export {
|
|
|
1463
1947
|
|
|
1464
1948
|
```
|
|
1465
1949
|
|
|
1950
|
+
## components/ui/dialog.tsx
|
|
1951
|
+
|
|
1952
|
+
```tsx
|
|
1953
|
+
"use client";
|
|
1954
|
+
|
|
1955
|
+
import * as React from "react";
|
|
1956
|
+
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
1957
|
+
import { XIcon } from "lucide-react";
|
|
1958
|
+
|
|
1959
|
+
import { cn } from "@/lib/utils";
|
|
1960
|
+
|
|
1961
|
+
function Dialog({
|
|
1962
|
+
...props
|
|
1963
|
+
}: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
|
1964
|
+
return <DialogPrimitive.Root data-slot="dialog" {...props} />;
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1967
|
+
function DialogTrigger({
|
|
1968
|
+
...props
|
|
1969
|
+
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
1970
|
+
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
function DialogPortal({
|
|
1974
|
+
...props
|
|
1975
|
+
}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
|
1976
|
+
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
function DialogClose({
|
|
1980
|
+
...props
|
|
1981
|
+
}: React.ComponentProps<typeof DialogPrimitive.Close>) {
|
|
1982
|
+
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
function DialogOverlay({
|
|
1986
|
+
className,
|
|
1987
|
+
...props
|
|
1988
|
+
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
1989
|
+
return (
|
|
1990
|
+
<DialogPrimitive.Overlay
|
|
1991
|
+
data-slot="dialog-overlay"
|
|
1992
|
+
className={cn(
|
|
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",
|
|
1994
|
+
className,
|
|
1995
|
+
)}
|
|
1996
|
+
{...props}
|
|
1997
|
+
/>
|
|
1998
|
+
);
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
function DialogContent({
|
|
2002
|
+
className,
|
|
2003
|
+
children,
|
|
2004
|
+
...props
|
|
2005
|
+
}: React.ComponentProps<typeof DialogPrimitive.Content>) {
|
|
2006
|
+
return (
|
|
2007
|
+
<DialogPortal data-slot="dialog-portal">
|
|
2008
|
+
<DialogOverlay />
|
|
2009
|
+
<DialogPrimitive.Content
|
|
2010
|
+
data-slot="dialog-content"
|
|
2011
|
+
className={cn(
|
|
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",
|
|
2013
|
+
className,
|
|
2014
|
+
)}
|
|
2015
|
+
{...props}
|
|
2016
|
+
>
|
|
2017
|
+
{children}
|
|
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">
|
|
2019
|
+
<XIcon />
|
|
2020
|
+
<span className="sr-only">Close</span>
|
|
2021
|
+
</DialogPrimitive.Close>
|
|
2022
|
+
</DialogPrimitive.Content>
|
|
2023
|
+
</DialogPortal>
|
|
2024
|
+
);
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
2028
|
+
return (
|
|
2029
|
+
<div
|
|
2030
|
+
data-slot="dialog-header"
|
|
2031
|
+
className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
|
|
2032
|
+
{...props}
|
|
2033
|
+
/>
|
|
2034
|
+
);
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
2038
|
+
return (
|
|
2039
|
+
<div
|
|
2040
|
+
data-slot="dialog-footer"
|
|
2041
|
+
className={cn(
|
|
2042
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
2043
|
+
className,
|
|
2044
|
+
)}
|
|
2045
|
+
{...props}
|
|
2046
|
+
/>
|
|
2047
|
+
);
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
function DialogTitle({
|
|
2051
|
+
className,
|
|
2052
|
+
...props
|
|
2053
|
+
}: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
2054
|
+
return (
|
|
2055
|
+
<DialogPrimitive.Title
|
|
2056
|
+
data-slot="dialog-title"
|
|
2057
|
+
className={cn("font-semibold text-lg leading-none", className)}
|
|
2058
|
+
{...props}
|
|
2059
|
+
/>
|
|
2060
|
+
);
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
function DialogDescription({
|
|
2064
|
+
className,
|
|
2065
|
+
...props
|
|
2066
|
+
}: React.ComponentProps<typeof DialogPrimitive.Description>) {
|
|
2067
|
+
return (
|
|
2068
|
+
<DialogPrimitive.Description
|
|
2069
|
+
data-slot="dialog-description"
|
|
2070
|
+
className={cn("text-muted-foreground text-sm", className)}
|
|
2071
|
+
{...props}
|
|
2072
|
+
/>
|
|
2073
|
+
);
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
export {
|
|
2077
|
+
Dialog,
|
|
2078
|
+
DialogClose,
|
|
2079
|
+
DialogContent,
|
|
2080
|
+
DialogDescription,
|
|
2081
|
+
DialogFooter,
|
|
2082
|
+
DialogHeader,
|
|
2083
|
+
DialogOverlay,
|
|
2084
|
+
DialogPortal,
|
|
2085
|
+
DialogTitle,
|
|
2086
|
+
DialogTrigger,
|
|
2087
|
+
};
|
|
2088
|
+
|
|
2089
|
+
```
|
|
2090
|
+
|
|
2091
|
+
## components/ui/skeleton.tsx
|
|
2092
|
+
|
|
2093
|
+
```tsx
|
|
2094
|
+
import { cn } from "@/lib/utils";
|
|
2095
|
+
|
|
2096
|
+
function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
|
|
2097
|
+
return (
|
|
2098
|
+
<div
|
|
2099
|
+
data-slot="skeleton"
|
|
2100
|
+
className={cn("animate-pulse rounded-md bg-accent", className)}
|
|
2101
|
+
{...props}
|
|
2102
|
+
/>
|
|
2103
|
+
);
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
export { Skeleton };
|
|
2107
|
+
|
|
2108
|
+
```
|
|
2109
|
+
|
|
1466
2110
|
## components/ui/tooltip.tsx
|
|
1467
2111
|
|
|
1468
2112
|
```tsx
|
|
@@ -1514,13 +2158,13 @@ function TooltipContent({
|
|
|
1514
2158
|
data-slot="tooltip-content"
|
|
1515
2159
|
sideOffset={sideOffset}
|
|
1516
2160
|
className={cn(
|
|
1517
|
-
"
|
|
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",
|
|
1518
2162
|
className,
|
|
1519
2163
|
)}
|
|
1520
2164
|
{...props}
|
|
1521
2165
|
>
|
|
1522
2166
|
{children}
|
|
1523
|
-
<TooltipPrimitive.Arrow className="
|
|
2167
|
+
<TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-primary fill-primary" />
|
|
1524
2168
|
</TooltipPrimitive.Content>
|
|
1525
2169
|
</TooltipPrimitive.Portal>
|
|
1526
2170
|
);
|
|
@@ -1619,18 +2263,6 @@ export function cn(...inputs: ClassValue[]) {
|
|
|
1619
2263
|
|
|
1620
2264
|
```
|
|
1621
2265
|
|
|
1622
|
-
## next-env.d.ts
|
|
1623
|
-
|
|
1624
|
-
```typescript
|
|
1625
|
-
/// <reference types="next" />
|
|
1626
|
-
/// <reference types="next/image-types/global" />
|
|
1627
|
-
import "./.next/types/routes.d.ts";
|
|
1628
|
-
|
|
1629
|
-
// NOTE: This file should not be edited
|
|
1630
|
-
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
|
1631
|
-
|
|
1632
|
-
```
|
|
1633
|
-
|
|
1634
2266
|
## next.config.ts
|
|
1635
2267
|
|
|
1636
2268
|
```typescript
|
|
@@ -1661,28 +2293,30 @@ export default nextConfig;
|
|
|
1661
2293
|
"scripts": {
|
|
1662
2294
|
"dev": "next dev --turbo",
|
|
1663
2295
|
"build": "next build",
|
|
1664
|
-
"start": "next start"
|
|
1665
|
-
"lint": "eslint ."
|
|
2296
|
+
"start": "next start"
|
|
1666
2297
|
},
|
|
1667
2298
|
"dependencies": {
|
|
1668
2299
|
"@assistant-ui/react": "workspace:*",
|
|
1669
2300
|
"@assistant-ui/react-langgraph": "workspace:*",
|
|
1670
2301
|
"@assistant-ui/react-markdown": "workspace:*",
|
|
1671
|
-
"@langchain/langgraph-sdk": "^1.
|
|
2302
|
+
"@langchain/langgraph-sdk": "^1.2.0",
|
|
2303
|
+
"@radix-ui/react-avatar": "^1.1.11",
|
|
2304
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
1672
2305
|
"@radix-ui/react-slot": "^1.2.4",
|
|
1673
2306
|
"@radix-ui/react-tooltip": "^1.2.8",
|
|
1674
2307
|
"class-variance-authority": "^0.7.1",
|
|
1675
2308
|
"clsx": "^2.1.1",
|
|
1676
2309
|
"js-cookie": "^3.0.5",
|
|
1677
|
-
"jsonwebtoken": "^9.0.
|
|
1678
|
-
"lucide-react": "^0.
|
|
2310
|
+
"jsonwebtoken": "^9.0.3",
|
|
2311
|
+
"lucide-react": "^0.556.0",
|
|
1679
2312
|
"nanoid": "5.1.6",
|
|
1680
|
-
"next": "16.0.
|
|
1681
|
-
"react": "19.2.
|
|
1682
|
-
"react-dom": "19.2.
|
|
2313
|
+
"next": "16.0.7",
|
|
2314
|
+
"react": "19.2.1",
|
|
2315
|
+
"react-dom": "19.2.1",
|
|
1683
2316
|
"remark-gfm": "^4.0.1",
|
|
1684
2317
|
"tailwind-merge": "^3.4.0",
|
|
1685
|
-
"tw-animate-css": "^1.4.0"
|
|
2318
|
+
"tw-animate-css": "^1.4.0",
|
|
2319
|
+
"zustand": "^5.0.9"
|
|
1686
2320
|
},
|
|
1687
2321
|
"devDependencies": {
|
|
1688
2322
|
"@assistant-ui/x-buildutils": "workspace:*",
|