librechat-data-provider 0.7.3 → 0.7.5

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.
@@ -5,7 +5,7 @@
5
5
  "module": "./index.es.js",
6
6
  "types": "../types/react-query/index.d.ts",
7
7
  "dependencies": {
8
- "axios": "^1.3.4",
8
+ "axios": "^1.7.7",
9
9
  "zod": "^3.22.4"
10
10
  }
11
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "librechat-data-provider",
3
- "version": "0.7.3",
3
+ "version": "0.7.5",
4
4
  "description": "data services for librechat apps",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.es.js",
@@ -40,7 +40,7 @@
40
40
  "homepage": "https://librechat.ai",
41
41
  "dependencies": {
42
42
  "@types/js-yaml": "^4.0.9",
43
- "axios": "^1.3.4",
43
+ "axios": "^1.7.7",
44
44
  "js-yaml": "^4.1.0",
45
45
  "openai": "4.11.1",
46
46
  "openapi-types": "^12.1.3",
@@ -62,7 +62,7 @@
62
62
  "jest": "^29.5.0",
63
63
  "jest-junit": "^16.0.0",
64
64
  "rimraf": "^5.0.1",
65
- "rollup": "^3.26.0",
65
+ "rollup": "^4.22.4",
66
66
  "rollup-plugin-generate-package-json": "^3.2.0",
67
67
  "rollup-plugin-peer-deps-external": "^2.2.4",
68
68
  "rollup-plugin-typescript2": "^0.35.0",
@@ -5,6 +5,6 @@
5
5
  "module": "./index.es.js",
6
6
  "types": "../dist/types/react-query/index.d.ts",
7
7
  "dependencies": {
8
- "axios": "^1.3.4"
8
+ "axios": "^1.7.7"
9
9
  }
10
10
  }
@@ -1,4 +1,5 @@
1
1
  import axios from 'axios';
2
+ import { z } from 'zod';
2
3
  import { OpenAPIV3 } from 'openapi-types';
3
4
  import {
4
5
  createURL,
@@ -8,7 +9,12 @@ import {
8
9
  FunctionSignature,
9
10
  validateAndParseOpenAPISpec,
10
11
  } from '../src/actions';
11
- import { getWeatherOpenapiSpec, whimsicalOpenapiSpec, scholarAIOpenapiSpec } from './openapiSpecs';
12
+ import {
13
+ getWeatherOpenapiSpec,
14
+ whimsicalOpenapiSpec,
15
+ scholarAIOpenapiSpec,
16
+ swapidev,
17
+ } from './openapiSpecs';
12
18
  import { AuthorizationTypeEnum, AuthTypeEnum } from '../src/types/assistants';
13
19
  import type { FlowchartSchema } from './openapiSpecs';
14
20
  import type { ParametersSchema } from '../src/actions';
@@ -548,4 +554,273 @@ describe('createURL', () => {
548
554
  'https://example.com/subdirectory/api/v1/users',
549
555
  );
550
556
  });
