import { useState } from "react"; import { ChevronRight, Wrench } from "lucide-react"; import { useTranslation } from "react-i18next"; import { MarkdownText } from "@/components/MarkdownText"; import { cn } from "@/lib/utils"; import type { UIMessage } from "@/lib/types"; interface MessageBubbleProps { message: UIMessage; } /** * Render a single message. Following agent-chat-ui: user turns are a rounded * "pill" right-aligned with a muted fill; assistant turns render as bare * markdown so prose/code read like a document rather than a chat bubble. * Each turn fades+slides in for a touch of motion polish. * * Trace rows (tool-call hints, progress breadcrumbs) render as a subdued * collapsible group so intermediate steps never masquerade as replies. */ export function MessageBubble({ message }: MessageBubbleProps) { const baseAnim = "animate-in fade-in-0 slide-in-from-bottom-1 duration-300"; if (message.kind === "trace") { return ; } if (message.role === "user") { return (

{message.content}

); } const empty = message.content.trim().length === 0; return (
{empty && message.isStreaming ? ( ) : ( <> {message.content} {message.isStreaming && } )}
); } /** Blinking cursor appended at the end of streaming text. */ function StreamCursor() { const { t } = useTranslation(); return ( ); } /** Pre-token-arrival placeholder: three bouncing dots. */ function TypingDots() { const { t } = useTranslation(); return ( ); } function Dot({ delay }: { delay: string }) { return ( ); } interface TraceGroupProps { message: UIMessage; animClass: string; } /** * Collapsible group of tool-call / progress breadcrumbs. Defaults to * expanded for discoverability; a single click on the header folds the * group down to a one-line summary so it never dominates the thread. */ function TraceGroup({ message, animClass }: TraceGroupProps) { const { t } = useTranslation(); const lines = message.traces ?? [message.content]; const count = lines.length; const [open, setOpen] = useState(true); return (
{open && (
    {lines.map((line, i) => (
  • {line}
  • ))}
)}
); }