diff --git a/client/src/components/Chat/Menus/Presets/PresetItems.tsx b/client/src/components/Chat/Menus/Presets/PresetItems.tsx
index 3e30b6b2c5b..b440b069d07 100644
--- a/client/src/components/Chat/Menus/Presets/PresetItems.tsx
+++ b/client/src/components/Chat/Menus/Presets/PresetItems.tsx
@@ -8,10 +8,10 @@ import type { TPreset } from 'librechat-data-provider';
import FileUpload from '~/components/Input/EndpointMenu/FileUpload';
import { PinIcon, EditIcon, TrashIcon } from '~/components/svg';
import DialogTemplate from '~/components/ui/DialogTemplate';
+import { getPresetTitle, getEndpointField } from '~/utils';
import { Dialog, DialogTrigger } from '~/components/ui/';
import { MenuSeparator, MenuItem } from '../UI';
import { icons } from '../Endpoints/Icons';
-import { getPresetTitle } from '~/utils';
import { useLocalize } from '~/hooks';
import store from '~/store';
@@ -95,7 +95,7 @@ const PresetItems: FC<{
return null;
}
- const iconKey = endpointsConfig?.[preset.endpoint ?? '']?.type
+ const iconKey = getEndpointField(endpointsConfig, preset.endpoint, 'type')
? 'unknown'
: preset.endpoint ?? 'unknown';
@@ -111,7 +111,7 @@ const PresetItems: FC<{
onClick={() => onSelectPreset(preset)}
icon={icons[iconKey]({
context: 'menu-item',
- iconURL: endpointsConfig?.[preset.endpoint ?? ''].iconURL,
+ iconURL: getEndpointField(endpointsConfig, preset.endpoint, 'iconURL'),
className: 'icon-md mr-1 dark:text-white',
endpoint: preset.endpoint,
})}
diff --git a/client/src/components/Conversations/Convo.tsx b/client/src/components/Conversations/Convo.tsx
index aa7d2cfd659..adf30e2851d 100644
--- a/client/src/components/Conversations/Convo.tsx
+++ b/client/src/components/Conversations/Convo.tsx
@@ -5,12 +5,14 @@ import {
useGetEndpointsQuery,
useUpdateConversationMutation,
} from 'librechat-data-provider/react-query';
+import { EModelEndpoint } from 'librechat-data-provider';
import type { MouseEvent, FocusEvent, KeyboardEvent } from 'react';
import { useConversations, useNavigateToConvo } from '~/hooks';
import { MinimalIcon } from '~/components/Endpoints';
import { NotificationSeverity } from '~/common';
import { useToastContext } from '~/Providers';
import DeleteButton from './NewDeleteButton';
+import { getEndpointField } from '~/utils';
import RenameButton from './RenameButton';
import store from '~/store';
@@ -41,7 +43,7 @@ export default function Conversation({ conversation, retainView, toggleNav, i })
document.title = title;
// set conversation to the new conversation
- if (conversation?.endpoint === 'gptPlugins') {
+ if (conversation?.endpoint === EModelEndpoint.gptPlugins) {
let lastSelectedTools = [];
try {
lastSelectedTools = JSON.parse(localStorage.getItem('lastSelectedTools') ?? '') ?? [];
@@ -90,7 +92,7 @@ export default function Conversation({ conversation, retainView, toggleNav, i })
const icon = MinimalIcon({
size: 20,
- iconURL: endpointsConfig?.[conversation.endpoint ?? '']?.iconURL,
+ iconURL: getEndpointField(endpointsConfig, conversation.endpoint, 'iconURL'),
endpoint: conversation.endpoint,
endpointType: conversation.endpointType,
model: conversation.model,
diff --git a/client/src/components/Input/EndpointMenu/EndpointItem.tsx b/client/src/components/Input/EndpointMenu/EndpointItem.tsx
index 21a865592a5..9e68ca3da44 100644
--- a/client/src/components/Input/EndpointMenu/EndpointItem.tsx
+++ b/client/src/components/Input/EndpointMenu/EndpointItem.tsx
@@ -4,9 +4,9 @@ import { alternateName } from 'librechat-data-provider';
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
import { DropdownMenuRadioItem } from '~/components';
import { SetKeyDialog } from '../SetKeyDialog';
+import { cn, getEndpointField } from '~/utils';
import { Icon } from '~/components/Endpoints';
import { useLocalize } from '~/hooks';
-import { cn } from '~/utils';
export default function ModelItem({
endpoint,
@@ -29,7 +29,11 @@ export default function ModelItem({
isCreatedByUser: false,
});
- const userProvidesKey = endpointsConfig?.[endpoint]?.userProvide;
+ const userProvidesKey: boolean | null | undefined = getEndpointField(
+ endpointsConfig,
+ endpoint,
+ 'userProvide',
+ );
const localize = useLocalize();
// regular model
diff --git a/client/src/components/Input/TextChat.tsx b/client/src/components/Input/TextChat.tsx
index af04409b561..26a000dd825 100644
--- a/client/src/components/Input/TextChat.tsx
+++ b/client/src/components/Input/TextChat.tsx
@@ -1,13 +1,14 @@
-import React, { useEffect, useContext, useRef, useState, useCallback } from 'react';
import TextareaAutosize from 'react-textarea-autosize';
import { useRecoilValue, useRecoilState, useSetRecoilState } from 'recoil';
-import SubmitButton from './SubmitButton';
+import React, { useEffect, useContext, useRef, useState, useCallback } from 'react';
-import OptionsBar from './OptionsBar';
import { EndpointMenu } from './EndpointMenu';
+import SubmitButton from './SubmitButton';
+import OptionsBar from './OptionsBar';
import Footer from './Footer';
+
import { useMessageHandler, ThemeContext } from '~/hooks';
-import { cn } from '~/utils';
+import { cn, getEndpointField } from '~/utils';
import store from '~/store';
interface TextChatProps {
@@ -195,7 +196,7 @@ export default function TextChat({ isSearchView = false }: TextChatProps) {
isSubmitting={isSubmitting}
userProvidesKey={
conversation?.endpoint
- ? endpointsConfig?.[conversation.endpoint]?.userProvide
+ ? getEndpointField(endpointsConfig, conversation.endpoint, 'userProvide')
: undefined
}
hasText={hasText}
diff --git a/client/src/hooks/Conversations/useGetSender.ts b/client/src/hooks/Conversations/useGetSender.ts
index 0b8ed9ffea3..5b444e614dc 100644
--- a/client/src/hooks/Conversations/useGetSender.ts
+++ b/client/src/hooks/Conversations/useGetSender.ts
@@ -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],
diff --git a/client/src/hooks/Conversations/usePresets.ts b/client/src/hooks/Conversations/usePresets.ts
index 14057271216..eb60616373c 100644
--- a/client/src/hooks/Conversations/usePresets.ts
+++ b/client/src/hooks/Conversations/usePresets.ts
@@ -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([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({
diff --git a/client/src/hooks/Input/useRequiresKey.ts b/client/src/hooks/Input/useRequiresKey.ts
index 10b8d973c8a..066aa741e8c 100644
--- a/client/src/hooks/Input/useRequiresKey.ts
+++ b/client/src/hooks/Input/useRequiresKey.ts
@@ -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;
diff --git a/client/src/hooks/Input/useUserKey.ts b/client/src/hooks/Input/useUserKey.ts
index fd99bf5a3a6..cdf7ba4fa4a 100644
--- a/client/src/hooks/Input/useUserKey.ts
+++ b/client/src/hooks/Input/useUserKey.ts
@@ -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;
diff --git a/client/src/hooks/Messages/useMessageHelpers.ts b/client/src/hooks/Messages/useMessageHelpers.ts
index 285d1a88dee..1ca2b74d962 100644
--- a/client/src/hooks/Messages/useMessageHelpers.ts
+++ b/client/src/hooks/Messages/useMessageHelpers.ts
@@ -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,
});
diff --git a/client/src/hooks/useChatHelpers.ts b/client/src/hooks/useChatHelpers.ts
index 2afd6122777..3d196859255 100644
--- a/client/src/hooks/useChatHelpers.ts
+++ b/client/src/hooks/useChatHelpers.ts
@@ -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,
diff --git a/client/src/hooks/useConversation.ts b/client/src/hooks/useConversation.ts
index d16493c2333..bf580eaa731 100644
--- a/client/src/hooks/useConversation.ts
+++ b/client/src/hooks/useConversation.ts
@@ -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] ?? [];
diff --git a/client/src/hooks/useNavigateToConvo.tsx b/client/src/hooks/useNavigateToConvo.tsx
index 1dca0afe475..5b8798f9c55 100644
--- a/client/src/hooks/useNavigateToConvo.tsx
+++ b/client/src/hooks/useNavigateToConvo.tsx
@@ -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([QueryKeys.models]);
+ const endpointsConfig = queryClient.getQueryData([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 {
diff --git a/client/src/hooks/useNewConvo.ts b/client/src/hooks/useNewConvo.ts
index 08ebef33b1c..897636e5876 100644
--- a/client/src/hooks/useNewConvo.ts
+++ b/client/src/hooks/useNewConvo.ts
@@ -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] ?? [];
diff --git a/client/src/utils/buildDefaultConvo.ts b/client/src/utils/buildDefaultConvo.ts
index 4b30f035505..6332d6bd627 100644
--- a/client/src/utils/buildDefaultConvo.ts
+++ b/client/src/utils/buildDefaultConvo.ts
@@ -11,6 +11,7 @@ const buildDefaultConvo = ({
conversation: TConversation;
endpoint: EModelEndpoint;
models: string[];
+ // TODO: fix this type as we should allow undefined
lastConversationSetup: TConversation;
}) => {
const { lastSelectedModel, lastSelectedTools, lastBingSettings } = getLocalStorageItems();
diff --git a/client/src/utils/endpoints.spec.ts b/client/src/utils/endpoints.spec.ts
new file mode 100644
index 00000000000..bd554828c46
--- /dev/null
+++ b/client/src/utils/endpoints.spec.ts
@@ -0,0 +1,94 @@
+import { EModelEndpoint } from 'librechat-data-provider';
+import type { TEndpointsConfig, TConfig } from 'librechat-data-provider';
+import {
+ getEndpointField,
+ getAvailableEndpoints,
+ getEndpointsFilter,
+ mapEndpoints,
+} from './endpoints';
+
+const mockEndpointsConfig: TEndpointsConfig = {
+ [EModelEndpoint.openAI]: { type: undefined, iconURL: 'openAI_icon.png', order: 0 },
+ [EModelEndpoint.google]: { type: undefined, iconURL: 'google_icon.png', order: 1 },
+ Mistral: { type: EModelEndpoint.custom, iconURL: 'custom_icon.png', order: 2 },
+};
+
+describe('getEndpointField', () => {
+ it('returns undefined if endpointsConfig is undefined', () => {
+ expect(getEndpointField(undefined, EModelEndpoint.openAI, 'type')).toBeUndefined();
+ });
+
+ it('returns undefined if endpoint is null', () => {
+ expect(getEndpointField(mockEndpointsConfig, null, 'type')).toBeUndefined();
+ });
+
+ it('returns undefined if endpoint is undefined', () => {
+ expect(getEndpointField(mockEndpointsConfig, undefined, 'type')).toBeUndefined();
+ });
+
+ it('returns undefined if the endpoint does not exist in endpointsConfig', () => {
+ expect(getEndpointField(mockEndpointsConfig, EModelEndpoint.bingAI, 'type')).toBeUndefined();
+ });
+
+ it('returns the correct value for a valid endpoint and property', () => {
+ expect(getEndpointField(mockEndpointsConfig, EModelEndpoint.openAI, 'order')).toEqual(0);
+ expect(getEndpointField(mockEndpointsConfig, EModelEndpoint.google, 'iconURL')).toEqual(
+ 'google_icon.png',
+ );
+ });
+
+ it('returns undefined for a valid endpoint but an invalid property', () => {
+ /* Type assertion as 'nonexistentProperty' is intentionally not a valid property of TConfig */
+ expect(
+ getEndpointField(
+ mockEndpointsConfig,
+ EModelEndpoint.openAI,
+ 'nonexistentProperty' as keyof TConfig,
+ ),
+ ).toBeUndefined();
+ });
+
+ it('returns the correct value for a non-enum endpoint and valid property', () => {
+ expect(getEndpointField(mockEndpointsConfig, 'Mistral', 'type')).toEqual(EModelEndpoint.custom);
+ });
+
+ it('returns undefined for a non-enum endpoint with an invalid property', () => {
+ expect(
+ getEndpointField(mockEndpointsConfig, 'Mistral', 'nonexistentProperty' as keyof TConfig),
+ ).toBeUndefined();
+ });
+});
+
+describe('getEndpointsFilter', () => {
+ it('returns an empty object if endpointsConfig is undefined', () => {
+ expect(getEndpointsFilter(undefined)).toEqual({});
+ });
+
+ it('returns a filter object based on endpointsConfig', () => {
+ const expectedFilter = {
+ [EModelEndpoint.openAI]: true,
+ [EModelEndpoint.google]: true,
+ Mistral: true,
+ };
+ expect(getEndpointsFilter(mockEndpointsConfig)).toEqual(expectedFilter);
+ });
+});
+
+describe('getAvailableEndpoints', () => {
+ it('returns available endpoints based on filter and config', () => {
+ const filter = {
+ [EModelEndpoint.openAI]: true,
+ [EModelEndpoint.google]: false,
+ Mistral: true,
+ };
+ const expectedEndpoints = [EModelEndpoint.openAI, 'Mistral'];
+ expect(getAvailableEndpoints(filter, mockEndpointsConfig)).toEqual(expectedEndpoints);
+ });
+});
+
+describe('mapEndpoints', () => {
+ it('returns sorted available endpoints', () => {
+ const expectedOrder = [EModelEndpoint.openAI, EModelEndpoint.google, 'Mistral'];
+ expect(mapEndpoints(mockEndpointsConfig)).toEqual(expectedOrder);
+ });
+});
diff --git a/client/src/utils/endpoints.ts b/client/src/utils/endpoints.ts
new file mode 100644
index 00000000000..e9004bf8a89
--- /dev/null
+++ b/client/src/utils/endpoints.ts
@@ -0,0 +1,58 @@
+import { defaultEndpoints } from 'librechat-data-provider';
+import type { EModelEndpoint, TEndpointsConfig, TConfig } from 'librechat-data-provider';
+
+export const getEndpointsFilter = (endpointsConfig: TEndpointsConfig) => {
+ const filter: Record = {};
+ if (!endpointsConfig) {
+ return filter;
+ }
+ for (const key of Object.keys(endpointsConfig)) {
+ filter[key] = !!endpointsConfig[key];
+ }
+ return filter;
+};
+
+export const getAvailableEndpoints = (
+ filter: Record,
+ endpointsConfig: TEndpointsConfig,
+) => {
+ const defaultSet = new Set(defaultEndpoints);
+ const availableEndpoints: EModelEndpoint[] = [];
+
+ for (const endpoint in endpointsConfig) {
+ // Check if endpoint is in the filter or its type is in defaultEndpoints
+ if (
+ filter[endpoint] ||
+ (endpointsConfig[endpoint]?.type &&
+ defaultSet.has(endpointsConfig[endpoint]?.type as EModelEndpoint))
+ ) {
+ availableEndpoints.push(endpoint as EModelEndpoint);
+ }
+ }
+
+ return availableEndpoints;
+};
+
+export function getEndpointField(
+ endpointsConfig: TEndpointsConfig | undefined,
+ endpoint: EModelEndpoint | string | null | undefined,
+ property: K,
+): TConfig[K] | undefined {
+ if (!endpointsConfig || endpoint === null || endpoint === undefined) {
+ return undefined;
+ }
+
+ const config = endpointsConfig[endpoint];
+ if (!config) {
+ return undefined;
+ }
+
+ return config[property];
+}
+
+export function mapEndpoints(endpointsConfig: TEndpointsConfig) {
+ const filter = getEndpointsFilter(endpointsConfig);
+ return getAvailableEndpoints(filter, endpointsConfig).sort(
+ (a, b) => (endpointsConfig?.[a]?.order ?? 0) - (endpointsConfig?.[b]?.order ?? 0),
+ );
+}
diff --git a/client/src/utils/getDefaultEndpoint.ts b/client/src/utils/getDefaultEndpoint.ts
index a70b20c159e..fc9f6ddd6b1 100644
--- a/client/src/utils/getDefaultEndpoint.ts
+++ b/client/src/utils/getDefaultEndpoint.ts
@@ -5,7 +5,7 @@ import type {
EModelEndpoint,
} from 'librechat-data-provider';
import getLocalStorageItems from './getLocalStorageItems';
-import mapEndpoints from './mapEndpoints';
+import { mapEndpoints } from './endpoints';
type TConvoSetup = Partial | Partial;
@@ -13,7 +13,7 @@ type TDefaultEndpoint = { convoSetup: TConvoSetup; endpointsConfig: TEndpointsCo
const getEndpointFromSetup = (convoSetup: TConvoSetup, endpointsConfig: TEndpointsConfig) => {
const { endpoint: targetEndpoint } = convoSetup || {};
- if (targetEndpoint && endpointsConfig?.[targetEndpoint]) {
+ if (targetEndpoint && endpointsConfig?.[targetEndpoint ?? '']) {
return targetEndpoint;
} else if (targetEndpoint) {
console.warn(`Illegal target endpoint ${targetEndpoint} ${endpointsConfig}`);
@@ -35,7 +35,7 @@ const getEndpointFromLocalStorage = (endpointsConfig: TEndpointsConfig) => {
return endpoint;
}
- return endpoint && endpointsConfig[endpoint] ? endpoint : null;
+ return endpoint && endpointsConfig?.[endpoint ?? ''] ? endpoint : null;
} catch (error) {
console.error(error);
return null;
diff --git a/client/src/utils/index.ts b/client/src/utils/index.ts
index ad356d9012f..bf7ab065c4c 100644
--- a/client/src/utils/index.ts
+++ b/client/src/utils/index.ts
@@ -1,9 +1,9 @@
export * from './json';
export * from './presets';
export * from './languages';
+export * from './endpoints';
export { default as cn } from './cn';
export { default as buildTree } from './buildTree';
-export { default as mapEndpoints } from './mapEndpoints';
export { default as getLoginError } from './getLoginError';
export { default as cleanupPreset } from './cleanupPreset';
export { default as validateIframe } from './validateIframe';
diff --git a/client/src/utils/mapEndpoints.ts b/client/src/utils/mapEndpoints.ts
deleted file mode 100644
index 74460e0dfe9..00000000000
--- a/client/src/utils/mapEndpoints.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { defaultEndpoints } from 'librechat-data-provider';
-import type { EModelEndpoint, TEndpointsConfig } from 'librechat-data-provider';
-
-const getEndpointsFilter = (endpointsConfig: TEndpointsConfig) => {
- const filter: Record = {};
- for (const key of Object.keys(endpointsConfig)) {
- filter[key] = !!endpointsConfig[key];
- }
- return filter;
-};
-
-const getAvailableEndpoints = (
- filter: Record,
- endpointsConfig: TEndpointsConfig,
-) => {
- const defaultSet = new Set(defaultEndpoints);
- const availableEndpoints: EModelEndpoint[] = [];
-
- for (const endpoint in endpointsConfig) {
- // Check if endpoint is in the filter or its type is in defaultEndpoints
- if (
- filter[endpoint] ||
- (endpointsConfig[endpoint]?.type && defaultSet.has(endpointsConfig[endpoint].type))
- ) {
- availableEndpoints.push(endpoint as EModelEndpoint);
- }
- }
-
- return availableEndpoints;
-};
-
-export default function mapEndpoints(endpointsConfig: TEndpointsConfig) {
- const filter = getEndpointsFilter(endpointsConfig);
- return getAvailableEndpoints(filter, endpointsConfig).sort(
- (a, b) => (endpointsConfig[a]?.order ?? 0) - (endpointsConfig[b]?.order ?? 0),
- );
-}
diff --git a/packages/data-provider/src/types.ts b/packages/data-provider/src/types.ts
index 0921cbbe97a..de3bd889337 100644
--- a/packages/data-provider/src/types.ts
+++ b/packages/data-provider/src/types.ts
@@ -139,9 +139,11 @@ export type TConfig = {
userProvideURL?: boolean | null;
};
-export type TModelsConfig = Record;
+export type TEndpointsConfig =
+ | Record
+ | undefined;
-export type TEndpointsConfig = Record;
+export type TModelsConfig = Record;
export type TUpdateTokenCountResponse = {
count: number;