import * as React from 'react'; import { AspectRatio, Box, Button, Grid, List, Stack, Typography, useTheme } from '@mui/joy'; import { SxProps } from '@mui/joy/styles/types'; import { ChatMessage } from '@/components/ChatMessage'; import { DMessage, useActiveConfiguration, useActiveConversation, useChatStore } from '@/lib/store-chats'; import { SystemPurposeId, SystemPurposes } from '@/lib/data'; import { useSettingsStore } from '@/lib/store'; function PurposeSelect() { const theme = useTheme(); const { setSystemPurposeId, systemPurposeId } = useActiveConfiguration(); const handlePurposeChange = (purpose: SystemPurposeId | null) => { if (purpose) { if (purpose === 'Custom') { const systemMessage = prompt('Enter your custom AI purpose', SystemPurposes['Custom'].systemMessage); SystemPurposes['Custom'].systemMessage = systemMessage || ''; } setSystemPurposeId(purpose); } }; return ( AI purpose {Object.keys(SystemPurposes).map(spId => ( ))} {SystemPurposes[systemPurposeId].description} ); } /** * A list of ChatMessages */ export function ChatMessageList(props: { disableSend: boolean, sx?: SxProps, runAssistant: (conversationId: string, history: DMessage[]) => void }) { const { id: activeConversationId, messages } = useActiveConversation(); const { editMessage, removeMessage } = useChatStore(state => ({ editMessage: state.editMessage, removeMessage: state.removeMessage })); const freeScroll = useSettingsStore(state => state.freeScroll); const messagesEndRef = React.useRef(null); // when messages change, scroll to bottom (aka: at every new token) React.useEffect(() => { if (freeScroll) return; messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [freeScroll, messages]); // when there are no messages, show the purpose selector if (!messages.length) return ( ); const handleMessageDelete = (messageId: string) => removeMessage(activeConversationId, messageId); const handleMessageEdit = (messageId: string, newText: string) => editMessage(activeConversationId, messageId, { text: newText }); const handleMessageRunAgain = (messageId: string) => { const truncatedHistory = messages.slice(0, messages.findIndex(m => m.id === messageId) + 1); props.runAssistant(activeConversationId, truncatedHistory); }; return ( {messages.map(message => handleMessageDelete(message.id)} onEdit={newText => handleMessageEdit(message.id, newText)} onRunAgain={() => handleMessageRunAgain(message.id)} />)}
); }