librechat-data-provider 0.4.6 → 0.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import type { TAzureGroups } from '../src/config';
2
- import { validateAzureGroups, mapModelToAzureConfig } from '../src/azure';
2
+ import { validateAzureGroups, mapModelToAzureConfig, mapGroupToAzureConfig } from '../src/azure';
3
3
 
4
4
  describe('validateAzureGroups', () => {
5
5
  it('should validate a correct configuration', () => {
@@ -785,3 +785,57 @@ describe('validateAzureGroups with modelGroupMap and groupMap', () => {
785
785
  });
786
786
  });
787
787
  });
788
+
789
+ describe('mapGroupToAzureConfig', () => {
790
+ // Test setup for a basic config with 2 groups
791
+ const groupMap = {
792
+ group1: {
793
+ apiKey: 'key-for-group1',
794
+ instanceName: 'instance-group1',
795
+ models: {
796
+ model1: { deploymentName: 'deployment1', version: '1.0' },
797
+ },
798
+ },
799
+ group2: {
800
+ apiKey: 'key-for-group2',
801
+ instanceName: 'instance-group2',
802
+ serverless: true,
803
+ baseURL: 'https://group2.example.com',
804
+ models: {
805
+ model2: true, // demonstrating a boolean style model configuration
806
+ },
807
+ },
808
+ };
809
+
810
+ it('should successfully map non-serverless group configuration', () => {
811
+ const groupName = 'group1';
812
+ const result = mapGroupToAzureConfig({ groupName, groupMap });
813
+ expect(result).toEqual({
814
+ azureOptions: expect.objectContaining({
815
+ azureOpenAIApiKey: 'key-for-group1',
816
+ azureOpenAIApiInstanceName: 'instance-group1',
817
+ azureOpenAIApiDeploymentName: expect.any(String),
818
+ azureOpenAIApiVersion: expect.any(String),
819
+ }),
820
+ });
821
+ });
822
+
823
+ it('should successfully map serverless group configuration', () => {
824
+ const groupName = 'group2';
825
+ const result = mapGroupToAzureConfig({ groupName, groupMap });
826
+ expect(result).toEqual({
827
+ azureOptions: expect.objectContaining({
828
+ azureOpenAIApiKey: 'key-for-group2',
829
+ }),
830
+ baseURL: 'https://group2.example.com',
831
+ serverless: true,
832
+ });
833
+ });
834
+
835
+ it('should throw error for nonexistent group name', () => {
836
+ const groupName = 'nonexistent-group';
837
+ expect(() => {
838
+ mapGroupToAzureConfig({ groupName, groupMap });
839
+ }).toThrow(`Group named "${groupName}" not found in configuration.`);
840
+ });
841
+ });
@@ -66,7 +66,20 @@ export const plugins = () => '/api/plugins';
66
66
 
67
67
  export const config = () => '/api/config';
68
68
 
69
- export const assistants = (id?: string) => `/api/assistants${id ? `/${id}` : ''}`;
69
+ export const assistants = (id?: string, options?: Record<string, string>) => {
70
+ let url = '/api/assistants';
71
+
72
+ if (id) {
73
+ url += `/${id}`;
74
+ }
75
+
76
+ if (options && Object.keys(options).length > 0) {
77
+ const queryParams = new URLSearchParams(options).toString();
78
+ url += `?${queryParams}`;
79
+ }
80
+
81
+ return url;
82
+ };
70
83
 
71
84
  export const files = () => '/api/files';
72
85
 
