librechat-data-provider 0.7.430 → 0.7.692

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.
package/src/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import OpenAI from 'openai';
1
+ import type OpenAI from 'openai';
2
2
  import type { InfiniteData } from '@tanstack/react-query';
3
3
  import type {
4
4
  TMessage,
@@ -10,10 +10,7 @@ import type {
10
10
  TConversationTag,
11
11
  TBanner,
12
12
  } from './schemas';
13
- import type { TSpecsConfig } from './models';
14
13
  export type TOpenAIMessage = OpenAI.Chat.ChatCompletionMessageParam;
15
- export type TOpenAIFunction = OpenAI.Chat.ChatCompletionCreateParams.Function;
16
- export type TOpenAIFunctionCall = OpenAI.Chat.ChatCompletionCreateParams.FunctionCallOption;
17
14
 
18
15
  export * from './schemas';
19
16
 
@@ -64,6 +61,7 @@ export type TSubmission = {
64
61
  initialResponse?: TMessage;
65
62
  conversation: Partial<TConversation>;
66
63
  endpointOption: TEndpointOption;
64
+ clientTimestamp?: string;
67
65
  };
68
66
 
69
67
  export type EventSubmission = Omit<TSubmission, 'initialResponse'> & { initialResponse: TMessage };
@@ -72,14 +70,13 @@ export type TPluginAction = {
72
70
  pluginKey: string;
73
71
  action: 'install' | 'uninstall';
74
72
  auth?: unknown;
75
- isAssistantTool?: boolean;
73
+ isEntityTool?: boolean;
76
74
  };
77
75
 
78
76
  export type GroupedConversations = [key: string, TConversation[]][];
79
77
 
80
78
  export type TUpdateUserPlugins = {
81
- isAssistantTool?: boolean;
82
- isAgentTool?: boolean;
79
+ isEntityTool?: boolean;
83
80
  pluginKey: string;
84
81
  action: string;
85
82
  auth?: unknown;
@@ -110,7 +107,7 @@ export type TUser = {
110
107
  avatar: string;
111
108
  role: string;
112
109
  provider: string;
113
- plugins: string[];
110
+ plugins?: string[];
114
111
  createdAt: string;
115
112
  updatedAt: string;
116
113
  };
@@ -152,6 +149,7 @@ export type TUpdateConversationResponse = TConversation;
152
149
  export type TDeleteConversationRequest = {
153
150
  conversationId?: string;
154
151
  thread_id?: string;
152
+ endpoint?: string;
155
153
  source?: string;
156
154
  };
157
155
 
@@ -196,12 +194,24 @@ export type TConversationTagRequest = Partial<
196
194
 
197
195
  export type TConversationTagResponse = TConversationTag;
198
196
 
199
- // type for tagging conversation
200
197
  export type TTagConversationRequest = {
201
198
  tags: string[];
199
+ tag: string;
202
200
  };
201
+
203
202
  export type TTagConversationResponse = string[];
204
203
 
204
+ export type TDuplicateConvoRequest = {
205
+ conversationId?: string;
206
+ };
207
+
208
+ export type TDuplicateConvoResponse =
209
+ | {
210
+ conversation: TConversation;
211
+ messages: TMessage[];
212
+ }
213
+ | undefined;
214
+
205
215
  export type TForkConvoRequest = {
206
216
  messageId: string;
207
217
  conversationId: string;
@@ -301,63 +311,6 @@ export type TVerifyEmail = {
301
311
 
302
312
  export type TResendVerificationEmail = Omit<TVerifyEmail, 'token'>;
303
313
 
304
- export type TInterfaceConfig = {
305
- privacyPolicy?: {
306
- externalUrl?: string;
307
- openNewTab?: boolean;
308
- };
309
- termsOfService?: {
310
- externalUrl?: string;
311
- openNewTab?: boolean;
312
- modalAcceptance?: boolean;
313
- modalTitle?: string;
314
- modalContent?: string;
315
- };
316
- endpointsMenu: boolean;
317
- modelSelect: boolean;
318
- parameters: boolean;
319
- sidePanel: boolean;
320
- presets: boolean;
321
- multiConvo: boolean;
322
- bookmarks: boolean;
323
- prompts: boolean;
324
- };
325
-
326
- export type TStartupConfig = {
327
- appTitle: string;
328
- socialLogins?: string[];
329
- interface?: TInterfaceConfig;
330
- discordLoginEnabled: boolean;
331
- facebookLoginEnabled: boolean;
332
- githubLoginEnabled: boolean;
333
- googleLoginEnabled: boolean;
334
- openidLoginEnabled: boolean;
335
- openidLabel: string;
336
- openidImageUrl: string;
337
- /** LDAP Auth Configuration */
338
- ldap?: {
339
- /** LDAP enabled */
340
- enabled: boolean;
341
- /** Whether LDAP uses username vs. email */
342
- username?: boolean;
343
- };
344
- serverDomain: string;
345
- emailLoginEnabled: boolean;
346
- registrationEnabled: boolean;
347
- socialLoginEnabled: boolean;
348
- passwordResetEnabled: boolean;
349
- emailEnabled: boolean;
350
- checkBalance: boolean;
351
- showBirthdayIcon: boolean;
352
- helpAndFaqURL: string;
353
- customFooter?: string;
354
- modelSpecs?: TSpecsConfig;
355
- sharedLinksEnabled: boolean;
356
- publicSharedLinksEnabled: boolean;
357
- analyticsGtmId?: string;
358
- instanceProjectId: string;
359
- };
360
-
361
314
  export type TRefreshTokenResponse = {
362
315
  token: string;
363
316
  user: TUser;
@@ -491,9 +444,7 @@ export type TUpdatePromptLabelsResponse = {
491
444
  message: string;
492
445
  };
493
446
 
494
- export type TDeletePromptGroupResponse = {
495
- promptGroup: string;
496
- };
447
+ export type TDeletePromptGroupResponse = TUpdatePromptLabelsResponse;
497
448
 
498
449
  export type TDeletePromptGroupRequest = {
499
450
  id: string;
@@ -0,0 +1,467 @@
1
+ /* eslint-disable jest/no-conditional-expect */
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ // zod.spec.ts
4
+ import { z } from 'zod';
5
+ import { convertJsonSchemaToZod } from './zod';
6
+ import type { JsonSchemaType } from './zod';
7
+
8
+ describe('convertJsonSchemaToZod', () => {
9
+ describe('primitive types', () => {
10
+ it('should convert string schema', () => {
11
+ const schema: JsonSchemaType = {
12
+ type: 'string',
13
+ };
14
+ const zodSchema = convertJsonSchemaToZod(schema);
15
+
16
+ expect(zodSchema.parse('test')).toBe('test');
17
+ expect(() => zodSchema.parse(123)).toThrow();
18
+ });
19
+
20
+ it('should convert string enum schema', () => {
21
+ const schema: JsonSchemaType = {
22
+ type: 'string',
23
+ enum: ['foo', 'bar', 'baz'],
24
+ };
25
+ const zodSchema = convertJsonSchemaToZod(schema);
26
+
27
+ expect(zodSchema.parse('foo')).toBe('foo');
28
+ expect(() => zodSchema.parse('invalid')).toThrow();
29
+ });
30
+
31
+ it('should convert number schema', () => {
32
+ const schema: JsonSchemaType = {
33
+ type: 'number',
34
+ };
35
+ const zodSchema = convertJsonSchemaToZod(schema);
36
+
37
+ expect(zodSchema.parse(123)).toBe(123);
38
+ expect(() => zodSchema.parse('123')).toThrow();
39
+ });
40
+
41
+ it('should convert boolean schema', () => {
42
+ const schema: JsonSchemaType = {
43
+ type: 'boolean',
44
+ };
45
+ const zodSchema = convertJsonSchemaToZod(schema);
46
+
47
+ expect(zodSchema.parse(true)).toBe(true);
48
+ expect(() => zodSchema.parse('true')).toThrow();
49
+ });
50
+ });
51
+
52
+ describe('array types', () => {
53
+ it('should convert array of strings schema', () => {
54
+ const schema: JsonSchemaType = {
55
+ type: 'array',
56
+ items: { type: 'string' },
57
+ };
58
+ const zodSchema = convertJsonSchemaToZod(schema);
59
+
60
+ expect(zodSchema.parse(['a', 'b', 'c'])).toEqual(['a', 'b', 'c']);
61
+ expect(() => zodSchema.parse(['a', 123, 'c'])).toThrow();
62
+ });
63
+
64
+ it('should convert array of numbers schema', () => {
65
+ const schema: JsonSchemaType = {
66
+ type: 'array',
67
+ items: { type: 'number' },
68
+ };
69
+ const zodSchema = convertJsonSchemaToZod(schema);
70
+
71
+ expect(zodSchema.parse([1, 2, 3])).toEqual([1, 2, 3]);
72
+ expect(() => zodSchema.parse([1, '2', 3])).toThrow();
73
+ });
74
+ });
75
+
76
+ describe('object types', () => {
77
+ it('should convert simple object schema', () => {
78
+ const schema: JsonSchemaType = {
79
+ type: 'object',
80
+ properties: {
81
+ name: { type: 'string' },
82
+ age: { type: 'number' },
83
+ },
84
+ };
85
+ const zodSchema = convertJsonSchemaToZod(schema);
86
+
87
+ expect(zodSchema.parse({ name: 'John', age: 30 })).toEqual({ name: 'John', age: 30 });
88
+ expect(() => zodSchema.parse({ name: 123, age: 30 })).toThrow();
89
+ });
90
+
91
+ it('should handle required fields', () => {
92
+ const schema: JsonSchemaType = {
93
+ type: 'object',
94
+ properties: {
95
+ name: { type: 'string' },
96
+ age: { type: 'number' },
97
+ },
98
+ required: ['name'],
99
+ };
100
+ const zodSchema = convertJsonSchemaToZod(schema);
101
+
102
+ expect(zodSchema.parse({ name: 'John' })).toEqual({ name: 'John' });
103
+ expect(() => zodSchema.parse({})).toThrow();
104
+ });
105
+
106
+ it('should handle nested objects', () => {
107
+ const schema: JsonSchemaType = {
108
+ type: 'object',
109
+ properties: {
110
+ user: {
111
+ type: 'object',
112
+ properties: {
113
+ name: { type: 'string' },
114
+ age: { type: 'number' },
115
+ },
116
+ required: ['name'],
117
+ },
118
+ },
119
+ required: ['user'],
120
+ };
121
+ const zodSchema = convertJsonSchemaToZod(schema);
122
+
123
+ expect(zodSchema.parse({ user: { name: 'John', age: 30 } })).toEqual({
124
+ user: { name: 'John', age: 30 },
125
+ });
126
+ expect(() => zodSchema.parse({ user: { age: 30 } })).toThrow();
127
+ });
128
+
129
+ it('should handle objects with arrays', () => {
130
+ const schema: JsonSchemaType = {
131
+ type: 'object',
132
+ properties: {
133
+ names: {
134
+ type: 'array',
135
+ items: { type: 'string' },
136
+ },
137
+ },
138
+ };
139
+ const zodSchema = convertJsonSchemaToZod(schema);
140
+
141
+ expect(zodSchema.parse({ names: ['John', 'Jane'] })).toEqual({ names: ['John', 'Jane'] });
142
+ expect(() => zodSchema.parse({ names: ['John', 123] })).toThrow();
143
+ });
144
+ });
145
+
146
+ describe('edge cases', () => {
147
+ it('should handle empty object schema', () => {
148
+ const schema: JsonSchemaType = {
149
+ type: 'object',
150
+ properties: {},
151
+ };
152
+ const zodSchema = convertJsonSchemaToZod(schema);
153
+
154
+ expect(zodSchema.parse({})).toEqual({});
155
+ });
156
+
157
+ it('should handle unknown types as unknown', () => {
158
+ const schema = {
159
+ type: 'invalid',
160
+ } as unknown as JsonSchemaType;
161
+ const zodSchema = convertJsonSchemaToZod(schema);
162
+
163
+ expect(zodSchema.parse('anything')).toBe('anything');
164
+ expect(zodSchema.parse(123)).toBe(123);
165
+ });
166
+
167
+ it('should handle empty enum arrays as regular strings', () => {
168
+ const schema: JsonSchemaType = {
169
+ type: 'string',
170
+ enum: [],
171
+ };
172
+ const zodSchema = convertJsonSchemaToZod(schema);
173
+
174
+ expect(zodSchema.parse('test')).toBe('test');
175
+ });
176
+ });
177
+
178
+ describe('complex schemas', () => {
179
+ it('should handle complex nested schema', () => {
180
+ const schema: JsonSchemaType = {
181
+ type: 'object',
182
+ properties: {
183
+ id: { type: 'number' },
184
+ user: {
185
+ type: 'object',
186
+ properties: {
187
+ name: { type: 'string' },
188
+ roles: {
189
+ type: 'array',
190
+ items: {
191
+ type: 'object',
192
+ properties: {
193
+ name: { type: 'string' },
194
+ permissions: {
195
+ type: 'array',
196
+ items: {
197
+ type: 'string',
198
+ enum: ['read', 'write', 'admin'],
199
+ },
200
+ },
201
+ },
202
+ required: ['name', 'permissions'],
203
+ },
204
+ },
205
+ },
206
+ required: ['name', 'roles'],
207
+ },
208
+ },
209
+ required: ['id', 'user'],
210
+ };
211
+
212
+ const zodSchema = convertJsonSchemaToZod(schema);
213
+
214
+ const validData = {
215
+ id: 1,
216
+ user: {
217
+ name: 'John',
218
+ roles: [
219
+ {
220
+ name: 'moderator',
221
+ permissions: ['read', 'write'],
222
+ },
223
+ ],
224
+ },
225
+ };
226
+
227
+ expect(zodSchema.parse(validData)).toEqual(validData);
228
+ expect(() =>
229
+ zodSchema.parse({
230
+ id: 1,
231
+ user: {
232
+ name: 'John',
233
+ roles: [
234
+ {
235
+ name: 'moderator',
236
+ permissions: ['invalid'],
237
+ },
238
+ ],
239
+ },
240
+ }),
241
+ ).toThrow();
242
+ });
243
+ });
244
+
245
+ // zod.spec.ts
246
+ describe('schema descriptions', () => {
247
+ it('should preserve top-level description', () => {
248
+ const schema: JsonSchemaType = {
249
+ type: 'object',
250
+ description: 'A test schema description',
251
+ properties: {
252
+ name: { type: 'string' },
253
+ },
254
+ };
255
+ const zodSchema = convertJsonSchemaToZod(schema);
256
+ expect(zodSchema.description).toBe('A test schema description');
257
+ });
258
+
259
+ it('should preserve field descriptions', () => {
260
+ const schema: JsonSchemaType = {
261
+ type: 'object',
262
+ properties: {
263
+ name: {
264
+ type: 'string',
265
+ description: 'The user\'s name',
266
+ },
267
+ age: {
268
+ type: 'number',
269
+ description: 'The user\'s age',
270
+ },
271
+ },
272
+ };
273
+ const zodSchema = convertJsonSchemaToZod(schema);
274
+
275
+ const shape = (zodSchema as z.ZodObject<any>).shape;
276
+ expect(shape.name.description).toBe('The user\'s name');
277
+ expect(shape.age.description).toBe('The user\'s age');
278
+ });
279
+
280
+ it('should preserve descriptions in nested objects', () => {
281
+ const schema: JsonSchemaType = {
282
+ type: 'object',
283
+ description: 'User record',
284
+ properties: {
285
+ user: {
286
+ type: 'object',
287
+ description: 'User details',
288
+ properties: {
289
+ name: {
290
+ type: 'string',
291
+ description: 'The user\'s name',
292
+ },
293
+ settings: {
294
+ type: 'object',
295
+ description: 'User preferences',
296
+ properties: {
297
+ theme: {
298
+ type: 'string',
299
+ description: 'UI theme preference',
300
+ enum: ['light', 'dark'],
301
+ },
302
+ },
303
+ },
304
+ },
305
+ },
306
+ },
307
+ };
308
+ const zodSchema = convertJsonSchemaToZod(schema);
309
+
310
+ // Type assertions for better type safety
311
+ const shape = zodSchema instanceof z.ZodObject ? zodSchema.shape : {};
312
+ expect(zodSchema.description).toBe('User record');
313
+
314
+ if ('user' in shape) {
315
+ expect(shape.user.description).toBe('User details');
316
+
317
+ const userShape = shape.user instanceof z.ZodObject ? shape.user.shape : {};
318
+ if ('name' in userShape && 'settings' in userShape) {
319
+ expect(userShape.name.description).toBe('The user\'s name');
320
+ expect(userShape.settings.description).toBe('User preferences');
321
+
322
+ const settingsShape =
323
+ userShape.settings instanceof z.ZodObject ? userShape.settings.shape : {};
324
+ if ('theme' in settingsShape) {
325
+ expect(settingsShape.theme.description).toBe('UI theme preference');
326
+ }
327
+ }
328
+ }
329
+ });
330
+
331
+ it('should preserve descriptions in arrays', () => {
332
+ const schema: JsonSchemaType = {
333
+ type: 'object',
334
+ properties: {
335
+ tags: {
336
+ type: 'array',
337
+ description: 'User tags',
338
+ items: {
339
+ type: 'string',
340
+ description: 'Individual tag',
341
+ },
342
+ },
343
+ scores: {
344
+ type: 'array',
345
+ description: 'Test scores',
346
+ items: {
347
+ type: 'number',
348
+ description: 'Individual score',
349
+ },
350
+ },
351
+ },
352
+ };
353
+ const zodSchema = convertJsonSchemaToZod(schema);
354
+
355
+ const shape = (zodSchema as z.ZodObject<any>).shape;
356
+ expect(shape.tags.description).toBe('User tags');
357
+ expect(shape.scores.description).toBe('Test scores');
358
+ });
359
+
360
+ it('should preserve descriptions in enums', () => {
361
+ const schema: JsonSchemaType = {
362
+ type: 'object',
363
+ properties: {
364
+ role: {
365
+ type: 'string',
366
+ description: 'User role in the system',
367
+ enum: ['admin', 'user', 'guest'],
368
+ },
369
+ status: {
370
+ type: 'string',
371
+ description: 'Account status',
372
+ enum: ['active', 'suspended', 'deleted'],
373
+ },
374
+ },
375
+ };
376
+ const zodSchema = convertJsonSchemaToZod(schema);
377
+
378
+ const shape = (zodSchema as z.ZodObject<any>).shape;
379
+ expect(shape.role.description).toBe('User role in the system');
380
+ expect(shape.status.description).toBe('Account status');
381
+ });
382
+
383
+ it('should preserve descriptions in a complex schema', () => {
384
+ const schema: JsonSchemaType = {
385
+ type: 'object',
386
+ description: 'User profile configuration',
387
+ properties: {
388
+ basicInfo: {
389
+ type: 'object',
390
+ description: 'Basic user information',
391
+ properties: {
392
+ name: {
393
+ type: 'string',
394
+ description: 'Full name of the user',
395
+ },
396
+ age: {
397
+ type: 'number',
398
+ description: 'User age in years',
399
+ },
400
+ },
401
+ required: ['name'],
402
+ },
403
+ preferences: {
404
+ type: 'object',
405
+ description: 'User preferences',
406
+ properties: {
407
+ notifications: {
408
+ type: 'array',
409
+ description: 'Notification settings',
410
+ items: {
411
+ type: 'object',
412
+ description: 'Individual notification preference',
413
+ properties: {
414
+ type: {
415
+ type: 'string',
416
+ description: 'Type of notification',
417
+ enum: ['email', 'sms', 'push'],
418
+ },
419
+ enabled: {
420
+ type: 'boolean',
421
+ description: 'Whether this notification is enabled',
422
+ },
423
+ },
424
+ },
425
+ },
426
+ theme: {
427
+ type: 'string',
428
+ description: 'UI theme preference',
429
+ enum: ['light', 'dark', 'system'],
430
+ },
431
+ },
432
+ },
433
+ },
434
+ };
435
+
436
+ const zodSchema = convertJsonSchemaToZod(schema);
437
+
438
+ // Test top-level description
439
+ expect(zodSchema.description).toBe('User profile configuration');
440
+
441
+ const shape = zodSchema instanceof z.ZodObject ? zodSchema.shape : {};
442
+
443
+ // Test basic info descriptions
444
+ if ('basicInfo' in shape) {
445
+ expect(shape.basicInfo.description).toBe('Basic user information');
446
+ const basicInfoShape = shape.basicInfo instanceof z.ZodObject ? shape.basicInfo.shape : {};
447
+
448
+ if ('name' in basicInfoShape && 'age' in basicInfoShape) {
449
+ expect(basicInfoShape.name.description).toBe('Full name of the user');
450
+ expect(basicInfoShape.age.description).toBe('User age in years');
451
+ }
452
+ }
453
+
454
+ // Test preferences descriptions
455
+ if ('preferences' in shape) {
456
+ expect(shape.preferences.description).toBe('User preferences');
457
+ const preferencesShape =
458
+ shape.preferences instanceof z.ZodObject ? shape.preferences.shape : {};
459
+
460
+ if ('notifications' in preferencesShape && 'theme' in preferencesShape) {
461
+ expect(preferencesShape.notifications.description).toBe('Notification settings');
462
+ expect(preferencesShape.theme.description).toBe('UI theme preference');
463
+ }
464
+ }
465
+ });
466
+ });
467
+ });
package/src/zod.ts ADDED
@@ -0,0 +1,66 @@
1
+ import { z } from 'zod';
2
+
3
+ export type JsonSchemaType = {
4
+ type: 'string' | 'number' | 'boolean' | 'array' | 'object';
5
+ enum?: string[];
6
+ items?: JsonSchemaType;
7
+ properties?: Record<string, JsonSchemaType>;
8
+ required?: string[];
9
+ description?: string;
10
+ };
11
+
12
+ export function convertJsonSchemaToZod(schema: JsonSchemaType): z.ZodType {
13
+ let zodSchema: z.ZodType;
14
+
15
+ // Handle primitive types
16
+ if (schema.type === 'string') {
17
+ if (Array.isArray(schema.enum) && schema.enum.length > 0) {
18
+ const [first, ...rest] = schema.enum;
19
+ zodSchema = z.enum([first, ...rest] as [string, ...string[]]);
20
+ } else {
21
+ zodSchema = z.string();
22
+ }
23
+ } else if (schema.type === 'number') {
24
+ zodSchema = z.number();
25
+ } else if (schema.type === 'boolean') {
26
+ zodSchema = z.boolean();
27
+ } else if (schema.type === 'array' && schema.items !== undefined) {
28
+ const itemSchema = convertJsonSchemaToZod(schema.items);
29
+ zodSchema = z.array(itemSchema);
30
+ } else if (schema.type === 'object') {
31
+ const shape: Record<string, z.ZodType> = {};
32
+ const properties = schema.properties ?? {};
33
+
34
+ for (const [key, value] of Object.entries(properties)) {
35
+ let fieldSchema = convertJsonSchemaToZod(value);
36
+ if (value.description != null && value.description !== '') {
37
+ fieldSchema = fieldSchema.describe(value.description);
38
+ }
39
+ shape[key] = fieldSchema;
40
+ }
41
+
42
+ let objectSchema = z.object(shape);
43
+
44
+ if (Array.isArray(schema.required) && schema.required.length > 0) {
45
+ const partial = Object.fromEntries(
46
+ Object.entries(shape).map(([key, value]) => [
47
+ key,
48
+ schema.required?.includes(key) === true ? value : value.optional(),
49
+ ]),
50
+ );
51
+ objectSchema = z.object(partial);
52
+ } else {
53
+ objectSchema = objectSchema.partial();
54
+ }
55
+ zodSchema = objectSchema;
56
+ } else {
57
+ zodSchema = z.unknown();
58
+ }
59
+
60
+ // Add description if present
61
+ if (schema.description != null && schema.description !== '') {
62
+ zodSchema = zodSchema.describe(schema.description);
63
+ }
64
+
65
+ return zodSchema;
66
+ }