@mastra/schema-compat 0.10.2-alpha.2
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 +23 -0
- package/CHANGELOG.md +7 -0
- package/LICENSE.md +46 -0
- package/README.md +148 -0
- package/dist/_tsup-dts-rollup.d.cts +473 -0
- package/dist/_tsup-dts-rollup.d.ts +473 -0
- package/dist/index.cjs +726 -0
- package/dist/index.d.cts +25 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +709 -0
- package/eslint.config.js +6 -0
- package/package.json +56 -0
- package/src/index.ts +32 -0
- package/src/provider-compats/anthropic.ts +54 -0
- package/src/provider-compats/deepseek.ts +41 -0
- package/src/provider-compats/google.ts +54 -0
- package/src/provider-compats/meta.ts +43 -0
- package/src/provider-compats/openai-reasoning.ts +86 -0
- package/src/provider-compats/openai.ts +61 -0
- package/src/provider-compats.test.ts +312 -0
- package/src/schema-compatibility.test.ts +350 -0
- package/src/schema-compatibility.ts +587 -0
- package/src/utils.test.ts +328 -0
- package/src/utils.ts +218 -0
- package/tsconfig.json +5 -0
- package/vitest.config.ts +7 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import { jsonSchema } from 'ai';
|
|
2
|
+
import type { LanguageModelV1, Schema } from 'ai';
|
|
3
|
+
import { MockLanguageModelV1 } from 'ai/test';
|
|
4
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { SchemaCompatLayer } from './schema-compatibility';
|
|
7
|
+
import { convertZodSchemaToAISDKSchema, convertSchemaToZod, applyCompatLayer } from './utils';
|
|
8
|
+
|
|
9
|
+
const mockModel = new MockLanguageModelV1({
|
|
10
|
+
modelId: 'test-model',
|
|
11
|
+
defaultObjectGenerationMode: 'json',
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
class MockSchemaCompatibility extends SchemaCompatLayer {
|
|
15
|
+
constructor(
|
|
16
|
+
model: LanguageModelV1,
|
|
17
|
+
private shouldApplyValue: boolean = true,
|
|
18
|
+
) {
|
|
19
|
+
super(model);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
shouldApply(): boolean {
|
|
23
|
+
return this.shouldApplyValue;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
getSchemaTarget() {
|
|
27
|
+
return 'jsonSchema7' as const;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
processZodType(value: z.ZodTypeAny): any {
|
|
31
|
+
if (value._def.typeName === 'ZodString') {
|
|
32
|
+
return z.string().describe('processed string');
|
|
33
|
+
}
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
describe('Builder Functions', () => {
|
|
39
|
+
describe('convertZodSchemaToAISDKSchema', () => {
|
|
40
|
+
it('should convert simple Zod schema to AI SDK schema', () => {
|
|
41
|
+
const zodSchema = z.object({
|
|
42
|
+
name: z.string(),
|
|
43
|
+
age: z.number(),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const result = convertZodSchemaToAISDKSchema(zodSchema);
|
|
47
|
+
|
|
48
|
+
expect(result).toHaveProperty('jsonSchema');
|
|
49
|
+
expect(result).toHaveProperty('validate');
|
|
50
|
+
expect(typeof result.validate).toBe('function');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should create schema with validation function', () => {
|
|
54
|
+
const zodSchema = z.object({
|
|
55
|
+
email: z.string().email(),
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const result = convertZodSchemaToAISDKSchema(zodSchema);
|
|
59
|
+
|
|
60
|
+
expect(result.validate).toBeDefined();
|
|
61
|
+
|
|
62
|
+
const validResult = result.validate!({ email: 'test@example.com' });
|
|
63
|
+
expect(validResult.success).toBe(true);
|
|
64
|
+
if (validResult.success) {
|
|
65
|
+
expect(validResult.value).toEqual({ email: 'test@example.com' });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const invalidResult = result.validate!({ email: 'invalid-email' });
|
|
69
|
+
expect(invalidResult.success).toBe(false);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should handle custom targets', () => {
|
|
73
|
+
const zodSchema = z.object({
|
|
74
|
+
name: z.string(),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const result = convertZodSchemaToAISDKSchema(zodSchema, 'openApi3');
|
|
78
|
+
|
|
79
|
+
expect(result).toHaveProperty('jsonSchema');
|
|
80
|
+
expect(result).toHaveProperty('validate');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should handle complex nested schemas', () => {
|
|
84
|
+
const zodSchema = z.object({
|
|
85
|
+
user: z.object({
|
|
86
|
+
name: z.string(),
|
|
87
|
+
preferences: z.object({
|
|
88
|
+
theme: z.enum(['light', 'dark']),
|
|
89
|
+
notifications: z.boolean(),
|
|
90
|
+
}),
|
|
91
|
+
}),
|
|
92
|
+
tags: z.array(z.string()),
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const result = convertZodSchemaToAISDKSchema(zodSchema);
|
|
96
|
+
|
|
97
|
+
expect(result).toHaveProperty('jsonSchema');
|
|
98
|
+
expect(result.jsonSchema).toHaveProperty('properties');
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('convertSchemaToZod', () => {
|
|
103
|
+
it('should return Zod schema unchanged', () => {
|
|
104
|
+
const zodSchema = z.object({
|
|
105
|
+
name: z.string(),
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const result = convertSchemaToZod(zodSchema);
|
|
109
|
+
|
|
110
|
+
expect(result).toBe(zodSchema);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should convert AI SDK schema to Zod', () => {
|
|
114
|
+
const aiSchema: Schema = jsonSchema({
|
|
115
|
+
type: 'object',
|
|
116
|
+
properties: {
|
|
117
|
+
name: { type: 'string' },
|
|
118
|
+
age: { type: 'number' },
|
|
119
|
+
},
|
|
120
|
+
required: ['name'],
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const result = convertSchemaToZod(aiSchema);
|
|
124
|
+
|
|
125
|
+
expect(result).toBeInstanceOf(z.ZodType);
|
|
126
|
+
const parseResult = result.safeParse({ name: 'John', age: 30 });
|
|
127
|
+
expect(parseResult.success).toBe(true);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should handle complex JSON schema conversion', () => {
|
|
131
|
+
const complexSchema: Schema = jsonSchema({
|
|
132
|
+
type: 'object',
|
|
133
|
+
properties: {
|
|
134
|
+
user: {
|
|
135
|
+
type: 'object',
|
|
136
|
+
properties: {
|
|
137
|
+
name: { type: 'string' },
|
|
138
|
+
email: { type: 'string', format: 'email' },
|
|
139
|
+
},
|
|
140
|
+
required: ['name'],
|
|
141
|
+
},
|
|
142
|
+
tags: {
|
|
143
|
+
type: 'array',
|
|
144
|
+
items: { type: 'string' },
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
required: ['user'],
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const result = convertSchemaToZod(complexSchema);
|
|
151
|
+
|
|
152
|
+
expect(result).toBeInstanceOf(z.ZodType);
|
|
153
|
+
|
|
154
|
+
const validData = {
|
|
155
|
+
user: { name: 'John', email: 'john@example.com' },
|
|
156
|
+
tags: ['tag1', 'tag2'],
|
|
157
|
+
};
|
|
158
|
+
const parseResult = result.safeParse(validData);
|
|
159
|
+
expect(parseResult.success).toBe(true);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
describe('applyCompatLayer', () => {
|
|
164
|
+
let mockCompatibility: MockSchemaCompatibility;
|
|
165
|
+
|
|
166
|
+
beforeEach(() => {
|
|
167
|
+
mockCompatibility = new MockSchemaCompatibility(mockModel);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('should process Zod object schema with compatibility', () => {
|
|
171
|
+
const zodSchema = z.object({
|
|
172
|
+
name: z.string(),
|
|
173
|
+
age: z.number(),
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const result = applyCompatLayer({
|
|
177
|
+
schema: zodSchema,
|
|
178
|
+
compatLayers: [mockCompatibility],
|
|
179
|
+
mode: 'aiSdkSchema',
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
expect(result).toHaveProperty('jsonSchema');
|
|
183
|
+
expect(result).toHaveProperty('validate');
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('should process AI SDK schema with compatibility', () => {
|
|
187
|
+
const aiSchema: Schema = jsonSchema({
|
|
188
|
+
type: 'object',
|
|
189
|
+
properties: {
|
|
190
|
+
name: { type: 'string' },
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
const result = applyCompatLayer({
|
|
195
|
+
schema: aiSchema,
|
|
196
|
+
compatLayers: [mockCompatibility],
|
|
197
|
+
mode: 'jsonSchema',
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
expect(typeof result).toBe('object');
|
|
201
|
+
expect(result).toHaveProperty('type');
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should handle object schema with string property', () => {
|
|
205
|
+
const stringSchema = z.object({ value: z.string() });
|
|
206
|
+
|
|
207
|
+
const result = applyCompatLayer({
|
|
208
|
+
schema: stringSchema,
|
|
209
|
+
compatLayers: [mockCompatibility],
|
|
210
|
+
mode: 'aiSdkSchema',
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
expect(result).toHaveProperty('jsonSchema');
|
|
214
|
+
expect(result).toHaveProperty('validate');
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('should return processed schema when compatibility applies', () => {
|
|
218
|
+
const zodSchema = z.object({
|
|
219
|
+
name: z.string(),
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const result = applyCompatLayer({
|
|
223
|
+
schema: zodSchema,
|
|
224
|
+
compatLayers: [mockCompatibility],
|
|
225
|
+
mode: 'aiSdkSchema',
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
expect(result).toHaveProperty('jsonSchema');
|
|
229
|
+
expect(result).toHaveProperty('validate');
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('should return fallback when no compatibility applies', () => {
|
|
233
|
+
const nonApplyingCompatibility = new MockSchemaCompatibility(mockModel, false);
|
|
234
|
+
const zodSchema = z.object({
|
|
235
|
+
name: z.string(),
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const result = applyCompatLayer({
|
|
239
|
+
schema: zodSchema,
|
|
240
|
+
compatLayers: [nonApplyingCompatibility],
|
|
241
|
+
mode: 'aiSdkSchema',
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
expect(result).toHaveProperty('jsonSchema');
|
|
245
|
+
expect(result).toHaveProperty('validate');
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should handle jsonSchema mode', () => {
|
|
249
|
+
const zodSchema = z.object({
|
|
250
|
+
name: z.string(),
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
const result = applyCompatLayer({
|
|
254
|
+
schema: zodSchema,
|
|
255
|
+
compatLayers: [mockCompatibility],
|
|
256
|
+
mode: 'jsonSchema',
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
expect(typeof result).toBe('object');
|
|
260
|
+
expect(result).toHaveProperty('type');
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('should handle empty compatLayers array', () => {
|
|
264
|
+
const zodSchema = z.object({
|
|
265
|
+
name: z.string(),
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
const result = applyCompatLayer({
|
|
269
|
+
schema: zodSchema,
|
|
270
|
+
compatLayers: [],
|
|
271
|
+
mode: 'aiSdkSchema',
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
expect(result).toHaveProperty('jsonSchema');
|
|
275
|
+
expect(result).toHaveProperty('validate');
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('should convert non-object AI SDK schema correctly', () => {
|
|
279
|
+
const stringSchema: Schema = jsonSchema({ type: 'string' });
|
|
280
|
+
|
|
281
|
+
const result = applyCompatLayer({
|
|
282
|
+
schema: stringSchema,
|
|
283
|
+
compatLayers: [mockCompatibility],
|
|
284
|
+
mode: 'aiSdkSchema',
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
expect(result).toHaveProperty('jsonSchema');
|
|
288
|
+
expect(result).toHaveProperty('validate');
|
|
289
|
+
|
|
290
|
+
// Verify the schema structure shows the string was wrapped in a 'value' property
|
|
291
|
+
const resultSchema = (result as Schema).jsonSchema;
|
|
292
|
+
expect(resultSchema).toHaveProperty('type', 'object');
|
|
293
|
+
expect(resultSchema).toHaveProperty('properties');
|
|
294
|
+
expect(resultSchema.properties).toHaveProperty('value');
|
|
295
|
+
|
|
296
|
+
// Verify the string property has the description added by the mock compatibility layer
|
|
297
|
+
const valueProperty = resultSchema.properties!.value as any;
|
|
298
|
+
expect(valueProperty).toHaveProperty('description', 'processed string');
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it('should handle complex schema with multiple compatLayers', () => {
|
|
302
|
+
const compat1 = new MockSchemaCompatibility(mockModel, false);
|
|
303
|
+
const compat2 = new MockSchemaCompatibility(mockModel, true);
|
|
304
|
+
|
|
305
|
+
vi.spyOn(compat1, 'processZodType');
|
|
306
|
+
vi.spyOn(compat2, 'processZodType');
|
|
307
|
+
|
|
308
|
+
const zodSchema = z.object({
|
|
309
|
+
name: z.string(),
|
|
310
|
+
settings: z.object({
|
|
311
|
+
theme: z.string(),
|
|
312
|
+
notifications: z.boolean(),
|
|
313
|
+
}),
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
const result = applyCompatLayer({
|
|
317
|
+
schema: zodSchema,
|
|
318
|
+
compatLayers: [compat1, compat2],
|
|
319
|
+
mode: 'aiSdkSchema',
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
expect(result).toHaveProperty('jsonSchema');
|
|
323
|
+
expect(result).toHaveProperty('validate');
|
|
324
|
+
expect(compat1.processZodType).not.toHaveBeenCalled();
|
|
325
|
+
expect(compat2.processZodType).toHaveBeenCalled();
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
});
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { jsonSchema } from 'ai';
|
|
2
|
+
import type { Schema } from 'ai';
|
|
3
|
+
import type { JSONSchema7 } from 'json-schema';
|
|
4
|
+
import type { ZodSchema } from 'zod';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { convertJsonSchemaToZod } from 'zod-from-json-schema';
|
|
7
|
+
import type { JSONSchema as ZodFromJSONSchema_JSONSchema } from 'zod-from-json-schema';
|
|
8
|
+
import type { Targets } from 'zod-to-json-schema';
|
|
9
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
10
|
+
import type { SchemaCompatLayer } from './schema-compatibility';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Converts a Zod schema to an AI SDK Schema with validation support.
|
|
14
|
+
*
|
|
15
|
+
* This function mirrors the behavior of Vercel's AI SDK zod-schema utility but allows
|
|
16
|
+
* customization of the JSON Schema target format.
|
|
17
|
+
*
|
|
18
|
+
* @param zodSchema - The Zod schema to convert
|
|
19
|
+
* @param target - The JSON Schema target format (defaults to 'jsonSchema7')
|
|
20
|
+
* @returns An AI SDK Schema object with built-in validation
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* import { z } from 'zod';
|
|
25
|
+
* import { convertZodSchemaToAISDKSchema } from '@mastra/schema-compat';
|
|
26
|
+
*
|
|
27
|
+
* const userSchema = z.object({
|
|
28
|
+
* name: z.string(),
|
|
29
|
+
* age: z.number().min(0)
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* const aiSchema = convertZodSchemaToAISDKSchema(userSchema);
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
// mirrors https://github.com/vercel/ai/blob/main/packages/ui-utils/src/zod-schema.ts#L21 but with a custom target
|
|
36
|
+
export function convertZodSchemaToAISDKSchema(zodSchema: ZodSchema, target: Targets = 'jsonSchema7') {
|
|
37
|
+
return jsonSchema(
|
|
38
|
+
zodToJsonSchema(zodSchema, {
|
|
39
|
+
$refStrategy: 'none',
|
|
40
|
+
target,
|
|
41
|
+
}) as JSONSchema7,
|
|
42
|
+
{
|
|
43
|
+
validate: value => {
|
|
44
|
+
const result = zodSchema.safeParse(value);
|
|
45
|
+
return result.success ? { success: true, value: result.data } : { success: false, error: result.error };
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Checks if a value is a Zod type by examining its properties and methods.
|
|
53
|
+
*
|
|
54
|
+
* @param value - The value to check
|
|
55
|
+
* @returns True if the value is a Zod type, false otherwise
|
|
56
|
+
* @internal
|
|
57
|
+
*/
|
|
58
|
+
function isZodType(value: unknown): value is z.ZodType {
|
|
59
|
+
// Check if it's a Zod schema by looking for common Zod properties and methods
|
|
60
|
+
return (
|
|
61
|
+
typeof value === 'object' &&
|
|
62
|
+
value !== null &&
|
|
63
|
+
'_def' in value &&
|
|
64
|
+
'parse' in value &&
|
|
65
|
+
typeof (value as any).parse === 'function' &&
|
|
66
|
+
'safeParse' in value &&
|
|
67
|
+
typeof (value as any).safeParse === 'function'
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Converts an AI SDK Schema or Zod schema to a Zod schema.
|
|
73
|
+
*
|
|
74
|
+
* If the input is already a Zod schema, it returns it unchanged.
|
|
75
|
+
* If the input is an AI SDK Schema, it extracts the JSON schema and converts it to Zod.
|
|
76
|
+
*
|
|
77
|
+
* @param schema - The schema to convert (AI SDK Schema or Zod schema)
|
|
78
|
+
* @returns A Zod schema equivalent of the input
|
|
79
|
+
* @throws Error if the conversion fails
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* import { jsonSchema } from 'ai';
|
|
84
|
+
* import { convertSchemaToZod } from '@mastra/schema-compat';
|
|
85
|
+
*
|
|
86
|
+
* const aiSchema = jsonSchema({
|
|
87
|
+
* type: 'object',
|
|
88
|
+
* properties: {
|
|
89
|
+
* name: { type: 'string' }
|
|
90
|
+
* }
|
|
91
|
+
* });
|
|
92
|
+
*
|
|
93
|
+
* const zodSchema = convertSchemaToZod(aiSchema);
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export function convertSchemaToZod(schema: Schema | z.ZodSchema): z.ZodType {
|
|
97
|
+
if (isZodType(schema)) {
|
|
98
|
+
return schema;
|
|
99
|
+
} else {
|
|
100
|
+
const jsonSchemaToConvert = ('jsonSchema' in schema ? schema.jsonSchema : schema) as ZodFromJSONSchema_JSONSchema;
|
|
101
|
+
try {
|
|
102
|
+
return convertJsonSchemaToZod(jsonSchemaToConvert);
|
|
103
|
+
} catch (e: unknown) {
|
|
104
|
+
const errorMessage = `[Schema Builder] Failed to convert schema parameters to Zod. Original schema: ${JSON.stringify(jsonSchemaToConvert)}`;
|
|
105
|
+
console.error(errorMessage, e);
|
|
106
|
+
throw new Error(errorMessage + (e instanceof Error ? `\n${e.stack}` : '\nUnknown error object'));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Processes a schema using provider compatibility layers and converts it to an AI SDK Schema.
|
|
113
|
+
*
|
|
114
|
+
* @param options - Configuration object for schema processing
|
|
115
|
+
* @param options.schema - The schema to process (AI SDK Schema or Zod object schema)
|
|
116
|
+
* @param options.compatLayers - Array of compatibility layers to try
|
|
117
|
+
* @param options.mode - Must be 'aiSdkSchema'
|
|
118
|
+
* @returns Processed schema as an AI SDK Schema
|
|
119
|
+
*/
|
|
120
|
+
export function applyCompatLayer(options: {
|
|
121
|
+
schema: Schema | z.AnyZodObject;
|
|
122
|
+
compatLayers: SchemaCompatLayer[];
|
|
123
|
+
mode: 'aiSdkSchema';
|
|
124
|
+
}): Schema;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Processes a schema using provider compatibility layers and converts it to a JSON Schema.
|
|
128
|
+
*
|
|
129
|
+
* @param options - Configuration object for schema processing
|
|
130
|
+
* @param options.schema - The schema to process (AI SDK Schema or Zod object schema)
|
|
131
|
+
* @param options.compatLayers - Array of compatibility layers to try
|
|
132
|
+
* @param options.mode - Must be 'jsonSchema'
|
|
133
|
+
* @returns Processed schema as a JSONSchema7
|
|
134
|
+
*/
|
|
135
|
+
export function applyCompatLayer(options: {
|
|
136
|
+
schema: Schema | z.AnyZodObject;
|
|
137
|
+
compatLayers: SchemaCompatLayer[];
|
|
138
|
+
mode: 'jsonSchema';
|
|
139
|
+
}): JSONSchema7;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Processes a schema using provider compatibility layers and converts it to the specified format.
|
|
143
|
+
*
|
|
144
|
+
* This function automatically applies the first matching compatibility layer from the provided
|
|
145
|
+
* list based on the model configuration. If no compatibility applies, it falls back to
|
|
146
|
+
* standard conversion.
|
|
147
|
+
*
|
|
148
|
+
* @param options - Configuration object for schema processing
|
|
149
|
+
* @param options.schema - The schema to process (AI SDK Schema or Zod object schema)
|
|
150
|
+
* @param options.compatLayers - Array of compatibility layers to try
|
|
151
|
+
* @param options.mode - Output format: 'jsonSchema' for JSONSchema7 or 'aiSdkSchema' for AI SDK Schema
|
|
152
|
+
* @returns Processed schema in the requested format
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* import { z } from 'zod';
|
|
157
|
+
* import { applyCompatLayer, OpenAISchemaCompatLayer, AnthropicSchemaCompatLayer } from '@mastra/schema-compat';
|
|
158
|
+
*
|
|
159
|
+
* const schema = z.object({
|
|
160
|
+
* query: z.string().email(),
|
|
161
|
+
* limit: z.number().min(1).max(100)
|
|
162
|
+
* });
|
|
163
|
+
*
|
|
164
|
+
* const compatLayers = [
|
|
165
|
+
* new OpenAISchemaCompatLayer(model),
|
|
166
|
+
* new AnthropicSchemaCompatLayer(model)
|
|
167
|
+
* ];
|
|
168
|
+
*
|
|
169
|
+
* const result = applyCompatLayer({
|
|
170
|
+
* schema,
|
|
171
|
+
* compatLayers,
|
|
172
|
+
* mode: 'aiSdkSchema'
|
|
173
|
+
* });
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
export function applyCompatLayer({
|
|
177
|
+
schema,
|
|
178
|
+
compatLayers,
|
|
179
|
+
mode,
|
|
180
|
+
}: {
|
|
181
|
+
schema: Schema | z.AnyZodObject;
|
|
182
|
+
compatLayers: SchemaCompatLayer[];
|
|
183
|
+
mode: 'jsonSchema' | 'aiSdkSchema';
|
|
184
|
+
}): JSONSchema7 | Schema {
|
|
185
|
+
let zodSchema: z.AnyZodObject;
|
|
186
|
+
|
|
187
|
+
if (!isZodType(schema)) {
|
|
188
|
+
// Convert Schema to ZodObject
|
|
189
|
+
const convertedSchema = convertSchemaToZod(schema);
|
|
190
|
+
if (convertedSchema instanceof z.ZodObject) {
|
|
191
|
+
zodSchema = convertedSchema;
|
|
192
|
+
} else {
|
|
193
|
+
// If it's not an object schema, wrap it in an object
|
|
194
|
+
zodSchema = z.object({ value: convertedSchema });
|
|
195
|
+
}
|
|
196
|
+
} else {
|
|
197
|
+
// Ensure it's a ZodObject
|
|
198
|
+
if (schema instanceof z.ZodObject) {
|
|
199
|
+
zodSchema = schema;
|
|
200
|
+
} else {
|
|
201
|
+
// Wrap non-object schemas in an object
|
|
202
|
+
zodSchema = z.object({ value: schema });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
for (const compat of compatLayers) {
|
|
207
|
+
if (compat.shouldApply()) {
|
|
208
|
+
return mode === 'jsonSchema' ? compat.processToJSONSchema(zodSchema) : compat.processToAISDKSchema(zodSchema);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// If no compatibility applied, convert back to appropriate format
|
|
213
|
+
if (mode === 'jsonSchema') {
|
|
214
|
+
return zodToJsonSchema(zodSchema, { $refStrategy: 'none', target: 'jsonSchema7' }) as JSONSchema7;
|
|
215
|
+
} else {
|
|
216
|
+
return convertZodSchemaToAISDKSchema(zodSchema);
|
|
217
|
+
}
|
|
218
|
+
}
|
package/tsconfig.json
ADDED