mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 16:30:15 +01:00
📢 fix: Invalid engineTTS and Conversation State on Navigation (#6904)
* fix: handle invalid engineTTS values and prevent VoiceDropdown render errors * refactor: add verbose developer logging for debugging conversation state issues * refactor: remove unnecessary effect for conversationId changes * chore: imports * fix: include model and entity IDs in conversation query selection * feat: add fetchFreshData function to retrieve conversation data on navigation * fix: remove unnecessary comment in fetchFreshData function * chore: reorder imports in useNavigateToConvo for consistency --------- Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
parent
d32f34e5d7
commit
000f3a3733
11 changed files with 75 additions and 18 deletions
|
|
@ -192,7 +192,9 @@ module.exports = {
|
|||
|
||||
try {
|
||||
const convos = await Conversation.find(query)
|
||||
.select('conversationId endpoint title createdAt updatedAt user')
|
||||
.select(
|
||||
'conversationId endpoint title createdAt updatedAt user model agent_id assistant_id',
|
||||
)
|
||||
.sort({ updatedAt: order === 'asc' ? 1 : -1 })
|
||||
.limit(limit + 1)
|
||||
.lean();
|
||||
|
|
|
|||
|
|
@ -136,6 +136,14 @@ function Speech() {
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [data]);
|
||||
|
||||
// Reset engineTTS if it is set to a removed/invalid value (e.g., 'edge')
|
||||
useEffect(() => {
|
||||
const validEngines = ['browser', 'external'];
|
||||
if (!validEngines.includes(engineTTS)) {
|
||||
setEngineTTS('browser');
|
||||
}
|
||||
}, [engineTTS, setEngineTTS]);
|
||||
|
||||
logger.log({ sttExternal, ttsExternal });
|
||||
|
||||
const contentRef = useRef(null);
|
||||
|
|
|
|||
|
|
@ -12,5 +12,9 @@ export default function VoiceDropdown() {
|
|||
const engineTTS = useRecoilValue<string>(store.engineTTS);
|
||||
const VoiceDropdownComponent = voiceDropdownComponentsMap[engineTTS];
|
||||
|
||||
if (!VoiceDropdownComponent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <VoiceDropdownComponent />;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ import { EModelEndpoint, isAgentsEndpoint, Constants, QueryKeys } from 'librecha
|
|||
import type { TConversation, TPreset, Agent } from 'librechat-data-provider';
|
||||
import useDefaultConvo from '~/hooks/Conversations/useDefaultConvo';
|
||||
import { useAgentsMapContext } from '~/Providers/AgentsMapContext';
|
||||
import { useGetAgentByIdQuery } from '~/data-provider';
|
||||
import { useChatContext } from '~/Providers/ChatContext';
|
||||
import { useGetAgentByIdQuery } from '~/data-provider';
|
||||
import { logger } from '~/utils';
|
||||
|
||||
export default function useSelectAgent() {
|
||||
const queryClient = useQueryClient();
|
||||
|
|
@ -22,6 +23,7 @@ export default function useSelectAgent() {
|
|||
|
||||
const updateConversation = useCallback(
|
||||
(agent: Partial<Agent>, template: Partial<TPreset | TConversation>) => {
|
||||
logger.log('conversation', 'Updating conversation with agent', agent);
|
||||
if (isAgentsEndpoint(conversation?.endpoint)) {
|
||||
const currentConvo = getDefaultConversation({
|
||||
conversation: { ...(conversation ?? {}), agent_id: agent.id },
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import type { AssistantsEndpoint, TConversation, TPreset } from 'librechat-data-
|
|||
import useDefaultConvo from '~/hooks/Conversations/useDefaultConvo';
|
||||
import { useChatContext } from '~/Providers/ChatContext';
|
||||
import useAssistantListMap from './useAssistantListMap';
|
||||
import { mapAssistants } from '~/utils';
|
||||
import { mapAssistants, logger } from '~/utils';
|
||||
|
||||
export default function useSelectAssistant(endpoint: AssistantsEndpoint) {
|
||||
const getDefaultConversation = useDefaultConvo();
|
||||
|
|
@ -24,6 +24,7 @@ export default function useSelectAssistant(endpoint: AssistantsEndpoint) {
|
|||
conversationId: 'new',
|
||||
};
|
||||
|
||||
logger.log('conversation', 'Updating conversation with assistant', assistant);
|
||||
if (isAssistantsEndpoint(conversation?.endpoint)) {
|
||||
const currentConvo = getDefaultConversation({
|
||||
conversation: { ...(conversation ?? {}) },
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import type {
|
|||
} from 'librechat-data-provider';
|
||||
import type { SetterOrUpdater } from 'recoil';
|
||||
import type { AssistantListItem } from '~/common';
|
||||
import { getEndpointField, buildDefaultConvo, getDefaultEndpoint } from '~/utils';
|
||||
import { getEndpointField, buildDefaultConvo, getDefaultEndpoint, logger } from '~/utils';
|
||||
import useAssistantListMap from '~/hooks/Assistants/useAssistantListMap';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { mainTextareaId } from '~/common';
|
||||
|
|
@ -44,6 +44,7 @@ const useGenerateConvo = ({
|
|||
conversationId: rootConvo.conversationId,
|
||||
} as TConversation;
|
||||
|
||||
logger.log('conversation', 'Setting conversation from `useNewConvo`', update);
|
||||
return update;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
import { useSetRecoilState } from 'recoil';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { QueryKeys, EModelEndpoint, LocalStorageKeys, Constants } from 'librechat-data-provider';
|
||||
import {
|
||||
QueryKeys,
|
||||
Constants,
|
||||
dataService,
|
||||
EModelEndpoint,
|
||||
LocalStorageKeys,
|
||||
} 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 +20,21 @@ const useNavigateToConvo = (index = 0) => {
|
|||
const setSubmission = useSetRecoilState(store.submissionByIndex(index));
|
||||
const { hasSetConversation, setConversation } = store.useCreateConversationAtom(index);
|
||||
|
||||
const fetchFreshData = async (conversationId?: string | null) => {
|
||||
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);
|
||||
} catch (error) {
|
||||
console.error('Error fetching conversation data on navigation', error);
|
||||
}
|
||||
};
|
||||
|
||||
const navigateToConvo = (
|
||||
conversation?: TConversation | null,
|
||||
_resetLatestMessage = true,
|
||||
|
|
@ -23,6 +44,7 @@ const useNavigateToConvo = (index = 0) => {
|
|||
logger.warn('conversation', 'Conversation not provided to `navigateToConvo`');
|
||||
return;
|
||||
}
|
||||
logger.log('conversation', 'Navigating to conversation', conversation);
|
||||
hasSetConversation.current = true;
|
||||
setSubmission(null);
|
||||
if (_resetLatestMessage) {
|
||||
|
|
@ -60,6 +82,10 @@ const useNavigateToConvo = (index = 0) => {
|
|||
clearAllConversations(true);
|
||||
setConversation(convo);
|
||||
navigate(`/c/${convo.conversationId ?? Constants.NEW_CONVO}`);
|
||||
if (convo.conversationId !== Constants.NEW_CONVO && convo.conversationId) {
|
||||
queryClient.invalidateQueries([QueryKeys.conversation, convo.conversationId]);
|
||||
fetchFreshData(convo.conversationId);
|
||||
}
|
||||
};
|
||||
|
||||
const navigateWithLastTools = (
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
} from 'librechat-data-provider';
|
||||
import type { TPreset, TEndpointsConfig, TStartupConfig } from 'librechat-data-provider';
|
||||
import type { ZodAny } from 'zod';
|
||||
import { getConvoSwitchLogic, getModelSpecIconURL, removeUnavailableTools } from '~/utils';
|
||||
import { getConvoSwitchLogic, getModelSpecIconURL, removeUnavailableTools, logger } from '~/utils';
|
||||
import useDefaultConvo from '~/hooks/Conversations/useDefaultConvo';
|
||||
import { useChatContext, useChatFormContext } from '~/Providers';
|
||||
import useSubmitMessage from '~/hooks/Messages/useSubmitMessage';
|
||||
|
|
@ -159,6 +159,7 @@ export default function useQueryParams({
|
|||
});
|
||||
|
||||
/* We don't reset the latest message, only when changing settings mid-converstion */
|
||||
logger.log('conversation', 'Switching conversation from query params', currentConvo);
|
||||
newConversation({
|
||||
template: currentConvo,
|
||||
preset: newPreset,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import type {
|
|||
TEndpointsConfig,
|
||||
} from 'librechat-data-provider';
|
||||
import type { MentionOption, ConvoGenerator } from '~/common';
|
||||
import { getConvoSwitchLogic, getModelSpecIconURL, removeUnavailableTools } from '~/utils';
|
||||
import { getConvoSwitchLogic, getModelSpecIconURL, removeUnavailableTools, logger } from '~/utils';
|
||||
import { useChatContext } from '~/Providers';
|
||||
import { useDefaultConvo } from '~/hooks';
|
||||
import store from '~/store';
|
||||
|
|
@ -86,6 +86,7 @@ export default function useSelectMention({
|
|||
});
|
||||
|
||||
/* We don't reset the latest message, only when changing settings mid-converstion */
|
||||
logger.info('conversation', 'Switching conversation to new spec (modular)', conversation);
|
||||
newConversation({
|
||||
template: currentConvo,
|
||||
preset,
|
||||
|
|
@ -95,6 +96,7 @@ export default function useSelectMention({
|
|||
return;
|
||||
}
|
||||
|
||||
logger.info('conversation', 'Switching conversation to new spec', conversation);
|
||||
newConversation({
|
||||
template: { ...(template as Partial<TConversation>) },
|
||||
preset,
|
||||
|
|
@ -172,6 +174,11 @@ export default function useSelectMention({
|
|||
});
|
||||
|
||||
/* We don't reset the latest message, only when changing settings mid-converstion */
|
||||
logger.info(
|
||||
'conversation',
|
||||
'Switching conversation to new endpoint/model (modular)',
|
||||
currentConvo,
|
||||
);
|
||||
newConversation({
|
||||
template: currentConvo,
|
||||
preset: currentConvo,
|
||||
|
|
@ -181,6 +188,7 @@ export default function useSelectMention({
|
|||
return;
|
||||
}
|
||||
|
||||
logger.info('conversation', 'Switching conversation to new endpoint/model', template);
|
||||
newConversation({
|
||||
template: { ...(template as Partial<TConversation>) },
|
||||
preset: { ...kwargs, spec: null, iconURL: null, modelLabel: null, endpoint: newEndpoint },
|
||||
|
|
@ -230,6 +238,7 @@ export default function useSelectMention({
|
|||
});
|
||||
|
||||
/* We don't reset the latest message, only when changing settings mid-converstion */
|
||||
logger.info('conversation', 'Switching conversation to new preset (modular)', currentConvo);
|
||||
newConversation({
|
||||
template: currentConvo,
|
||||
preset: newPreset,
|
||||
|
|
@ -239,6 +248,7 @@ export default function useSelectMention({
|
|||
return;
|
||||
}
|
||||
|
||||
logger.info('conversation', 'Switching conversation to new preset', template);
|
||||
newConversation({ preset: newPreset, keepAddedConvos: isModular });
|
||||
},
|
||||
[
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import useAssistantListMap from './Assistants/useAssistantListMap';
|
|||
import { useResetChatBadges } from './useChatBadges';
|
||||
import { usePauseGlobalAudio } from './Audio';
|
||||
import { mainTextareaId } from '~/common';
|
||||
import { logger } from '~/utils';
|
||||
import store from '~/store';
|
||||
|
||||
const useNewConvo = (index = 0) => {
|
||||
|
|
@ -151,6 +152,7 @@ const useNewConvo = (index = 0) => {
|
|||
if (!(keepAddedConvos ?? false)) {
|
||||
clearAllConversations(true);
|
||||
}
|
||||
logger.log('conversation', 'Setting conversation from `useNewConvo`', conversation);
|
||||
setConversation(conversation);
|
||||
setSubmission({} as TSubmission);
|
||||
if (!(keepLatestMessage ?? false)) {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
import { useEffect, useRef } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { Constants, EModelEndpoint } from 'librechat-data-provider';
|
||||
import { useGetModelsQuery } from 'librechat-data-provider/react-query';
|
||||
import type { TPreset } from 'librechat-data-provider';
|
||||
import {
|
||||
useGetConvoIdQuery,
|
||||
useHealthCheck,
|
||||
useGetEndpointsQuery,
|
||||
useGetConvoIdQuery,
|
||||
useGetStartupConfig,
|
||||
useGetEndpointsQuery,
|
||||
} from '~/data-provider';
|
||||
import { useNewConvo, useAppStartup, useAssistantListMap } from '~/hooks';
|
||||
import { getDefaultModelSpec, getModelSpecIconURL } from '~/utils';
|
||||
import { getDefaultModelSpec, getModelSpecIconURL, logger } from '~/utils';
|
||||
import { ToolCallsMapProvider } from '~/Providers';
|
||||
import ChatView from '~/components/Chat/ChatView';
|
||||
import useAuthRedirect from './useAuthRedirect';
|
||||
|
|
@ -38,11 +38,6 @@ export default function ChatRoute() {
|
|||
const { hasSetConversation, conversation } = store.useCreateConversationAtom(index);
|
||||
const { newConversation } = useNewConvo();
|
||||
|
||||
// Reset the guard flag whenever conversationId changes
|
||||
useEffect(() => {
|
||||
hasSetConversation.current = false;
|
||||
}, [conversationId]);
|
||||
|
||||
const modelsQuery = useGetModelsQuery({
|
||||
enabled: isAuthenticated,
|
||||
refetchOnMount: 'always',
|
||||
|
|
@ -53,6 +48,9 @@ export default function ChatRoute() {
|
|||
const endpointsQuery = useGetEndpointsQuery({ enabled: isAuthenticated });
|
||||
const assistantListMap = useAssistantListMap();
|
||||
|
||||
/** This effect is mainly for the first conversation state change on first load of the page.
|
||||
* Adjusting this may have unintended consequences on the conversation state.
|
||||
*/
|
||||
useEffect(() => {
|
||||
const shouldSetConvo =
|
||||
(startupConfig && !hasSetConversation.current && !modelsQuery.data?.initial) ?? false;
|
||||
|
|
@ -63,7 +61,7 @@ export default function ChatRoute() {
|
|||
|
||||
if (conversationId === Constants.NEW_CONVO && endpointsQuery.data && modelsQuery.data) {
|
||||
const spec = getDefaultModelSpec(startupConfig);
|
||||
|
||||
logger.log('conversation', 'ChatRoute, new convo effect', conversation);
|
||||
newConversation({
|
||||
modelsData: modelsQuery.data,
|
||||
template: conversation ? conversation : undefined,
|
||||
|
|
@ -80,6 +78,7 @@ export default function ChatRoute() {
|
|||
|
||||
hasSetConversation.current = true;
|
||||
} else if (initialConvoQuery.data && endpointsQuery.data && modelsQuery.data) {
|
||||
logger.log('conversation', 'ChatRoute initialConvoQuery', initialConvoQuery.data);
|
||||
newConversation({
|
||||
template: initialConvoQuery.data,
|
||||
/* this is necessary to load all existing settings */
|
||||
|
|
@ -94,6 +93,7 @@ export default function ChatRoute() {
|
|||
assistantListMap[EModelEndpoint.azureAssistants]
|
||||
) {
|
||||
const spec = getDefaultModelSpec(startupConfig);
|
||||
logger.log('conversation', 'ChatRoute new convo, assistants effect', conversation);
|
||||
newConversation({
|
||||
modelsData: modelsQuery.data,
|
||||
template: conversation ? conversation : undefined,
|
||||
|
|
@ -112,6 +112,7 @@ export default function ChatRoute() {
|
|||
assistantListMap[EModelEndpoint.assistants] &&
|
||||
assistantListMap[EModelEndpoint.azureAssistants]
|
||||
) {
|
||||
logger.log('conversation', 'ChatRoute convo, assistants effect', initialConvoQuery.data);
|
||||
newConversation({
|
||||
template: initialConvoQuery.data,
|
||||
preset: initialConvoQuery.data as TPreset,
|
||||
|
|
@ -127,7 +128,6 @@ export default function ChatRoute() {
|
|||
endpointsQuery.data,
|
||||
modelsQuery.data,
|
||||
assistantListMap,
|
||||
conversationId,
|
||||
]);
|
||||
|
||||
if (endpointsQuery.isLoading || modelsQuery.isLoading) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue