@ai-sdk/provider-utils 4.0.4 → 4.0.6

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.
Files changed (165) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/index.js +6 -4
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +6 -4
  5. package/dist/index.mjs.map +1 -1
  6. package/package.json +4 -2
  7. package/src/__snapshots__/schema.test.ts.snap +346 -0
  8. package/src/add-additional-properties-to-json-schema.test.ts +289 -0
  9. package/src/add-additional-properties-to-json-schema.ts +53 -0
  10. package/src/combine-headers.ts +11 -0
  11. package/src/convert-async-iterator-to-readable-stream.test.ts +78 -0
  12. package/src/convert-async-iterator-to-readable-stream.ts +47 -0
  13. package/src/convert-image-model-file-to-data-uri.test.ts +85 -0
  14. package/src/convert-image-model-file-to-data-uri.ts +19 -0
  15. package/src/convert-to-form-data.test.ts +167 -0
  16. package/src/convert-to-form-data.ts +61 -0
  17. package/src/create-tool-name-mapping.test.ts +163 -0
  18. package/src/create-tool-name-mapping.ts +66 -0
  19. package/src/delay.test.ts +212 -0
  20. package/src/delay.ts +47 -0
  21. package/src/delayed-promise.test.ts +132 -0
  22. package/src/delayed-promise.ts +61 -0
  23. package/src/download-blob.test.ts +145 -0
  24. package/src/download-blob.ts +31 -0
  25. package/src/download-error.ts +39 -0
  26. package/src/extract-response-headers.ts +9 -0
  27. package/src/fetch-function.ts +4 -0
  28. package/src/generate-id.test.ts +31 -0
  29. package/src/generate-id.ts +57 -0
  30. package/src/get-error-message.ts +15 -0
  31. package/src/get-from-api.test.ts +199 -0
  32. package/src/get-from-api.ts +97 -0
  33. package/src/get-runtime-environment-user-agent.test.ts +47 -0
  34. package/src/get-runtime-environment-user-agent.ts +24 -0
  35. package/src/handle-fetch-error.ts +39 -0
  36. package/src/index.ts +67 -0
  37. package/src/inject-json-instruction.test.ts +404 -0
  38. package/src/inject-json-instruction.ts +63 -0
  39. package/src/is-abort-error.ts +8 -0
  40. package/src/is-async-iterable.ts +3 -0
  41. package/src/is-non-nullable.ts +12 -0
  42. package/src/is-url-supported.test.ts +282 -0
  43. package/src/is-url-supported.ts +40 -0
  44. package/src/load-api-key.ts +45 -0
  45. package/src/load-optional-setting.ts +30 -0
  46. package/src/load-setting.ts +62 -0
  47. package/src/maybe-promise-like.ts +3 -0
  48. package/src/media-type-to-extension.test.ts +26 -0
  49. package/src/media-type-to-extension.ts +22 -0
  50. package/src/normalize-headers.test.ts +64 -0
  51. package/src/normalize-headers.ts +38 -0
  52. package/src/parse-json-event-stream.ts +33 -0
  53. package/src/parse-json.test.ts +191 -0
  54. package/src/parse-json.ts +122 -0
  55. package/src/parse-provider-options.ts +32 -0
  56. package/src/post-to-api.ts +166 -0
  57. package/src/provider-tool-factory.ts +125 -0
  58. package/src/remove-undefined-entries.test.ts +57 -0
  59. package/src/remove-undefined-entries.ts +12 -0
  60. package/src/resolve.test.ts +125 -0
  61. package/src/resolve.ts +17 -0
  62. package/src/response-handler.test.ts +89 -0
  63. package/src/response-handler.ts +187 -0
  64. package/src/schema.test-d.ts +11 -0
  65. package/src/schema.test.ts +502 -0
  66. package/src/schema.ts +267 -0
  67. package/src/secure-json-parse.test.ts +59 -0
  68. package/src/secure-json-parse.ts +92 -0
  69. package/src/test/convert-array-to-async-iterable.ts +9 -0
  70. package/src/test/convert-array-to-readable-stream.ts +15 -0
  71. package/src/test/convert-async-iterable-to-array.ts +9 -0
  72. package/src/test/convert-readable-stream-to-array.ts +14 -0
  73. package/src/test/convert-response-stream-to-array.ts +9 -0
  74. package/src/test/index.ts +7 -0
  75. package/src/test/is-node-version.ts +4 -0
  76. package/src/test/mock-id.ts +8 -0
  77. package/src/to-json-schema/zod3-to-json-schema/LICENSE +16 -0
  78. package/src/to-json-schema/zod3-to-json-schema/README.md +24 -0
  79. package/src/to-json-schema/zod3-to-json-schema/get-relative-path.ts +7 -0
  80. package/src/to-json-schema/zod3-to-json-schema/index.ts +1 -0
  81. package/src/to-json-schema/zod3-to-json-schema/options.ts +98 -0
  82. package/src/to-json-schema/zod3-to-json-schema/parse-def.test.ts +224 -0
  83. package/src/to-json-schema/zod3-to-json-schema/parse-def.ts +109 -0
  84. package/src/to-json-schema/zod3-to-json-schema/parse-types.ts +57 -0
  85. package/src/to-json-schema/zod3-to-json-schema/parsers/any.ts +5 -0
  86. package/src/to-json-schema/zod3-to-json-schema/parsers/array.test.ts +98 -0
  87. package/src/to-json-schema/zod3-to-json-schema/parsers/array.ts +38 -0
  88. package/src/to-json-schema/zod3-to-json-schema/parsers/bigint.test.ts +51 -0
  89. package/src/to-json-schema/zod3-to-json-schema/parsers/bigint.ts +44 -0
  90. package/src/to-json-schema/zod3-to-json-schema/parsers/boolean.ts +7 -0
  91. package/src/to-json-schema/zod3-to-json-schema/parsers/branded.test.ts +16 -0
  92. package/src/to-json-schema/zod3-to-json-schema/parsers/branded.ts +7 -0
  93. package/src/to-json-schema/zod3-to-json-schema/parsers/catch.test.ts +15 -0
  94. package/src/to-json-schema/zod3-to-json-schema/parsers/catch.ts +7 -0
  95. package/src/to-json-schema/zod3-to-json-schema/parsers/date.test.ts +97 -0
  96. package/src/to-json-schema/zod3-to-json-schema/parsers/date.ts +64 -0
  97. package/src/to-json-schema/zod3-to-json-schema/parsers/default.test.ts +54 -0
  98. package/src/to-json-schema/zod3-to-json-schema/parsers/default.ts +14 -0
  99. package/src/to-json-schema/zod3-to-json-schema/parsers/effects.test.ts +41 -0
  100. package/src/to-json-schema/zod3-to-json-schema/parsers/effects.ts +14 -0
  101. package/src/to-json-schema/zod3-to-json-schema/parsers/enum.ts +13 -0
  102. package/src/to-json-schema/zod3-to-json-schema/parsers/intersection.test.ts +92 -0
  103. package/src/to-json-schema/zod3-to-json-schema/parsers/intersection.ts +52 -0
  104. package/src/to-json-schema/zod3-to-json-schema/parsers/literal.ts +29 -0
  105. package/src/to-json-schema/zod3-to-json-schema/parsers/map.test.ts +48 -0
  106. package/src/to-json-schema/zod3-to-json-schema/parsers/map.ts +47 -0
  107. package/src/to-json-schema/zod3-to-json-schema/parsers/native-enum.test.ts +102 -0
  108. package/src/to-json-schema/zod3-to-json-schema/parsers/native-enum.ts +31 -0
  109. package/src/to-json-schema/zod3-to-json-schema/parsers/never.ts +9 -0
  110. package/src/to-json-schema/zod3-to-json-schema/parsers/null.ts +9 -0
  111. package/src/to-json-schema/zod3-to-json-schema/parsers/nullable.test.ts +67 -0
  112. package/src/to-json-schema/zod3-to-json-schema/parsers/nullable.ts +42 -0
  113. package/src/to-json-schema/zod3-to-json-schema/parsers/number.test.ts +65 -0
  114. package/src/to-json-schema/zod3-to-json-schema/parsers/number.ts +44 -0
  115. package/src/to-json-schema/zod3-to-json-schema/parsers/object.test.ts +149 -0
  116. package/src/to-json-schema/zod3-to-json-schema/parsers/object.ts +88 -0
  117. package/src/to-json-schema/zod3-to-json-schema/parsers/optional.test.ts +147 -0
  118. package/src/to-json-schema/zod3-to-json-schema/parsers/optional.ts +23 -0
  119. package/src/to-json-schema/zod3-to-json-schema/parsers/pipe.test.ts +35 -0
  120. package/src/to-json-schema/zod3-to-json-schema/parsers/pipeline.ts +29 -0
  121. package/src/to-json-schema/zod3-to-json-schema/parsers/promise.test.ts +15 -0
  122. package/src/to-json-schema/zod3-to-json-schema/parsers/promise.ts +11 -0
  123. package/src/to-json-schema/zod3-to-json-schema/parsers/readonly.test.ts +20 -0
  124. package/src/to-json-schema/zod3-to-json-schema/parsers/readonly.ts +7 -0
  125. package/src/to-json-schema/zod3-to-json-schema/parsers/record.test.ts +108 -0
  126. package/src/to-json-schema/zod3-to-json-schema/parsers/record.ts +71 -0
  127. package/src/to-json-schema/zod3-to-json-schema/parsers/set.test.ts +20 -0
  128. package/src/to-json-schema/zod3-to-json-schema/parsers/set.ts +35 -0
  129. package/src/to-json-schema/zod3-to-json-schema/parsers/string.test.ts +438 -0
  130. package/src/to-json-schema/zod3-to-json-schema/parsers/string.ts +426 -0
  131. package/src/to-json-schema/zod3-to-json-schema/parsers/tuple.test.ts +33 -0
  132. package/src/to-json-schema/zod3-to-json-schema/parsers/tuple.ts +61 -0
  133. package/src/to-json-schema/zod3-to-json-schema/parsers/undefined.ts +11 -0
  134. package/src/to-json-schema/zod3-to-json-schema/parsers/union.test.ts +226 -0
  135. package/src/to-json-schema/zod3-to-json-schema/parsers/union.ts +144 -0
  136. package/src/to-json-schema/zod3-to-json-schema/parsers/unknown.ts +7 -0
  137. package/src/to-json-schema/zod3-to-json-schema/refs.test.ts +919 -0
  138. package/src/to-json-schema/zod3-to-json-schema/refs.ts +39 -0
  139. package/src/to-json-schema/zod3-to-json-schema/select-parser.ts +115 -0
  140. package/src/to-json-schema/zod3-to-json-schema/zod3-to-json-schema.test.ts +862 -0
  141. package/src/to-json-schema/zod3-to-json-schema/zod3-to-json-schema.ts +93 -0
  142. package/src/types/assistant-model-message.ts +39 -0
  143. package/src/types/content-part.ts +379 -0
  144. package/src/types/data-content.ts +4 -0
  145. package/src/types/execute-tool.ts +27 -0
  146. package/src/types/index.ts +40 -0
  147. package/src/types/model-message.ts +14 -0
  148. package/src/types/provider-options.ts +9 -0
  149. package/src/types/system-model-message.ts +20 -0
  150. package/src/types/tool-approval-request.ts +16 -0
  151. package/src/types/tool-approval-response.ts +27 -0
  152. package/src/types/tool-call.ts +31 -0
  153. package/src/types/tool-model-message.ts +23 -0
  154. package/src/types/tool-result.ts +35 -0
  155. package/src/types/tool.test-d.ts +193 -0
  156. package/src/types/tool.ts +324 -0
  157. package/src/types/user-model-message.ts +22 -0
  158. package/src/uint8-utils.ts +26 -0
  159. package/src/validate-types.test.ts +105 -0
  160. package/src/validate-types.ts +81 -0
  161. package/src/version.ts +6 -0
  162. package/src/with-user-agent-suffix.test.ts +84 -0
  163. package/src/with-user-agent-suffix.ts +27 -0
  164. package/src/without-trailing-slash.ts +3 -0
  165. package/LICENSE +0 -13
