import { ActionBarPrimitive, MessagePrimitive, useAssistantState } from "@assistant-ui/react"; import { useAtomValue } from "jotai"; import { FileText, PencilIcon } from "lucide-react"; import { type FC, useState } from "react"; import { messageDocumentsMapAtom } from "@/atoms/chat/mentioned-documents.atom"; import { UserMessageAttachments } from "@/components/assistant-ui/attachment"; import { BranchPicker } from "@/components/assistant-ui/branch-picker"; import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button"; interface AuthorMetadata { displayName: string | null; avatarUrl: string | null; } const UserAvatar: FC = ({ displayName, avatarUrl }) => { const [hasError, setHasError] = useState(false); const initials = displayName ? displayName .split(" ") .map((n) => n[0]) .join("") .toUpperCase() .slice(0, 2) : "U"; if (avatarUrl && !hasError) { return ( {displayName setHasError(true)} /> ); } return (
{initials}
); }; export const UserMessage: FC = () => { const messageId = useAssistantState(({ message }) => message?.id); const messageDocumentsMap = useAtomValue(messageDocumentsMapAtom); const mentionedDocs = messageId ? messageDocumentsMap[messageId] : undefined; const metadata = useAssistantState(({ message }) => message?.metadata); const author = metadata?.custom?.author as AuthorMetadata | undefined; const hasAttachments = useAssistantState( ({ message }) => message?.attachments && message.attachments.length > 0 ); return (
{/* Display attachments and mentioned documents */} {(hasAttachments || (mentionedDocs && mentionedDocs.length > 0)) && (
{/* Attachments (images show as thumbnails, documents as chips) */} {/* Mentioned documents as chips */} {mentionedDocs?.map((doc) => ( {doc.title} ))}
)} {/* Message bubble with action bar positioned relative to it */}
{/* User avatar - only shown in shared chats */} {author && (
)}
); }; const UserActionBar: FC = () => { return ( ); };