import { useState } from "react"; import { ChatMarkdownMessage } from "./ChatMarkdownMessage"; import { ChatMessageIdentityBar } from "./ChatMessageIdentityBar"; import { ChatStreamingCursor } from "./ChatStreamingCursor"; import { ChatMessageActions } from "./ChatMessageActions"; import { ChatSpecCard } from "./ChatSpecCard"; import { ChatHandoffIndicator } from "./ChatHandoffIndicator"; import { ChatTaskCreatedBadge } from "./ChatTaskCreatedBadge"; import { ChatStatusUpdateBadge } from "./ChatStatusUpdateBadge"; import { ChatFilePreview } from "./ChatFilePreview"; import { ChatVoiceBadge } from "./ChatVoiceBadge"; import { Button } from "@/components/ui/button"; import { cn } from "../lib/utils"; import type { AgentRole, ChatFile } from "@paperclipai/shared"; interface ChatMessageProps { id?: string; role: "user" | "assistant" | "system"; content: string; messageType?: string | null; conversationId?: string; agentName?: string | null; agentIcon?: string | null; agentRole?: AgentRole | null; timestamp?: string; isStreaming?: boolean; isAnyStreaming?: boolean; onEdit?: (messageId: string, newContent: string) => void; onRetry?: (messageId: string) => void; onHandoff?: (spec: { what: string; why: string; constraints: string; success: string }) => void; onBookmark?: (messageId: string) => void; isBookmarked?: boolean; files?: ChatFile[]; } export function ChatMessage({ id, role, content, messageType, conversationId, agentName, agentIcon, agentRole, timestamp, isStreaming, isAnyStreaming, onEdit, onRetry, onHandoff, onBookmark, isBookmarked, files, }: ChatMessageProps) { const [isEditing, setIsEditing] = useState(false); const [editValue, setEditValue] = useState(content); // Dispatch to specialized system message components (Phase 23) if (role === "system" || messageType) { if (messageType === "spec_card") { return ( ); } if (messageType === "handoff") { return ; } if (messageType === "task_created") { try { const data = JSON.parse(content) as { taskId?: string; taskTitle?: string; taskUrl?: string }; return ; } catch { return ; } } if (messageType === "status_update") { try { const data = JSON.parse(content) as { agentName: string; taskId: string; taskTitle?: string; taskUrl?: string }; return ; } catch { return null; } } if (messageType === "voice_input" || messageType === "voice_full") { const autoPlay = typeof window !== "undefined" ? localStorage.getItem("nexus:voice:autoplay") === "true" : false; return (
{agentName && ( )} {isStreaming && } onRetry(id) : undefined} onBookmark={id && onBookmark ? () => onBookmark(id) : undefined} isBookmarked={isBookmarked} />
); } // Fall through to default system message rendering (plain markdown) } if (role === "user") { if (isEditing) { return (