557
+
558
+ describe('openapiToFunction zodSchemas', () => {
559
+ describe('getWeatherOpenapiSpec', () => {
560
+ const { zodSchemas } = openapiToFunction(getWeatherOpenapiSpec, true);
561
+
562
+ it('generates correct Zod schema for GetCurrentWeather', () => {
563
+ expect(zodSchemas).toBeDefined();
564
+ expect(zodSchemas?.GetCurrentWeather).toBeDefined();
565
+
566
+ const GetCurrentWeatherSchema = zodSchemas?.GetCurrentWeather;
567
+
568
+ expect(GetCurrentWeatherSchema instanceof z.ZodObject).toBe(true);
569
+
570
+ if (!(GetCurrentWeatherSchema instanceof z.ZodObject)) {
571
+ throw new Error('GetCurrentWeatherSchema is not a ZodObject');
572
+ }
573
+
574
+ const shape = GetCurrentWeatherSchema.shape;
575
+ expect(shape.location instanceof z.ZodString).toBe(true);
576
+
577
+ // Check locations property
578
+ expect(shape.locations).toBeDefined();
579
+ expect(shape.locations instanceof z.ZodOptional).toBe(true);
580
+
581
+ if (!(shape.locations instanceof z.ZodOptional)) {
582
+ throw new Error('locations is not a ZodOptional');
583
+ }
584
+
585
+ const locationsInnerType = shape.locations._def.innerType;
586
+ expect(locationsInnerType instanceof z.ZodArray).toBe(true);
587
+
588
+ if (!(locationsInnerType instanceof z.ZodArray)) {
589
+ throw new Error('locationsInnerType is not a ZodArray');
590
+ }
591
+
592
+ const locationsItemSchema = locationsInnerType.element;
593
+ expect(locationsItemSchema instanceof z.ZodObject).toBe(true);
594
+
595
+ if (!(locationsItemSchema instanceof z.ZodObject)) {
596
+ throw new Error('locationsItemSchema is not a ZodObject');
597
+ }
598
+
599
+ // Validate the structure of locationsItemSchema
600
+ expect(locationsItemSchema.shape.city instanceof z.ZodString).toBe(true);
601
+ expect(locationsItemSchema.shape.state instanceof z.ZodString).toBe(true);
602
+ expect(locationsItemSchema.shape.countryCode instanceof z.ZodString).toBe(true);
603
+
604
+ // Check if time is optional
605
+ const timeSchema = locationsItemSchema.shape.time;
606
+ expect(timeSchema instanceof z.ZodOptional).toBe(true);
607
+
608
+ if (!(timeSchema instanceof z.ZodOptional)) {
609
+ throw new Error('timeSchema is not a ZodOptional');
610
+ }
611
+
612
+ expect(timeSchema._def.innerType instanceof z.ZodString).toBe(true);
613
+
614
+ // Check the description
615
+ expect(shape.locations._def.description).toBe(
616
+ 'A list of locations to retrieve the weather for.',
617
+ );
618
+ });
619
+
620
+ it('validates correct data for GetCurrentWeather', () => {
621
+ const GetCurrentWeatherSchema = zodSchemas?.GetCurrentWeather as z.ZodTypeAny;
622
+ const validData = {
623
+ location: 'New York',
624
+ locations: [
625
+ { city: 'New York', state: 'NY', countryCode: 'US', time: '2023-12-04T14:00:00Z' },
626
+ ],
627
+ };
628
+ expect(() => GetCurrentWeatherSchema.parse(validData)).not.toThrow();
629
+ });
630
+
631
+ it('throws error for invalid data for GetCurrentWeather', () => {
632
+ const GetCurrentWeatherSchema = zodSchemas?.GetCurrentWeather as z.ZodTypeAny;
633
+ const invalidData = {
634
+ location: 123,
635
+ locations: [{ city: 'New York', state: 'NY', countryCode: 'US', time: 'invalid-time' }],
636
+ };
637
+ expect(() => GetCurrentWeatherSchema.parse(invalidData)).toThrow();
638
+ });
639
+ });
640
+
641
+ describe('whimsicalOpenapiSpec', () => {
642
+ const { zodSchemas } = openapiToFunction(whimsicalOpenapiSpec, true);
643
+
644
+ it('generates correct Zod schema for postRenderFlowchart', () => {
645
+ expect(zodSchemas).toBeDefined();
646
+ expect(zodSchemas?.postRenderFlowchart).toBeDefined();
647
+
648
+ const PostRenderFlowchartSchema = zodSchemas?.postRenderFlowchart;
649
+ expect(PostRenderFlowchartSchema).toBeInstanceOf(z.ZodObject);
650
+
651
+ if (!(PostRenderFlowchartSchema instanceof z.ZodObject)) {
652
+ return;
653
+ }
654
+
655
+ const shape = PostRenderFlowchartSchema.shape;
656
+ expect(shape.mermaid).toBeInstanceOf(z.ZodString);
657
+ expect(shape.title).toBeInstanceOf(z.ZodOptional);
658
+ expect((shape.title as z.ZodOptional<z.ZodString>)._def.innerType).toBeInstanceOf(
659
+ z.ZodString,
660
+ );
661
+ });
662
+
663
+ it('validates correct data for postRenderFlowchart', () => {
664
+ const PostRenderFlowchartSchema = zodSchemas?.postRenderFlowchart;
665
+ const validData = {
666
+ mermaid: 'graph TD; A-->B; B-->C; C-->D;',
667
+ title: 'Test Flowchart',
668
+ };
669
+ expect(() => PostRenderFlowchartSchema?.parse(validData)).not.toThrow();
670
+ });
671
+
672
+ it('throws error for invalid data for postRenderFlowchart', () => {
673
+ const PostRenderFlowchartSchema = zodSchemas?.postRenderFlowchart;
674
+ const invalidData = {
675
+ mermaid: 123,
676
+ title: 42,
677
+ };
678
+ expect(() => PostRenderFlowchartSchema?.parse(invalidData)).toThrow();
679
+ });
680
+ });
681
+
682
+ describe('scholarAIOpenapiSpec', () => {
683
+ const result = validateAndParseOpenAPISpec(scholarAIOpenapiSpec);
684
+ const spec = result.spec as OpenAPIV3.Document;
685
+ const { zodSchemas } = openapiToFunction(spec, true);
686
+
687
+ it('generates correct Zod schema for searchAbstracts', () => {
688
+ expect(zodSchemas).toBeDefined();
689
+ expect(zodSchemas?.searchAbstracts).toBeDefined();
690
+
691
+ const SearchAbstractsSchema = zodSchemas?.searchAbstracts;
692
+ expect(SearchAbstractsSchema).toBeInstanceOf(z.ZodObject);
693
+
694
+ if (!(SearchAbstractsSchema instanceof z.ZodObject)) {
695
+ return;
696
+ }
697
+
698
+ const shape = SearchAbstractsSchema.shape;
699
+ expect(shape.keywords).toBeInstanceOf(z.ZodString);
700
+ expect(shape.sort).toBeInstanceOf(z.ZodOptional);
701
+ expect(
702
+ (shape.sort as z.ZodOptional<z.ZodEnum<[string, ...string[]]>>)._def.innerType,
703
+ ).toBeInstanceOf(z.ZodEnum);
704
+ expect(shape.query).toBeInstanceOf(z.ZodString);
705
+ expect(shape.peer_reviewed_only).toBeInstanceOf(z.ZodOptional);
706
+ expect(shape.start_year).toBeInstanceOf(z.ZodOptional);
707
+ expect(shape.end_year).toBeInstanceOf(z.ZodOptional);
708
+ expect(shape.offset).toBeInstanceOf(z.ZodOptional);
709
+ });
710
+
711
+ it('validates correct data for searchAbstracts', () => {
712
+ const SearchAbstractsSchema = zodSchemas?.searchAbstracts;
713
+ const validData = {
714
+ keywords: 'machine learning',
715
+ sort: 'cited_by_count',
716
+ query: 'AI applications',
717
+ peer_reviewed_only: 'true',
718
+ start_year: '2020',
719
+ end_year: '2023',
720
+ offset: '0',
721
+ };
722
+ expect(() => SearchAbstractsSchema?.parse(validData)).not.toThrow();
723
+ });
724
+
725
+ it('throws error for invalid data for searchAbstracts', () => {
726
+ const SearchAbstractsSchema = zodSchemas?.searchAbstracts;
727
+ const invalidData = {
728
+ keywords: 123,
729
+ sort: 'invalid_sort',
730
+ query: 42,
731
+ peer_reviewed_only: 'maybe',
732
+ start_year: 2020,
733
+ end_year: 2023,
734
+ offset: 0,
735
+ };
736
+ expect(() => SearchAbstractsSchema?.parse(invalidData)).toThrow();
737
+ });
738
+
739
+ it('generates correct Zod schema for getFullText', () => {
740
+ expect(zodSchemas?.getFullText).toBeDefined();
741
+
742
+ const GetFullTextSchema = zodSchemas?.getFullText;
743
+ expect(GetFullTextSchema).toBeInstanceOf(z.ZodObject);
744
+
745
+ if (!(GetFullTextSchema instanceof z.ZodObject)) {
746
+ return;
747
+ }
748
+
749
+ const shape = GetFullTextSchema.shape;
750
+ expect(shape.pdf_url).toBeInstanceOf(z.ZodString);
751
+ expect(shape.chunk).toBeInstanceOf(z.ZodOptional);
752
+ expect((shape.chunk as z.ZodOptional<z.ZodNumber>)._def.innerType).toBeInstanceOf(
753
+ z.ZodNumber,
754
+ );
755
+ });
756
+
757
+ it('generates correct Zod schema for saveCitation', () => {
758
+ expect(zodSchemas?.saveCitation).toBeDefined();
759
+
760
+ const SaveCitationSchema = zodSchemas?.saveCitation;
761
+ expect(SaveCitationSchema).toBeInstanceOf(z.ZodObject);
762
+
763
+ if (!(SaveCitationSchema instanceof z.ZodObject)) {
764
+ return;
765
+ }
766
+
767
+ const shape = SaveCitationSchema.shape;
768
+ expect(shape.doi).toBeInstanceOf(z.ZodString);
769
+ expect(shape.zotero_user_id).toBeInstanceOf(z.ZodString);
770
+ expect(shape.zotero_api_key).toBeInstanceOf(z.ZodString);
771
+ });
772
+ });
773
+ });
774
+
775
+ describe('openapiToFunction zodSchemas for SWAPI', () => {
776
+ const result = validateAndParseOpenAPISpec(swapidev);
777
+ const spec = result.spec as OpenAPIV3.Document;
778
+ const { zodSchemas } = openapiToFunction(spec, true);
779
+
780
+ describe('getPeople schema', () => {
781
+ it('does not generate Zod schema for getPeople (no parameters)', () => {
782
+ expect(zodSchemas).toBeDefined();
783
+ expect(zodSchemas?.getPeople).toBeUndefined();
784
+ });
785
+
786
+ it('validates correct data for getPeople', () => {
787
+ const GetPeopleSchema = zodSchemas?.getPeople;
788
+ expect(GetPeopleSchema).toBeUndefined();
789
+ });
790
+
791
+ it('does not throw for invalid data for getPeople', () => {
792
+ const GetPeopleSchema = zodSchemas?.getPeople;
793
+ expect(GetPeopleSchema).toBeUndefined();
794
+ });
795
+ });
796
+
797
+ describe('getPersonById schema', () => {
798
+ it('generates correct Zod schema for getPersonById', () => {
799
+ expect(zodSchemas).toBeDefined();
800
+ expect(zodSchemas?.getPersonById).toBeDefined();
801
+
802
+ const GetPersonByIdSchema = zodSchemas?.getPersonById;
803
+ expect(GetPersonByIdSchema).toBeInstanceOf(z.ZodObject);
804
+
805
+ if (!(GetPersonByIdSchema instanceof z.ZodObject)) {
806
+ return;
807
+ }
808
+
809
+ const shape = GetPersonByIdSchema.shape;
810
+ expect(shape.id).toBeInstanceOf(z.ZodString);
811
+ });
812
+
813
+ it('validates correct data for getPersonById', () => {
814
+ const GetPersonByIdSchema = zodSchemas?.getPersonById;
815
+ const validData = { id: '1' };
816
+ expect(() => GetPersonByIdSchema?.parse(validData)).not.toThrow();
817
+ });
818
+
819
+ it('throws error for invalid data for getPersonById', () => {
820
+ const GetPersonByIdSchema = zodSchemas?.getPersonById;
821
+ const invalidData = { id: 1 }; // should be string
822
+ expect(() => GetPersonByIdSchema?.parse(invalidData)).toThrow();
823
+ });
824
+ });
825
+ });
551
826
  });
