import { v4 } from 'uuid'; import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'; import { parseConvo, getResponseSender } from 'librechat-data-provider'; import type { TMessage } from 'librechat-data-provider'; import store from '~/store'; type TAskProps = { text: string; parentMessageId?: string | null; conversationId?: string | null; messageId?: string | null; }; const useMessageHandler = () => { const currentConversation = useRecoilValue(store.conversation) || { endpoint: null }; const setSubmission = useSetRecoilState(store.submission); const isSubmitting = useRecoilValue(store.isSubmitting); const endpointsConfig = useRecoilValue(store.endpointsConfig); const latestMessage = useRecoilValue(store.latestMessage); const [messages, setMessages] = useRecoilState(store.messages); const { endpoint } = currentConversation; const { getToken } = store.useToken(endpoint ?? ''); const ask = ( { text, parentMessageId = null, conversationId = null, messageId = null }: TAskProps, { isRegenerate = false, isEdited = false } = {}, ) => { if (!!isSubmitting || text === '') { return; } if (endpoint === null) { console.error('No endpoint available'); return; } conversationId = conversationId ?? currentConversation?.conversationId; if (conversationId == 'search') { console.error('cannot send any message under search view!'); return; } if (isEdited && !latestMessage) { console.error('cannot edit AI message without latestMessage!'); return; } const { userProvide } = endpointsConfig[endpoint] ?? {}; // set the endpoint option const convo = parseConvo(endpoint, currentConversation); const endpointOption = { endpoint, ...convo, token: userProvide ? getToken() : null, }; const responseSender = getResponseSender(endpointOption); let currentMessages: TMessage[] | null = messages ?? []; // construct the query message // this is not a real messageId, it is used as placeholder before real messageId returned text = text.trim(); const fakeMessageId = v4(); parentMessageId = parentMessageId || latestMessage?.messageId || '00000000-0000-0000-0000-000000000000'; if (conversationId == 'new') { parentMessageId = '00000000-0000-0000-0000-000000000000'; currentMessages = []; conversationId = null; } const currentMsg: TMessage = { sender: 'User', text, current: true, isCreatedByUser: true, parentMessageId, conversationId, messageId: isEdited && messageId ? messageId : fakeMessageId, error: false, }; // construct the placeholder response message const generation = latestMessage?.text ?? ''; const responseText = isEdited ? generation : ''; const responseMessageId = isEdited ? latestMessage?.messageId : null; const initialResponse: TMessage = { sender: responseSender, text: responseText, parentMessageId: isRegenerate ? messageId : fakeMessageId, messageId: responseMessageId ?? `${isRegenerate ? messageId : fakeMessageId}_`, conversationId, unfinished: false, submitting: true, isCreatedByUser: false, error: false, }; const submission = { conversation: { ...currentConversation, conversationId, }, endpointOption, message: { ...currentMsg, generation, responseMessageId, overrideParentMessageId: isRegenerate ? messageId : null, }, messages: currentMessages, isEdited, isRegenerate, initialResponse, }; console.log('User Input:', text, submission); if (isRegenerate) { setMessages([ ...(isEdited ? currentMessages.slice(0, -1) : currentMessages), initialResponse, ]); } else { setMessages([...currentMessages, currentMsg, initialResponse]); } setSubmission(submission); }; const regenerate = ({ parentMessageId }) => { const parentMessage = messages?.find((element) => element.messageId == parentMessageId); if (parentMessage && parentMessage.isCreatedByUser) { ask({ ...parentMessage }, { isRegenerate: true }); } else { console.error( 'Failed to regenerate the message: parentMessage not found or not created by user.', ); } }; const continueGeneration = () => { if (!latestMessage) { console.error('Failed to regenerate the message: latestMessage not found.'); return; } const parentMessage = messages?.find( (element) => element.messageId == latestMessage.parentMessageId, ); if (parentMessage && parentMessage.isCreatedByUser) { ask({ ...parentMessage }, { isRegenerate: true, isEdited: true }); } else { console.error( 'Failed to regenerate the message: parentMessage not found, or not created by user.', ); } }; const stopGenerating = () => { setSubmission(null); }; const handleStopGenerating = (e: React.MouseEvent) => { e.preventDefault(); stopGenerating(); }; const handleRegenerate = (e: React.MouseEvent) => { e.preventDefault(); const parentMessageId = latestMessage?.parentMessageId; if (!parentMessageId) { console.error('Failed to regenerate the message: parentMessageId not found.'); return; } regenerate({ parentMessageId }); }; const handleContinue = (e: React.MouseEvent) => { e.preventDefault(); continueGeneration(); }; return { ask, regenerate, stopGenerating, handleStopGenerating, handleRegenerate, handleContinue, endpointsConfig, latestMessage, isSubmitting, messages, }; }; export default useMessageHandler;