"use client"; import { ActionBarPrimitive, AuiIf, MessagePrimitive, ThreadPrimitive, useAuiState, } from "@assistant-ui/react"; import { CheckIcon, CopyIcon } from "lucide-react"; import dynamic from "next/dynamic"; import Image from "next/image"; import { type FC, type ReactNode, useState } from "react"; import { CitationMetadataProvider } from "@/components/assistant-ui/citation-metadata-context"; import { MarkdownText } from "@/components/assistant-ui/markdown-text"; import { ToolFallback } from "@/components/assistant-ui/tool-fallback"; import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button"; import { GenerateImageToolUI } from "@/components/tool-ui/generate-image"; import { GeneratePodcastToolUI } from "@/components/tool-ui/generate-podcast"; import { GenerateReportToolUI } from "@/components/tool-ui/generate-report"; const GenerateVideoPresentationToolUI = dynamic( () => import("@/components/tool-ui/video-presentation").then((m) => ({ default: m.GenerateVideoPresentationToolUI })), { ssr: false } ); interface PublicThreadProps { footer?: ReactNode; } /** * Read-only thread component for public chat viewing. * No composer, no edit capabilities - just message display. */ export const PublicThread: FC = ({ footer }) => { return ( {/* Spacer to ensure footer doesn't overlap last message */}
{footer && (
{footer}
)} ); }; /** * User avatar component with fallback to initials */ interface AuthorMetadata { displayName: string | null; avatarUrl: string | null; } const UserAvatar: FC void }> = ({ displayName, avatarUrl, hasError, onError, }) => { const initials = displayName ? displayName .split(" ") .map((n) => n[0]) .join("") .toUpperCase() .slice(0, 2) : "U"; if (avatarUrl && !hasError) { return ( {displayName ); } return (
{initials}
); }; const PublicUserMessage: FC = () => { const metadata = useAuiState(({ message }) => message?.metadata); const author = metadata?.custom?.author as AuthorMetadata | undefined; return (
{author && (
)}
); }; const UserAvatarWithState: FC = ({ displayName, avatarUrl }) => { const [hasError, setHasError] = useState(false); return ( setHasError(true)} /> ); }; const PublicAssistantMessage: FC = () => { return (
null, link_preview: () => null, multi_link_preview: () => null, scrape_webpage: () => null, }, Fallback: ToolFallback, }, }} />
); }; const PublicAssistantActionBar: FC = () => { return ( message.isCopied}> !message.isCopied}> ); };