import { useCallback, useEffect, useRef, useMemo } from 'react'; import { Box, Stack, Typography } from '@mui/material'; import MessageBubble from './MessageBubble'; import ActivityStatusBar from './ActivityStatusBar'; import { useAgentStore } from '@/store/agentStore'; import type { UIMessage } from 'ai'; interface MessageListProps { messages: UIMessage[]; isProcessing: boolean; sessionId?: string | null; approveTools: (approvals: Array<{ tool_call_id: string; approved: boolean; feedback?: string | null }>) => Promise; onUndoLastTurn: () => void | Promise; onEditAndRegenerate?: (messageId: string, newText: string) => void | Promise; } function getGreeting(): string { const h = new Date().getHours(); if (h < 12) return 'Morning'; if (h < 17) return 'Afternoon'; return 'Evening'; } function WelcomeGreeting() { const { user } = useAgentStore(); const firstName = user?.name?.split(' ')[0] || user?.username; const greeting = firstName ? `${getGreeting()}, ${firstName}` : getGreeting(); return ( {greeting} Let's build something impressive? ); } export default function MessageList({ messages, isProcessing, sessionId, approveTools, onUndoLastTurn, onEditAndRegenerate }: MessageListProps) { const scrollContainerRef = useRef(null); const stickToBottom = useRef(true); const scrollToBottom = useCallback(() => { const el = scrollContainerRef.current; if (el) el.scrollTop = el.scrollHeight; }, []); useEffect(() => { const el = scrollContainerRef.current; if (!el) return; const onScroll = () => { const distFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight; stickToBottom.current = distFromBottom < 80; }; el.addEventListener('scroll', onScroll, { passive: true }); return () => el.removeEventListener('scroll', onScroll); }, []); useEffect(() => { if (stickToBottom.current) scrollToBottom(); }, [messages, isProcessing, scrollToBottom]); useEffect(() => { const el = scrollContainerRef.current; if (!el) return; const observer = new MutationObserver(() => { if (stickToBottom.current) el.scrollTop = el.scrollHeight; }); observer.observe(el, { childList: true, subtree: true, characterData: true }); return () => observer.disconnect(); }, []); const lastUserMsgId = useMemo(() => { for (let i = messages.length - 1; i >= 0; i--) { if (messages[i].role === 'user') return messages[i].id; } return null; }, [messages]); // The last assistant message is "streaming" when we're processing const lastAssistantId = useMemo(() => { for (let i = messages.length - 1; i >= 0; i--) { if (messages[i].role === 'assistant') return messages[i].id; } return null; }, [messages]); return ( {messages.length === 0 && !isProcessing ? ( ) : ( messages.map((msg) => ( )) )}
); }