@mastra/schema-compat 0.0.0-ai-v5-20250729181825 → 0.0.0-ai-v5-20250813235735

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 (41) hide show
  1. package/.turbo/turbo-build.log +2 -21
  2. package/CHANGELOG.md +34 -1
  3. package/dist/index.cjs +4 -5
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.ts +9 -31
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +4 -5
  8. package/dist/index.js.map +1 -0
  9. package/dist/provider-compats/anthropic.d.ts +11 -0
  10. package/dist/provider-compats/anthropic.d.ts.map +1 -0
  11. package/dist/provider-compats/deepseek.d.ts +11 -0
  12. package/dist/provider-compats/deepseek.d.ts.map +1 -0
  13. package/dist/provider-compats/google.d.ts +11 -0
  14. package/dist/provider-compats/google.d.ts.map +1 -0
  15. package/dist/provider-compats/meta.d.ts +11 -0
  16. package/dist/provider-compats/meta.d.ts.map +1 -0
  17. package/dist/provider-compats/openai-reasoning.d.ts +12 -0
  18. package/dist/provider-compats/openai-reasoning.d.ts.map +1 -0
  19. package/dist/provider-compats/openai.d.ts +11 -0
  20. package/dist/provider-compats/openai.d.ts.map +1 -0
  21. package/dist/schema-compatibility.d.ts +282 -0
  22. package/dist/schema-compatibility.d.ts.map +1 -0
  23. package/dist/utils.d.ts +84 -0
  24. package/dist/utils.d.ts.map +1 -0
  25. package/package.json +8 -7
  26. package/src/provider-compats/anthropic.ts +2 -2
  27. package/src/provider-compats/deepseek.ts +2 -2
  28. package/src/provider-compats/google.ts +2 -3
  29. package/src/provider-compats/meta.ts +2 -2
  30. package/src/provider-compats/openai-reasoning.ts +7 -4
  31. package/src/provider-compats/openai.ts +2 -2
  32. package/src/provider-compats.test.ts +96 -25
  33. package/src/schema-compatibility.test.ts +18 -6
  34. package/src/schema-compatibility.ts +10 -8
  35. package/src/utils.test.ts +27 -6
  36. package/tsconfig.build.json +9 -0
  37. package/tsconfig.json +1 -1
  38. package/tsup.config.ts +17 -0
  39. package/dist/_tsup-dts-rollup.d.cts +0 -509
  40. package/dist/_tsup-dts-rollup.d.ts +0 -509
  41. package/dist/index.d.cts +0 -31
