@assistant-ui/mcp-docs-server 0.1.19 → 0.1.21

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 (108) hide show
  1. package/.docs/organized/code-examples/with-ag-ui.md +172 -1633
  2. package/.docs/organized/code-examples/with-ai-sdk-v6.md +42 -1640
  3. package/.docs/organized/code-examples/with-assistant-transport.md +40 -1743
  4. package/.docs/organized/code-examples/with-cloud.md +71 -1745
  5. package/.docs/organized/code-examples/with-custom-thread-list.md +87 -1723
  6. package/.docs/organized/code-examples/with-elevenlabs-scribe.md +70 -1637
  7. package/.docs/organized/code-examples/with-external-store.md +67 -1624
  8. package/.docs/organized/code-examples/with-ffmpeg.md +71 -1629
  9. package/.docs/organized/code-examples/with-langgraph.md +95 -1893
  10. package/.docs/organized/code-examples/with-parent-id-grouping.md +57 -1654
  11. package/.docs/organized/code-examples/with-react-hook-form.md +220 -2163
  12. package/.docs/organized/code-examples/with-react-router.md +66 -1318
  13. package/.docs/organized/code-examples/with-store.md +31 -31
  14. package/.docs/organized/code-examples/with-tanstack.md +77 -861
  15. package/.docs/organized/code-examples/with-tap-runtime.md +812 -0
  16. package/.docs/raw/docs/(docs)/cli.mdx +66 -0
  17. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool-ui.mdx +0 -1
  18. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool.mdx +0 -1
  19. package/.docs/raw/docs/(docs)/copilots/model-context.mdx +4 -4
  20. package/.docs/raw/docs/(docs)/copilots/motivation.mdx +3 -3
  21. package/.docs/raw/docs/(docs)/devtools.mdx +0 -1
  22. package/.docs/raw/docs/(docs)/guides/attachments.mdx +2 -3
  23. package/.docs/raw/docs/(docs)/guides/context-api.mdx +117 -117
  24. package/.docs/raw/docs/(docs)/guides/suggestions.mdx +296 -0
  25. package/.docs/raw/docs/(docs)/guides/tools.mdx +336 -513
  26. package/.docs/raw/docs/(docs)/index.mdx +33 -410
  27. package/.docs/raw/docs/(docs)/installation.mdx +450 -0
  28. package/.docs/raw/docs/(docs)/llm.mdx +209 -0
  29. package/.docs/raw/docs/(reference)/api-reference/context-providers/assistant-runtime-provider.mdx +0 -1
  30. package/.docs/raw/docs/(reference)/api-reference/context-providers/text-message-part-provider.mdx +0 -1
  31. package/.docs/raw/docs/(reference)/api-reference/integrations/react-data-stream.mdx +48 -3
  32. package/.docs/raw/docs/(reference)/api-reference/integrations/react-hook-form.mdx +0 -1
  33. package/.docs/raw/docs/(reference)/api-reference/integrations/vercel-ai-sdk.mdx +0 -1
  34. package/.docs/raw/docs/(reference)/api-reference/overview.mdx +9 -3
  35. package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar-more.mdx +20 -52
  36. package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar.mdx +16 -39
  37. package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +49 -50
  38. package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-modal.mdx +3 -11
  39. package/.docs/raw/docs/(reference)/api-reference/primitives/attachment.mdx +0 -3
  40. package/.docs/raw/docs/(reference)/api-reference/primitives/branch-picker.mdx +0 -1
  41. package/.docs/raw/docs/(reference)/api-reference/primitives/composer.mdx +5 -16
  42. package/.docs/raw/docs/(reference)/api-reference/primitives/composition.mdx +0 -1
  43. package/.docs/raw/docs/(reference)/api-reference/primitives/error.mdx +0 -1
  44. package/.docs/raw/docs/(reference)/api-reference/primitives/message-part.mdx +1 -2
  45. package/.docs/raw/docs/(reference)/api-reference/primitives/message.mdx +0 -1
  46. package/.docs/raw/docs/(reference)/api-reference/primitives/suggestion.mdx +152 -0
  47. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list-item-more.mdx +0 -1
  48. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list-item.mdx +1 -2
  49. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list.mdx +1 -2
  50. package/.docs/raw/docs/(reference)/api-reference/primitives/thread.mdx +28 -40
  51. package/.docs/raw/docs/(reference)/api-reference/runtimes/assistant-runtime.mdx +0 -1
  52. package/.docs/raw/docs/(reference)/api-reference/runtimes/attachment-runtime.mdx +1 -2
  53. package/.docs/raw/docs/(reference)/api-reference/runtimes/composer-runtime.mdx +2 -3
  54. package/.docs/raw/docs/(reference)/api-reference/runtimes/message-part-runtime.mdx +1 -2
  55. package/.docs/raw/docs/(reference)/api-reference/runtimes/message-runtime.mdx +1 -2
  56. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-item-runtime.mdx +0 -1
  57. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-runtime.mdx +0 -1
  58. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-runtime.mdx +1 -2
  59. package/.docs/raw/docs/(reference)/legacy/styled/assistant-modal.mdx +0 -1
  60. package/.docs/raw/docs/(reference)/legacy/styled/decomposition.mdx +5 -5
  61. package/.docs/raw/docs/(reference)/legacy/styled/markdown.mdx +0 -1
  62. package/.docs/raw/docs/(reference)/legacy/styled/thread.mdx +0 -1
  63. package/.docs/raw/docs/(reference)/migrations/v0-12.mdx +207 -33
  64. package/.docs/raw/docs/(reference)/react-compatibility.mdx +0 -1
  65. package/.docs/raw/docs/cloud/persistence/ai-sdk.mdx +0 -1
  66. package/.docs/raw/docs/cloud/persistence/langgraph.mdx +0 -1
  67. package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +0 -1
  68. package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +118 -0
  69. package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +198 -0
  70. package/.docs/raw/docs/runtimes/assistant-transport.mdx +3 -3
  71. package/.docs/raw/docs/runtimes/custom/custom-thread-list.mdx +5 -6
  72. package/.docs/raw/docs/runtimes/custom/external-store.mdx +9 -11
  73. package/.docs/raw/docs/runtimes/custom/local.mdx +43 -36
  74. package/.docs/raw/docs/runtimes/data-stream.mdx +35 -3
  75. package/.docs/raw/docs/runtimes/langgraph/index.mdx +1 -2
  76. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +0 -1
  77. package/.docs/raw/docs/runtimes/langserve.mdx +0 -1
  78. package/.docs/raw/docs/runtimes/mastra/full-stack-integration.mdx +0 -1
  79. package/.docs/raw/docs/runtimes/mastra/separate-server-integration.mdx +0 -1
  80. package/.docs/raw/docs/ui/accordion.mdx +259 -0
  81. package/.docs/raw/docs/ui/assistant-modal.mdx +1 -3
  82. package/.docs/raw/docs/ui/assistant-sidebar.mdx +1 -3
  83. package/.docs/raw/docs/ui/attachment.mdx +0 -2
  84. package/.docs/raw/docs/ui/badge.mdx +138 -0
  85. package/.docs/raw/docs/ui/diff-viewer.mdx +279 -0
  86. package/.docs/raw/docs/ui/file.mdx +152 -0
  87. package/.docs/raw/docs/ui/image.mdx +100 -0
  88. package/.docs/raw/docs/ui/markdown.mdx +0 -1
  89. package/.docs/raw/docs/ui/mermaid.mdx +0 -1
  90. package/.docs/raw/docs/ui/model-selector.mdx +224 -0
  91. package/.docs/raw/docs/ui/part-grouping.mdx +4 -5
  92. package/.docs/raw/docs/ui/reasoning.mdx +6 -5
  93. package/.docs/raw/docs/ui/scrollbar.mdx +26 -9
  94. package/.docs/raw/docs/ui/select.mdx +245 -0
  95. package/.docs/raw/docs/ui/sources.mdx +6 -5
  96. package/.docs/raw/docs/ui/streamdown.mdx +348 -0
  97. package/.docs/raw/docs/ui/syntax-highlighting.mdx +8 -63
  98. package/.docs/raw/docs/ui/tabs.mdx +259 -0
  99. package/.docs/raw/docs/ui/thread-list.mdx +98 -16
  100. package/.docs/raw/docs/ui/thread.mdx +57 -73
  101. package/.docs/raw/docs/ui/tool-fallback.mdx +0 -1
  102. package/.docs/raw/docs/ui/tool-group.mdx +1 -3
  103. package/README.md +3 -3
  104. package/package.json +4 -4
  105. package/src/tools/tests/examples.test.ts +1 -1
  106. package/.docs/raw/docs/(docs)/about-assistantui.mdx +0 -54
  107. package/.docs/raw/docs/(docs)/mcp-docs-server.mdx +0 -321
  108. package/.docs/raw/docs/runtimes/ai-sdk/use-chat.mdx +0 -219
