refactor(loadConfigModels): Stricter Default Model Fallback (#2239)

* chore: add TEndpoint type/typedef

* refactor(loadConfigModels.spec): stricter default model matching (fails with current impl.)

* refactor(loadConfigModels): return default models on endpoint basis and not fetch basis

* refactor: rename `uniqueKeyToNameMap` to `uniqueKeyToEndpointsMap` for clarity
This commit is contained in:
Danny Avila 2024-03-29 11:49:38 -04:00 committed by GitHub
parent 0a8118deed
commit dec7879cc1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 36 additions and 16 deletions

View file

@ -46,12 +46,23 @@ async function loadConfigModels(req) {
(endpoint.models.fetch || endpoint.models.default),
);
const fetchPromisesMap = {}; // Map for promises keyed by unique combination of baseURL and apiKey
const uniqueKeyToNameMap = {}; // Map to associate unique keys with endpoint names
/**
* @type {Record<string, string[]>}
* Map for promises keyed by unique combination of baseURL and apiKey */
const fetchPromisesMap = {};
/**
* @type {Record<string, string[]>}
* Map to associate unique keys with endpoint names; note: one key may can correspond to multiple endpoints */
const uniqueKeyToEndpointsMap = {};
/**
* @type {Record<string, Partial<TEndpoint>>}
* Map to associate endpoint names to their configurations */
const endpointsMap = {};
for (let i = 0; i < customEndpoints.length; i++) {
const endpoint = customEndpoints[i];
const { models, name, baseURL, apiKey } = endpoint;
endpointsMap[name] = endpoint;
const API_KEY = extractEnvVariable(apiKey);
const BASE_URL = extractEnvVariable(baseURL);
@ -69,11 +80,9 @@ async function loadConfigModels(req) {
apiKey: API_KEY,
name,
userIdQuery: models.userIdQuery,
}).then((result) => {
return !result?.length ? models.default ?? [] : result;
});
uniqueKeyToNameMap[uniqueKey] = uniqueKeyToNameMap[uniqueKey] || [];
uniqueKeyToNameMap[uniqueKey].push(name);
uniqueKeyToEndpointsMap[uniqueKey] = uniqueKeyToEndpointsMap[uniqueKey] || [];
uniqueKeyToEndpointsMap[uniqueKey].push(name);
continue;
}
@ -88,10 +97,11 @@ async function loadConfigModels(req) {
for (let i = 0; i < fetchedData.length; i++) {
const currentKey = uniqueKeys[i];
const modelData = fetchedData[i];
const associatedNames = uniqueKeyToNameMap[currentKey];
const associatedNames = uniqueKeyToEndpointsMap[currentKey];
for (const name of associatedNames) {
modelsConfig[name] = modelData;
const endpoint = endpointsMap[name];
modelsConfig[name] = !modelData?.length ? endpoint.models.default ?? [] : modelData;
}
}

View file

@ -267,6 +267,15 @@ describe('loadConfigModels', () => {
getCustomConfig.mockResolvedValue({
endpoints: {
custom: [
{
name: 'EndpointWithSameFetchKey',
apiKey: 'API_KEY',
baseURL: 'http://example.com',
models: {
fetch: true,
default: ['defaultModel1'],
},
},
{
name: 'EmptyFetchModel',
apiKey: 'API_KEY',
@ -283,14 +292,7 @@ describe('loadConfigModels', () => {
fetchModels.mockResolvedValue([]);
const result = await loadConfigModels(mockRequest);
expect(fetchModels).toHaveBeenCalledWith(
expect.objectContaining({
name: 'EmptyFetchModel',
apiKey: 'API_KEY',
}),
);
expect(fetchModels).toHaveBeenCalledTimes(1);
expect(result.EmptyFetchModel).toEqual(['defaultModel1', 'defaultModel2']);
});

View file

@ -277,6 +277,12 @@
* @memberof typedefs
*/
/**
* @exports TEndpoint
* @typedef {import('librechat-data-provider').TEndpoint} TEndpoint
* @memberof typedefs
*/
/**
* @exports TEndpointsConfig
* @typedef {import('librechat-data-provider').TEndpointsConfig} TEndpointsConfig

View file

@ -150,6 +150,8 @@ export const endpointSchema = z.object({
customOrder: z.number().optional(),
});
export type TEndpoint = z.infer<typeof endpointSchema>;
export const azureEndpointSchema = z
.object({
groups: azureGroupConfigsSchema,