@@ -0,0 +1,97 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { z } from 'zod/v3';
3
+ import { parseDateDef } from './date';
4
+ import { getRefs } from '../refs';
5
+ import { JSONSchema7 } from '@ai-sdk/provider';
6
+
7
+ describe('Date validations', it => {
8
+ it('should be possible to date as a string type', () => {
9
+ const zodDateSchema = z.date();
10
+ const parsedSchemaWithOption = parseDateDef(
11
+ zodDateSchema._def,
12
+ getRefs({ dateStrategy: 'string' }),
13
+ );
14
+ const parsedSchemaFromDefault = parseDateDef(zodDateSchema._def, getRefs());
15
+
16
+ const jsonSchema: JSONSchema7 = {
17
+ type: 'string',
18
+ format: 'date-time',
19
+ };
20
+
21
+ expect(parsedSchemaWithOption).toStrictEqual(jsonSchema);
22
+ expect(parsedSchemaFromDefault).toStrictEqual(jsonSchema);
23
+ });
24
+
25
+ it('should be possible to describe minimum date', () => {
26
+ const zodDateSchema = z
27
+ .date()
28
+ .min(new Date('1970-01-02'), { message: 'Too old' });
29
+ const parsedSchema = parseDateDef(
30
+ zodDateSchema._def,
31
+ getRefs({ dateStrategy: 'integer' }),
32
+ );
33
+
34
+ expect(parsedSchema).toStrictEqual({
35
+ type: 'integer',
36
+ format: 'unix-time',
37
+ minimum: 86400000,
38
+ } satisfies JSONSchema7);
39
+ });
40
+
41
+ it('should be possible to describe maximum date', () => {
42
+ const zodDateSchema = z.date().max(new Date('1970-01-02'));
43
+ const parsedSchema = parseDateDef(
44
+ zodDateSchema._def,
45
+ getRefs({ dateStrategy: 'integer' }),
46
+ );
47
+
48
+ expect(parsedSchema).toStrictEqual({
49
+ type: 'integer',
50
+ format: 'unix-time',
51
+ maximum: 86400000,
52
+ } satisfies JSONSchema7);
53
+ });
54
+
55
+ it('should be possible to describe both maximum and minimum date', () => {
56
+ const zodDateSchema = z
57
+ .date()
58
+ .min(new Date('1970-01-02'))
59
+ .max(new Date('1972-01-02'));
60
+ const parsedSchema = parseDateDef(
61
+ zodDateSchema._def,
62
+ getRefs({ dateStrategy: 'integer' }),
63
+ );
64
+
65
+ expect(parsedSchema).toStrictEqual({
66
+ type: 'integer',
67
+ format: 'unix-time',
68
+ minimum: 86400000,
69
+ maximum: 63158400000,
70
+ } satisfies JSONSchema7);
71
+ });
72
+
73
+ it('multiple choices of strategy should result in anyOf', () => {
74
+ const zodDateSchema = z.date();
75
+ const parsedSchema = parseDateDef(
76
+ zodDateSchema._def,
77
+ getRefs({ dateStrategy: ['format:date-time', 'format:date', 'integer'] }),
78
+ );
79
+
80
+ expect(parsedSchema).toStrictEqual({
81
+ anyOf: [
82
+ {
83
+ type: 'string',
84
+ format: 'date-time',
85
+ },
86
+ {
87
+ type: 'string',
88
+ format: 'date',
89
+ },
90
+ {
91
+ type: 'integer',
92
+ format: 'unix-time',
93
+ },
94
+ ],
95
+ } satisfies JSONSchema7);
96
+ });
97
+ });
@@ -0,0 +1,64 @@
1
+ import { ZodDateDef } from 'zod/v3';
2
+ import { Refs } from '../refs';
3
+ import { DateStrategy } from '../options';
4
+
5
+ export type JsonSchema7DateType =
6
+ | {
7
+ type: 'integer' | 'string';
8
+ format: 'unix-time' | 'date-time' | 'date';
9
+ minimum?: number;
10
+ maximum?: number;
11
+ }
12
+ | {
13
+ anyOf: JsonSchema7DateType[];
14
+ };
15
+
16
+ export function parseDateDef(
17
+ def: ZodDateDef,
18
+ refs: Refs,
19
+ overrideDateStrategy?: DateStrategy,
20
+ ): JsonSchema7DateType {
21
+ const strategy = overrideDateStrategy ?? refs.dateStrategy;
22
+
23
+ if (Array.isArray(strategy)) {
24
+ return {
25
+ anyOf: strategy.map((item, i) => parseDateDef(def, refs, item)),
26
+ };
27
+ }
28
+
29
+ switch (strategy) {
30
+ case 'string':
31
+ case 'format:date-time':
32
+ return {
33
+ type: 'string',
34
+ format: 'date-time',
35
+ };
36
+ case 'format:date':
37
+ return {
38
+ type: 'string',
39
+ format: 'date',
40
+ };
41
+ case 'integer':
42
+ return integerDateParser(def);
43
+ }
44
+ }
45
+
46
+ const integerDateParser = (def: ZodDateDef) => {
47
+ const res: JsonSchema7DateType = {
48
+ type: 'integer',
49
+ format: 'unix-time',
50
+ };
51
+
52
+ for (const check of def.checks) {
53
+ switch (check.kind) {
54
+ case 'min':
55
+ res.minimum = check.value;
56
+ break;
57
+ case 'max':
58
+ res.maximum = check.value;
59
+ break;
60
+ }
61
+ }
62
+
63
+ return res;
64
+ };
@@ -0,0 +1,54 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { z } from 'zod/v3';
3
+ import { parseDefaultDef } from './default';
4
+ import { getRefs } from '../refs';
5
+ import { JSONSchema7 } from '@ai-sdk/provider';
6
+
7
+ describe('default', () => {
8
+ it('should be possible to use default on objects', () => {
9
+ const parsedSchema = parseDefaultDef(
10
+ z.object({ foo: z.boolean() }).default({ foo: true })._def,
11
+ getRefs(),
12
+ );
13
+
14
+ expect(parsedSchema).toStrictEqual({
15
+ type: 'object',
16
+ additionalProperties: false,
17
+ required: ['foo'],
18
+ properties: {
19
+ foo: {
20
+ type: 'boolean',
21
+ },
22
+ },
23
+ default: {
24
+ foo: true,
25
+ },
26
+ } satisfies JSONSchema7);
27
+ });
28
+
29
+ it('should be possible to use default on primitives', () => {
30
+ const parsedSchema = parseDefaultDef(
31
+ z.string().default('default')._def,
32
+ getRefs(),
33
+ );
34
+
35
+ expect(parsedSchema).toStrictEqual({
36
+ type: 'string',
37
+ default: 'default',
38
+ } satisfies JSONSchema7);
39
+ });
40
+
41
+ it('default with transform', () => {
42
+ const stringWithDefault = z
43
+ .string()
44
+ .transform(val => val.toUpperCase())
45
+ .default('default');
46
+
47
+ const parsedSchema = parseDefaultDef(stringWithDefault._def, getRefs());
48
+
49
+ expect(parsedSchema).toStrictEqual({
50
+ type: 'string',
51
+ default: 'default',
52
+ } satisfies JSONSchema7);
53
+ });
54
+ });
@@ -0,0 +1,14 @@
1
+ import { ZodDefaultDef } from 'zod/v3';
2
+ import { parseDef } from '../parse-def';
3
+ import { JsonSchema7Type } from '../parse-types';
4
+ import { Refs } from '../refs';
5
+
6
+ export function parseDefaultDef(
7
+ _def: ZodDefaultDef,
8
+ refs: Refs,
9
+ ): JsonSchema7Type & { default: any } {
10
+ return {
11
+ ...parseDef(_def.innerType._def, refs),
12
+ default: _def.defaultValue(),
13
+ };
14
+ }
@@ -0,0 +1,41 @@
1
+ import { describe, it, expect, test } from 'vitest';
2
+ import { z } from 'zod/v3';
3
+ import { parseEffectsDef } from './effects';
4
+ import { getRefs } from '../refs';
5
+ import { JSONSchema7 } from '@ai-sdk/provider';
6
+
7
+ describe('effects', () => {
8
+ it('should be possible to use refine', () => {
9
+ const parsedSchema = parseEffectsDef(
10
+ z.number().refine(x => x + 1)._def,
11
+ getRefs(),
12
+ );
13
+
14
+ expect(parsedSchema).toStrictEqual({
15
+ type: 'number',
16
+ } satisfies JSONSchema7);
17
+ });
18
+
19
+ it('should default to the input type', () => {
20
+ const schema = z.string().transform(arg => parseInt(arg));
21
+
22
+ const jsonSchema = parseEffectsDef(schema._def, getRefs());
23
+
24
+ expect(jsonSchema).toStrictEqual({
25
+ type: 'string',
26
+ } satisfies JSONSchema7);
27
+ });
28
+
29
+ test("should return object based on 'any' strategy", () => {
30
+ const schema = z.string().transform(arg => parseInt(arg));
31
+
32
+ const jsonSchema = parseEffectsDef(
33
+ schema._def,
34
+ getRefs({
35
+ effectStrategy: 'any',
36
+ }),
37
+ );
38
+
39
+ expect(jsonSchema).toStrictEqual({} satisfies JSONSchema7);
40
+ });
41
+ });
@@ -0,0 +1,14 @@
1
+ import { ZodEffectsDef } from 'zod/v3';
2
+ import { parseDef } from '../parse-def';
3
+ import { JsonSchema7Type } from '../parse-types';
4
+ import { Refs } from '../refs';
5
+ import { parseAnyDef } from './any';
6
+
7
+ export function parseEffectsDef(
8
+ _def: ZodEffectsDef,
9
+ refs: Refs,
10
+ ): JsonSchema7Type | undefined {
11
+ return refs.effectStrategy === 'input'
12
+ ? parseDef(_def.schema._def, refs)
13
+ : parseAnyDef();
14
+ }
@@ -0,0 +1,13 @@
1
+ import { ZodEnumDef } from 'zod/v3';
2
+
3
+ export type JsonSchema7EnumType = {
4
+ type: 'string';
5
+ enum: string[];
6
+ };
7
+
8
+ export function parseEnumDef(def: ZodEnumDef): JsonSchema7EnumType {
9
+ return {
10
+ type: 'string',
11
+ enum: Array.from(def.values),
12
+ };
13
+ }
@@ -0,0 +1,92 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { z } from 'zod/v3';
3
+ import { parseIntersectionDef } from './intersection';
4
+ import { getRefs } from '../refs';
5
+ import { JSONSchema7 } from '@ai-sdk/provider';
6
+
7
+ describe('intersection', () => {
8
+ it('should be possible to use intersections', () => {
9
+ const intersection = z.intersection(z.string().min(1), z.string().max(3));
10
+
11
+ const jsonSchema = parseIntersectionDef(intersection._def, getRefs());
12
+
13
+ expect(jsonSchema).toStrictEqual({
14
+ allOf: [
15
+ {
16
+ type: 'string',
17
+ minLength: 1,
18
+ },
19
+ {
20
+ type: 'string',
21
+ maxLength: 3,
22
+ },
23
+ ],
24
+ } satisfies JSONSchema7);
25
+ });
26
+
27
+ it('should be possible to deref intersections', () => {
28
+ const schema = z.string();
29
+ const intersection = z.intersection(schema, schema);
30
+ const jsonSchema = parseIntersectionDef(intersection._def, getRefs());
31
+
32
+ expect(jsonSchema).toStrictEqual({
33
+ allOf: [
34
+ {
35
+ type: 'string',
36
+ },
37
+ {
38
+ $ref: '#/allOf/0',
39
+ },
40
+ ],
41
+ } satisfies JSONSchema7);
42
+ });
43
+
44
+ it('should return `unevaluatedProperties` only if all of the multiple sub-schemas have additionalProperties set to false', () => {
45
+ const schema1 = z.object({
46
+ foo: z.string(),
47
+ });
48
+ const schema2 = z.object({
49
+ bar: z.string(),
50
+ });
51
+ const schema3 = z
52
+ .object({
53
+ baz: z.string(),
54
+ })
55
+ .passthrough();
56
+ const intersection = schema1.and(schema2).and(schema3);
57
+ const jsonSchema = parseIntersectionDef(intersection._def, getRefs());
58
+
59
+ expect(jsonSchema).toStrictEqual({
60
+ allOf: [
61
+ {
62
+ properties: {
63
+ foo: {
64
+ type: 'string',
65
+ },
66
+ },
67
+ required: ['foo'],
68
+ type: 'object',
69
+ },
70
+ {
71
+ properties: {
72
+ bar: {
73
+ type: 'string',
74
+ },
75
+ },
76
+ required: ['bar'],
77
+ type: 'object',
78
+ },
79
+ {
80
+ additionalProperties: true,
81
+ properties: {
82
+ baz: {
83
+ type: 'string',
84
+ },
85
+ },
86
+ required: ['baz'],
87
+ type: 'object',
88
+ },
89
+ ],
90
+ } satisfies JSONSchema7);
91
+ });
92
+ });
@@ -0,0 +1,52 @@
1
+ import { ZodIntersectionDef } from 'zod/v3';
2
+ import { parseDef } from '../parse-def';
3
+ import { JsonSchema7Type } from '../parse-types';
4
+ import { Refs } from '../refs';
5
+ import { JsonSchema7StringType } from './string';
6
+
7
+ export type JsonSchema7AllOfType = {
8
+ allOf: JsonSchema7Type[];
9
+ unevaluatedProperties?: boolean;
10
+ };
11
+
12
+ const isJsonSchema7AllOfType = (
13
+ type: JsonSchema7Type | JsonSchema7StringType,
14
+ ): type is JsonSchema7AllOfType => {
15
+ if ('type' in type && type.type === 'string') return false;
16
+ return 'allOf' in type;
17
+ };
18
+
19
+ export function parseIntersectionDef(
20
+ def: ZodIntersectionDef,
21
+ refs: Refs,
22
+ ): JsonSchema7AllOfType | JsonSchema7Type | undefined {
23
+ const allOf = [
24
+ parseDef(def.left._def, {
25
+ ...refs,
26
+ currentPath: [...refs.currentPath, 'allOf', '0'],
27
+ }),
28
+ parseDef(def.right._def, {
29
+ ...refs,
30
+ currentPath: [...refs.currentPath, 'allOf', '1'],
31
+ }),
32
+ ].filter((x): x is JsonSchema7Type => !!x);
33
+
34
+ const mergedAllOf: JsonSchema7Type[] = [];
35
+ // If either of the schemas is an allOf, merge them into a single allOf
36
+ allOf.forEach(schema => {
37
+ if (isJsonSchema7AllOfType(schema)) {
38
+ mergedAllOf.push(...schema.allOf);
39
+ } else {
40
+ let nestedSchema: JsonSchema7Type = schema;
41
+ if (
42
+ 'additionalProperties' in schema &&
43
+ schema.additionalProperties === false
44
+ ) {
45
+ const { additionalProperties, ...rest } = schema;
46
+ nestedSchema = rest;
47
+ }
48
+ mergedAllOf.push(nestedSchema);
49
+ }
50
+ });
51
+ return mergedAllOf.length ? { allOf: mergedAllOf } : undefined;
52
+ }
@@ -0,0 +1,29 @@
1
+ import { ZodLiteralDef } from 'zod/v3';
2
+
3
+ export type JsonSchema7LiteralType =
4
+ | {
5
+ type: 'string' | 'number' | 'integer' | 'boolean';
6
+ const: string | number | boolean;
7
+ }
8
+ | {
9
+ type: 'object' | 'array';
10
+ };
11
+
12
+ export function parseLiteralDef(def: ZodLiteralDef): JsonSchema7LiteralType {
13
+ const parsedType = typeof def.value;
14
+ if (
15
+ parsedType !== 'bigint' &&
16
+ parsedType !== 'number' &&
17
+ parsedType !== 'boolean' &&
18
+ parsedType !== 'string'
19
+ ) {
20
+ return {
21
+ type: Array.isArray(def.value) ? 'array' : 'object',
22
+ };
23
+ }
24
+
25
+ return {
26
+ type: parsedType === 'bigint' ? 'integer' : parsedType,
27
+ const: def.value,
28
+ };
29
+ }
@@ -0,0 +1,48 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { z } from 'zod/v3';
3
+ import { parseMapDef } from './map';
4
+ import { getRefs } from '../refs';
5
+ import { JSONSchema7 } from '@ai-sdk/provider';
6
+
7
+ describe('map', () => {
8
+ it('should be possible to use Map', () => {
9
+ const mapSchema = z.map(z.string(), z.number());
10
+
11
+ const parsedSchema = parseMapDef(mapSchema._def, getRefs());
12
+
13
+ expect(parsedSchema).toStrictEqual({
14
+ type: 'array',
15
+ maxItems: 125,
16
+ items: {
17
+ type: 'array',
18
+ items: [
19
+ {
20
+ type: 'string',
21
+ },
22
+ {
23
+ type: 'number',
24
+ },
25
+ ],
26
+ minItems: 2,
27
+ maxItems: 2,
28
+ },
29
+ } satisfies JSONSchema7);
30
+ });
31
+
32
+ it('should be possible to use additionalProperties-pattern (record)', () => {
33
+ expect(
34
+ parseMapDef(
35
+ z.map(z.string().min(1), z.number())._def,
36
+ getRefs({ mapStrategy: 'record' }),
37
+ ),
38
+ ).toStrictEqual({
39
+ type: 'object',
40
+ additionalProperties: {
41
+ type: 'number',
42
+ },
43
+ propertyNames: {
44
+ minLength: 1,
45
+ },
46
+ } satisfies JSONSchema7);
47
+ });
48
+ });
@@ -0,0 +1,47 @@
1
+ import { ZodMapDef } from 'zod/v3';
2
+ import { parseDef } from '../parse-def';
3
+ import { JsonSchema7Type } from '../parse-types';
4
+ import { Refs } from '../refs';
5
+ import { parseAnyDef } from './any';
6
+ import { JsonSchema7RecordType, parseRecordDef } from './record';
7
+
8
+ export type JsonSchema7MapType = {
9
+ type: 'array';
10
+ maxItems: 125;
11
+ items: {
12
+ type: 'array';
13
+ items: [JsonSchema7Type, JsonSchema7Type];
14
+ minItems: 2;
15
+ maxItems: 2;
16
+ };
17
+ };
18
+
19
+ export function parseMapDef(
20
+ def: ZodMapDef,
21
+ refs: Refs,
22
+ ): JsonSchema7MapType | JsonSchema7RecordType {
23
+ if (refs.mapStrategy === 'record') {
24
+ return parseRecordDef(def, refs);
25
+ }
26
+
27
+ const keys =
28
+ parseDef(def.keyType._def, {
29
+ ...refs,
30
+ currentPath: [...refs.currentPath, 'items', 'items', '0'],
31
+ }) || parseAnyDef();
32
+ const values =
33
+ parseDef(def.valueType._def, {
34
+ ...refs,
35
+ currentPath: [...refs.currentPath, 'items', 'items', '1'],
36
+ }) || parseAnyDef();
37
+ return {
38
+ type: 'array',
39
+ maxItems: 125,
40
+ items: {
41
+ type: 'array',
42
+ items: [keys, values],
43
+ minItems: 2,
44
+ maxItems: 2,
45
+ },
46
+ };
47
+ }
@@ -0,0 +1,102 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { z } from 'zod/v3';
3
+ import { parseNativeEnumDef } from './native-enum';
4
+ import { JSONSchema7 } from '@ai-sdk/provider';
5
+
6
+ describe('native enum', () => {
7
+ it('should be possible to convert a basic native number enum', () => {
8
+ enum MyEnum {
9
+ val1,
10
+ val2,
11
+ val3,
12
+ }
13
+
14
+ const parsedSchema = parseNativeEnumDef(z.nativeEnum(MyEnum)._def);
15
+
16
+ expect(parsedSchema).toStrictEqual({
17
+ type: 'number',
18
+ enum: [0, 1, 2],
19
+ } satisfies JSONSchema7);
20
+ });
21
+
22
+ it('should be possible to convert a native string enum', () => {
23
+ enum MyEnum {
24
+ val1 = 'a',
25
+ val2 = 'b',
26
+ val3 = 'c',
27
+ }
28
+
29
+ const parsedSchema = parseNativeEnumDef(z.nativeEnum(MyEnum)._def);
30
+
31
+ expect(parsedSchema).toStrictEqual({
32
+ type: 'string',
33
+ enum: ['a', 'b', 'c'],
34
+ } satisfies JSONSchema7);
35
+ });
36
+
37
+ it('should be possible to convert a mixed value native enum', () => {
38
+ enum MyEnum {
39
+ val1 = 'a',
40
+ val2 = 1,
41
+ val3 = 'c',
42
+ }
43
+
44
+ const parsedSchema = parseNativeEnumDef(z.nativeEnum(MyEnum)._def);
45
+
46
+ expect(parsedSchema).toStrictEqual({
47
+ type: ['string', 'number'],
48
+ enum: ['a', 1, 'c'],
49
+ } satisfies JSONSchema7);
50
+ });
51
+
52
+ it('should be possible to convert a native const assertion object', () => {
53
+ const MyConstAssertionObject = {
54
+ val1: 0,
55
+ val2: 1,
56
+ val3: 2,
57
+ } as const;
58
+
59
+ const parsedSchema = parseNativeEnumDef(
60
+ z.nativeEnum(MyConstAssertionObject)._def,
61
+ );
62
+
63
+ expect(parsedSchema).toStrictEqual({
64
+ type: 'number',
65
+ enum: [0, 1, 2],
66
+ } satisfies JSONSchema7);
67
+ });
68
+
69
+ it('should be possible to convert a native const assertion string object', () => {
70
+ const MyConstAssertionObject = {
71
+ val1: 'a',
72
+ val2: 'b',
73
+ val3: 'c',
74
+ } as const;
75
+
76
+ const parsedSchema = parseNativeEnumDef(
77
+ z.nativeEnum(MyConstAssertionObject)._def,
78
+ );
79
+
80
+ expect(parsedSchema).toStrictEqual({
81
+ type: 'string',
82
+ enum: ['a', 'b', 'c'],
83
+ } satisfies JSONSchema7);
84
+ });
85
+
86
+ it('should be possible to convert a mixed value native const assertion string object', () => {
87
+ const MyConstAssertionObject = {
88
+ val1: 'a',
89
+ val2: 1,
90
+ val3: 'c',
91
+ } as const;
92
+
93
+ const parsedSchema = parseNativeEnumDef(
94
+ z.nativeEnum(MyConstAssertionObject)._def,
95
+ );
96
+
97
+ expect(parsedSchema).toStrictEqual({
98
+ type: ['string', 'number'],
99
+ enum: ['a', 1, 'c'],
100
+ } satisfies JSONSchema7);
101
+ });
102
+ });