@@ -79,6 +79,8 @@ export async function POST() {
79
79
  @import "tailwindcss";
80
80
  @import "tw-animate-css";
81
81
 
82
+ @source "../../../packages/ui/src";
83
+
82
84
  @custom-variant dark (&:is(.dark *));
83
85
 
84
86
  @theme inline {
@@ -279,1630 +281,12 @@ export default function Home() {
279
281
  "lib": "@/lib",
280
282
  "hooks": "@/hooks"
281
283
  },
282
- "iconLibrary": "lucide"
283
- }
284
-
285
- ```
286
-
287
- ## components/assistant-ui/attachment.tsx
288
-
289
- ```tsx
290
- "use client";
291
-
292
- import { PropsWithChildren, useEffect, useState, type FC } from "react";
293
- import Image from "next/image";
294
- import { XIcon, PlusIcon, FileText } from "lucide-react";
295
- import {
296
- AttachmentPrimitive,
297
- ComposerPrimitive,
298
- MessagePrimitive,
299
- useAssistantState,
300
- useAssistantApi,
301
- } from "@assistant-ui/react";
302
- import { useShallow } from "zustand/shallow";
303
- import {
304
- Tooltip,
305
- TooltipContent,
306
- TooltipTrigger,
307
- } from "@/components/ui/tooltip";
308
- import {
309
- Dialog,
310
- DialogTitle,
311
- DialogContent,
312
- DialogTrigger,
313
- } from "@/components/ui/dialog";
314
- import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
315
- import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
316
- import { cn } from "@/lib/utils";
317
-
318
- const useFileSrc = (file: File | undefined) => {
319
- const [src, setSrc] = useState<string | undefined>(undefined);
320
-
321
- useEffect(() => {
322
- if (!file) {
323
- setSrc(undefined);
324
- return;
325
- }
326
-
327
- const objectUrl = URL.createObjectURL(file);
328
- setSrc(objectUrl);
329
-
330
- return () => {
331
- URL.revokeObjectURL(objectUrl);
332
- };
333
- }, [file]);
334
-
335
- return src;
336
- };
337
-
338
- const useAttachmentSrc = () => {
339
- const { file, src } = useAssistantState(
340
- useShallow(({ attachment }): { file?: File; src?: string } => {
341
- if (attachment.type !== "image") return {};
342
- if (attachment.file) return { file: attachment.file };
343
- const src = attachment.content?.filter((c) => c.type === "image")[0]
344
- ?.image;
345
- if (!src) return {};
346
- return { src };
347
- }),
348
- );
349
-
350
- return useFileSrc(file) ?? src;
351
- };
352
-
353
- type AttachmentPreviewProps = {
354
- src: string;
355
- };
356
-
357
- const AttachmentPreview: FC<AttachmentPreviewProps> = ({ src }) => {
358
- const [isLoaded, setIsLoaded] = useState(false);
359
- return (
360
- <Image
361
- src={src}
362
- alt="Image Preview"
363
- width={1}
364
- height={1}
365
- className={
366
- isLoaded
367
- ? "aui-attachment-preview-image-loaded block h-auto max-h-[80vh] w-auto max-w-full object-contain"
368
- : "aui-attachment-preview-image-loading hidden"
369
- }
370
- onLoadingComplete={() => setIsLoaded(true)}
371
- priority={false}
372
- />
373
- );
374
- };
375
-
376
- const AttachmentPreviewDialog: FC<PropsWithChildren> = ({ children }) => {
377
- const src = useAttachmentSrc();
378
-
379
- if (!src) return children;
380
-
381
- return (
382
- <Dialog>
383
- <DialogTrigger
384
- className="aui-attachment-preview-trigger cursor-pointer transition-colors hover:bg-accent/50"
385
- asChild
386
- >
387
- {children}
388
- </DialogTrigger>
389
- <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">
390
- <DialogTitle className="aui-sr-only sr-only">
391
- Image Attachment Preview
392
- </DialogTitle>
393
- <div className="aui-attachment-preview relative mx-auto flex max-h-[80dvh] w-full items-center justify-center overflow-hidden bg-background">
394
- <AttachmentPreview src={src} />
395
- </div>
396
- </DialogContent>
397
- </Dialog>
398
- );
399
- };
400
-
401
- const AttachmentThumb: FC = () => {
402
- const isImage = useAssistantState(
403
- ({ attachment }) => attachment.type === "image",
404
- );
405
- const src = useAttachmentSrc();
406
-
407
- return (
408
- <Avatar className="aui-attachment-tile-avatar h-full w-full rounded-none">
409
- <AvatarImage
410
- src={src}
411
- alt="Attachment preview"
412
- className="aui-attachment-tile-image object-cover"
413
- />
414
- <AvatarFallback delayMs={isImage ? 200 : 0}>
415
- <FileText className="aui-attachment-tile-fallback-icon size-8 text-muted-foreground" />
416
- </AvatarFallback>
417
- </Avatar>
418
- );
419
- };
420
-
421
- const AttachmentUI: FC = () => {
422
- const api = useAssistantApi();
423
- const isComposer = api.attachment.source === "composer";
424
-
425
- const isImage = useAssistantState(
426
- ({ attachment }) => attachment.type === "image",
427
- );
428
- const typeLabel = useAssistantState(({ attachment }) => {
429
- const type = attachment.type;
430
- switch (type) {
431
- case "image":
432
- return "Image";
433
- case "document":
434
- return "Document";
435
- case "file":
436
- return "File";
437
- default:
438
- const _exhaustiveCheck: never = type;
439
- throw new Error(`Unknown attachment type: ${_exhaustiveCheck}`);
440
- }
441
- });
442
-
443
- return (
444
- <Tooltip>
445
- <AttachmentPrimitive.Root
446
- className={cn(
447
- "aui-attachment-root relative",
448
- isImage &&
449
- "aui-attachment-root-composer only:[&>#attachment-tile]:size-24",
450
- )}
451
- >
452
- <AttachmentPreviewDialog>
453
- <TooltipTrigger asChild>
454
- <div
455
- className={cn(
456
- "aui-attachment-tile size-14 cursor-pointer overflow-hidden rounded-[14px] border bg-muted transition-opacity hover:opacity-75",
457
- isComposer &&
458
- "aui-attachment-tile-composer border-foreground/20",
459
- )}
460
- role="button"
461
- id="attachment-tile"
462
- aria-label={`${typeLabel} attachment`}
463
- >
464
- <AttachmentThumb />
465
- </div>
466
- </TooltipTrigger>
467
- </AttachmentPreviewDialog>
468
- {isComposer && <AttachmentRemove />}
469
- </AttachmentPrimitive.Root>
470
- <TooltipContent side="top">
471
- <AttachmentPrimitive.Name />
472
- </TooltipContent>
473
- </Tooltip>
474
- );
475
- };
476
-
477
- const AttachmentRemove: FC = () => {
478
- return (
479
- <AttachmentPrimitive.Remove asChild>
480
- <TooltipIconButton
481
- tooltip="Remove file"
482
- 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"
483
- side="top"
484
- >
485
- <XIcon className="aui-attachment-remove-icon size-3 dark:stroke-[2.5px]" />
486
- </TooltipIconButton>
487
- </AttachmentPrimitive.Remove>
488
- );
489
- };
490
-
491
- export const UserMessageAttachments: FC = () => {
492
- return (
493
- <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">
494
- <MessagePrimitive.Attachments components={{ Attachment: AttachmentUI }} />
495
- </div>
496
- );
497
- };
498
-
499
- export const ComposerAttachments: FC = () => {
500
- return (
501
- <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">
502
- <ComposerPrimitive.Attachments
503
- components={{ Attachment: AttachmentUI }}
504
- />
505
- </div>
506
- );
507
- };
508
-
509
- export const ComposerAddAttachment: FC = () => {
510
- return (
511
- <ComposerPrimitive.AddAttachment asChild>
512
- <TooltipIconButton
513
- tooltip="Add Attachment"
514
- side="bottom"
515
- variant="ghost"
516
- size="icon"
517
- className="aui-composer-add-attachment size-8.5 rounded-full p-1 font-semibold text-xs hover:bg-muted-foreground/15 dark:border-muted-foreground/15 dark:hover:bg-muted-foreground/30"
518
- aria-label="Add Attachment"
519
- >
520
- <PlusIcon className="aui-attachment-add-icon size-5 stroke-[1.5px]" />
521
- </TooltipIconButton>
522
- </ComposerPrimitive.AddAttachment>
523
- );
524
- };
525
-
526
- ```
527
-
528
- ## components/assistant-ui/markdown-text.tsx
529
-
530
- ```tsx
531
- "use client";
532
-
533
- import "@assistant-ui/react-markdown/styles/dot.css";
534
-
535
- import {
536
- type CodeHeaderProps,
537
- MarkdownTextPrimitive,
538
- unstable_memoizeMarkdownComponents as memoizeMarkdownComponents,
539
- useIsMarkdownCodeBlock,
540
- } from "@assistant-ui/react-markdown";
541
- import remarkGfm from "remark-gfm";
542
- import { type FC, memo, useState } from "react";
543
- import { CheckIcon, CopyIcon } from "lucide-react";
544
-
545
- import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
546
- import { cn } from "@/lib/utils";
547
-
548
- const MarkdownTextImpl = () => {
549
- return (
550
- <MarkdownTextPrimitive
551
- remarkPlugins={[remarkGfm]}
552
- className="aui-md"
553
- components={defaultComponents}
554
- />
555
- );
556
- };
557
-
558
- export const MarkdownText = memo(MarkdownTextImpl);
559
-
560
- const CodeHeader: FC<CodeHeaderProps> = ({ language, code }) => {
561
- const { isCopied, copyToClipboard } = useCopyToClipboard();
562
- const onCopy = () => {
563
- if (!code || isCopied) return;
564
- copyToClipboard(code);
565
- };
566
-
567
- return (
568
- <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">
569
- <span className="aui-code-header-language lowercase [&>span]:text-xs">
570
- {language}
571
- </span>
572
- <TooltipIconButton tooltip="Copy" onClick={onCopy}>
573
- {!isCopied && <CopyIcon />}
574
- {isCopied && <CheckIcon />}
575
- </TooltipIconButton>
576
- </div>
577
- );
578
- };
579
-
580
- const useCopyToClipboard = ({
581
- copiedDuration = 3000,
582
- }: {
583
- copiedDuration?: number;
584
- } = {}) => {
585
- const [isCopied, setIsCopied] = useState<boolean>(false);
586
-
587
- const copyToClipboard = (value: string) => {
588
- if (!value) return;
589
-
590
- navigator.clipboard.writeText(value).then(() => {
591
- setIsCopied(true);
592
- setTimeout(() => setIsCopied(false), copiedDuration);
593
- });
594
- };
595
-
596
- return { isCopied, copyToClipboard };
597
- };
598
-
599
- const defaultComponents = memoizeMarkdownComponents({
600
- h1: ({ className, ...props }) => (
601
- <h1
602
- className={cn(
603
- "aui-md-h1 mb-8 scroll-m-20 font-extrabold text-4xl tracking-tight last:mb-0",
604
- className,
605
- )}
606
- {...props}
607
- />
608
- ),
609
- h2: ({ className, ...props }) => (
610
- <h2
611
- className={cn(
612
- "aui-md-h2 mt-8 mb-4 scroll-m-20 font-semibold text-3xl tracking-tight first:mt-0 last:mb-0",
613
- className,
614
- )}
615
- {...props}
616
- />
617
- ),
618
- h3: ({ className, ...props }) => (
619
- <h3
620
- className={cn(
621
- "aui-md-h3 mt-6 mb-4 scroll-m-20 font-semibold text-2xl tracking-tight first:mt-0 last:mb-0",
622
- className,
623
- )}
624
- {...props}
625
- />
626
- ),
627
- h4: ({ className, ...props }) => (
628
- <h4
629
- className={cn(
630
- "aui-md-h4 mt-6 mb-4 scroll-m-20 font-semibold text-xl tracking-tight first:mt-0 last:mb-0",
631
- className,
632
- )}
633
- {...props}
634
- />
635
- ),
636
- h5: ({ className, ...props }) => (
637
- <h5
638
- className={cn(
639
- "aui-md-h5 my-4 font-semibold text-lg first:mt-0 last:mb-0",
640
- className,
641
- )}
642
- {...props}
643
- />
644
- ),
645
- h6: ({ className, ...props }) => (
646
- <h6
647
- className={cn(
648
- "aui-md-h6 my-4 font-semibold first:mt-0 last:mb-0",
649
- className,
650
- )}
651
- {...props}
652
- />
653
- ),
654
- p: ({ className, ...props }) => (
655
- <p
656
- className={cn(
657
- "aui-md-p mt-5 mb-5 leading-7 first:mt-0 last:mb-0",
658
- className,
659
- )}
660
- {...props}
661
- />
662
- ),
663
- a: ({ className, ...props }) => (
664
- <a
665
- className={cn(
666
- "aui-md-a font-medium text-primary underline underline-offset-4",
667
- className,
668
- )}
669
- {...props}
670
- />
671
- ),
672
- blockquote: ({ className, ...props }) => (
673
- <blockquote
674
- className={cn("aui-md-blockquote border-l-2 pl-6 italic", className)}
675
- {...props}
676
- />
677
- ),
678
- ul: ({ className, ...props }) => (
679
- <ul
680
- className={cn("aui-md-ul my-5 ml-6 list-disc [&>li]:mt-2", className)}
681
- {...props}
682
- />
683
- ),
684
- ol: ({ className, ...props }) => (
685
- <ol
686
- className={cn("aui-md-ol my-5 ml-6 list-decimal [&>li]:mt-2", className)}
687
- {...props}
688
- />
689
- ),
690
- hr: ({ className, ...props }) => (
691
- <hr className={cn("aui-md-hr my-5 border-b", className)} {...props} />
692
- ),
693
- table: ({ className, ...props }) => (
694
- <table
695
- className={cn(
696
- "aui-md-table my-5 w-full border-separate border-spacing-0 overflow-y-auto",
697
- className,
698
- )}
699
- {...props}
700
- />
701
- ),
702
- th: ({ className, ...props }) => (
703
- <th
704
- className={cn(
705
- "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",
706
- className,
707
- )}
708
- {...props}
709
- />
710
- ),
711
- td: ({ className, ...props }) => (
712
- <td
713
- className={cn(
714
- "aui-md-td border-b border-l px-4 py-2 text-left last:border-r [[align=center]]:text-center [[align=right]]:text-right",
715
- className,
716
- )}
717
- {...props}
718
- />
719
- ),
720
- tr: ({ className, ...props }) => (
721
- <tr
722
- className={cn(
723
- "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",
724
- className,
725
- )}
726
- {...props}
727
- />
728
- ),
729
- sup: ({ className, ...props }) => (
730
- <sup
731
- className={cn("aui-md-sup [&>a]:text-xs [&>a]:no-underline", className)}
732
- {...props}
733
- />
734
- ),
735
- pre: ({ className, ...props }) => (
736
- <pre
737
- className={cn(
738
- "aui-md-pre overflow-x-auto rounded-t-none! rounded-b-lg bg-black p-4 text-white",
739
- className,
740
- )}
741
- {...props}
742
- />
743
- ),
744
- code: function Code({ className, ...props }) {
745
- const isCodeBlock = useIsMarkdownCodeBlock();
746
- return (
747
- <code
748
- className={cn(
749
- !isCodeBlock &&
750
- "aui-md-inline-code rounded border bg-muted font-semibold",
751
- className,
752
- )}
753
- {...props}
754
- />
755
- );
756
- },
757
- CodeHeader,
758
- });
759
-
760
- ```
761
-
762
- ## components/assistant-ui/thread.tsx
763
-
764
- ```tsx
765
- import {
766
- ComposerAddAttachment,
767
- ComposerAttachments,
768
- UserMessageAttachments,
769
- } from "@/components/assistant-ui/attachment";
770
- import { MarkdownText } from "@/components/assistant-ui/markdown-text";
771
- import { ToolFallback } from "@/components/assistant-ui/tool-fallback";
772
- import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
773
- import { Button } from "@/components/ui/button";
774
- import { cn } from "@/lib/utils";
775
- import {
776
- ActionBarPrimitive,
777
- AssistantIf,
778
- BranchPickerPrimitive,
779
- ComposerPrimitive,
780
- ErrorPrimitive,
781
- MessagePrimitive,
782
- ThreadPrimitive,
783
- } from "@assistant-ui/react";
784
- import {
785
- ArrowDownIcon,
786
- ArrowUpIcon,
787
- CheckIcon,
788
- ChevronLeftIcon,
789
- ChevronRightIcon,
790
- CopyIcon,
791
- DownloadIcon,
792
- MicIcon,
793
- PencilIcon,
794
- RefreshCwIcon,
795
- SquareIcon,
796
- } from "lucide-react";
797
- import type { FC } from "react";
798
-
799
- export const Thread: FC = () => {
800
- return (
801
- <ThreadPrimitive.Root
802
- className="aui-root aui-thread-root @container flex h-full flex-col bg-background"
803
- style={{
804
- ["--thread-max-width" as string]: "44rem",
805
- }}
806
- >
807
- <ThreadPrimitive.Viewport
808
- turnAnchor="top"
809
- className="aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-smooth px-4 pt-4"
810
- >
811
- <AssistantIf condition={({ thread }) => thread.isEmpty}>
812
- <ThreadWelcome />
813
- </AssistantIf>
814
-
815
- <ThreadPrimitive.Messages
816
- components={{
817
- UserMessage,
818
- EditComposer,
819
- AssistantMessage,
820
- }}
821
- />
822
-
823
- <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">
824
- <ThreadScrollToBottom />
825
- <Composer />
826
- </ThreadPrimitive.ViewportFooter>
827
- </ThreadPrimitive.Viewport>
828
- </ThreadPrimitive.Root>
829
- );
830
- };
831
-
832
- const ThreadScrollToBottom: FC = () => {
833
- return (
834
- <ThreadPrimitive.ScrollToBottom asChild>
835
- <TooltipIconButton
836
- tooltip="Scroll to bottom"
837
- variant="outline"
838
- className="aui-thread-scroll-to-bottom absolute -top-12 z-10 self-center rounded-full p-4 disabled:invisible dark:bg-background dark:hover:bg-accent"
839
- >
840
- <ArrowDownIcon />
841
- </TooltipIconButton>
842
- </ThreadPrimitive.ScrollToBottom>
843
- );
844
- };
845
-
846
- const ThreadWelcome: FC = () => {
847
- return (
848
- <div className="aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col">
849
- <div className="aui-thread-welcome-center flex w-full grow flex-col items-center justify-center">
850
- <div className="aui-thread-welcome-message flex size-full flex-col justify-center px-4">
851
- <h1 className="aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in font-semibold text-2xl duration-200">
852
- Voice Input Demo
853
- </h1>
854
- <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">
855
- Click the mic button to speak
856
- </p>
857
- </div>
858
- </div>
859
- <ThreadSuggestions />
860
- </div>
861
- );
862
- };
863
-
864
- const SUGGESTIONS = [
865
- {
866
- title: "What's the weather",
867
- label: "in San Francisco?",
868
- prompt: "What's the weather in San Francisco?",
869
- },
870
- {
871
- title: "Explain React hooks",
872
- label: "like useState and useEffect",
873
- prompt: "Explain React hooks like useState and useEffect",
874
- },
875
- ] as const;
876
-
877
- const ThreadSuggestions: FC = () => {
878
- return (
879
- <div className="aui-thread-welcome-suggestions grid w-full @md:grid-cols-2 gap-2 pb-4">
880
- {SUGGESTIONS.map((suggestion, index) => (
881
- <div
882
- key={suggestion.prompt}
883
- 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"
884
- style={{ animationDelay: `${100 + index * 50}ms` }}
885
- >
886
- <ThreadPrimitive.Suggestion prompt={suggestion.prompt} send asChild>
887
- <Button
888
- variant="ghost"
889
- 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"
890
- aria-label={suggestion.prompt}
891
- >
892
- <span className="aui-thread-welcome-suggestion-text-1 font-medium">
893
- {suggestion.title}
894
- </span>
895
- <span className="aui-thread-welcome-suggestion-text-2 text-muted-foreground">
896
- {suggestion.label}
897
- </span>
898
- </Button>
899
- </ThreadPrimitive.Suggestion>
900
- </div>
901
- ))}
902
- </div>
903
- );
904
- };
905
-
906
- const Composer: FC = () => {
907
- return (
908
- <ComposerPrimitive.Root className="aui-composer-root relative flex w-full flex-col">
909
- <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">
910
- <ComposerAttachments />
911
- <ComposerPrimitive.Input
912
- placeholder="Send a message..."
913
- 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"
914
- rows={1}
915
- autoFocus
916
- aria-label="Message input"
917
- />
918
- <ComposerAction />
919
- </ComposerPrimitive.AttachmentDropzone>
920
- </ComposerPrimitive.Root>
921
- );
922
- };
923
-
924
- const ComposerAction: FC = () => {
925
- return (
926
- <div className="aui-composer-action-wrapper relative mx-2 mb-2 flex items-center justify-between">
927
- <div className="flex items-center gap-1">
928
- <ComposerAddAttachment />
929
-
930
- <ComposerPrimitive.If dictation={false}>
931
- <ComposerPrimitive.Dictate asChild>
932
- <TooltipIconButton
933
- tooltip="Voice input"
934
- side="top"
935
- variant="ghost"
936
- className="aui-composer-dictate size-8 rounded-full"
937
- aria-label="Start voice input"
938
- >
939
- <MicIcon className="size-4" />
940
- </TooltipIconButton>
941
- </ComposerPrimitive.Dictate>
942
- </ComposerPrimitive.If>
943
-
944
- <ComposerPrimitive.If dictation>
945
- <ComposerPrimitive.StopDictation asChild>
946
- <TooltipIconButton
947
- tooltip="Stop dictation"
948
- side="top"
949
- variant="default"
950
- className="aui-composer-stop-dictation size-8 rounded-full"
951
- aria-label="Stop voice input"
952
- >
953
- <SquareIcon className="size-3 animate-pulse fill-current" />
954
- </TooltipIconButton>
955
- </ComposerPrimitive.StopDictation>
956
- </ComposerPrimitive.If>
957
- </div>
958
-
959
- <AssistantIf condition={({ thread }) => !thread.isRunning}>
960
- <ComposerPrimitive.Send asChild>
961
- <TooltipIconButton
962
- tooltip="Send message"
963
- side="bottom"
964
- type="submit"
965
- variant="default"
966
- size="icon"
967
- className="aui-composer-send size-8 rounded-full"
968
- aria-label="Send message"
969
- >
970
- <ArrowUpIcon className="aui-composer-send-icon size-4" />
971
- </TooltipIconButton>
972
- </ComposerPrimitive.Send>
973
- </AssistantIf>
974
-
975
- <AssistantIf condition={({ thread }) => thread.isRunning}>
976
- <ComposerPrimitive.Cancel asChild>
977
- <Button
978
- type="button"
979
- variant="default"
980
- size="icon"
981
- className="aui-composer-cancel size-8 rounded-full"
982
- aria-label="Stop generating"
983
- >
984
- <SquareIcon className="aui-composer-cancel-icon size-3 fill-current" />
985
- </Button>
986
- </ComposerPrimitive.Cancel>
987
- </AssistantIf>
988
- </div>
989
- );
990
- };
991
-
992
- const MessageError: FC = () => {
993
- return (
994
- <MessagePrimitive.Error>
995
- <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">
996
- <ErrorPrimitive.Message className="aui-message-error-message line-clamp-2" />
997
- </ErrorPrimitive.Root>
998
- </MessagePrimitive.Error>
999
- );
1000
- };
1001
-
1002
- const AssistantMessage: FC = () => {
1003
- return (
1004
- <MessagePrimitive.Root
1005
- 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"
1006
- data-role="assistant"
1007
- >
1008
- <div className="aui-assistant-message-content wrap-break-word px-2 text-foreground leading-relaxed">
1009
- <MessagePrimitive.Parts
1010
- components={{
1011
- Text: MarkdownText,
1012
- tools: { Fallback: ToolFallback },
1013
- }}
1014
- />
1015
- <MessageError />
1016
- </div>
1017
-
1018
- <div className="aui-assistant-message-footer mt-1 ml-2 flex">
1019
- <BranchPicker />
1020
- <AssistantActionBar />
1021
- </div>
1022
- </MessagePrimitive.Root>
1023
- );
1024
- };
1025
-
1026
- const AssistantActionBar: FC = () => {
1027
- return (
1028
- <ActionBarPrimitive.Root
1029
- hideWhenRunning
1030
- autohide="not-last"
1031
- autohideFloat="single-branch"
1032
- className="aui-assistant-action-bar-root col-start-3 row-start-2 -ml-1 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"
1033
- >
1034
- <ActionBarPrimitive.Copy asChild>
1035
- <TooltipIconButton tooltip="Copy">
1036
- <AssistantIf condition={({ message }) => message.isCopied}>
1037
- <CheckIcon />
1038
- </AssistantIf>
1039
- <AssistantIf condition={({ message }) => !message.isCopied}>
1040
- <CopyIcon />
1041
- </AssistantIf>
1042
- </TooltipIconButton>
1043
- </ActionBarPrimitive.Copy>
1044
- <ActionBarPrimitive.ExportMarkdown asChild>
1045
- <TooltipIconButton tooltip="Export as Markdown">
1046
- <DownloadIcon />
1047
- </TooltipIconButton>
1048
- </ActionBarPrimitive.ExportMarkdown>
1049
- <ActionBarPrimitive.Reload asChild>
1050
- <TooltipIconButton tooltip="Refresh">
1051
- <RefreshCwIcon />
1052
- </TooltipIconButton>
1053
- </ActionBarPrimitive.Reload>
1054
- </ActionBarPrimitive.Root>
1055
- );
1056
- };
1057
-
1058
- const UserMessage: FC = () => {
1059
- return (
1060
- <MessagePrimitive.Root
1061
- 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"
1062
- data-role="user"
1063
- >
1064
- <UserMessageAttachments />
1065
-
1066
- <div className="aui-user-message-content-wrapper relative col-start-2 min-w-0">
1067
- <div className="aui-user-message-content wrap-break-word rounded-2xl bg-muted px-4 py-2.5 text-foreground">
1068
- <MessagePrimitive.Parts />
1069
- </div>
1070
- <div className="aui-user-action-bar-wrapper absolute top-1/2 left-0 -translate-x-full -translate-y-1/2 pr-2">
1071
- <UserActionBar />
1072
- </div>
1073
- </div>
1074
-
1075
- <BranchPicker className="aui-user-branch-picker col-span-full col-start-1 row-start-3 -mr-1 justify-end" />
1076
- </MessagePrimitive.Root>
1077
- );
1078
- };
1079
-
1080
- const UserActionBar: FC = () => {
1081
- return (
1082
- <ActionBarPrimitive.Root
1083
- hideWhenRunning
1084
- autohide="not-last"
1085
- className="aui-user-action-bar-root flex flex-col items-end"
1086
- >
1087
- <ActionBarPrimitive.Edit asChild>
1088
- <TooltipIconButton tooltip="Edit" className="aui-user-action-edit p-4">
1089
- <PencilIcon />
1090
- </TooltipIconButton>
1091
- </ActionBarPrimitive.Edit>
1092
- </ActionBarPrimitive.Root>
1093
- );
1094
- };
1095
-
1096
- const EditComposer: FC = () => {
1097
- return (
1098
- <MessagePrimitive.Root className="aui-edit-composer-wrapper mx-auto flex w-full max-w-(--thread-max-width) flex-col px-2 py-3">
1099
- <ComposerPrimitive.Root className="aui-edit-composer-root ml-auto flex w-full max-w-[85%] flex-col rounded-2xl bg-muted">
1100
- <ComposerPrimitive.Input
1101
- className="aui-edit-composer-input min-h-14 w-full resize-none bg-transparent p-4 text-foreground text-sm outline-none"
1102
- autoFocus
1103
- />
1104
- <div className="aui-edit-composer-footer mx-3 mb-3 flex items-center gap-2 self-end">
1105
- <ComposerPrimitive.Cancel asChild>
1106
- <Button variant="ghost" size="sm">
1107
- Cancel
1108
- </Button>
1109
- </ComposerPrimitive.Cancel>
1110
- <ComposerPrimitive.Send asChild>
1111
- <Button size="sm">Update</Button>
1112
- </ComposerPrimitive.Send>
1113
- </div>
1114
- </ComposerPrimitive.Root>
1115
- </MessagePrimitive.Root>
1116
- );
1117
- };
1118
-
1119
- const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
1120
- className,
1121
- ...rest
1122
- }) => {
1123
- return (
1124
- <BranchPickerPrimitive.Root
1125
- hideWhenSingleBranch
1126
- className={cn(
1127
- "aui-branch-picker-root mr-2 -ml-2 inline-flex items-center text-muted-foreground text-xs",
1128
- className,
1129
- )}
1130
- {...rest}
1131
- >
1132
- <BranchPickerPrimitive.Previous asChild>
1133
- <TooltipIconButton tooltip="Previous">
1134
- <ChevronLeftIcon />
1135
- </TooltipIconButton>
1136
- </BranchPickerPrimitive.Previous>
1137
- <span className="aui-branch-picker-state font-medium">
1138
- <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
1139
- </span>
1140
- <BranchPickerPrimitive.Next asChild>
1141
- <TooltipIconButton tooltip="Next">
1142
- <ChevronRightIcon />
1143
- </TooltipIconButton>
1144
- </BranchPickerPrimitive.Next>
1145
- </BranchPickerPrimitive.Root>
1146
- );
1147
- };
1148
-
1149
- ```
1150
-
1151
- ## components/assistant-ui/tool-fallback.tsx
1152
-
1153
- ```tsx
1154
- "use client";
1155
-
1156
- import { memo, useCallback, useRef, useState } from "react";
1157
- import {
1158
- AlertCircleIcon,
1159
- CheckIcon,
1160
- ChevronDownIcon,
1161
- LoaderIcon,
1162
- XCircleIcon,
1163
- } from "lucide-react";
1164
- import {
1165
- useScrollLock,
1166
- type ToolCallMessagePartStatus,
1167
- type ToolCallMessagePartComponent,
1168
- } from "@assistant-ui/react";
1169
- import {
1170
- Collapsible,
1171
- CollapsibleContent,
1172
- CollapsibleTrigger,
1173
- } from "@/components/ui/collapsible";
1174
- import { cn } from "@/lib/utils";
1175
-
1176
- const ANIMATION_DURATION = 200;
1177
-
1178
- export type ToolFallbackRootProps = Omit<
1179
- React.ComponentProps<typeof Collapsible>,
1180
- "open" | "onOpenChange"
1181
- > & {
1182
- open?: boolean;
1183
- onOpenChange?: (open: boolean) => void;
1184
- defaultOpen?: boolean;
1185
- };
1186
-
1187
- function ToolFallbackRoot({
1188
- className,
1189
- open: controlledOpen,
1190
- onOpenChange: controlledOnOpenChange,
1191
- defaultOpen = false,
1192
- children,
1193
- ...props
1194
- }: ToolFallbackRootProps) {
1195
- const collapsibleRef = useRef<HTMLDivElement>(null);
1196
- const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
1197
- const lockScroll = useScrollLock(collapsibleRef, ANIMATION_DURATION);
1198
-
1199
- const isControlled = controlledOpen !== undefined;
1200
- const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
1201
-
1202
- const handleOpenChange = useCallback(
1203
- (open: boolean) => {
1204
- if (!open) {
1205
- lockScroll();
1206
- }
1207
- if (!isControlled) {
1208
- setUncontrolledOpen(open);
1209
- }
1210
- controlledOnOpenChange?.(open);
1211
- },
1212
- [lockScroll, isControlled, controlledOnOpenChange],
1213
- );
1214
-
1215
- return (
1216
- <Collapsible
1217
- ref={collapsibleRef}
1218
- data-slot="tool-fallback-root"
1219
- open={isOpen}
1220
- onOpenChange={handleOpenChange}
1221
- className={cn(
1222
- "aui-tool-fallback-root group/tool-fallback-root w-full rounded-lg border py-3",
1223
- className,
1224
- )}
1225
- style={
1226
- {
1227
- "--animation-duration": `${ANIMATION_DURATION}ms`,
1228
- } as React.CSSProperties
1229
- }
1230
- {...props}
1231
- >
1232
- {children}
1233
- </Collapsible>
1234
- );
1235
- }
1236
-
1237
- type ToolStatus = ToolCallMessagePartStatus["type"];
1238
-
1239
- const statusIconMap: Record<ToolStatus, React.ElementType> = {
1240
- running: LoaderIcon,
1241
- complete: CheckIcon,
1242
- incomplete: XCircleIcon,
1243
- "requires-action": AlertCircleIcon,
1244
- };
1245
-
1246
- function ToolFallbackTrigger({
1247
- toolName,
1248
- status,
1249
- className,
1250
- ...props
1251
- }: React.ComponentProps<typeof CollapsibleTrigger> & {
1252
- toolName: string;
1253
- status?: ToolCallMessagePartStatus;
1254
- }) {
1255
- const statusType = status?.type ?? "complete";
1256
- const isRunning = statusType === "running";
1257
- const isCancelled =
1258
- status?.type === "incomplete" && status.reason === "cancelled";
1259
-
1260
- const Icon = statusIconMap[statusType];
1261
- const label = isCancelled ? "Cancelled tool" : "Used tool";
1262
-
1263
- return (
1264
- <CollapsibleTrigger
1265
- data-slot="tool-fallback-trigger"
1266
- className={cn(
1267
- "aui-tool-fallback-trigger group/trigger flex w-full items-center gap-2 px-4 text-sm transition-colors",
1268
- className,
1269
- )}
1270
- {...props}
1271
- >
1272
- <Icon
1273
- data-slot="tool-fallback-trigger-icon"
1274
- className={cn(
1275
- "aui-tool-fallback-trigger-icon size-4 shrink-0",
1276
- isCancelled && "text-muted-foreground",
1277
- isRunning && "animate-spin",
1278
- )}
1279
- />
1280
- <span
1281
- data-slot="tool-fallback-trigger-label"
1282
- className={cn(
1283
- "aui-tool-fallback-trigger-label-wrapper relative inline-block grow text-left leading-none",
1284
- isCancelled && "text-muted-foreground line-through",
1285
- )}
1286
- >
1287
- <span>
1288
- {label}: <b>{toolName}</b>
1289
- </span>
1290
- {isRunning && (
1291
- <span
1292
- aria-hidden
1293
- data-slot="tool-fallback-trigger-shimmer"
1294
- className="aui-tool-fallback-trigger-shimmer shimmer pointer-events-none absolute inset-0 motion-reduce:animate-none"
1295
- >
1296
- {label}: <b>{toolName}</b>
1297
- </span>
1298
- )}
1299
- </span>
1300
- <ChevronDownIcon
1301
- data-slot="tool-fallback-trigger-chevron"
1302
- className={cn(
1303
- "aui-tool-fallback-trigger-chevron size-4 shrink-0",
1304
- "transition-transform duration-(--animation-duration) ease-out",
1305
- "group-data-[state=closed]/trigger:-rotate-90",
1306
- "group-data-[state=open]/trigger:rotate-0",
1307
- )}
1308
- />
1309
- </CollapsibleTrigger>
1310
- );
1311
- }
1312
-
1313
- function ToolFallbackContent({
1314
- className,
1315
- children,
1316
- ...props
1317
- }: React.ComponentProps<typeof CollapsibleContent>) {
1318
- return (
1319
- <CollapsibleContent
1320
- data-slot="tool-fallback-content"
1321
- className={cn(
1322
- "aui-tool-fallback-content relative overflow-hidden text-sm outline-none",
1323
- "group/collapsible-content ease-out",
1324
- "data-[state=closed]:animate-collapsible-up",
1325
- "data-[state=open]:animate-collapsible-down",
1326
- "data-[state=closed]:fill-mode-forwards",
1327
- "data-[state=closed]:pointer-events-none",
1328
- "data-[state=open]:duration-(--animation-duration)",
1329
- "data-[state=closed]:duration-(--animation-duration)",
1330
- className,
1331
- )}
1332
- {...props}
1333
- >
1334
- <div className="mt-3 flex flex-col gap-2 border-t pt-2">{children}</div>
1335
- </CollapsibleContent>
1336
- );
1337
- }
1338
-
1339
- function ToolFallbackArgs({
1340
- argsText,
1341
- className,
1342
- ...props
1343
- }: React.ComponentProps<"div"> & {
1344
- argsText?: string;
1345
- }) {
1346
- if (!argsText) return null;
1347
-
1348
- return (
1349
- <div
1350
- data-slot="tool-fallback-args"
1351
- className={cn("aui-tool-fallback-args px-4", className)}
1352
- {...props}
1353
- >
1354
- <pre className="aui-tool-fallback-args-value whitespace-pre-wrap">
1355
- {argsText}
1356
- </pre>
1357
- </div>
1358
- );
1359
- }
1360
-
1361
- function ToolFallbackResult({
1362
- result,
1363
- className,
1364
- ...props
1365
- }: React.ComponentProps<"div"> & {
1366
- result?: unknown;
1367
- }) {
1368
- if (result === undefined) return null;
1369
-
1370
- return (
1371
- <div
1372
- data-slot="tool-fallback-result"
1373
- className={cn(
1374
- "aui-tool-fallback-result border-t border-dashed px-4 pt-2",
1375
- className,
1376
- )}
1377
- {...props}
1378
- >
1379
- <p className="aui-tool-fallback-result-header font-semibold">Result:</p>
1380
- <pre className="aui-tool-fallback-result-content whitespace-pre-wrap">
1381
- {typeof result === "string" ? result : JSON.stringify(result, null, 2)}
1382
- </pre>
1383
- </div>
1384
- );
1385
- }
1386
-
1387
- function ToolFallbackError({
1388
- status,
1389
- className,
1390
- ...props
1391
- }: React.ComponentProps<"div"> & {
1392
- status?: ToolCallMessagePartStatus;
1393
- }) {
1394
- if (status?.type !== "incomplete") return null;
1395
-
1396
- const error = status.error;
1397
- const errorText = error
1398
- ? typeof error === "string"
1399
- ? error
1400
- : JSON.stringify(error)
1401
- : null;
1402
-
1403
- if (!errorText) return null;
1404
-
1405
- const isCancelled = status.reason === "cancelled";
1406
- const headerText = isCancelled ? "Cancelled reason:" : "Error:";
1407
-
1408
- return (
1409
- <div
1410
- data-slot="tool-fallback-error"
1411
- className={cn("aui-tool-fallback-error px-4", className)}
1412
- {...props}
1413
- >
1414
- <p className="aui-tool-fallback-error-header font-semibold text-muted-foreground">
1415
- {headerText}
1416
- </p>
1417
- <p className="aui-tool-fallback-error-reason text-muted-foreground">
1418
- {errorText}
1419
- </p>
1420
- </div>
1421
- );
1422
- }
1423
-
1424
- const ToolFallbackImpl: ToolCallMessagePartComponent = ({
1425
- toolName,
1426
- argsText,
1427
- result,
1428
- status,
1429
- }) => {
1430
- const isCancelled =
1431
- status?.type === "incomplete" && status.reason === "cancelled";
1432
-
1433
- return (
1434
- <ToolFallbackRoot
1435
- className={cn(isCancelled && "border-muted-foreground/30 bg-muted/30")}
1436
- >
1437
- <ToolFallbackTrigger toolName={toolName} status={status} />
1438
- <ToolFallbackContent>
1439
- <ToolFallbackError status={status} />
1440
- <ToolFallbackArgs
1441
- argsText={argsText}
1442
- className={cn(isCancelled && "opacity-60")}
1443
- />
1444
- {!isCancelled && <ToolFallbackResult result={result} />}
1445
- </ToolFallbackContent>
1446
- </ToolFallbackRoot>
1447
- );
1448
- };
1449
-
1450
- const ToolFallback = memo(
1451
- ToolFallbackImpl,
1452
- ) as unknown as ToolCallMessagePartComponent & {
1453
- Root: typeof ToolFallbackRoot;
1454
- Trigger: typeof ToolFallbackTrigger;
1455
- Content: typeof ToolFallbackContent;
1456
- Args: typeof ToolFallbackArgs;
1457
- Result: typeof ToolFallbackResult;
1458
- Error: typeof ToolFallbackError;
1459
- };
1460
-
1461
- ToolFallback.displayName = "ToolFallback";
1462
- ToolFallback.Root = ToolFallbackRoot;
1463
- ToolFallback.Trigger = ToolFallbackTrigger;
1464
- ToolFallback.Content = ToolFallbackContent;
1465
- ToolFallback.Args = ToolFallbackArgs;
1466
- ToolFallback.Result = ToolFallbackResult;
1467
- ToolFallback.Error = ToolFallbackError;
1468
-
1469
- export {
1470
- ToolFallback,
1471
- ToolFallbackRoot,
1472
- ToolFallbackTrigger,
1473
- ToolFallbackContent,
1474
- ToolFallbackArgs,
1475
- ToolFallbackResult,
1476
- ToolFallbackError,
1477
- };
1478
-
1479
- ```
1480
-
1481
- ## components/assistant-ui/tooltip-icon-button.tsx
1482
-
1483
- ```tsx
1484
- "use client";
1485
-
1486
- import { ComponentPropsWithRef, forwardRef } from "react";
1487
- import { Slottable } from "@radix-ui/react-slot";
1488
-
1489
- import {
1490
- Tooltip,
1491
- TooltipContent,
1492
- TooltipTrigger,
1493
- } from "@/components/ui/tooltip";
1494
- import { Button } from "@/components/ui/button";
1495
- import { cn } from "@/lib/utils";
1496
-
1497
- export type TooltipIconButtonProps = ComponentPropsWithRef<typeof Button> & {
1498
- tooltip: string;
1499
- side?: "top" | "bottom" | "left" | "right";
1500
- };
1501
-
1502
- export const TooltipIconButton = forwardRef<
1503
- HTMLButtonElement,
1504
- TooltipIconButtonProps
1505
- >(({ children, tooltip, side = "bottom", className, ...rest }, ref) => {
1506
- return (
1507
- <Tooltip>
1508
- <TooltipTrigger asChild>
1509
- <Button
1510
- variant="ghost"
1511
- size="icon"
1512
- {...rest}
1513
- className={cn("aui-button-icon size-6 p-1", className)}
1514
- ref={ref}
1515
- >
1516
- <Slottable>{children}</Slottable>
1517
- <span className="aui-sr-only sr-only">{tooltip}</span>
1518
- </Button>
1519
- </TooltipTrigger>
1520
- <TooltipContent side={side}>{tooltip}</TooltipContent>
1521
- </Tooltip>
1522
- );
1523
- });
1524
-
1525
- TooltipIconButton.displayName = "TooltipIconButton";
1526
-
1527
- ```
1528
-
1529
- ## components/ui/avatar.tsx
1530
-
1531
- ```tsx
1532
- "use client";
1533
-
1534
- import * as React from "react";
1535
- import * as AvatarPrimitive from "@radix-ui/react-avatar";
1536
-
1537
- import { cn } from "@/lib/utils";
1538
-
1539
- function Avatar({
1540
- className,
1541
- ...props
1542
- }: React.ComponentProps<typeof AvatarPrimitive.Root>) {
1543
- return (
1544
- <AvatarPrimitive.Root
1545
- data-slot="avatar"
1546
- className={cn(
1547
- "relative flex size-8 shrink-0 overflow-hidden rounded-full",
1548
- className,
1549
- )}
1550
- {...props}
1551
- />
1552
- );
1553
- }
1554
-
1555
- function AvatarImage({
1556
- className,
1557
- ...props
1558
- }: React.ComponentProps<typeof AvatarPrimitive.Image>) {
1559
- return (
1560
- <AvatarPrimitive.Image
1561
- data-slot="avatar-image"
1562
- className={cn("aspect-square size-full", className)}
1563
- {...props}
1564
- />
1565
- );
1566
- }
1567
-
1568
- function AvatarFallback({
1569
- className,
1570
- ...props
1571
- }: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
1572
- return (
1573
- <AvatarPrimitive.Fallback
1574
- data-slot="avatar-fallback"
1575
- className={cn(
1576
- "flex size-full items-center justify-center rounded-full bg-muted",
1577
- className,
1578
- )}
1579
- {...props}
1580
- />
1581
- );
1582
- }
1583
-
1584
- export { Avatar, AvatarImage, AvatarFallback };
1585
-
1586
- ```
1587
-
1588
- ## components/ui/button.tsx
1589
-
1590
- ```tsx
1591
- import * as React from "react";
1592
- import { Slot } from "@radix-ui/react-slot";
1593
- import { cva, type VariantProps } from "class-variance-authority";
1594
-
1595
- import { cn } from "@/lib/utils";
1596
-
1597
- const buttonVariants = cva(
1598
- "inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md font-medium text-sm outline-none transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
1599
- {
1600
- variants: {
1601
- variant: {
1602
- default:
1603
- "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
1604
- destructive:
1605
- "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
1606
- outline:
1607
- "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
1608
- secondary:
1609
- "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
1610
- ghost:
1611
- "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
1612
- link: "text-primary underline-offset-4 hover:underline",
1613
- },
1614
- size: {
1615
- default: "h-9 px-4 py-2 has-[>svg]:px-3",
1616
- sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
1617
- lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
1618
- icon: "size-9",
1619
- },
1620
- },
1621
- defaultVariants: {
1622
- variant: "default",
1623
- size: "default",
1624
- },
1625
- },
1626
- );
1627
-
1628
- function Button({
1629
- className,
1630
- variant,
1631
- size,
1632
- asChild = false,
1633
- ...props
1634
- }: React.ComponentProps<"button"> &
1635
- VariantProps<typeof buttonVariants> & {
1636
- asChild?: boolean;
1637
- }) {
1638
- const Comp = asChild ? Slot : "button";
1639
-
1640
- return (
1641
- <Comp
1642
- data-slot="button"
1643
- className={cn(buttonVariants({ variant, size, className }))}
1644
- {...props}
1645
- />
1646
- );
1647
- }
1648
-
1649
- export { Button, buttonVariants };
1650
-
1651
- ```
1652
-
1653
- ## components/ui/collapsible.tsx
1654
-
1655
- ```tsx
1656
- "use client";
1657
-
1658
- import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
1659
-
1660
- function Collapsible({
1661
- ...props
1662
- }: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {
1663
- return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />;
1664
- }
1665
-
1666
- function CollapsibleTrigger({
1667
- ...props
1668
- }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) {
1669
- return (
1670
- <CollapsiblePrimitive.CollapsibleTrigger
1671
- data-slot="collapsible-trigger"
1672
- {...props}
1673
- />
1674
- );
1675
- }
1676
-
1677
- function CollapsibleContent({
1678
- ...props
1679
- }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {
1680
- return (
1681
- <CollapsiblePrimitive.CollapsibleContent
1682
- data-slot="collapsible-content"
1683
- {...props}
1684
- />
1685
- );
1686
- }
1687
-
1688
- export { Collapsible, CollapsibleTrigger, CollapsibleContent };
1689
-
1690
- ```
1691
-
1692
- ## components/ui/dialog.tsx
1693
-
1694
- ```tsx
1695
- "use client";
1696
-
1697
- import * as React from "react";
1698
- import * as DialogPrimitive from "@radix-ui/react-dialog";
1699
- import { XIcon } from "lucide-react";
1700
-
1701
- import { cn } from "@/lib/utils";
1702
-
1703
- function Dialog({
1704
- ...props
1705
- }: React.ComponentProps<typeof DialogPrimitive.Root>) {
1706
- return <DialogPrimitive.Root data-slot="dialog" {...props} />;
1707
- }
1708
-
1709
- function DialogTrigger({
1710
- ...props
1711
- }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
1712
- return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
1713
- }
1714
-
1715
- function DialogPortal({
1716
- ...props
1717
- }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
1718
- return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
1719
- }
1720
-
1721
- function DialogClose({
1722
- ...props
1723
- }: React.ComponentProps<typeof DialogPrimitive.Close>) {
1724
- return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
1725
- }
1726
-
1727
- function DialogOverlay({
1728
- className,
1729
- ...props
1730
- }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
1731
- return (
1732
- <DialogPrimitive.Overlay
1733
- data-slot="dialog-overlay"
1734
- className={cn(
1735
- "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=open]:animate-in",
1736
- className,
1737
- )}
1738
- {...props}
1739
- />
1740
- );
1741
- }
1742
-
1743
- function DialogContent({
1744
- className,
1745
- children,
1746
- showCloseButton = true,
1747
- ...props
1748
- }: React.ComponentProps<typeof DialogPrimitive.Content> & {
1749
- showCloseButton?: boolean;
1750
- }) {
1751
- return (
1752
- <DialogPortal data-slot="dialog-portal">
1753
- <DialogOverlay />
1754
- <DialogPrimitive.Content
1755
- data-slot="dialog-content"
1756
- className={cn(
1757
- "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 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 outline-none duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in sm:max-w-lg",
1758
- className,
1759
- )}
1760
- {...props}
1761
- >
1762
- {children}
1763
- {showCloseButton && (
1764
- <DialogPrimitive.Close
1765
- data-slot="dialog-close"
1766
- 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"
1767
- >
1768
- <XIcon />
1769
- <span className="sr-only">Close</span>
1770
- </DialogPrimitive.Close>
1771
- )}
1772
- </DialogPrimitive.Content>
1773
- </DialogPortal>
1774
- );
1775
- }
1776
-
1777
- function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
1778
- return (
1779
- <div
1780
- data-slot="dialog-header"
1781
- className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
1782
- {...props}
1783
- />
1784
- );
1785
- }
1786
-
1787
- function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
1788
- return (
1789
- <div
1790
- data-slot="dialog-footer"
1791
- className={cn(
1792
- "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
1793
- className,
1794
- )}
1795
- {...props}
1796
- />
1797
- );
1798
- }
1799
-
1800
- function DialogTitle({
1801
- className,
1802
- ...props
1803
- }: React.ComponentProps<typeof DialogPrimitive.Title>) {
1804
- return (
1805
- <DialogPrimitive.Title
1806
- data-slot="dialog-title"
1807
- className={cn("font-semibold text-lg leading-none", className)}
1808
- {...props}
1809
- />
1810
- );
1811
- }
1812
-
1813
- function DialogDescription({
1814
- className,
1815
- ...props
1816
- }: React.ComponentProps<typeof DialogPrimitive.Description>) {
1817
- return (
1818
- <DialogPrimitive.Description
1819
- data-slot="dialog-description"
1820
- className={cn("text-muted-foreground text-sm", className)}
1821
- {...props}
1822
- />
1823
- );
1824
- }
1825
-
1826
- export {
1827
- Dialog,
1828
- DialogClose,
1829
- DialogContent,
1830
- DialogDescription,
1831
- DialogFooter,
1832
- DialogHeader,
1833
- DialogOverlay,
1834
- DialogPortal,
1835
- DialogTitle,
1836
- DialogTrigger,
1837
- };
1838
-
1839
- ```
1840
-
1841
- ## components/ui/tooltip.tsx
1842
-
1843
- ```tsx
1844
- "use client";
1845
-
1846
- import * as React from "react";
1847
- import * as TooltipPrimitive from "@radix-ui/react-tooltip";
1848
-
1849
- import { cn } from "@/lib/utils";
1850
-
1851
- function TooltipProvider({
1852
- delayDuration = 0,
1853
- ...props
1854
- }: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
1855
- return (
1856
- <TooltipPrimitive.Provider
1857
- data-slot="tooltip-provider"
1858
- delayDuration={delayDuration}
1859
- {...props}
1860
- />
1861
- );
1862
- }
1863
-
1864
- function Tooltip({
1865
- ...props
1866
- }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
1867
- return (
1868
- <TooltipProvider>
1869
- <TooltipPrimitive.Root data-slot="tooltip" {...props} />
1870
- </TooltipProvider>
1871
- );
1872
- }
1873
-
1874
- function TooltipTrigger({
1875
- ...props
1876
- }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
1877
- return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
1878
- }
1879
-
1880
- function TooltipContent({
1881
- className,
1882
- sideOffset = 0,
1883
- children,
1884
- ...props
1885
- }: React.ComponentProps<typeof TooltipPrimitive.Content>) {
1886
- return (
1887
- <TooltipPrimitive.Portal>
1888
- <TooltipPrimitive.Content
1889
- data-slot="tooltip-content"
1890
- sideOffset={sideOffset}
1891
- className={cn(
1892
- "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",
1893
- className,
1894
- )}
1895
- {...props}
1896
- >
1897
- {children}
1898
- <TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-primary fill-primary" />
1899
- </TooltipPrimitive.Content>
1900
- </TooltipPrimitive.Portal>
1901
- );
284
+ "iconLibrary": "lucide",
285
+ "registries": {
286
+ "@assistant-ui": "https://r.assistant-ui.com/{name}.json"
287
+ }
1902
288
  }
