diff --git a/client/src/Providers/MessageContext.tsx b/client/src/Providers/MessageContext.tsx index 31e16460f..c69939760 100644 --- a/client/src/Providers/MessageContext.tsx +++ b/client/src/Providers/MessageContext.tsx @@ -1,10 +1,15 @@ import { createContext, useContext } from 'react'; + type MessageContext = { messageId: string; nextType?: string; partIndex?: number; isExpanded: boolean; conversationId?: string | null; + /** Submission state for cursor display - only true for latest message when submitting */ + isSubmitting?: boolean; + /** Whether this is the latest message in the conversation */ + isLatestMessage?: boolean; }; export const MessageContext = createContext({} as MessageContext); diff --git a/client/src/Providers/MessagesViewContext.tsx b/client/src/Providers/MessagesViewContext.tsx new file mode 100644 index 000000000..630ad277f --- /dev/null +++ b/client/src/Providers/MessagesViewContext.tsx @@ -0,0 +1,150 @@ +import React, { createContext, useContext, useMemo } from 'react'; +import { useAddedChatContext } from './AddedChatContext'; +import { useChatContext } from './ChatContext'; + +interface MessagesViewContextValue { + /** Core conversation data */ + conversation: ReturnType['conversation']; + conversationId: string | null | undefined; + + /** Submission and control states */ + isSubmitting: ReturnType['isSubmitting']; + isSubmittingFamily: boolean; + abortScroll: ReturnType['abortScroll']; + setAbortScroll: ReturnType['setAbortScroll']; + + /** Message operations */ + ask: ReturnType['ask']; + regenerate: ReturnType['regenerate']; + handleContinue: ReturnType['handleContinue']; + + /** Message state management */ + index: ReturnType['index']; + latestMessage: ReturnType['latestMessage']; + setLatestMessage: ReturnType['setLatestMessage']; + getMessages: ReturnType['getMessages']; + setMessages: ReturnType['setMessages']; +} + +const MessagesViewContext = createContext(undefined); + +export function MessagesViewProvider({ children }: { children: React.ReactNode }) { + const chatContext = useChatContext(); + const addedChatContext = useAddedChatContext(); + + const { + ask, + index, + regenerate, + isSubmitting: isSubmittingRoot, + conversation, + latestMessage, + setAbortScroll, + handleContinue, + setLatestMessage, + abortScroll, + getMessages, + setMessages, + } = chatContext; + + const { isSubmitting: isSubmittingAdditional } = addedChatContext; + + /** Memoize conversation-related values */ + const conversationValues = useMemo( + () => ({ + conversation, + conversationId: conversation?.conversationId, + }), + [conversation], + ); + + /** Memoize submission states */ + const submissionStates = useMemo( + () => ({ + isSubmitting: isSubmittingRoot, + isSubmittingFamily: isSubmittingRoot || isSubmittingAdditional, + abortScroll, + setAbortScroll, + }), + [isSubmittingRoot, isSubmittingAdditional, abortScroll, setAbortScroll], + ); + + /** Memoize message operations (these are typically stable references) */ + const messageOperations = useMemo( + () => ({ + ask, + regenerate, + getMessages, + setMessages, + handleContinue, + }), + [ask, regenerate, handleContinue, getMessages, setMessages], + ); + + /** Memoize message state values */ + const messageState = useMemo( + () => ({ + index, + latestMessage, + setLatestMessage, + }), + [index, latestMessage, setLatestMessage], + ); + + /** Combine all values into final context value */ + const contextValue = useMemo( + () => ({ + ...conversationValues, + ...submissionStates, + ...messageOperations, + ...messageState, + }), + [conversationValues, submissionStates, messageOperations, messageState], + ); + + return ( + {children} + ); +} + +export function useMessagesViewContext() { + const context = useContext(MessagesViewContext); + if (!context) { + throw new Error('useMessagesViewContext must be used within MessagesViewProvider'); + } + return context; +} + +/** Hook for components that only need conversation data */ +export function useMessagesConversation() { + const { conversation, conversationId } = useMessagesViewContext(); + return useMemo(() => ({ conversation, conversationId }), [conversation, conversationId]); +} + +/** Hook for components that only need submission states */ +export function useMessagesSubmission() { + const { isSubmitting, isSubmittingFamily, abortScroll, setAbortScroll } = + useMessagesViewContext(); + return useMemo( + () => ({ isSubmitting, isSubmittingFamily, abortScroll, setAbortScroll }), + [isSubmitting, isSubmittingFamily, abortScroll, setAbortScroll], + ); +} + +/** Hook for components that only need message operations */ +export function useMessagesOperations() { + const { ask, regenerate, handleContinue, getMessages, setMessages } = useMessagesViewContext(); + return useMemo( + () => ({ ask, regenerate, handleContinue, getMessages, setMessages }), + [ask, regenerate, handleContinue, getMessages, setMessages], + ); +} + +/** Hook for components that only need message state */ +export function useMessagesState() { + const { index, latestMessage, setLatestMessage } = useMessagesViewContext(); + return useMemo( + () => ({ index, latestMessage, setLatestMessage }), + [index, latestMessage, setLatestMessage], + ); +} diff --git a/client/src/Providers/index.ts b/client/src/Providers/index.ts index 6e4384a74..c12a4e184 100644 --- a/client/src/Providers/index.ts +++ b/client/src/Providers/index.ts @@ -26,4 +26,5 @@ export * from './SidePanelContext'; export * from './MCPPanelContext'; export * from './ArtifactsContext'; export * from './PromptGroupsContext'; +export * from './MessagesViewContext'; export { default as BadgeRowProvider } from './BadgeRowContext'; diff --git a/client/src/components/Chat/Messages/Content/ContentParts.tsx b/client/src/components/Chat/Messages/Content/ContentParts.tsx index 5dc9f25f6..d9efa34cc 100644 --- a/client/src/components/Chat/Messages/Content/ContentParts.tsx +++ b/client/src/components/Chat/Messages/Content/ContentParts.tsx @@ -26,6 +26,7 @@ type ContentPartsProps = { isCreatedByUser: boolean; isLast: boolean; isSubmitting: boolean; + isLatestMessage?: boolean; edit?: boolean; enterEdit?: (cancel?: boolean) => void | null | undefined; siblingIdx?: number; @@ -45,6 +46,7 @@ const ContentParts = memo( isCreatedByUser, isLast, isSubmitting, + isLatestMessage, edit, enterEdit, siblingIdx, @@ -55,6 +57,8 @@ const ContentParts = memo( const [isExpanded, setIsExpanded] = useState(showThinking); const attachmentMap = useMemo(() => mapAttachments(attachments ?? []), [attachments]); + const effectiveIsSubmitting = isLatestMessage ? isSubmitting : false; + const hasReasoningParts = useMemo(() => { const hasThinkPart = content?.some((part) => part?.type === ContentTypes.THINK) ?? false; const allThinkPartsHaveContent = @@ -134,7 +138,9 @@ const ContentParts = memo( }) } label={ - isSubmitting && isLast ? localize('com_ui_thinking') : localize('com_ui_thoughts') + effectiveIsSubmitting && isLast + ? localize('com_ui_thinking') + : localize('com_ui_thoughts') } /> @@ -155,12 +161,14 @@ const ContentParts = memo( conversationId, partIndex: idx, nextType: content[idx + 1]?.type, + isSubmitting: effectiveIsSubmitting, + isLatestMessage, }} > (null); const submitButtonRef = useRef(null); - const { getMessages, setMessages, conversation } = useChatContext(); + const { conversation } = useMessagesConversation(); + const { getMessages, setMessages } = useMessagesOperations(); const [latestMultiMessage, setLatestMultiMessage] = useRecoilState( store.latestMessageFamily(addedIndex), ); diff --git a/client/src/components/Chat/Messages/Content/MessageContent.tsx b/client/src/components/Chat/Messages/Content/MessageContent.tsx index dd3433d56..f36375234 100644 --- a/client/src/components/Chat/Messages/Content/MessageContent.tsx +++ b/client/src/components/Chat/Messages/Content/MessageContent.tsx @@ -5,7 +5,7 @@ import type { TMessage } from 'librechat-data-provider'; import type { TMessageContentProps, TDisplayProps } from '~/common'; import Error from '~/components/Messages/Content/Error'; import Thinking from '~/components/Artifacts/Thinking'; -import { useChatContext } from '~/Providers'; +import { useMessageContext } from '~/Providers'; import MarkdownLite from './MarkdownLite'; import EditMessage from './EditMessage'; import { useLocalize } from '~/hooks'; @@ -70,16 +70,12 @@ export const ErrorMessage = ({ }; const DisplayMessage = ({ text, isCreatedByUser, message, showCursor }: TDisplayProps) => { - const { isSubmitting, latestMessage } = useChatContext(); + const { isSubmitting = false, isLatestMessage = false } = useMessageContext(); const enableUserMsgMarkdown = useRecoilValue(store.enableUserMsgMarkdown); const showCursorState = useMemo( () => showCursor === true && isSubmitting, [showCursor, isSubmitting], ); - const isLatestMessage = useMemo( - () => message.messageId === latestMessage?.messageId, - [message.messageId, latestMessage?.messageId], - ); let content: React.ReactElement; if (!isCreatedByUser) { diff --git a/client/src/components/Chat/Messages/Content/Part.tsx b/client/src/components/Chat/Messages/Content/Part.tsx index 75e6d6ea1..5d98b5aca 100644 --- a/client/src/components/Chat/Messages/Content/Part.tsx +++ b/client/src/components/Chat/Messages/Content/Part.tsx @@ -85,13 +85,14 @@ const Part = memo( const isToolCall = 'args' in toolCall && (!toolCall.type || toolCall.type === ToolCallTypes.TOOL_CALL); - if (isToolCall && toolCall.name === Tools.execute_code && toolCall.args) { + if (isToolCall && toolCall.name === Tools.execute_code) { return ( ); } else if ( diff --git a/client/src/components/Chat/Messages/Content/Parts/EditTextPart.tsx b/client/src/components/Chat/Messages/Content/Parts/EditTextPart.tsx index 2d83f2418..242b13765 100644 --- a/client/src/components/Chat/Messages/Content/Parts/EditTextPart.tsx +++ b/client/src/components/Chat/Messages/Content/Parts/EditTextPart.tsx @@ -6,8 +6,8 @@ import { useRecoilState, useRecoilValue } from 'recoil'; import { useUpdateMessageContentMutation } from 'librechat-data-provider/react-query'; import type { Agents } from 'librechat-data-provider'; import type { TEditProps } from '~/common'; +import { useMessagesOperations, useMessagesConversation, useAddedChatContext } from '~/Providers'; import Container from '~/components/Chat/Messages/Content/Container'; -import { useChatContext, useAddedChatContext } from '~/Providers'; import { cn, removeFocusRings } from '~/utils'; import { useLocalize } from '~/hooks'; import store from '~/store'; @@ -25,7 +25,8 @@ const EditTextPart = ({ }) => { const localize = useLocalize(); const { addedIndex } = useAddedChatContext(); - const { ask, getMessages, setMessages, conversation } = useChatContext(); + const { conversation } = useMessagesConversation(); + const { ask, getMessages, setMessages } = useMessagesOperations(); const [latestMultiMessage, setLatestMultiMessage] = useRecoilState( store.latestMessageFamily(addedIndex), ); diff --git a/client/src/components/Chat/Messages/Content/Parts/ExecuteCode.tsx b/client/src/components/Chat/Messages/Content/Parts/ExecuteCode.tsx index 29961955a..729011bdb 100644 --- a/client/src/components/Chat/Messages/Content/Parts/ExecuteCode.tsx +++ b/client/src/components/Chat/Messages/Content/Parts/ExecuteCode.tsx @@ -45,26 +45,28 @@ export function useParseArgs(args?: string): ParsedArgs | null { } export default function ExecuteCode({ + isSubmitting, initialProgress = 0.1, args, output = '', attachments, }: { initialProgress: number; + isSubmitting: boolean; args?: string; output?: string; attachments?: TAttachment[]; }) { const localize = useLocalize(); - const showAnalysisCode = useRecoilValue(store.showCode); - const [showCode, setShowCode] = useState(showAnalysisCode); - const codeContentRef = useRef(null); - const [contentHeight, setContentHeight] = useState(0); - const [isAnimating, setIsAnimating] = useState(false); const hasOutput = output.length > 0; const outputRef = useRef(output); - const prevShowCodeRef = useRef(showCode); + const codeContentRef = useRef(null); + const [isAnimating, setIsAnimating] = useState(false); + const showAnalysisCode = useRecoilValue(store.showCode); + const [showCode, setShowCode] = useState(showAnalysisCode); + const [contentHeight, setContentHeight] = useState(0); + const prevShowCodeRef = useRef(showCode); const { lang, code } = useParseArgs(args) ?? ({} as ParsedArgs); const progress = useProgress(initialProgress); @@ -136,6 +138,8 @@ export default function ExecuteCode({ }; }, [showCode, isAnimating]); + const cancelled = !isSubmitting && progress < 1; + return ( <>
@@ -143,9 +147,12 @@ export default function ExecuteCode({ progress={progress} onClick={() => setShowCode((prev) => !prev)} inProgressText={localize('com_ui_analyzing')} - finishedText={localize('com_ui_analyzing_finished')} + finishedText={ + cancelled ? localize('com_ui_cancelled') : localize('com_ui_analyzing_finished') + } hasInput={!!code?.length} isExpanded={showCode} + error={cancelled} />
{ - const { messageId } = useMessageContext(); - const { isSubmitting, latestMessage } = useChatContext(); + const { isSubmitting = false, isLatestMessage = false } = useMessageContext(); const enableUserMsgMarkdown = useRecoilValue(store.enableUserMsgMarkdown); const showCursorState = useMemo(() => showCursor && isSubmitting, [showCursor, isSubmitting]); - const isLatestMessage = useMemo( - () => messageId === latestMessage?.messageId, - [messageId, latestMessage?.messageId], - ); const content: ContentType = useMemo(() => { if (!isCreatedByUser) { diff --git a/client/src/components/Chat/Messages/HoverButtons.tsx b/client/src/components/Chat/Messages/HoverButtons.tsx index 8c9067374..a8df7dfbb 100644 --- a/client/src/components/Chat/Messages/HoverButtons.tsx +++ b/client/src/components/Chat/Messages/HoverButtons.tsx @@ -21,7 +21,7 @@ type THoverButtons = { latestMessage: TMessage | null; isLast: boolean; index: number; - handleFeedback: ({ feedback }: { feedback: TFeedback | undefined }) => void; + handleFeedback?: ({ feedback }: { feedback: TFeedback | undefined }) => void; }; type HoverButtonProps = { @@ -238,7 +238,7 @@ const HoverButtons = ({ /> {/* Feedback Buttons */} - {!isCreatedByUser && ( + {!isCreatedByUser && handleFeedback != null && ( )} diff --git a/client/src/components/Chat/Messages/Message.tsx b/client/src/components/Chat/Messages/Message.tsx index 56969a891..8867a0252 100644 --- a/client/src/components/Chat/Messages/Message.tsx +++ b/client/src/components/Chat/Messages/Message.tsx @@ -73,7 +73,7 @@ export default function Message(props: TMessageProps) {
) : ( -
+
)} diff --git a/client/src/components/Chat/Messages/MessageParts.tsx b/client/src/components/Chat/Messages/MessageParts.tsx index d53522e64..a79f0985d 100644 --- a/client/src/components/Chat/Messages/MessageParts.tsx +++ b/client/src/components/Chat/Messages/MessageParts.tsx @@ -125,6 +125,7 @@ export default function Message(props: TMessageProps) { setSiblingIdx={setSiblingIdx} isCreatedByUser={message.isCreatedByUser} conversationId={conversation?.conversationId} + isLatestMessage={messageId === latestMessage?.messageId} content={message.content as Array} />
diff --git a/client/src/components/Chat/Messages/MessagesView.tsx b/client/src/components/Chat/Messages/MessagesView.tsx index bc6e285a5..01459203f 100644 --- a/client/src/components/Chat/Messages/MessagesView.tsx +++ b/client/src/components/Chat/Messages/MessagesView.tsx @@ -4,11 +4,12 @@ import { CSSTransition } from 'react-transition-group'; import type { TMessage } from 'librechat-data-provider'; import { useScreenshot, useMessageScrolling, useLocalize } from '~/hooks'; import ScrollToBottom from '~/components/Messages/ScrollToBottom'; +import { MessagesViewProvider } from '~/Providers'; import MultiMessage from './MultiMessage'; import { cn } from '~/utils'; import store from '~/store'; -export default function MessagesView({ +function MessagesViewContent({ messagesTree: _messagesTree, }: { messagesTree?: TMessage[] | null; @@ -92,3 +93,11 @@ export default function MessagesView({ ); } + +export default function MessagesView({ messagesTree }: { messagesTree?: TMessage[] | null }) { + return ( + + + + ); +} diff --git a/client/src/components/Chat/Messages/MultiMessage.tsx b/client/src/components/Chat/Messages/MultiMessage.tsx index 99733143f..13eb2d143 100644 --- a/client/src/components/Chat/Messages/MultiMessage.tsx +++ b/client/src/components/Chat/Messages/MultiMessage.tsx @@ -27,7 +27,7 @@ export default function MultiMessage({ useEffect(() => { // reset siblingIdx when the tree changes, mostly when a new message is submitting. setSiblingIdx(0); - }, [messagesTree?.length]); + }, [messagesTree?.length, setSiblingIdx]); useEffect(() => { if (messagesTree?.length && siblingIdx >= messagesTree.length) { diff --git a/client/src/components/Chat/Messages/ui/MessageRender.tsx b/client/src/components/Chat/Messages/ui/MessageRender.tsx index 0ad10ecf0..ad38f1ee4 100644 --- a/client/src/components/Chat/Messages/ui/MessageRender.tsx +++ b/client/src/components/Chat/Messages/ui/MessageRender.tsx @@ -71,6 +71,9 @@ const MessageRender = memo( const showCardRender = isLast && !isSubmittingFamily && isCard; const isLatestCard = isCard && !isSubmittingFamily && isLatestMessage; + /** Only pass isSubmitting to the latest message to prevent unnecessary re-renders */ + const effectiveIsSubmitting = isLatestMessage ? isSubmitting : false; + const iconData: TMessageIcon = useMemo( () => ({ endpoint: msg?.endpoint ?? conversation?.endpoint, @@ -166,6 +169,8 @@ const MessageRender = memo( messageId: msg.messageId, conversationId: conversation?.conversationId, isExpanded: false, + isSubmitting: effectiveIsSubmitting, + isLatestMessage, }} > {msg.plugin && } @@ -177,7 +182,7 @@ const MessageRender = memo( message={msg} enterEdit={enterEdit} error={!!(msg.error ?? false)} - isSubmitting={isSubmitting} + isSubmitting={effectiveIsSubmitting} unfinished={msg.unfinished ?? false} isCreatedByUser={msg.isCreatedByUser ?? true} siblingIdx={siblingIdx ?? 0} @@ -186,7 +191,7 @@ const MessageRender = memo( - {hasNoChildren && (isSubmittingFamily === true || isSubmitting) ? ( + {hasNoChildren && (isSubmittingFamily === true || effectiveIsSubmitting) ? ( ) : ( diff --git a/client/src/components/Conversations/Conversations.tsx b/client/src/components/Conversations/Conversations.tsx index 10203c89e..3a04f558f 100644 --- a/client/src/components/Conversations/Conversations.tsx +++ b/client/src/components/Conversations/Conversations.tsx @@ -1,6 +1,5 @@ import { useMemo, memo, type FC, useCallback } from 'react'; import throttle from 'lodash/throttle'; -import { parseISO, isToday } from 'date-fns'; import { Spinner, useMediaQuery } from '@librechat/client'; import { List, AutoSizer, CellMeasurer, CellMeasurerCache } from 'react-virtualized'; import { TConversation } from 'librechat-data-provider'; @@ -50,27 +49,17 @@ const MemoizedConvo = memo( conversation, retainView, toggleNav, - isLatestConvo, }: { conversation: TConversation; retainView: () => void; toggleNav: () => void; - isLatestConvo: boolean; }) => { - return ( - - ); + return ; }, (prevProps, nextProps) => { return ( prevProps.conversation.conversationId === nextProps.conversation.conversationId && prevProps.conversation.title === nextProps.conversation.title && - prevProps.isLatestConvo === nextProps.isLatestConvo && prevProps.conversation.endpoint === nextProps.conversation.endpoint ); }, @@ -98,13 +87,6 @@ const Conversations: FC = ({ [filteredConversations], ); - const firstTodayConvoId = useMemo( - () => - filteredConversations.find((convo) => convo.updatedAt && isToday(parseISO(convo.updatedAt))) - ?.conversationId ?? undefined, - [filteredConversations], - ); - const flattenedItems = useMemo(() => { const items: FlattenedItem[] = []; groupedConversations.forEach(([groupName, convos]) => { @@ -154,26 +136,25 @@ const Conversations: FC = ({ ); } + let rendering: JSX.Element; + if (item.type === 'header') { + rendering = ; + } else if (item.type === 'convo') { + rendering = ( + + ); + } return ( {({ registerChild }) => (
- {item.type === 'header' ? ( - - ) : item.type === 'convo' ? ( - - ) : null} + {rendering}
)}
); }, - [cache, flattenedItems, firstTodayConvoId, moveToTop, toggleNav], + [cache, flattenedItems, moveToTop, toggleNav], ); const getRowHeight = useCallback( diff --git a/client/src/components/Conversations/Convo.tsx b/client/src/components/Conversations/Convo.tsx index 3804cbf2b..190cef2a4 100644 --- a/client/src/components/Conversations/Convo.tsx +++ b/client/src/components/Conversations/Convo.tsx @@ -11,23 +11,17 @@ import { useGetEndpointsQuery } from '~/data-provider'; import { NotificationSeverity } from '~/common'; import { ConvoOptions } from './ConvoOptions'; import RenameForm from './RenameForm'; +import { cn, logger } from '~/utils'; import ConvoLink from './ConvoLink'; -import { cn } from '~/utils'; import store from '~/store'; interface ConversationProps { conversation: TConversation; retainView: () => void; toggleNav: () => void; - isLatestConvo: boolean; } -export default function Conversation({ - conversation, - retainView, - toggleNav, - isLatestConvo, -}: ConversationProps) { +export default function Conversation({ conversation, retainView, toggleNav }: ConversationProps) { const params = useParams(); const localize = useLocalize(); const { showToast } = useToastContext(); @@ -84,6 +78,7 @@ export default function Conversation({ }); setRenaming(false); } catch (error) { + logger.error('Error renaming conversation', error); setTitleInput(title as string); showToast({ message: localize('com_ui_rename_failed'), diff --git a/client/src/components/Messages/ContentRender.tsx b/client/src/components/Messages/ContentRender.tsx index daeccbc13..bdf051453 100644 --- a/client/src/components/Messages/ContentRender.tsx +++ b/client/src/components/Messages/ContentRender.tsx @@ -173,6 +173,7 @@ const ContentRender = memo( isSubmitting={isSubmitting} searchResults={searchResults} setSiblingIdx={setSiblingIdx} + isLatestMessage={isLatestMessage} isCreatedByUser={msg.isCreatedByUser} conversationId={conversation?.conversationId} content={msg.content as Array} diff --git a/client/src/components/Share/Message.tsx b/client/src/components/Share/Message.tsx index efd9bc5dd..eddd5060e 100644 --- a/client/src/components/Share/Message.tsx +++ b/client/src/components/Share/Message.tsx @@ -76,6 +76,8 @@ export default function Message(props: TMessageProps) { messageId, isExpanded: false, conversationId: conversation?.conversationId, + isSubmitting: false, // Share view is always read-only + isLatestMessage: false, // No concept of latest message in share view }} > {/* Legacy Plugins */} diff --git a/client/src/hooks/Messages/useMessageHelpers.tsx b/client/src/hooks/Messages/useMessageHelpers.tsx index 6ffc01e30..264fe666d 100644 --- a/client/src/hooks/Messages/useMessageHelpers.tsx +++ b/client/src/hooks/Messages/useMessageHelpers.tsx @@ -2,7 +2,7 @@ import throttle from 'lodash/throttle'; import { useEffect, useRef, useCallback, useMemo } from 'react'; import { Constants, isAssistantsEndpoint, isAgentsEndpoint } from 'librechat-data-provider'; import type { TMessageProps } from '~/common'; -import { useChatContext, useAssistantsMapContext, useAgentsMapContext } from '~/Providers'; +import { useMessagesViewContext, useAssistantsMapContext, useAgentsMapContext } from '~/Providers'; import useCopyToClipboard from './useCopyToClipboard'; import { getTextKey, logger } from '~/utils'; @@ -20,9 +20,9 @@ export default function useMessageHelpers(props: TMessageProps) { setAbortScroll, handleContinue, setLatestMessage, - } = useChatContext(); - const assistantMap = useAssistantsMapContext(); + } = useMessagesViewContext(); const agentsMap = useAgentsMapContext(); + const assistantMap = useAssistantsMapContext(); const { text, content, children, messageId = null, isCreatedByUser } = message ?? {}; const edit = messageId === currentEditId; diff --git a/client/src/hooks/Messages/useMessageProcess.tsx b/client/src/hooks/Messages/useMessageProcess.tsx index 8349a80a0..ea5779a69 100644 --- a/client/src/hooks/Messages/useMessageProcess.tsx +++ b/client/src/hooks/Messages/useMessageProcess.tsx @@ -3,7 +3,7 @@ import { useRecoilValue } from 'recoil'; import { Constants } from 'librechat-data-provider'; import { useEffect, useRef, useCallback, useMemo, useState } from 'react'; import type { TMessage } from 'librechat-data-provider'; -import { useChatContext, useAddedChatContext } from '~/Providers'; +import { useMessagesViewContext } from '~/Providers'; import { getTextKey, logger } from '~/utils'; import store from '~/store'; @@ -18,14 +18,9 @@ export default function useMessageProcess({ message }: { message?: TMessage | nu latestMessage, setAbortScroll, setLatestMessage, - isSubmitting: isSubmittingRoot, - } = useChatContext(); - const { isSubmitting: isSubmittingAdditional } = useAddedChatContext(); + isSubmittingFamily, + } = useMessagesViewContext(); const latestMultiMessage = useRecoilValue(store.latestMessageFamily(index + 1)); - const isSubmittingFamily = useMemo( - () => isSubmittingRoot || isSubmittingAdditional, - [isSubmittingRoot, isSubmittingAdditional], - ); useEffect(() => { const convoId = conversation?.conversationId; diff --git a/client/src/hooks/Messages/useMessageScrolling.ts b/client/src/hooks/Messages/useMessageScrolling.ts index a9c033f23..9fa51f085 100644 --- a/client/src/hooks/Messages/useMessageScrolling.ts +++ b/client/src/hooks/Messages/useMessageScrolling.ts @@ -2,8 +2,8 @@ import { useRecoilValue } from 'recoil'; import { Constants } from 'librechat-data-provider'; import { useState, useRef, useCallback, useEffect } from 'react'; import type { TMessage } from 'librechat-data-provider'; +import { useMessagesConversation, useMessagesSubmission } from '~/Providers'; import useScrollToRef from '~/hooks/useScrollToRef'; -import { useChatContext } from '~/Providers'; import store from '~/store'; const threshold = 0.85; @@ -15,8 +15,8 @@ export default function useMessageScrolling(messagesTree?: TMessage[] | null) { const scrollableRef = useRef(null); const messagesEndRef = useRef(null); const [showScrollButton, setShowScrollButton] = useState(false); - const { conversation, setAbortScroll, isSubmitting, abortScroll } = useChatContext(); - const { conversationId } = conversation ?? {}; + const { conversation, conversationId } = useMessagesConversation(); + const { setAbortScroll, isSubmitting, abortScroll } = useMessagesSubmission(); const timeoutIdRef = useRef();