@mastra/schema-compat 0.0.0-taofeeq-fix-tool-call-showing-after-message-20250806184630 → 0.0.0-vector-query-tool-provider-options-20250828222356
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +62 -1
- package/README.md +0 -4
- package/dist/chunk-MKYBUMTK.js +27 -0
- package/dist/chunk-MKYBUMTK.js.map +1 -0
- package/dist/chunk-V7Y3FXBJ.cjs +33 -0
- package/dist/chunk-V7Y3FXBJ.cjs.map +1 -0
- package/dist/index.cjs +842 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +10 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +841 -84
- package/dist/index.js.map +1 -1
- package/dist/provider-compats/anthropic.d.ts +7 -5
- package/dist/provider-compats/anthropic.d.ts.map +1 -1
- package/dist/provider-compats/deepseek.d.ts +7 -5
- package/dist/provider-compats/deepseek.d.ts.map +1 -1
- package/dist/provider-compats/google.d.ts +7 -5
- package/dist/provider-compats/google.d.ts.map +1 -1
- package/dist/provider-compats/meta.d.ts +7 -5
- package/dist/provider-compats/meta.d.ts.map +1 -1
- package/dist/provider-compats/openai-reasoning.d.ts +7 -5
- package/dist/provider-compats/openai-reasoning.d.ts.map +1 -1
- package/dist/provider-compats/openai.d.ts +7 -5
- package/dist/provider-compats/openai.d.ts.map +1 -1
- package/dist/schema-compatibility-v3.d.ts +319 -0
- package/dist/schema-compatibility-v3.d.ts.map +1 -0
- package/dist/schema-compatibility-v4.d.ts +310 -0
- package/dist/schema-compatibility-v4.d.ts.map +1 -0
- package/dist/schema-compatibility.d.ts +79 -131
- package/dist/schema-compatibility.d.ts.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils-test-suite.d.ts +2 -0
- package/dist/utils-test-suite.d.ts.map +1 -0
- package/dist/utils.d.ts +17 -5
- package/dist/utils.d.ts.map +1 -1
- package/dist/zod-to-json.cjs +12 -0
- package/dist/zod-to-json.cjs.map +1 -0
- package/dist/zod-to-json.d.ts +6 -0
- package/dist/zod-to-json.d.ts.map +1 -0
- package/dist/zod-to-json.js +3 -0
- package/dist/zod-to-json.js.map +1 -0
- package/dist/zodTypes.d.ts +21 -0
- package/dist/zodTypes.d.ts.map +1 -0
- package/package.json +16 -6
- package/src/index.ts +4 -3
- package/src/provider-compats/anthropic.ts +30 -13
- package/src/provider-compats/deepseek.ts +15 -10
- package/src/provider-compats/google.ts +19 -33
- package/src/provider-compats/meta.ts +16 -11
- package/src/provider-compats/openai-reasoning.ts +19 -25
- package/src/provider-compats/openai.ts +23 -14
- package/src/provider-compats.test.ts +120 -25
- package/src/schema-compatibility-v3.ts +664 -0
- package/src/schema-compatibility-v4.test.ts +476 -0
- package/src/schema-compatibility-v4.ts +706 -0
- package/src/schema-compatibility.test.ts +9 -9
- package/src/schema-compatibility.ts +266 -383
- package/src/types.ts +5 -0
- package/src/utils-test-suite.ts +467 -0
- package/src/utils-v3.test.ts +9 -0
- package/src/utils-v4.test.ts +9 -0
- package/src/utils.ts +30 -24
- package/src/zod-to-json.ts +28 -0
- package/src/zodTypes.ts +56 -0
- package/tsup.config.ts +8 -3
- package/src/utils.test.ts +0 -434
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import { MockLanguageModelV1 } from 'ai/test';
|
|
2
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
3
|
+
import { z } from 'zod/v4';
|
|
4
|
+
import { SchemaCompatLayer } from './schema-compatibility';
|
|
5
|
+
import type { ModelInformation } from './types';
|
|
6
|
+
|
|
7
|
+
vi.mock('zod', () => ({
|
|
8
|
+
z,
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
class MockSchemaCompatibility extends SchemaCompatLayer {
|
|
12
|
+
constructor(model: ModelInformation) {
|
|
13
|
+
super(model);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
shouldApply(): boolean {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
getSchemaTarget() {
|
|
21
|
+
return 'jsonSchema7' as const;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
processZodType(value: z.ZodTypeAny): z.ZodTypeAny {
|
|
25
|
+
if (this.isObj(value)) {
|
|
26
|
+
return this.defaultZodObjectHandler(value);
|
|
27
|
+
} else if (this.isArr(value)) {
|
|
28
|
+
// For these tests, we will handle all checks by converting them to descriptions.
|
|
29
|
+
return this.defaultZodArrayHandler(value, ['min', 'max', 'length']);
|
|
30
|
+
} else if (this.isOptional(value)) {
|
|
31
|
+
return this.defaultZodOptionalHandler(value);
|
|
32
|
+
} else if (this.isUnion(value)) {
|
|
33
|
+
return this.defaultZodUnionHandler(value);
|
|
34
|
+
} else if (this.isString(value)) {
|
|
35
|
+
// Add a marker to confirm it was processed
|
|
36
|
+
return z.string().describe(`${value.description || 'string'}:processed`);
|
|
37
|
+
} else {
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const mockModel = new MockLanguageModelV1({
|
|
44
|
+
modelId: 'test-model',
|
|
45
|
+
defaultObjectGenerationMode: 'json',
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe('SchemaCompatLayer', () => {
|
|
49
|
+
let compatibility: MockSchemaCompatibility;
|
|
50
|
+
|
|
51
|
+
beforeEach(() => {
|
|
52
|
+
compatibility = new MockSchemaCompatibility(mockModel);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('constructor and getModel', () => {
|
|
56
|
+
it('should store and return the model', () => {
|
|
57
|
+
expect(compatibility.getModel()).toBe(mockModel);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('mergeParameterDescription', () => {
|
|
62
|
+
it('should return original description when no constraints', () => {
|
|
63
|
+
const description = 'Original description';
|
|
64
|
+
const constraints = {};
|
|
65
|
+
|
|
66
|
+
const result = compatibility.mergeParameterDescription(description, constraints);
|
|
67
|
+
|
|
68
|
+
expect(result).toBe(description);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should append constraints to description', () => {
|
|
72
|
+
const description = 'Original description';
|
|
73
|
+
const constraints = { minLength: 5, maxLength: 10 };
|
|
74
|
+
|
|
75
|
+
const result = compatibility.mergeParameterDescription(description, constraints);
|
|
76
|
+
|
|
77
|
+
expect(result).toBe('Original description\n{"minLength":5,"maxLength":10}');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should handle undefined description with constraints', () => {
|
|
81
|
+
const constraints = { email: true };
|
|
82
|
+
|
|
83
|
+
const result = compatibility.mergeParameterDescription(undefined, constraints);
|
|
84
|
+
|
|
85
|
+
expect(result).toBe('{"email":true}');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should handle empty constraints', () => {
|
|
89
|
+
const description = 'Test description';
|
|
90
|
+
const constraints = {};
|
|
91
|
+
|
|
92
|
+
const result = compatibility.mergeParameterDescription(description, constraints);
|
|
93
|
+
|
|
94
|
+
expect(result).toBe(description);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('defaultZodObjectHandler', () => {
|
|
99
|
+
it('should process object shape correctly and recursively', () => {
|
|
100
|
+
const testSchema = z.object({
|
|
101
|
+
name: z.string().describe('The name'),
|
|
102
|
+
age: z.number(), // not a string, so won't get a description
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const result = compatibility.defaultZodObjectHandler(testSchema) as z.ZodObject<any, any, any>;
|
|
106
|
+
const newShape = result.shape;
|
|
107
|
+
|
|
108
|
+
expect(newShape.name).toBeInstanceOf(z.ZodString);
|
|
109
|
+
expect(newShape.name.description).toBe('The name:processed');
|
|
110
|
+
expect(newShape.age.description).toBeUndefined();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should preserve description', () => {
|
|
114
|
+
const testSchema = z
|
|
115
|
+
.object({
|
|
116
|
+
name: z.string(),
|
|
117
|
+
})
|
|
118
|
+
.describe('Test object');
|
|
119
|
+
|
|
120
|
+
const result = compatibility.defaultZodObjectHandler(testSchema);
|
|
121
|
+
|
|
122
|
+
expect(result.description).toBe('Test object');
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should preserve strictness', () => {
|
|
126
|
+
const strictSchema = z.strictObject({ name: z.string() });
|
|
127
|
+
const result = compatibility.defaultZodObjectHandler(strictSchema);
|
|
128
|
+
expect(result._zod.def.catchall).toBeInstanceOf(z.ZodNever);
|
|
129
|
+
|
|
130
|
+
const nonStrictSchema = z.object({ name: z.string() });
|
|
131
|
+
const nonStrictResult = compatibility.defaultZodObjectHandler(nonStrictSchema);
|
|
132
|
+
expect(nonStrictResult._zod.def.catchall).toBeUndefined(); // default
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe('defaultUnsupportedZodTypeHandler', () => {
|
|
137
|
+
it('should throw error for unsupported types', () => {
|
|
138
|
+
const unsupportedSchema = z.never();
|
|
139
|
+
|
|
140
|
+
expect(() => {
|
|
141
|
+
compatibility.defaultUnsupportedZodTypeHandler(unsupportedSchema);
|
|
142
|
+
}).toThrow('test-model does not support zod type: ZodNever');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should return value for supported types', () => {
|
|
146
|
+
const supportedSchema = z.string();
|
|
147
|
+
|
|
148
|
+
const result = compatibility.defaultUnsupportedZodTypeHandler(supportedSchema);
|
|
149
|
+
|
|
150
|
+
expect(result).toBe(supportedSchema);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should respect custom throwOnTypes parameter', () => {
|
|
154
|
+
const neverSchema = z.never();
|
|
155
|
+
|
|
156
|
+
const result = compatibility.defaultUnsupportedZodTypeHandler(neverSchema, []);
|
|
157
|
+
|
|
158
|
+
expect(result).toBe(neverSchema);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe('defaultZodArrayHandler', () => {
|
|
163
|
+
it('should handle array with constraints and convert to description', () => {
|
|
164
|
+
const arraySchema = z.array(z.string()).min(2).max(10);
|
|
165
|
+
const result = compatibility.defaultZodArrayHandler(arraySchema);
|
|
166
|
+
expect(result.description).toContain('minLength');
|
|
167
|
+
expect(result.description).toContain('maxLength');
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('should preserve constraints not in handleChecks', () => {
|
|
171
|
+
const arraySchema = z.array(z.string()).min(2).max(10);
|
|
172
|
+
// Only handle 'min', so 'max' should be preserved as a validator
|
|
173
|
+
const result = compatibility.defaultZodArrayHandler(arraySchema, ['min']);
|
|
174
|
+
|
|
175
|
+
expect(result.description).toContain('minLength');
|
|
176
|
+
expect(result.description).not.toContain('maxLength');
|
|
177
|
+
expect(result._zod.def.checks.find(check => check._zod.def.check === 'max_length')?._zod.def.maximum).toBe(10); // Preserved
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should handle exact length constraint', () => {
|
|
181
|
+
const arraySchema = z.array(z.string()).length(5);
|
|
182
|
+
const result = compatibility.defaultZodArrayHandler(arraySchema);
|
|
183
|
+
expect(result.description).toContain('exactLength');
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('should preserve original description', () => {
|
|
187
|
+
const arraySchema = z.array(z.string()).min(1).meta({ description: 'String array' });
|
|
188
|
+
const result = compatibility.defaultZodArrayHandler(arraySchema);
|
|
189
|
+
expect(result.description).toContain('minLength');
|
|
190
|
+
expect(result.description).toContain('String array');
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe('defaultZodUnionHandler', () => {
|
|
195
|
+
it('should throw error for union with less than 2 options', () => {
|
|
196
|
+
const mockUnion = {
|
|
197
|
+
_def: {
|
|
198
|
+
typeName: 'ZodUnion' as const,
|
|
199
|
+
options: [z.string()],
|
|
200
|
+
},
|
|
201
|
+
} as z.ZodUnion<[z.ZodString]>;
|
|
202
|
+
|
|
203
|
+
expect(() => {
|
|
204
|
+
compatibility.defaultZodUnionHandler(mockUnion);
|
|
205
|
+
}).toThrow('Union must have at least 2 options');
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('should handle union types and process recursively', () => {
|
|
209
|
+
const unionSchema = z.union([z.string().describe('A string'), z.number()]);
|
|
210
|
+
const result = compatibility.defaultZodUnionHandler(unionSchema) as z.ZodUnion<any>;
|
|
211
|
+
const processedString = result.options[0];
|
|
212
|
+
expect(processedString.description).toBe('A string:processed');
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('should preserve description', () => {
|
|
216
|
+
const unionSchema = z.union([z.string(), z.number()]).describe('String or number');
|
|
217
|
+
const result = compatibility.defaultZodUnionHandler(unionSchema);
|
|
218
|
+
expect(result.description).toBe('String or number');
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
describe('defaultZodStringHandler', () => {
|
|
223
|
+
it('should handle string with length constraints', () => {
|
|
224
|
+
const stringSchema = z.string().min(5).max(10);
|
|
225
|
+
|
|
226
|
+
const result = compatibility.defaultZodStringHandler(stringSchema);
|
|
227
|
+
|
|
228
|
+
expect(result).toBeInstanceOf(z.ZodString);
|
|
229
|
+
expect(result.description).toContain('minLength');
|
|
230
|
+
expect(result.description).toContain('maxLength');
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('should handle email constraint', () => {
|
|
234
|
+
const stringSchema = z.string().email();
|
|
235
|
+
|
|
236
|
+
const result = compatibility.defaultZodStringHandler(stringSchema);
|
|
237
|
+
|
|
238
|
+
expect(result).toBeInstanceOf(z.ZodString);
|
|
239
|
+
expect(result.description).toContain('email');
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('should handle url constraint', () => {
|
|
243
|
+
const stringSchema = z.string().url();
|
|
244
|
+
|
|
245
|
+
const result = compatibility.defaultZodStringHandler(stringSchema);
|
|
246
|
+
|
|
247
|
+
expect(result).toBeInstanceOf(z.ZodString);
|
|
248
|
+
expect(result.description).toContain('url');
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('should handle uuid constraint', () => {
|
|
252
|
+
const stringSchema = z.string().uuid();
|
|
253
|
+
|
|
254
|
+
const result = compatibility.defaultZodStringHandler(stringSchema);
|
|
255
|
+
|
|
256
|
+
expect(result).toBeInstanceOf(z.ZodString);
|
|
257
|
+
expect(result.description).toContain('uuid');
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it('should handle regex constraint', () => {
|
|
261
|
+
const stringSchema = z.string().regex(/^[A-Z]+$/);
|
|
262
|
+
|
|
263
|
+
const result = compatibility.defaultZodStringHandler(stringSchema);
|
|
264
|
+
|
|
265
|
+
expect(result).toBeInstanceOf(z.ZodString);
|
|
266
|
+
expect(result.description).toContain('regex');
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('should preserve checks not in handleChecks', () => {
|
|
270
|
+
const stringSchema = z.string().min(5).max(10);
|
|
271
|
+
|
|
272
|
+
const result = compatibility.defaultZodStringHandler(stringSchema, ['min']);
|
|
273
|
+
|
|
274
|
+
expect(result).toBeInstanceOf(z.ZodString);
|
|
275
|
+
expect(result.description).toContain('minLength');
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
describe('defaultZodNumberHandler', () => {
|
|
280
|
+
it('should handle number with min/max constraints', () => {
|
|
281
|
+
const numberSchema = z.number().min(0).max(100);
|
|
282
|
+
|
|
283
|
+
const result = compatibility.defaultZodNumberHandler(numberSchema);
|
|
284
|
+
|
|
285
|
+
expect(result).toBeInstanceOf(z.ZodNumber);
|
|
286
|
+
expect(result.description).toContain('gte');
|
|
287
|
+
expect(result.description).toContain('lte');
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it('should handle exclusive min/max', () => {
|
|
291
|
+
const numberSchema = z.number().gt(0).lt(100);
|
|
292
|
+
|
|
293
|
+
const result = compatibility.defaultZodNumberHandler(numberSchema);
|
|
294
|
+
|
|
295
|
+
expect(result).toBeInstanceOf(z.ZodNumber);
|
|
296
|
+
expect(result.description).toContain('gt');
|
|
297
|
+
expect(result.description).toContain('lt');
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('should handle multipleOf constraint', () => {
|
|
301
|
+
const numberSchema = z.number().multipleOf(5);
|
|
302
|
+
|
|
303
|
+
const result = compatibility.defaultZodNumberHandler(numberSchema);
|
|
304
|
+
|
|
305
|
+
expect(result).toBeInstanceOf(z.ZodNumber);
|
|
306
|
+
expect(result.description).toContain('multipleOf');
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it('should handle int', () => {
|
|
310
|
+
const numberSchema = z.number().int();
|
|
311
|
+
const result = compatibility.defaultZodNumberHandler(numberSchema);
|
|
312
|
+
expect(result).toBeInstanceOf(z.ZodNumber);
|
|
313
|
+
expect(result._zod.def.checks.find(check => check._zod.def.check === 'number_format')?._zod.def.format).toEqual(
|
|
314
|
+
'safeint',
|
|
315
|
+
);
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
describe('defaultZodDateHandler', () => {
|
|
320
|
+
it('should convert date to string with date-time format', () => {
|
|
321
|
+
const dateSchema = z.date();
|
|
322
|
+
|
|
323
|
+
const result = compatibility.defaultZodDateHandler(dateSchema);
|
|
324
|
+
|
|
325
|
+
expect(result).toBeInstanceOf(z.ZodString);
|
|
326
|
+
expect(result.description).toContain('date-time');
|
|
327
|
+
expect(result.description).toContain('dateFormat');
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it('should handle date with min/max constraints', () => {
|
|
331
|
+
const minDate = new Date('2023-01-01');
|
|
332
|
+
const maxDate = new Date('2023-12-31');
|
|
333
|
+
const dateSchema = z.date().min(minDate).max(maxDate);
|
|
334
|
+
|
|
335
|
+
const result = compatibility.defaultZodDateHandler(dateSchema);
|
|
336
|
+
|
|
337
|
+
expect(result).toBeInstanceOf(z.ZodString);
|
|
338
|
+
expect(result.description).toContain('minDate');
|
|
339
|
+
expect(result.description).toContain('maxDate');
|
|
340
|
+
expect(result.description).toContain('2023-01-01');
|
|
341
|
+
expect(result.description).toContain('2023-12-31');
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
describe('defaultZodOptionalHandler', () => {
|
|
346
|
+
it('should handle optional string', () => {
|
|
347
|
+
const optionalSchema = z.string().optional();
|
|
348
|
+
|
|
349
|
+
class TestCompatibility extends MockSchemaCompatibility {
|
|
350
|
+
processZodType(value: z.ZodTypeAny): any {
|
|
351
|
+
if (value.constructor.name === 'ZodString') {
|
|
352
|
+
return z.string().describe('processed');
|
|
353
|
+
}
|
|
354
|
+
return value;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const testCompat = new TestCompatibility(mockModel);
|
|
359
|
+
const result = testCompat.defaultZodOptionalHandler(optionalSchema);
|
|
360
|
+
|
|
361
|
+
expect(result.constructor.name).toBe('ZodOptional');
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
it('should return original value for unsupported types', () => {
|
|
365
|
+
const optionalNever = z.never().optional();
|
|
366
|
+
|
|
367
|
+
const result = compatibility.defaultZodOptionalHandler(optionalNever, ['ZodString']);
|
|
368
|
+
|
|
369
|
+
expect(result).toBe(optionalNever);
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
describe('Top-level schema processing (processToAISDKSchema)', () => {
|
|
374
|
+
it('should process a simple object schema', () => {
|
|
375
|
+
const objectSchema = z.object({ user: z.string().describe('user name') });
|
|
376
|
+
const result = compatibility.processToAISDKSchema(objectSchema);
|
|
377
|
+
const userProp = result.jsonSchema.properties?.user as any;
|
|
378
|
+
expect(userProp.description).toBe('user name:processed');
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
it('should preserve top-level array constraints during processing', () => {
|
|
382
|
+
const arraySchema = z.array(z.string().describe('item')).min(1);
|
|
383
|
+
|
|
384
|
+
// In our mock, 'min' is converted to a description.
|
|
385
|
+
const result = compatibility.processToAISDKSchema(arraySchema);
|
|
386
|
+
|
|
387
|
+
expect(result.jsonSchema.type).toBe('array');
|
|
388
|
+
expect(result.jsonSchema.description).toContain('minLength');
|
|
389
|
+
// The validator itself should be gone
|
|
390
|
+
expect(
|
|
391
|
+
result.validate?.([
|
|
392
|
+
/* empty array */
|
|
393
|
+
]).success,
|
|
394
|
+
).toBe(true);
|
|
395
|
+
|
|
396
|
+
// Now test that a constraint is preserved if not handled
|
|
397
|
+
class PreservingMock extends MockSchemaCompatibility {
|
|
398
|
+
processZodType(value: z.ZodTypeAny): z.ZodTypeAny {
|
|
399
|
+
if (value instanceof z.ZodArray) {
|
|
400
|
+
return this.defaultZodArrayHandler(value as any, [
|
|
401
|
+
/* handle nothing */
|
|
402
|
+
]);
|
|
403
|
+
}
|
|
404
|
+
return super.processZodType(value);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
const preservingCompat = new PreservingMock(mockModel);
|
|
408
|
+
const preservingResult = preservingCompat.processToAISDKSchema(arraySchema);
|
|
409
|
+
expect(preservingResult.jsonSchema.description).toBeUndefined();
|
|
410
|
+
expect(
|
|
411
|
+
preservingResult.validate?.([
|
|
412
|
+
/* empty array */
|
|
413
|
+
]).success,
|
|
414
|
+
).toBe(false); // validator preserved
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it('should preserve top-level object constraints (strict)', () => {
|
|
418
|
+
const strictSchema = z.object({ name: z.string() }).strict();
|
|
419
|
+
const result = compatibility.processToAISDKSchema(strictSchema);
|
|
420
|
+
expect(result.jsonSchema.additionalProperties).toBe(false);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
it('should process array of objects, including nested properties', () => {
|
|
424
|
+
const arraySchema = z.array(
|
|
425
|
+
z.object({
|
|
426
|
+
name: z.string().describe('The name'),
|
|
427
|
+
value: z.number().describe('The value'), // number is not processed in our mock
|
|
428
|
+
}),
|
|
429
|
+
);
|
|
430
|
+
const result = compatibility.processToAISDKSchema(arraySchema);
|
|
431
|
+
const items = result.jsonSchema.items as any;
|
|
432
|
+
expect(items.properties.name.description).toBe('The name:processed');
|
|
433
|
+
expect(items.properties.value.description).toBe('The value');
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
// TODO: figure out how to handle this, with z.toJSONSchema, optional schemas are represented as-is
|
|
437
|
+
it.skip('should handle optional object schemas', () => {
|
|
438
|
+
const optionalSchema = z
|
|
439
|
+
.object({
|
|
440
|
+
name: z.string(),
|
|
441
|
+
})
|
|
442
|
+
.optional();
|
|
443
|
+
|
|
444
|
+
const result = compatibility.processToAISDKSchema(optionalSchema);
|
|
445
|
+
expect(result.validate!({ name: 'test' }).success).toBe(true);
|
|
446
|
+
expect(result.validate!(undefined).success).toBe(true);
|
|
447
|
+
|
|
448
|
+
const jsonSchema = result.jsonSchema;
|
|
449
|
+
const objectDef = (jsonSchema.anyOf as any[])?.find(def => def.type === 'object');
|
|
450
|
+
expect(objectDef.properties.name.description).toBe('string:processed');
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
it.skip('should handle optional array schemas', () => {
|
|
454
|
+
const optionalSchema = z.array(z.string()).optional();
|
|
455
|
+
const result = compatibility.processToAISDKSchema(optionalSchema);
|
|
456
|
+
expect(result.validate!(['test']).success).toBe(true);
|
|
457
|
+
expect(result.validate!(undefined).success).toBe(true);
|
|
458
|
+
|
|
459
|
+
const jsonSchema = result.jsonSchema;
|
|
460
|
+
const arrayDef = (jsonSchema.anyOf as any[])?.find(def => def.type === 'array');
|
|
461
|
+
const items = arrayDef.items as any;
|
|
462
|
+
expect(items.description).toBe('string:processed');
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
it.skip('should handle optional scalar schemas', () => {
|
|
466
|
+
const optionalSchema = z.string().optional();
|
|
467
|
+
const result = compatibility.processToAISDKSchema(optionalSchema);
|
|
468
|
+
expect(result.validate!('test').success).toBe(true);
|
|
469
|
+
expect(result.validate!(undefined).success).toBe(true);
|
|
470
|
+
|
|
471
|
+
const jsonSchema = result.jsonSchema;
|
|
472
|
+
const stringDef = (jsonSchema.anyOf as any[])?.find(def => def.type === 'string');
|
|
473
|
+
expect(stringDef.description).toBe('string:processed');
|
|
474
|
+
});
|
|
475
|
+
});
|
|
476
|
+
});
|