1903
289
 
1904
- export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
1905
-
1906
290
  ```
1907
291
 
1908
292
  ## lib/elevenlabs-scribe-adapter.ts
@@ -2158,42 +542,41 @@ export default nextConfig;
2158
542
 
2159
543
  ```json
2160
544
  {
2161
- "name": "example-with-elevenlabs-scribe",
545
+ "name": "with-elevenlabs-scribe",
2162
546
  "private": true,
2163
547
  "version": "0.0.0",
2164
548
  "type": "module",
2165
549
  "dependencies": {
2166
- "@ai-sdk/openai": "^3.0.13",
2167
- "@ai-sdk/react": "^3.0.44",
550
+ "@ai-sdk/openai": "^3.0.25",
551
+ "@ai-sdk/react": "^3.0.71",
2168
552
  "@assistant-ui/react": "workspace:^",
2169
553
  "@assistant-ui/react-ai-sdk": "workspace:*",
2170
554
  "@assistant-ui/react-markdown": "workspace:^",
2171
- "@elevenlabs/client": "^0.13.0",
555
+ "@assistant-ui/ui": "workspace:*",
556
+ "@elevenlabs/client": "^0.13.1",
2172
557
  "@radix-ui/react-avatar": "^1.1.11",
2173
558
  "@radix-ui/react-collapsible": "^1.1.12",
2174
559
  "@radix-ui/react-dialog": "^1.1.15",
2175
560
  "@radix-ui/react-slot": "^1.2.4",
2176
561
  "@radix-ui/react-tooltip": "^1.2.8",
2177
562
  "@tailwindcss/postcss": "^4.1.18",
2178
- "ai": "^6.0.42",
563
+ "ai": "^6.0.69",
2179
564
  "class-variance-authority": "^0.7.1",
2180
565
  "clsx": "^2.1.1",
2181
- "lucide-react": "^0.562.0",
2182
- "motion": "^12.27.5",
2183
- "next": "^16.1.4",
566
+ "lucide-react": "^0.563.0",
567
+ "motion": "^12.31.0",
568
+ "next": "^16.1.6",
2184
569
  "postcss": "^8.5.6",
2185
- "react": "^19.2.3",
2186
- "react-dom": "^19.2.3",
2187
- "remark-gfm": "^4.0.1",
570
+ "react": "^19.2.4",
571
+ "react-dom": "^19.2.4",
2188
572
  "tailwind-merge": "^3.4.0",
2189
573
  "tailwindcss": "^4.1.18",
2190
- "zod": "^4.3.5",
2191
- "zustand": "^5.0.10"
574
+ "zod": "^4.3.6"
2192
575
  },
2193
576
  "devDependencies": {
2194
577
  "@assistant-ui/x-buildutils": "workspace:*",
2195
- "@types/node": "^25.0.9",
2196
- "@types/react": "^19.2.9",
578
+ "@types/node": "^25.2.0",
579
+ "@types/react": "^19.2.10",
2197
580
  "@types/react-dom": "^19.2.3",
2198
581
  "tw-animate-css": "^1.4.0",
2199
582
  "typescript": "^5.9.3"
@@ -2207,6 +590,51 @@ export default nextConfig;
2207
590
 
2208
591
  ```
2209
592
 
593
+ ## README.md
594
+
595
+ ```markdown
596
+ # ElevenLabs Scribe Integration
597
+
598
+ This example demonstrates how to add voice-to-text dictation using ElevenLabs Scribe with assistant-ui.
599
+
600
+ ## Quick Start
601
+
602
+ ### Using CLI (Recommended)
603
+
604
+ ```bash
605
+ npx assistant-ui@latest create my-app --example with-elevenlabs-scribe
606
+ cd my-app
607
+ ```
608
+
609
+ ### Environment Variables
610
+
611
+ Create `.env.local`:
612
+
613
+ ```
614
+ OPENAI_API_KEY=sk-...
615
+ ELEVENLABS_API_KEY=sk-...
616
+ ```
617
+
618
+ ### Run
619
+
620
+ ```bash
621
+ npm run dev
622
+ ```
623
+
624
+ ## Features
625
+
626
+ - ElevenLabs Scribe voice-to-text integration
627
+ - Custom dictation adapter
628
+ - Real-time voice transcription
629
+ - Vercel AI SDK integration
630
+
631
+ ## Related Documentation
632
+
633
+ - [assistant-ui Documentation](https://www.assistant-ui.com/docs)
634
+ - [ElevenLabs Scribe](https://elevenlabs.io/docs/api-reference/scribe)
635
+
636
+ ```
637
+
2210
638
  ## tsconfig.json
2211
639
 
2212
640
  ```json
@@ -2226,6 +654,11 @@ export default nextConfig;
2226
654
  "jsx": "preserve",
2227
655
  "paths": {
2228
656
  "@/*": ["./*"],
657
+ "@/components/assistant-ui/*": [
658
+ "../../packages/ui/src/components/assistant-ui/*"
659
+ ],
660
+ "@/components/ui/*": ["../../packages/ui/src/components/ui/*"],
661
+ "@assistant-ui/ui/*": ["../../packages/ui/src/*"],
2229
662
  "@assistant-ui/*": ["../../packages/*/src"],
2230
663
  "@assistant-ui/react/*": ["../../packages/react/src/*"],
2231
664
  "@assistant-ui/tap/*": ["../../packages/tap/src/*"],