import { useState } from 'react'; import { User, Bot, Settings, ChevronDown, ChevronRight, Clock, Sparkles, ArrowDown } from 'lucide-react'; import { MessageContent } from './MessageContent'; import { formatLargeText } from '../utils/formatters'; interface ConversationMessage { role: 'user' | 'assistant' | 'system'; content: any; timestamp: string; turnNumber?: number; isNewInTurn?: boolean; isDuplicate?: boolean; } interface MessageFlowProps { message: ConversationMessage; index: number; isLast: boolean; totalMessages: number; } export function MessageFlow({ message, index, isLast, totalMessages }: MessageFlowProps) { const [isExpanded, setIsExpanded] = useState(false); const getRoleConfig = () => { switch (message.role) { case 'user': return { icon: , bgColor: 'bg-blue-50', borderColor: 'border-blue-200', accentColor: 'border-l-blue-500', textColor: 'text-blue-900', titleColor: 'text-blue-700', name: 'User' }; case 'assistant': return { icon: , bgColor: 'bg-gray-50', borderColor: 'border-gray-200', accentColor: 'border-l-gray-500', textColor: 'text-gray-900', titleColor: 'text-gray-700', name: 'Assistant' }; case 'system': return { icon: , bgColor: 'bg-amber-50', borderColor: 'border-amber-200', accentColor: 'border-l-amber-500', textColor: 'text-amber-900', titleColor: 'text-amber-700', name: 'System' }; default: return { icon: , bgColor: 'bg-gray-50', borderColor: 'border-gray-200', accentColor: 'border-l-gray-500', textColor: 'text-gray-900', titleColor: 'text-gray-700', name: 'Unknown' }; } }; const roleConfig = getRoleConfig(); // Helper function to check if content is a system reminder const isSystemReminder = (text: string) => { return text.includes('') || text.includes(''); }; // Helper function to extract non-system-reminder content for preview const extractNonSystemContent = (content: string) => { // Split by system-reminder tags and filter out the reminder parts const parts = content.split(/[\s\S]*?<\/system-reminder>/g); return parts.filter(part => part.trim()).join(' ').trim(); }; // Determine if content should be expandable const getContentPreview = () => { if (typeof message.content === 'string') { const nonSystemContent = extractNonSystemContent(message.content); if (!nonSystemContent && isSystemReminder(message.content)) { return "[System reminder]"; } return nonSystemContent.length > 300 ? nonSystemContent.substring(0, 300) + '...' : nonSystemContent; } if (Array.isArray(message.content)) { const allText = message.content .filter(c => c.type === 'text' && c.text) .map(c => { const nonSystemContent = extractNonSystemContent(c.text); return nonSystemContent; }) .filter(text => text) .join('\\n'); if (!allText) { const hasToolUse = message.content.some(c => c.type === 'tool_use'); const hasSystemReminder = message.content.some(c => c.type === 'text' && c.text && isSystemReminder(c.text)); if (hasToolUse) return "[Tool call]"; if (hasSystemReminder) return "[System reminder]"; return "[Context message]"; } return allText.length > 300 ? allText.substring(0, 300) + '...' : allText; } if (message.content?.type) { return `[${message.content.type.replace('_', ' ')}]`; } try { const str = JSON.stringify(message.content, null, 2); return str.length > 300 ? str.substring(0, 300) + '...' : str; } catch { return '[Complex content]'; } }; const shouldShowExpander = () => { if (typeof message.content === 'string') { // Show expander if content is long OR contains system reminders return message.content.length > 300 || isSystemReminder(message.content); } if (Array.isArray(message.content)) { const allText = message.content .filter(c => c.type === 'text' && c.text) .map(c => c.text) .join('\\n'); return allText.length > 300 || message.content.length > 1; } return true; }; const formatTimestamp = (timestamp: string) => { try { const date = new Date(timestamp); return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: true }); } catch { return timestamp; } }; return (
{/* Connection line to next message */} {!isLast && (
)} {/* Message container */}
{/* New message indicator */} {message.isNewInTurn && (
)}
{/* Avatar */}
{roleConfig.icon}
{/* Message content */}
{/* Header */}
{roleConfig.name} {message.isNewInTurn && ( NEW )} #{index + 1} {message.turnNumber && ( Turn {message.turnNumber} )}
{formatTimestamp(message.timestamp)}
{/* Content */}
{shouldShowExpander() && !isExpanded ? (
{typeof message.content === 'string' ? (
) : (
{Array.isArray(message.content) ? ( `Message contains ${message.content.length} content blocks` ) : ( 'Complex content' )}
{Array.isArray(message.content) && (
{message.content.map(item => item.type).join(' → ')}
)}
{getContentPreview()}
)}
) : (
{shouldShowExpander() && isExpanded && (
)}
)}
{/* Flow indicator */} {!isLast && (
)}
); }