@@ -348,3 +348,130 @@ components:
348
348
  message:
349
349
  type: string
350
350
  description: Confirmation of successful save or error message.`;
351
+
352
+ export const swapidev = `
353
+ openapi: 3.0.3
354
+ info:
355
+ title: Star Wars API
356
+ description: This is a simple API that provides information about the Star Wars universe.
357
+ version: 1.0.0
358
+ servers:
359
+ - url: https://swapi.dev
360
+
361
+ paths:
362
+ /api/people:
363
+ get:
364
+ summary: List all people
365
+ operationId: getPeople
366
+ tags:
367
+ - People
368
+ responses:
369
+ '200':
370
+ description: A list of people
371
+ content:
372
+ application/json:
373
+ schema:
374
+ type: object
375
+ properties:
376
+ count:
377
+ type: integer
378
+ example: 82
379
+ next:
380
+ type: string
381
+ nullable: true
382
+ example: https://swapi.dev/api/people/?page=2
383
+ previous:
384
+ type: string
385
+ nullable: true
386
+ example: null
387
+ results:
388
+ type: array
389
+ items:
390
+ $ref: '#/components/schemas/Person'
391
+
392
+ /api/people/{id}:
393
+ get:
394
+ summary: Get a person by ID
395
+ operationId: getPersonById
396
+ tags:
397
+ - People
398
+ parameters:
399
+ - name: id
400
+ in: path
401
+ required: true
402
+ description: The ID of the person to retrieve
403
+ schema:
404
+ type: string
405
+ responses:
406
+ '200':
407
+ description: A single person
408
+ content:
409
+ application/json:
410
+ schema:
411
+ $ref: '#/components/schemas/Person'
412
+ '404':
413
+ description: Person not found
414
+
415
+ components:
416
+ schemas:
417
+ Person:
418
+ type: object
419
+ properties:
420
+ name:
421
+ type: string
422
+ example: Luke Skywalker
423
+ height:
424
+ type: string
425
+ example: "172"
426
+ mass:
427
+ type: string
428
+ example: "77"
429
+ hair_color:
430
+ type: string
431
+ example: blond
432
+ skin_color:
433
+ type: string
434
+ example: fair
435
+ eye_color:
436
+ type: string
437
+ example: blue
438
+ birth_year:
439
+ type: string
440
+ example: "19BBY"
441
+ gender:
442
+ type: string
443
+ example: male
444
+ homeworld:
445
+ type: string
446
+ example: https://swapi.dev/api/planets/1/
447
+ films:
448
+ type: array
449
+ items:
450
+ type: string
451
+ example: https://swapi.dev/api/films/1/
452
+ species:
453
+ type: array
454
+ items:
455
+ type: string
456
+ example: https://swapi.dev/api/species/1/
457
+ vehicles:
458
+ type: array
459
+ items:
460
+ type: string
461
+ example: https://swapi.dev/api/vehicles/14/
462
+ starships:
463
+ type: array
464
+ items:
465
+ type: string
466
+ example: https://swapi.dev/api/starships/12/
467
+ created:
468
+ type: string
469
+ format: date-time
470
+ example: 2014-12-09T13:50:51.644000Z
471
+ edited:
472
+ type: string
473
+ format: date-time
474
+ example: 2014-12-20T21:17:56.891000Z
475
+ url:
476
+ type: string
477
+ example: https://swapi.dev/api/people/1/`;
package/src/actions.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { z } from 'zod';
1
2
  import axios from 'axios';
