diff --git a/client/src/data-provider/queries.ts b/client/src/data-provider/queries.ts index ec0aab52ad..35dd8957b8 100644 --- a/client/src/data-provider/queries.ts +++ b/client/src/data-provider/queries.ts @@ -30,6 +30,7 @@ import type { SharedLinksResponse, } from 'librechat-data-provider'; import type { ConversationCursorData } from '~/utils/convos'; +import { findConversationInInfinite } from '~/utils'; export const useGetPresetsQuery = ( config?: UseQueryOptions, @@ -68,14 +69,13 @@ export const useGetConvoIdQuery = ( [QueryKeys.conversation, id], () => { // Try to find in all fetched infinite pages - const convosQuery = queryClient.getQueryData>([ - QueryKeys.allConversations, - ]); - const found = convosQuery?.pages - .flatMap((page) => page.conversations) - .find((c) => c.conversationId === id); + const convosQuery = queryClient.getQueryData>( + [QueryKeys.allConversations], + { exact: false }, + ); + const found = findConversationInInfinite(convosQuery, id); - if (found) { + if (found && found.messages != null) { return found; } // Otherwise, fetch from API diff --git a/client/src/hooks/Conversations/useNavigateToConvo.tsx b/client/src/hooks/Conversations/useNavigateToConvo.tsx index 2b2981f41d..dd8ce11aa5 100644 --- a/client/src/hooks/Conversations/useNavigateToConvo.tsx +++ b/client/src/hooks/Conversations/useNavigateToConvo.tsx @@ -1,7 +1,7 @@ import { useSetRecoilState } from 'recoil'; import { useNavigate } from 'react-router-dom'; import { useQueryClient } from '@tanstack/react-query'; -import { QueryKeys, Constants } from 'librechat-data-provider'; +import { QueryKeys, Constants, dataService } from 'librechat-data-provider'; import type { TConversation, TEndpointsConfig, TModelsConfig } from 'librechat-data-provider'; import { buildDefaultConvo, getDefaultEndpoint, getEndpointField, logger } from '~/utils'; import store from '~/store'; @@ -14,6 +14,27 @@ const useNavigateToConvo = (index = 0) => { const clearAllLatestMessages = store.useClearLatestMessages(`useNavigateToConvo ${index}`); const { hasSetConversation, setConversation } = store.useCreateConversationAtom(index); + const fetchFreshData = async (conversation?: Partial) => { + const conversationId = conversation?.conversationId; + if (!conversationId) { + return; + } + try { + const data = await queryClient.fetchQuery([QueryKeys.conversation, conversationId], () => + dataService.getConversationById(conversationId), + ); + logger.log('conversation', 'Fetched fresh conversation data', data); + setConversation(data); + navigate(`/c/${conversationId ?? Constants.NEW_CONVO}`, { state: { focusChat: true } }); + } catch (error) { + console.error('Error fetching conversation data on navigation', error); + if (conversation) { + setConversation(conversation as TConversation); + navigate(`/c/${conversationId}`, { state: { focusChat: true } }); + } + } + }; + const navigateToConvo = ( conversation?: TConversation | null, options?: { @@ -58,9 +79,14 @@ const useNavigateToConvo = (index = 0) => { }); } clearAllConversations(true); - setConversation(convo); queryClient.setQueryData([QueryKeys.messages, currentConvoId], []); - navigate(`/c/${convo.conversationId ?? Constants.NEW_CONVO}`, { state: { focusChat: true } }); + if (convo.conversationId !== Constants.NEW_CONVO && convo.conversationId) { + queryClient.invalidateQueries([QueryKeys.conversation, convo.conversationId]); + fetchFreshData(convo); + } else { + setConversation(convo); + navigate(`/c/${convo.conversationId ?? Constants.NEW_CONVO}`, { state: { focusChat: true } }); + } }; return { diff --git a/client/src/routes/ChatRoute.tsx b/client/src/routes/ChatRoute.tsx index 3ae8eb8535..03c9e1f385 100644 --- a/client/src/routes/ChatRoute.tsx +++ b/client/src/routes/ChatRoute.tsx @@ -43,7 +43,8 @@ export default function ChatRoute() { refetchOnMount: 'always', }); const initialConvoQuery = useGetConvoIdQuery(conversationId, { - enabled: isAuthenticated && conversationId !== Constants.NEW_CONVO, + enabled: + isAuthenticated && conversationId !== Constants.NEW_CONVO && !hasSetConversation.current, }); const endpointsQuery = useGetEndpointsQuery({ enabled: isAuthenticated }); const assistantListMap = useAssistantListMap(); diff --git a/client/src/utils/convos.spec.ts b/client/src/utils/convos.spec.ts index bf21c48bc5..2bcc95e999 100644 --- a/client/src/utils/convos.spec.ts +++ b/client/src/utils/convos.spec.ts @@ -431,14 +431,14 @@ describe('Conversation Utilities', () => { pageParams: [], }; const newConvo = makeConversation('new'); - const updated = addConversationToInfinitePages(data, newConvo); + const updated = addConversationToInfinitePages(data, newConvo as TConversation); expect(updated.pages[0].conversations[0].conversationId).toBe('new'); expect(updated.pages[0].conversations[1].conversationId).toBe('1'); }); it('creates new InfiniteData if data is undefined', () => { const newConvo = makeConversation('new'); - const updated = addConversationToInfinitePages(undefined, newConvo); + const updated = addConversationToInfinitePages(undefined, newConvo as TConversation); expect(updated.pages[0].conversations[0].conversationId).toBe('new'); expect(updated.pageParams).toEqual([undefined]); }); @@ -531,12 +531,12 @@ describe('Conversation Utilities', () => { it('stores model for endpoint', () => { const conversation = { conversationId: '1', - endpoint: 'openai', + endpoint: 'openAI', model: 'gpt-3', }; storeEndpointSettings(conversation as any); const stored = JSON.parse(localStorage.getItem('lastModel') || '{}'); - expect([undefined, 'gpt-3']).toContain(stored.openai); + expect([undefined, 'gpt-3']).toContain(stored.openAI); }); it('stores secondaryModel for gptPlugins endpoint', () => { @@ -574,14 +574,14 @@ describe('Conversation Utilities', () => { conversationId: 'a', updatedAt: '2024-01-01T12:00:00Z', createdAt: '2024-01-01T10:00:00Z', - endpoint: 'openai', + endpoint: 'openAI', model: 'gpt-3', title: 'Conversation A', } as TConversation; convoB = { conversationId: 'b', updatedAt: '2024-01-02T12:00:00Z', - endpoint: 'openai', + endpoint: 'openAI', model: 'gpt-3', } as TConversation; queryClient.setQueryData(['allConversations'], { diff --git a/client/src/utils/convos.ts b/client/src/utils/convos.ts index 43704d930b..f5746c7d3e 100644 --- a/client/src/utils/convos.ts +++ b/client/src/utils/convos.ts @@ -280,11 +280,11 @@ export function updateConvoFieldsInfinite( pages: data.pages.map((page, pi) => pi === pageIdx ? { - ...page, - conversations: page.conversations.map((c, ci) => - ci === convoIdx ? { ...c, ...updatedConversation } : c, - ), - } + ...page, + conversations: page.conversations.map((c, ci) => + ci === convoIdx ? { ...c, ...updatedConversation } : c, + ), + } : page, ), }; diff --git a/eslint.config.mjs b/eslint.config.mjs index c23393cc21..5013f9f500 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -4,6 +4,7 @@ import typescriptEslintEslintPlugin from '@typescript-eslint/eslint-plugin'; import { fixupConfigRules, fixupPluginRules } from '@eslint/compat'; // import perfectionist from 'eslint-plugin-perfectionist'; import reactHooks from 'eslint-plugin-react-hooks'; +import prettier from 'eslint-plugin-prettier'; import tsParser from '@typescript-eslint/parser'; import importPlugin from 'eslint-plugin-import'; import { FlatCompat } from '@eslint/eslintrc'; @@ -62,6 +63,7 @@ export default [ 'import/parsers': tsParser, i18next, // perfectionist, + prettier: fixupPluginRules(prettier), }, languageOptions: { @@ -357,4 +359,4 @@ export default [ }, }, }, -]; \ No newline at end of file +];