🔧 fix: Improve Endpoint Handling and Address Edge Cases (#1486)

* fix(TEndpointsConfig): resolve property access issues with typesafe helper function

* fix: undefined or null endpoint edge case

* refactor(mapEndpoints -> endpoints): renamed module to be more general for endpoint handling, wrote unit tests, export all helpers
This commit is contained in:
Danny Avila 2024-01-04 10:17:15 -05:00 committed by GitHub
parent 42f2353509
commit 9864fc8700
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 275 additions and 99 deletions

View file

@ -7,7 +7,7 @@ export default function useGetSender() {
const { data: endpointsConfig = {} as TEndpointsConfig } = useGetEndpointsQuery();
return useCallback(
(endpointOption: TEndpointOption) => {
const { modelDisplayLabel } = endpointsConfig[endpointOption.endpoint ?? ''] ?? {};
const { modelDisplayLabel } = endpointsConfig?.[endpointOption.endpoint ?? ''] ?? {};
return getResponseSender({ ...endpointOption, modelDisplayLabel });
},
[endpointsConfig],

View file

@ -13,11 +13,11 @@ import {
} from '~/data-provider';
import { useChatContext, useToastContext } from '~/Providers';
import useNavigateToConvo from '~/hooks/useNavigateToConvo';
import { cleanupPreset, getEndpointField } from '~/utils';
import useDefaultConvo from '~/hooks/useDefaultConvo';
import { useAuthContext } from '~/hooks/AuthContext';
import { NotificationSeverity } from '~/common';
import useLocalize from '~/hooks/useLocalize';
import { cleanupPreset } from '~/utils';
import store from '~/store';
export default function usePresets() {
@ -162,12 +162,13 @@ export default function usePresets() {
const endpointsConfig = queryClient.getQueryData<TEndpointsConfig>([QueryKeys.endpoints]);
const currentEndpointType = endpointsConfig?.[endpoint ?? '']?.type ?? '';
const endpointType = endpointsConfig?.[newPreset?.endpoint ?? '']?.type;
const currentEndpointType = getEndpointField(endpointsConfig, endpoint, 'type');
const endpointType = getEndpointField(endpointsConfig, newPreset.endpoint, 'type');
if (
(modularEndpoints.has(endpoint ?? '') || modularEndpoints.has(currentEndpointType)) &&
(modularEndpoints.has(newPreset?.endpoint ?? '') || modularEndpoints.has(endpointType)) &&
(modularEndpoints.has(endpoint ?? '') || modularEndpoints.has(currentEndpointType ?? '')) &&
(modularEndpoints.has(newPreset?.endpoint ?? '') ||
modularEndpoints.has(endpointType ?? '')) &&
(endpoint === newPreset?.endpoint || modularChat)
) {
const currentConvo = getDefaultConversation({

View file

@ -1,12 +1,17 @@
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
import { useChatContext } from '~/Providers/ChatContext';
import { getEndpointField } from '~/utils';
import useUserKey from './useUserKey';
export default function useRequiresKey() {
const { conversation } = useChatContext();
const { data: endpointsConfig } = useGetEndpointsQuery();
const { endpoint } = conversation || {};
const userProvidesKey = endpointsConfig?.[endpoint ?? '']?.userProvide;
const userProvidesKey: boolean | null | undefined = getEndpointField(
endpointsConfig,
endpoint,
'userProvide',
);
const { getExpiry } = useUserKey(endpoint ?? '');
const expiryTime = getExpiry();
const requiresKey = !expiryTime && userProvidesKey;

View file

@ -8,7 +8,7 @@ import {
const useUserKey = (endpoint: string) => {
const { data: endpointsConfig } = useGetEndpointsQuery();
const config = endpointsConfig?.[endpoint];
const config = endpointsConfig?.[endpoint ?? ''];
const { azure } = config ?? {};
let keyName = endpoint;

View file

@ -5,6 +5,7 @@ import type { TMessage } from 'librechat-data-provider';
import type { TMessageProps } from '~/common';
import Icon from '~/components/Endpoints/Icon';
import { useChatContext } from '~/Providers';
import { getEndpointField } from '~/utils';
export default function useMessageHelpers(props: TMessageProps) {
const latestText = useRef('');
@ -53,7 +54,7 @@ export default function useMessageHelpers(props: TMessageProps) {
const icon = Icon({
...conversation,
...(message as TMessage),
iconURL: endpointsConfig?.[conversation?.endpoint ?? '']?.iconURL,
iconURL: getEndpointField(endpointsConfig, conversation?.endpoint, 'iconURL'),
model: message?.model ?? conversation?.model,
size: 28.8,
});

View file

@ -161,7 +161,7 @@ export default function useChatHelpers(index = 0, paramId: string | undefined) {
conversation: conversation ?? {},
});
const { modelDisplayLabel } = endpointsConfig[endpoint ?? ''] ?? {};
const { modelDisplayLabel } = endpointsConfig?.[endpoint ?? ''] ?? {};
const endpointOption = {
...convo,
endpoint,

View file

@ -9,7 +9,7 @@ import type {
TModelsConfig,
TEndpointsConfig,
} from 'librechat-data-provider';
import { buildDefaultConvo, getDefaultEndpoint } from '~/utils';
import { buildDefaultConvo, getDefaultEndpoint, getEndpointField } from '~/utils';
import useOriginNavigate from './useOriginNavigate';
import store from '~/store';
@ -38,8 +38,9 @@ const useConversation = () => {
endpointsConfig,
});
if (!conversation.endpointType && endpointsConfig[defaultEndpoint]?.type) {
conversation.endpointType = endpointsConfig[defaultEndpoint]?.type;
const endpointType = getEndpointField(endpointsConfig, defaultEndpoint, 'type');
if (!conversation.endpointType && endpointType) {
conversation.endpointType = endpointType;
}
const models = modelsConfig?.[defaultEndpoint] ?? [];

View file

@ -1,11 +1,15 @@
import { useQueryClient } from '@tanstack/react-query';
import { useSetRecoilState, useResetRecoilState } from 'recoil';
import type { TConversation } from 'librechat-data-provider';
import { QueryKeys } from 'librechat-data-provider';
import type { TConversation, TEndpointsConfig, TModelsConfig } from 'librechat-data-provider';
import { buildDefaultConvo, getDefaultEndpoint, getEndpointField } from '~/utils';
import useOriginNavigate from './useOriginNavigate';
import useSetStorage from './useSetStorage';
import store from '~/store';
const useNavigateToConvo = (index = 0) => {
const setStorage = useSetStorage();
const queryClient = useQueryClient();
const navigate = useOriginNavigate();
const { setConversation } = store.useCreateConversationAtom(index);
const setSubmission = useSetRecoilState(store.submissionByIndex(index));
@ -21,9 +25,34 @@ const useNavigateToConvo = (index = 0) => {
if (_resetLatestMessage) {
resetLatestMessage();
}
setStorage(conversation);
setConversation(conversation);
navigate(conversation?.conversationId);
let convo = { ...conversation };
if (!convo?.endpoint) {
/* undefined endpoint edge case */
const modelsConfig = queryClient.getQueryData<TModelsConfig>([QueryKeys.models]);
const endpointsConfig = queryClient.getQueryData<TEndpointsConfig>([QueryKeys.endpoints]);
const defaultEndpoint = getDefaultEndpoint({
convoSetup: conversation,
endpointsConfig,
});
const endpointType = getEndpointField(endpointsConfig, defaultEndpoint, 'type');
if (!conversation.endpointType && endpointType) {
conversation.endpointType = endpointType;
}
const models = modelsConfig?.[defaultEndpoint ?? ''] ?? [];
convo = buildDefaultConvo({
conversation,
endpoint: defaultEndpoint,
lastConversationSetup: conversation,
models,
});
}
setStorage(convo);
setConversation(convo);
navigate(convo?.conversationId);
};
return {

View file

@ -14,7 +14,7 @@ import type {
TModelsConfig,
TEndpointsConfig,
} from 'librechat-data-provider';
import { buildDefaultConvo, getDefaultEndpoint } from '~/utils';
import { buildDefaultConvo, getDefaultEndpoint, getEndpointField } from '~/utils';
import { useDeleteFilesMutation } from '~/data-provider';
import useOriginNavigate from './useOriginNavigate';
import useSetStorage from './useSetStorage';
@ -69,8 +69,9 @@ const useNewConvo = (index = 0) => {
endpointsConfig,
});
if (!conversation.endpointType && endpointsConfig[defaultEndpoint]?.type) {
conversation.endpointType = endpointsConfig[defaultEndpoint]?.type;
const endpointType = getEndpointField(endpointsConfig, defaultEndpoint, 'type');
if (!conversation.endpointType && endpointType) {
conversation.endpointType = endpointType;
}
const models = modelsConfig?.[defaultEndpoint] ?? [];