2
3
  import { URL } from 'url';
3
4
  import crypto from 'crypto';
@@ -12,6 +13,11 @@ export type ParametersSchema = {
12
13
  required: string[];
13
14
  };
14
15
 
16
+ export type OpenAPISchema = OpenAPIV3.SchemaObject &
17
+ ParametersSchema & {
18
+ items?: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject;
19
+ };
20
+
15
21
  export type ApiKeyCredentials = {
16
22
  api_key: string;
17
23
  custom_auth_header?: string;
@@ -38,6 +44,70 @@ export function createURL(domain: string, path: string) {
38
44
  return new URL(fullURL).toString();
39
45
  }
40
46
 
47
+ const schemaTypeHandlers: Record<string, (schema: OpenAPISchema) => z.ZodTypeAny> = {
48
+ string: (schema) => {
49
+ if (schema.enum) {
50
+ return z.enum(schema.enum as [string, ...string[]]);
51
+ }
52
+
53
+ let stringSchema = z.string();
54
+ if (schema.minLength !== undefined) {
55
+ stringSchema = stringSchema.min(schema.minLength);
56
+ }
57
+ if (schema.maxLength !== undefined) {
58
+ stringSchema = stringSchema.max(schema.maxLength);
59
+ }
60
+ return stringSchema;
61
+ },
62
+ number: (schema) => {
63
+ let numberSchema = z.number();
64
+ if (schema.minimum !== undefined) {
65
+ numberSchema = numberSchema.min(schema.minimum);
66
+ }
67
+ if (schema.maximum !== undefined) {
68
+ numberSchema = numberSchema.max(schema.maximum);
69
+ }
70
+ return numberSchema;
71
+ },
72
+ integer: (schema) => (schemaTypeHandlers.number(schema) as z.ZodNumber).int(),
73
+ boolean: () => z.boolean(),
74
+ array: (schema) => {
75
+ if (schema.items) {
76
+ const zodSchema = openAPISchemaToZod(schema.items as OpenAPISchema);
77
+ if (zodSchema) {
78
+ return z.array(zodSchema);
79
+ }
80
+
81
+ return z.array(z.unknown());
82
+ }
83
+ return z.array(z.unknown());
84
+ },
85
+ object: (schema) => {
86
+ const shape: { [key: string]: z.ZodTypeAny } = {};
87
+ if (schema.properties) {
88
+ Object.entries(schema.properties).forEach(([key, value]) => {
89
+ const zodSchema = openAPISchemaToZod(value as OpenAPISchema);
90
+ shape[key] = zodSchema || z.unknown();
91
+ if (schema.required && schema.required.includes(key)) {
92
+ shape[key] = shape[key].describe(value.description || '');
93
+ } else {
94
+ shape[key] = shape[key].optional().describe(value.description || '');
95
+ }
96
+ });
97
+ }
98
+ return z.object(shape);
99
+ },
100
+ };
101
+
102
+ function openAPISchemaToZod(schema: OpenAPISchema): z.ZodTypeAny | undefined {
103
+ if (schema.type === 'object' && Object.keys(schema.properties || {}).length === 0) {
104
+ return undefined;
105
+ }
106
+
107
+ const handler = schemaTypeHandlers[schema.type as string] || (() => z.unknown());
108
+ return handler(schema);
109
+ }
110
+
41
111
  export class FunctionSignature {
42
112
  name: string;
43
113
  description: string;
@@ -46,11 +116,7 @@ export class FunctionSignature {
46
116
  constructor(name: string, description: string, parameters: ParametersSchema) {
47
117
  this.name = name;
48
118
  this.description = description;
49
- if (parameters.properties?.['requestBody']) {
50
- this.parameters = parameters.properties?.['requestBody'] as ParametersSchema;
51
- } else {
52
- this.parameters = parameters;
53
- }
119
+ this.parameters = parameters;
54
120
  }
55
121
 
56
122
  toObjectTool(): FunctionTool {
@@ -219,14 +285,17 @@ function sanitizeOperationId(input: string) {
219
285
  }
220
286
 
221
287
  /** Function to convert OpenAPI spec to function signatures and request builders */
222
- export function openapiToFunction(openapiSpec: OpenAPIV3.Document): {
288
+ export function openapiToFunction(
289
+ openapiSpec: OpenAPIV3.Document,
290
+ generateZodSchemas = false,
291
+ ): {
223
292
  functionSignatures: FunctionSignature[];
224
293
  requestBuilders: Record<string, ActionRequest>;
294
+ zodSchemas?: Record<string, z.ZodTypeAny>;
225
295
  } {
226
296
  const functionSignatures: FunctionSignature[] = [];
227
297
  const requestBuilders: Record<string, ActionRequest> = {};
228
-
229
- // Base URL from OpenAPI spec servers
298
+ const zodSchemas: Record<string, z.ZodTypeAny> = {};
230
299
  const baseUrl = openapiSpec.servers?.[0]?.url ?? '';
231
300
 
232
301
  // Iterate over each path and method in the OpenAPI spec
@@ -241,19 +310,11 @@ export function openapiToFunction(openapiSpec: OpenAPIV3.Document): {
241
310
  const operationId = operationObj.operationId || sanitizeOperationId(defaultOperationId);
242
311
  const description = operationObj.summary || operationObj.description || '';
243
312
 
244
- const parametersSchema: ParametersSchema = { type: 'object', properties: {}, required: [] };
245
-
246
- if (operationObj.requestBody) {
247
- const requestBody = operationObj.requestBody as OpenAPIV3.RequestBodyObject;
248
- const content = requestBody.content;
249
- const contentType = Object.keys(content)[0];
250
- const schema = content[contentType]?.schema;
251
- const resolvedSchema = resolveRef(
252
- schema as OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject,
253
- openapiSpec.components,
254
- );
255
- parametersSchema.properties['requestBody'] = resolvedSchema;
256
- }
313
+ const parametersSchema: OpenAPISchema = {
314
+ type: 'object',
315
+ properties: {},
316
+ required: [],
317
+ };
257
318
 
258
319
  if (operationObj.parameters) {
259
320
  for (const param of operationObj.parameters) {
@@ -266,9 +327,24 @@ export function openapiToFunction(openapiSpec: OpenAPIV3.Document): {
266
327
  if (paramObj.required) {
267
328
  parametersSchema.required.push(paramObj.name);
268
329
  }
269
- if (paramObj.description && !('$$ref' in parametersSchema.properties[paramObj.name])) {
270
- parametersSchema.properties[paramObj.name].description = paramObj.description;
271
- }
330
+ }
331
+ }
332
+
333
+ if (operationObj.requestBody) {
334
+ const requestBody = operationObj.requestBody as OpenAPIV3.RequestBodyObject;
335
+ const content = requestBody.content;
336
+ const contentType = Object.keys(content)[0];
337
+ const schema = content[contentType]?.schema;
338
+ const resolvedSchema = resolveRef(
339
+ schema as OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject,
340
+ openapiSpec.components,
341
+ );
342
+ parametersSchema.properties = {
343
+ ...parametersSchema.properties,
344
+ ...resolvedSchema.properties,
345
+ };
346
+ if (resolvedSchema.required) {
347
+ parametersSchema.required.push(...resolvedSchema.required);
272
348
  }
273
349
  }
274
350
 
@@ -285,10 +361,17 @@ export function openapiToFunction(openapiSpec: OpenAPIV3.Document): {
285
361
  );
286
362
 
287
363
  requestBuilders[operationId] = actionRequest;
364
+
365
+ if (generateZodSchemas && Object.keys(parametersSchema.properties).length > 0) {
366
+ const schema = openAPISchemaToZod(parametersSchema);
367
+ if (schema) {
368
+ zodSchemas[operationId] = schema;
369
+ }
370
+ }
288
371
  }
289
372
  }
290
373
 
291
- return { functionSignatures, requestBuilders };
374
+ return { functionSignatures, requestBuilders, zodSchemas };
292
375
  }
293
376
 
294
377
  export type ValidationResult = {