package/src/azure.ts CHANGED
@@ -234,14 +234,16 @@ export function mapModelToAzureConfig({
234
234
  }
235
235
 
236
236
  const modelDetails = groupConfig.models[modelName];
237
- const deploymentName =
237
+ const { deploymentName, version } =
238
238
  typeof modelDetails === 'object'
239
- ? modelDetails.deploymentName || groupConfig.deploymentName
240
- : groupConfig.deploymentName;
241
- const version =
242
- typeof modelDetails === 'object'
243
- ? modelDetails.version || groupConfig.version
244
- : groupConfig.version;
239
+ ? {
240
+ deploymentName: modelDetails.deploymentName || groupConfig.deploymentName,
241
+ version: modelDetails.version || groupConfig.version,
242
+ }
243
+ : {
244
+ deploymentName: groupConfig.deploymentName,
245
+ version: groupConfig.version,
246
+ };
245
247
 
246
248
  if (!deploymentName || !version) {
247
249
  throw new Error(
@@ -274,3 +276,86 @@ export function mapModelToAzureConfig({
274
276
 
275
277
  return result;
276
278
  }
279
+
280
+ export function mapGroupToAzureConfig({
281
+ groupName,
282
+ groupMap,
283
+ }: {
284
+ groupName: string;
285
+ groupMap: TAzureGroupMap;
286
+ }): MappedAzureConfig {
287
+ const groupConfig = groupMap[groupName];
288
+ if (!groupConfig) {
289
+ throw new Error(`Group named "${groupName}" not found in configuration.`);
290
+ }
291
+
292
+ const instanceName = groupConfig.instanceName as string;
293
+
294
+ if (!instanceName && !groupConfig.serverless) {
295
+ throw new Error(
296
+ `Group "${groupName}" is missing an instanceName for non-serverless configuration.`,
297
+ );
298
+ }
299
+
300
+ if (groupConfig.serverless && !groupConfig.baseURL) {
301
+ throw new Error(
302
+ `Group "${groupName}" is missing the required base URL for serverless configuration.`,
303
+ );
304
+ }
305
+
306
+ const models = Object.keys(groupConfig.models);
307
+ if (models.length === 0) {
308
+ throw new Error(`Group "${groupName}" does not have any models configured.`);
309
+ }
310
+
311
+ // Use the first available model in the group
312
+ const firstModelName = models[0];
313
+ const modelDetails = groupConfig.models[firstModelName];
314
+
315
+ const azureOptions: AzureOptions = {
316
+ azureOpenAIApiKey: extractEnvVariable(groupConfig.apiKey),
317
+ azureOpenAIApiInstanceName: extractEnvVariable(instanceName),
318
+ // DeploymentName and Version set below
319
+ };
320
+
321
+ if (groupConfig.serverless) {
322
+ return {
323
+ azureOptions,
324
+ baseURL: extractEnvVariable(groupConfig.baseURL ?? ''),
325
+ serverless: true,
326
+ ...(groupConfig.additionalHeaders && { headers: groupConfig.additionalHeaders }),
327
+ };
328
+ }
329
+
330
+ const { deploymentName, version } =
331
+ typeof modelDetails === 'object'
332
+ ? {
333
+ deploymentName: modelDetails.deploymentName || groupConfig.deploymentName,
334
+ version: modelDetails.version || groupConfig.version,
335
+ }
336
+ : {
337
+ deploymentName: groupConfig.deploymentName,
338
+ version: groupConfig.version,
339
+ };
340
+
341
+ if (!deploymentName || !version) {
342
+ throw new Error(
343
+ `Model "${firstModelName}" in group "${groupName}" or the group itself is missing a deploymentName ("${deploymentName}") or version ("${version}").`,
344
+ );
345
+ }
346
+
347
+ azureOptions.azureOpenAIApiDeploymentName = extractEnvVariable(deploymentName);
348
+ azureOptions.azureOpenAIApiVersion = extractEnvVariable(version);
349
+
350
+ const result: MappedAzureConfig = { azureOptions };
351
+
352
+ if (groupConfig.baseURL) {
353
+ result.baseURL = extractEnvVariable(groupConfig.baseURL);
354
+ }
355
+
356
+ if (groupConfig.additionalHeaders) {
357
+ result.headers = groupConfig.additionalHeaders;
358
+ }
359
+
360
+ return result;
361
+ }
package/src/config.ts CHANGED
@@ -6,12 +6,25 @@ import { FileSources } from './types/files';
6
6
 
7
7
  export const defaultSocialLogins = ['google', 'facebook', 'openid', 'github', 'discord'];
8
8
 
9
+ export const defaultRetrievalModels = [
10
+ 'gpt-4-turbo-preview',
11
+ 'gpt-3.5-turbo-0125',
12
+ 'gpt-4-0125-preview',
13
+ 'gpt-4-1106-preview',
14
+ 'gpt-3.5-turbo-1106',
15
+ 'gpt-3.5-turbo-0125',
16
+ 'gpt-4-turbo',
17
+ 'gpt-4-0125',
18
+ 'gpt-4-1106',
19
+ ];
20
+
9
21
  export const fileSourceSchema = z.nativeEnum(FileSources);
10
22
 
11
23
  export const modelConfigSchema = z
12
24
  .object({
13
25
  deploymentName: z.string().optional(),
14
26
  version: z.string().optional(),
27
+ assistants: z.boolean().optional(),
15
28
  })
16
29
  .or(z.boolean());
17
30
 
@@ -22,6 +35,7 @@ export const azureBaseSchema = z.object({
22
35
  serverless: z.boolean().optional(),
23
36
  instanceName: z.string().optional(),
24
37
  deploymentName: z.string().optional(),
38
+ assistants: z.boolean().optional(),
25
39
  addParams: z.record(z.any()).optional(),
26
40
  dropParams: z.array(z.string()).optional(),
27
41
  forcePrompt: z.boolean().optional(),
@@ -61,6 +75,13 @@ export type TValidatedAzureConfig = {
61
75
  groupMap: TAzureGroupMap;
62
76
  };
63
77
 
78
+ export enum Capabilities {
79
+ code_interpreter = 'code_interpreter',
80
+ retrieval = 'retrieval',
81
+ actions = 'actions',
82
+ tools = 'tools',
83
+ }
84
+
64
85
  export const assistantEndpointSchema = z.object({
65
86
  /* assistants specific */
66
87
  disableBuilder: z.boolean().optional(),
@@ -68,6 +89,16 @@ export const assistantEndpointSchema = z.object({
68
89
  timeoutMs: z.number().optional(),
69
90
  supportedIds: z.array(z.string()).min(1).optional(),
70
91
  excludedIds: z.array(z.string()).min(1).optional(),
92
+ retrievalModels: z.array(z.string()).min(1).optional().default(defaultRetrievalModels),
93
+ capabilities: z
94
+ .array(z.nativeEnum(Capabilities))
95
+ .optional()
96
+ .default([
97
+ Capabilities.code_interpreter,
98
+ Capabilities.retrieval,
99
+ Capabilities.actions,
100
+ Capabilities.tools,
101
+ ]),
71
102
  /* general */
72
103
  apiKey: z.string().optional(),
73
104
  baseURL: z.string().optional(),
@@ -116,6 +147,7 @@ export const azureEndpointSchema = z
116
147
  .object({
117
148
  groups: azureGroupConfigsSchema,
118
149
  plugins: z.boolean().optional(),
150
+ assistants: z.boolean().optional(),
119
151
  })
120
152
  .and(
121
153
  endpointSchema
@@ -147,6 +179,22 @@ export const rateLimitSchema = z.object({
147
179
  export const configSchema = z.object({
148
180
  version: z.string(),
149
181
  cache: z.boolean(),
182
+ interface: z
183
+ .object({
184
+ privacyPolicy: z
185
+ .object({
186
+ externalUrl: z.string().optional(),
187
+ openNewTab: z.boolean().optional(),
188
+ })
189
+ .optional(),
190
+ termsOfService: z
191
+ .object({
192
+ externalUrl: z.string().optional(),
193
+ openNewTab: z.boolean().optional(),
194
+ })
195
+ .optional(),
196
+ })
197
+ .optional(),
150
198
  fileStrategy: fileSourceSchema.optional(),
151
199
  registration: z
152
200
  .object({
@@ -241,6 +289,8 @@ export const defaultModels = {
241
289
  'code-bison-32k',
242
290
  ],
243
291
  [EModelEndpoint.anthropic]: [
292
+ 'claude-3-opus-20240229',
293
+ 'claude-3-sonnet-20240229',
244
294
  'claude-2.1',
245
295
  'claude-2',
246
296
  'claude-1.2',
@@ -270,14 +320,6 @@ export const defaultModels = {
270
320
  ],
271
321
  };
272
322
 
273
- export const supportsRetrieval = new Set([
274
- 'gpt-3.5-turbo-0125',
275
- 'gpt-4-0125-preview',
276
- 'gpt-4-turbo-preview',
277
- 'gpt-4-1106-preview',
278
- 'gpt-3.5-turbo-1106',
279
- ]);
280
-
281
323
  export const EndpointURLs: { [key in EModelEndpoint]: string } = {
282
324
  [EModelEndpoint.openAI]: `/api/ask/${EModelEndpoint.openAI}`,
283
325
  [EModelEndpoint.bingAI]: `/api/ask/${EModelEndpoint.bingAI}`,
@@ -301,21 +343,31 @@ export const modularEndpoints = new Set<EModelEndpoint | string>([
301
343
 
302
344
  export const supportsBalanceCheck = {
303
345
  [EModelEndpoint.openAI]: true,
346
+ [EModelEndpoint.anthropic]: true,
304
347
  [EModelEndpoint.azureOpenAI]: true,
305
348
  [EModelEndpoint.gptPlugins]: true,
306
349
  [EModelEndpoint.custom]: true,
307
350
  };
308
351
 
309
- export const visionModels = ['gpt-4-vision', 'llava-13b', 'gemini-pro-vision'];
310
-
311
- export function validateVisionModel(
312
- model: string | undefined,
313
- additionalModels: string[] | undefined = [],
314
- ) {
352
+ export const visionModels = ['gpt-4-vision', 'llava-13b', 'gemini-pro-vision', 'claude-3'];
353
+
354
+ export function validateVisionModel({
355
+ model,
356
+ additionalModels = [],
357
+ availableModels,
358
+ }: {
359
+ model: string;
360
+ additionalModels?: string[];
361
+ availableModels?: string[];
362
+ }) {
315
363
  if (!model) {
316
364
  return false;
317
365
  }
318
366
 
367
+ if (availableModels && !availableModels.includes(model)) {
368
+ return false;
369
+ }
370
+
319
371
  return visionModels.concat(additionalModels).some((visionModel) => model.includes(visionModel));
320
372
  }
321
373
 
@@ -457,7 +509,7 @@ export enum Constants {
457
509
  /**
458
510
  * Key for the Custom Config's version (librechat.yaml).
459
511
  */
460
- CONFIG_VERSION = '1.0.4',
512
+ CONFIG_VERSION = '1.0.5',
461
513
  /**
462
514
  * Standard value for the first message's `parentMessageId` value, to indicate no parent exists.
463
515
  */
@@ -186,8 +186,8 @@ export const updateAssistant = (
186
186
  return request.patch(endpoints.assistants(assistant_id), data);
187
187
  };
188
188
 
189
- export const deleteAssistant = (assistant_id: string): Promise<void> => {
190
- return request.delete(endpoints.assistants(assistant_id));
189
+ export const deleteAssistant = (assistant_id: string, model: string): Promise<void> => {
190
+ return request.delete(endpoints.assistants(assistant_id, { model }));
191
191
  };
192
192
 
193
193
  export const listAssistants = (
@@ -225,7 +225,10 @@ export const uploadAvatar = (data: FormData): Promise<f.AvatarUploadResponse> =>
225
225
  };
226
226
 
227
227
  export const uploadAssistantAvatar = (data: m.AssistantAvatarVariables): Promise<a.Assistant> => {
228
- return request.postMultiPart(endpoints.assistants(`avatar/${data.assistant_id}`), data.formData);
228
+ return request.postMultiPart(
229
+ endpoints.assistants(`avatar/${data.assistant_id}`, { model: data.model }),
230
+ data.formData,
231
+ );
229
232
  };
230
233
 
231
234
  export const updateAction = (data: m.UpdateActionVariables): Promise<m.UpdateActionResponse> => {
@@ -8,6 +8,7 @@ export const supportsFiles = {
8
8
  [EModelEndpoint.google]: true,
9
9
  [EModelEndpoint.assistants]: true,
10
10
  [EModelEndpoint.azureOpenAI]: true,
11
+ [EModelEndpoint.anthropic]: true,
11
12
  [EModelEndpoint.custom]: true,
12
13
  };
13
14
 
package/src/schemas.ts CHANGED
@@ -22,7 +22,7 @@ export const defaultAssistantFormValues = {
22
22
  name: '',
23
23
  description: '',
24
24
  instructions: '',
25
- model: 'gpt-3.5-turbo-1106',
25
+ model: '',
26
26
  functions: [],
27
27
  code_interpreter: false,
28
28
  retrieval: false,
@@ -391,6 +391,7 @@ export const anthropicSchema = tConversationSchema
391
391
  maxOutputTokens: true,
392
392
  topP: true,
393
393
  topK: true,
394
+ resendImages: true,
394
395
  })
395
396
  .transform((obj) => ({
396
397
  ...obj,
@@ -401,6 +402,7 @@ export const anthropicSchema = tConversationSchema
401
402
  maxOutputTokens: obj.maxOutputTokens ?? 4000,
402
403
  topP: obj.topP ?? 0.7,
403
404
  topK: obj.topK ?? 5,
405
+ resendImages: obj.resendImages ?? false,
404
406
  }))
405
407
  .catch(() => ({
406
408
  model: 'claude-1',
@@ -410,6 +412,7 @@ export const anthropicSchema = tConversationSchema
410
412
  maxOutputTokens: 4000,
411
413
  topP: 0.7,
412
414
  topK: 5,
415
+ resendImages: false,
413
416
  }));
414
417
 
415
418
  export const chatGPTBrowserSchema = tConversationSchema
@@ -568,6 +571,7 @@ export const compactAnthropicSchema = tConversationSchema
568
571
  maxOutputTokens: true,
569
572
  topP: true,
570
573
  topK: true,
574
+ resendImages: true,
571
575
  })
572
576
  .transform((obj) => {
573
577
  const newObj: Partial<TConversation> = { ...obj };
@@ -583,6 +587,9 @@ export const compactAnthropicSchema = tConversationSchema
583
587
  if (newObj.topK === 5) {
584
588
  delete newObj.topK;
585
589
  }
590
+ if (newObj.resendImages !== true) {
591
+ delete newObj.resendImages;
592
+ }
586
593
 
587
594
  return removeNullishValues(newObj);
588
595
  })
@@ -46,6 +46,7 @@ export type LogoutOptions = {
46
46
 
47
47
  export type AssistantAvatarVariables = {
48
48
  assistant_id: string;
49
+ model: string;
49
50
  formData: FormData;
50
51
  postCreation?: boolean;
51
52
  };
@@ -86,6 +87,8 @@ export type UpdateAssistantMutationOptions = {
86
87
  ) => void;
87
88
  };
88
89
 
90
+ export type DeleteAssistantBody = { assistant_id: string; model: string };
91
+
89
92
  export type DeleteAssistantMutationOptions = {
90
93
  onSuccess?: (data: void, variables: { assistant_id: string }, context?: unknown) => void;
91
94
  onMutate?: (variables: { assistant_id: string }) => void | Promise<unknown>;
package/src/types.ts CHANGED
@@ -146,6 +146,8 @@ export type TConfig = {
146
146
  userProvide?: boolean | null;
147
147
  userProvideURL?: boolean | null;
148
148
  disableBuilder?: boolean;
149
+ retrievalModels?: string[];
150
+ capabilities?: string[];
149
151
  };
150
152
 
151
153
  export type TEndpointsConfig =
@@ -193,9 +195,21 @@ export type TResetPassword = {
193
195
  confirm_password?: string;
194
196
  };
195
197
 
198
+ export type TInterfaceConfig = {
199
+ privacyPolicy?: {
200
+ externalUrl?: string;
201
+ openNewTab?: boolean;
202
+ };
203
+ termsOfService?: {
204
+ externalUrl?: string;
205
+ openNewTab?: boolean;
206
+ };
207
+ };
208
+
196
209
  export type TStartupConfig = {
197
210
  appTitle: string;
198
211
  socialLogins?: string[];
212
+ interface?: TInterfaceConfig;
199
213
  discordLoginEnabled: boolean;
200
214
  facebookLoginEnabled: boolean;
201
215
  githubLoginEnabled: boolean;