@@ -40,22 +40,34 @@ describe('Provider Compatibility Classes', () => {
40
40
 
41
41
  describe('AnthropicSchemaCompatLayer', () => {
42
42
  it('should apply for Anthropic models', () => {
43
- const compat = new AnthropicSchemaCompatLayer(mockModels.anthropic);
43
+ const compat = new AnthropicSchemaCompatLayer({
44
+ modelId: mockModels.anthropic.modelId,
45
+ provider: mockModels.anthropic.provider,
46
+ });
44
47
  expect(compat.shouldApply()).toBe(true);
45
48
  });
46
49
 
47
50
  it('should not apply for non-Anthropic models', () => {
48
- const compat = new AnthropicSchemaCompatLayer(mockModels.openai);
51
+ const compat = new AnthropicSchemaCompatLayer({
52
+ modelId: mockModels.openai.modelId,
53
+ provider: mockModels.openai.provider,
54
+ });
49
55
  expect(compat.shouldApply()).toBe(false);
50
56
  });
51
57
 
52
58
  it('should return correct schema target', () => {
53
- const compat = new AnthropicSchemaCompatLayer(mockModels.anthropic);
59
+ const compat = new AnthropicSchemaCompatLayer({
60
+ modelId: mockModels.anthropic.modelId,
61
+ provider: mockModels.anthropic.provider,
62
+ });
54
63
  expect(compat.getSchemaTarget()).toBe('jsonSchema7');
55
64
  });
56
65
 
57
66
  it('should process schemas correctly', () => {
58
- const compat = new AnthropicSchemaCompatLayer(mockModels.anthropic);
67
+ const compat = new AnthropicSchemaCompatLayer({
68
+ modelId: mockModels.anthropic.modelId,
69
+ provider: mockModels.anthropic.provider,
70
+ });
59
71
  const schema = z.object({
60
72
  text: z.string().min(1).max(100),
61
73
  count: z.number().min(1),
@@ -79,17 +91,26 @@ describe('Provider Compatibility Classes', () => {
79
91
 
80
92
  describe('OpenAISchemaCompatLayer', () => {
81
93
  it('should apply for OpenAI models without structured outputs support', () => {
82
- const compat = new OpenAISchemaCompatLayer(mockModels.openai);
94
+ const compat = new OpenAISchemaCompatLayer({
95
+ modelId: mockModels.openai.modelId,
96
+ provider: mockModels.openai.provider,
97
+ });
83
98
  expect(compat.shouldApply()).toBe(true);
84
99
  });
85
100
 
86
101
  it('should return correct schema target', () => {
87
- const compat = new OpenAISchemaCompatLayer(mockModels.openai);
102
+ const compat = new OpenAISchemaCompatLayer({
103
+ modelId: mockModels.openai.modelId,
104
+ provider: mockModels.openai.provider,
105
+ });
88
106
  expect(compat.getSchemaTarget()).toBe('jsonSchema7');
89
107
  });
90
108
 
91
109
  it('should process complex schemas', () => {
92
- const compat = new OpenAISchemaCompatLayer(mockModels.openai);
110
+ const compat = new OpenAISchemaCompatLayer({
111
+ modelId: mockModels.openai.modelId,
112
+ provider: mockModels.openai.provider,
113
+ });
93
114
  const schema = z.object({
94
115
  user: z.object({
95
116
  name: z.string().email(),
@@ -122,29 +143,44 @@ describe('Provider Compatibility Classes', () => {
122
143
 
123
144
  describe('OpenAIReasoningSchemaCompatLayer', () => {
124
145
  it('should have consistent behavior', () => {
125
- const compat = new OpenAIReasoningSchemaCompatLayer(mockModels.openaiReasoning);
146
+ const compat = new OpenAIReasoningSchemaCompatLayer({
147
+ modelId: mockModels.openaiReasoning.modelId,
148
+ provider: mockModels.openaiReasoning.provider,
149
+ });
126
150
  expect(compat.shouldApply()).toBe(true);
127
151
  });
128
152
 
129
153
  it('should return correct schema target', () => {
130
- const compat = new OpenAIReasoningSchemaCompatLayer(mockModels.openaiReasoning);
154
+ const compat = new OpenAIReasoningSchemaCompatLayer({
155
+ modelId: mockModels.openaiReasoning.modelId,
156
+ provider: mockModels.openaiReasoning.provider,
157
+ });
131
158
  expect(compat.getSchemaTarget()).toBe('openApi3');
132
159
  });
133
160
  });
134
161
 
135
162
  describe('GoogleSchemaCompatLayer', () => {
136
163
  it('should have consistent behavior', () => {
137
- const compat = new GoogleSchemaCompatLayer(mockModels.google);
164
+ const compat = new GoogleSchemaCompatLayer({
165
+ modelId: mockModels.google.modelId,
166
+ provider: mockModels.google.provider,
167
+ });
138
168
  expect(typeof compat.shouldApply()).toBe('boolean');
139
169
  });
140
170
 
141
171
  it('should return correct schema target', () => {
142
- const compat = new GoogleSchemaCompatLayer(mockModels.google);
172
+ const compat = new GoogleSchemaCompatLayer({
173
+ modelId: mockModels.google.modelId,
174
+ provider: mockModels.google.provider,
175
+ });
143
176
  expect(compat.getSchemaTarget()).toBe('jsonSchema7');
144
177
  });
145
178
 
146
179
  it('should handle date types correctly', () => {
147
- const compat = new GoogleSchemaCompatLayer(mockModels.google);
180
+ const compat = new GoogleSchemaCompatLayer({
181
+ modelId: mockModels.google.modelId,
182
+ provider: mockModels.google.provider,
183
+ });
148
184
  const schema = z.object({
149
185
  startDate: z.date(),
150
186
  endDate: z.date().optional(),
@@ -169,22 +205,34 @@ describe('Provider Compatibility Classes', () => {
169
205
 
170
206
  describe('DeepSeekSchemaCompatLayer', () => {
171
207
  it('should apply for DeepSeek models', () => {
172
- const compat = new DeepSeekSchemaCompatLayer(mockModels.deepseek);
208
+ const compat = new DeepSeekSchemaCompatLayer({
209
+ modelId: mockModels.deepseek.modelId,
210
+ provider: mockModels.deepseek.provider,
211
+ });
173
212
  expect(compat.shouldApply()).toBe(true);
174
213
  });
175
214
 
176
215
  it('should not apply for non-DeepSeek models', () => {
177
- const compat = new DeepSeekSchemaCompatLayer(mockModels.openai);
216
+ const compat = new DeepSeekSchemaCompatLayer({
217
+ modelId: mockModels.openai.modelId,
218
+ provider: mockModels.openai.provider,
219
+ });
178
220
  expect(compat.shouldApply()).toBe(false);
179
221
  });
180
222
 
181
223
  it('should return correct schema target', () => {
182
- const compat = new DeepSeekSchemaCompatLayer(mockModels.deepseek);
224
+ const compat = new DeepSeekSchemaCompatLayer({
225
+ modelId: mockModels.deepseek.modelId,
226
+ provider: mockModels.deepseek.provider,
227
+ });
183
228
  expect(compat.getSchemaTarget()).toBe('jsonSchema7');
184
229
  });
185
230
 
186
231
  it('should handle string constraints', () => {
187
- const compat = new DeepSeekSchemaCompatLayer(mockModels.deepseek);
232
+ const compat = new DeepSeekSchemaCompatLayer({
233
+ modelId: mockModels.deepseek.modelId,
234
+ provider: mockModels.deepseek.provider,
235
+ });
188
236
  const schema = z.object({
189
237
  email: z.string().email(),
190
238
  url: z.string().url(),
@@ -212,17 +260,26 @@ describe('Provider Compatibility Classes', () => {
212
260
 
213
261
  describe('MetaSchemaCompatLayer', () => {
214
262
  it('should have consistent behavior', () => {
215
- const compat = new MetaSchemaCompatLayer(mockModels.meta);
263
+ const compat = new MetaSchemaCompatLayer({
264
+ modelId: mockModels.meta.modelId,
265
+ provider: mockModels.meta.provider,
266
+ });
216
267
  expect(typeof compat.shouldApply()).toBe('boolean');
217
268
  });
218
269
 
219
270
  it('should return correct schema target', () => {
220
- const compat = new MetaSchemaCompatLayer(mockModels.meta);
271
+ const compat = new MetaSchemaCompatLayer({
272
+ modelId: mockModels.meta.modelId,
273
+ provider: mockModels.meta.provider,
274
+ });
221
275
  expect(compat.getSchemaTarget()).toBe('jsonSchema7');
222
276
  });
223
277
 
224
278
  it('should handle array and union types', () => {
225
- const compat = new MetaSchemaCompatLayer(mockModels.meta);
279
+ const compat = new MetaSchemaCompatLayer({
280
+ modelId: mockModels.meta.modelId,
281
+ provider: mockModels.meta.provider,
282
+ });
226
283
  const schema = z.object({
227
284
  tags: z.array(z.string()).min(1).max(10),
228
285
  status: z.union([z.literal('active'), z.literal('inactive')]),
@@ -271,12 +328,26 @@ describe('Provider Compatibility Classes', () => {
271
328
  });
272
329
 
273
330
  const providers = [
274
- new AnthropicSchemaCompatLayer(mockModels.anthropic),
275
- new OpenAISchemaCompatLayer(mockModels.openai),
276
- new OpenAIReasoningSchemaCompatLayer(mockModels.openaiReasoning),
277
- new GoogleSchemaCompatLayer(mockModels.google),
278
- new DeepSeekSchemaCompatLayer(mockModels.deepseek),
279
- new MetaSchemaCompatLayer(mockModels.meta),
331
+ new AnthropicSchemaCompatLayer({
332
+ modelId: mockModels.anthropic.modelId,
333
+ provider: mockModels.anthropic.provider,
334
+ }),
335
+ new OpenAISchemaCompatLayer({
336
+ modelId: mockModels.openai.modelId,
337
+ provider: mockModels.openai.provider,
338
+ }),
339
+ new OpenAIReasoningSchemaCompatLayer({
340
+ modelId: mockModels.openaiReasoning.modelId,
341
+ provider: mockModels.openaiReasoning.provider,
342
+ }),
343
+ new GoogleSchemaCompatLayer({
344
+ modelId: mockModels.google.modelId,
345
+ provider: mockModels.google.provider,
346
+ }),
347
+ new MetaSchemaCompatLayer({
348
+ modelId: mockModels.meta.modelId,
349
+ provider: mockModels.meta.provider,
350
+ }),
280
351
  ];
281
352
 
282
353
  providers.forEach(provider => {
@@ -1,11 +1,11 @@
1
1
  import { MockLanguageModelV2 } from 'ai/test';
2
2
  import { describe, it, expect, beforeEach } from 'vitest';
3
3
  import { z } from 'zod';
4
- import type { SchemaCompatModel } from './schema-compatibility';
4
+ import type { ModelInformation } from './schema-compatibility';
5
5
  import { isArr, isObj, isOptional, isString, isUnion, SchemaCompatLayer } from './schema-compatibility';
6
6
 
7
7
  class MockSchemaCompatibility extends SchemaCompatLayer {
8
- constructor(model: SchemaCompatModel) {
8
+ constructor(model: ModelInformation) {
9
9
  super(model);
10
10
  }
11
11
 
@@ -44,12 +44,18 @@ describe('SchemaCompatLayer', () => {
44
44
  let compatibility: MockSchemaCompatibility;
45
45
 
46
46
  beforeEach(() => {
47
- compatibility = new MockSchemaCompatibility(mockModel);
47
+ compatibility = new MockSchemaCompatibility({
48
+ modelId: mockModel.modelId,
49
+ provider: mockModel.provider,
50
+ });
48
51
  });
49
52
 
50
53
  describe('constructor and getModel', () => {
51
54
  it('should store and return the model', () => {
52
- expect(compatibility.getModel()).toBe(mockModel);
55
+ expect(compatibility.getModel()).toEqual({
56
+ modelId: mockModel.modelId,
57
+ provider: mockModel.provider,
58
+ });
53
59
  });
54
60
  });
55
61
 
@@ -350,7 +356,10 @@ describe('SchemaCompatLayer', () => {
350
356
  }
351
357
  }
352
358
 
353
- const testCompat = new TestCompatibility(mockModel);
359
+ const testCompat = new TestCompatibility({
360
+ modelId: mockModel.modelId,
361
+ provider: mockModel.provider,
362
+ });
354
363
  const result = testCompat.defaultZodOptionalHandler(optionalSchema);
355
364
 
356
365
  expect(result._def.typeName).toBe('ZodOptional');
@@ -401,7 +410,10 @@ describe('SchemaCompatLayer', () => {
401
410
  return super.processZodType(value);
402
411
  }
403
412
  }
404
- const preservingCompat = new PreservingMock(mockModel);
413
+ const preservingCompat = new PreservingMock({
414
+ modelId: mockModel.modelId,
415
+ provider: mockModel.provider,
416
+ });
405
417
  const preservingResult = preservingCompat.processToAISDKSchema(arraySchema);
406
418
  expect(preservingResult.jsonSchema.description).toBeUndefined();
407
419
  expect(
@@ -121,7 +121,7 @@ type StringConstraints = {
121
121
  uuid?: boolean;
122
122
  cuid?: boolean;
123
123
  emoji?: boolean;
124
- regex?: { pattern: string; flags?: string };
124
+ regex?: string;
125
125
  };
126
126
 
127
127
  type NumberConstraints = {
@@ -144,6 +144,11 @@ type DateConstraints = {
144
144
  dateFormat?: string;
145
145
  };
146
146
 
147
+ export type ModelInformation = {
148
+ modelId: string;
149
+ provider: string;
150
+ };
151
+
147
152
  /**
148
153
  * Abstract base class for creating schema compatibility layers for different AI model providers.
149
154
  *
@@ -184,14 +189,14 @@ type DateConstraints = {
184
189
  * ```
185
190
  */
186
191
  export abstract class SchemaCompatLayer {
187
- private model: SchemaCompatModel;
192
+ private model: ModelInformation;
188
193
 
189
194
  /**
190
195
  * Creates a new schema compatibility instance.
191
196
  *
192
197
  * @param model - The language model this compatibility layer applies to
193
198
  */
194
- constructor(model: SchemaCompatModel) {
199
+ constructor(model: ModelInformation) {
195
200
  this.model = model;
196
201
  }
197
202
 
@@ -200,7 +205,7 @@ export abstract class SchemaCompatLayer {
200
205
  *
201
206
  * @returns The language model instance
202
207
  */
203
- getModel(): SchemaCompatModel {
208
+ getModel(): ModelInformation {
204
209
  return this.model;
205
210
  }
206
211
 
@@ -394,10 +399,7 @@ export abstract class SchemaCompatLayer {
394
399
  if (handleChecks.includes(check.kind as StringCheckType)) {
395
400
  switch (check.kind) {
396
401
  case 'regex': {
397
- constraints.regex = {
398
- pattern: check.regex.source,
399
- flags: check.regex.flags,
400
- };
402
+ constraints.regex = `A string that must match the regex pattern: ${check.regex.source}, with flags: ${check.regex.flags}`;
401
403
  break;
402
404
  }
403
405
  case 'emoji': {
package/src/utils.test.ts CHANGED
@@ -3,7 +3,7 @@ import type { Schema } from 'ai';
3
3
  import { MockLanguageModelV2 } from 'ai/test';
4
4
  import { describe, it, expect, beforeEach, vi } from 'vitest';
5
5
  import { z } from 'zod';
6
- import type { SchemaCompatModel } from './schema-compatibility';
6
+ import type { ModelInformation } from './schema-compatibility';
7
7
  import { SchemaCompatLayer } from './schema-compatibility';
8
8
  import { convertZodSchemaToAISDKSchema, convertSchemaToZod, applyCompatLayer } from './utils';
9
9
 
@@ -13,7 +13,7 @@ const mockModel = new MockLanguageModelV2({
13
13
 
14
14
  class MockSchemaCompatibility extends SchemaCompatLayer {
15
15
  constructor(
16
- model: SchemaCompatModel,
16
+ model: ModelInformation,
17
17
  private shouldApplyValue: boolean = true,
18
18
  ) {
19
19
  super(model);
@@ -199,7 +199,10 @@ describe('Builder Functions', () => {
199
199
  let mockCompatibility: MockSchemaCompatibility;
200
200
 
201
201
  beforeEach(() => {
202
- mockCompatibility = new MockSchemaCompatibility(mockModel);
202
+ mockCompatibility = new MockSchemaCompatibility({
203
+ modelId: mockModel.modelId,
204
+ provider: mockModel.provider,
205
+ });
203
206
  });
204
207
 
205
208
  it('should process Zod object schema with compatibility', () => {
@@ -265,7 +268,13 @@ describe('Builder Functions', () => {
265
268
  });
266
269
 
267
270
  it('should return fallback when no compatibility applies', () => {
268
- const nonApplyingCompatibility = new MockSchemaCompatibility(mockModel, false);
271
+ const nonApplyingCompatibility = new MockSchemaCompatibility(
272
+ {
273
+ modelId: mockModel.modelId,
274
+ provider: mockModel.provider,
275
+ },
276
+ false,
277
+ );
269
278
  const zodSchema = z.object({
270
279
  name: z.string(),
271
280
  });
@@ -311,8 +320,20 @@ describe('Builder Functions', () => {
311
320
  });
312
321
 
313
322
  it('should handle complex schema with multiple compatLayers', () => {
314
- const compat1 = new MockSchemaCompatibility(mockModel, false);
315
- const compat2 = new MockSchemaCompatibility(mockModel, true);
323
+ const compat1 = new MockSchemaCompatibility(
324
+ {
325
+ modelId: mockModel.modelId,
326
+ provider: mockModel.provider,
327
+ },
328
+ false,
329
+ );
330
+ const compat2 = new MockSchemaCompatibility(
331
+ {
332
+ modelId: mockModel.modelId,
333
+ provider: mockModel.provider,
334
+ },
335
+ true,
336
+ );
316
337
 
317
338
  vi.spyOn(compat1, 'processZodType');
318
339
  vi.spyOn(compat2, 'processZodType');
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": ["./tsconfig.json", "../../tsconfig.build.json"],
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src"
6
+ },
7
+ "include": ["src/**/*"],
8
+ "exclude": ["node_modules", "**/*.test.ts", "src/**/*.mock.ts"]
9
+ }
package/tsconfig.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "extends": "../../tsconfig.node.json",
3
- "include": ["src/**/*"],
3
+ "include": ["src/**/*", "tsup.config.ts"],
4
4
  "exclude": ["node_modules", "**/*.test.ts"]
5
5
  }
package/tsup.config.ts ADDED
@@ -0,0 +1,17 @@
1
+ import { generateTypes } from '@internal/types-builder';
2
+ import { defineConfig } from 'tsup';
3
+
4
+ export default defineConfig({
5
+ entry: ['src/index.ts'],
6
+ format: ['esm', 'cjs'],
7
+ clean: true,
8
+ dts: false,
9
+ splitting: true,
10
+ treeshake: {
11
+ preset: 'smallest',
12
+ },
13
+ sourcemap: true,
14
+ onSuccess: async () => {
15
+ await generateTypes(process.cwd());
16
+ },
17
+ });