@ank1015/providers 0.0.1
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/README.md +453 -0
- package/biome.json +43 -0
- package/dist/agent/agent-loop.d.ts +5 -0
- package/dist/agent/agent-loop.d.ts.map +1 -0
- package/dist/agent/agent-loop.js +219 -0
- package/dist/agent/agent-loop.js.map +1 -0
- package/dist/agent/types.d.ts +67 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +3 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/models.d.ts +3 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.generated.d.ts +247 -0
- package/dist/models.generated.d.ts.map +1 -0
- package/dist/models.generated.js +315 -0
- package/dist/models.generated.js.map +1 -0
- package/dist/models.js +41 -0
- package/dist/models.js.map +1 -0
- package/dist/providers/convert.d.ts +6 -0
- package/dist/providers/convert.d.ts.map +1 -0
- package/dist/providers/convert.js +207 -0
- package/dist/providers/convert.js.map +1 -0
- package/dist/providers/google.d.ts +26 -0
- package/dist/providers/google.d.ts.map +1 -0
- package/dist/providers/google.js +434 -0
- package/dist/providers/google.js.map +1 -0
- package/dist/providers/openai.d.ts +17 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +396 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/stream.d.ts +4 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +40 -0
- package/dist/stream.js.map +1 -0
- package/dist/test-google-agent-loop.d.ts +2 -0
- package/dist/test-google-agent-loop.d.ts.map +1 -0
- package/dist/test-google-agent-loop.js +186 -0
- package/dist/test-google-agent-loop.js.map +1 -0
- package/dist/test-google.d.ts +2 -0
- package/dist/test-google.d.ts.map +1 -0
- package/dist/test-google.js +41 -0
- package/dist/test-google.js.map +1 -0
- package/dist/types.d.ts +187 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/event-stream.d.ts +16 -0
- package/dist/utils/event-stream.d.ts.map +1 -0
- package/dist/utils/event-stream.js +61 -0
- package/dist/utils/event-stream.js.map +1 -0
- package/dist/utils/json-parse.d.ts +9 -0
- package/dist/utils/json-parse.d.ts.map +1 -0
- package/dist/utils/json-parse.js +32 -0
- package/dist/utils/json-parse.js.map +1 -0
- package/dist/utils/sanitize-unicode.d.ts +22 -0
- package/dist/utils/sanitize-unicode.d.ts.map +1 -0
- package/dist/utils/sanitize-unicode.js +29 -0
- package/dist/utils/sanitize-unicode.js.map +1 -0
- package/dist/utils/validation.d.ts +11 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +61 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +33 -0
- package/src/agent/agent-loop.ts +275 -0
- package/src/agent/types.ts +80 -0
- package/src/index.ts +72 -0
- package/src/models.generated.ts +314 -0
- package/src/models.ts +45 -0
- package/src/providers/convert.ts +222 -0
- package/src/providers/google.ts +496 -0
- package/src/providers/openai.ts +437 -0
- package/src/stream.ts +60 -0
- package/src/types.ts +198 -0
- package/src/utils/event-stream.ts +60 -0
- package/src/utils/json-parse.ts +28 -0
- package/src/utils/sanitize-unicode.ts +25 -0
- package/src/utils/validation.ts +69 -0
- package/test/core/agent-loop.test.ts +958 -0
- package/test/core/stream.test.ts +409 -0
- package/test/data/red-circle.png +0 -0
- package/test/data/superintelligentwill.pdf +0 -0
- package/test/edge-cases/general.test.ts +565 -0
- package/test/integration/e2e.test.ts +530 -0
- package/test/models/cost.test.ts +499 -0
- package/test/models/registry.test.ts +298 -0
- package/test/providers/convert.test.ts +846 -0
- package/test/providers/google-schema.test.ts +666 -0
- package/test/providers/google-stream.test.ts +369 -0
- package/test/providers/openai-stream.test.ts +251 -0
- package/test/utils/event-stream.test.ts +289 -0
- package/test/utils/json-parse.test.ts +344 -0
- package/test/utils/sanitize-unicode.test.ts +329 -0
- package/test/utils/validation.test.ts +614 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +9 -0
|
@@ -0,0 +1,666 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { Type } from '@sinclair/typebox';
|
|
3
|
+
|
|
4
|
+
// We'll test this by importing the google provider and using its internal logic
|
|
5
|
+
// Since transformSchemaForGoogle is not exported, we'll test through the tool conversion
|
|
6
|
+
// For now, let's create a standalone copy to test
|
|
7
|
+
function transformSchemaForGoogle(schema: any): any {
|
|
8
|
+
if (!schema || typeof schema !== 'object') {
|
|
9
|
+
return schema;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Handle arrays
|
|
13
|
+
if (Array.isArray(schema)) {
|
|
14
|
+
return schema.map(transformSchemaForGoogle);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const transformed: any = {};
|
|
18
|
+
|
|
19
|
+
// Handle const keyword - convert to enum
|
|
20
|
+
if ('const' in schema) {
|
|
21
|
+
transformed.enum = [schema.const];
|
|
22
|
+
// Copy over other properties except const
|
|
23
|
+
for (const key in schema) {
|
|
24
|
+
if (key !== 'const') {
|
|
25
|
+
transformed[key] = schema[key];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return transformed;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Handle anyOf with const values - convert to enum
|
|
32
|
+
if ('anyOf' in schema && Array.isArray(schema.anyOf) && schema.anyOf.length > 0) {
|
|
33
|
+
const allConst = schema.anyOf.every((item: any) => item && typeof item === 'object' && 'const' in item);
|
|
34
|
+
if (allConst) {
|
|
35
|
+
// Extract all const values into a single enum
|
|
36
|
+
transformed.enum = schema.anyOf.map((item: any) => item.const);
|
|
37
|
+
// Copy over other properties from the parent schema
|
|
38
|
+
for (const key in schema) {
|
|
39
|
+
if (key !== 'anyOf') {
|
|
40
|
+
transformed[key] = schema[key];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Copy type and other properties from the first anyOf item if not already set
|
|
44
|
+
if (schema.anyOf.length > 0) {
|
|
45
|
+
const firstItem = schema.anyOf[0];
|
|
46
|
+
for (const key in firstItem) {
|
|
47
|
+
if (key !== 'const' && !(key in transformed)) {
|
|
48
|
+
transformed[key] = firstItem[key];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return transformed;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Recursively process all properties
|
|
57
|
+
for (const key in schema) {
|
|
58
|
+
if (key === 'properties' && typeof schema.properties === 'object') {
|
|
59
|
+
// Recursively transform each property
|
|
60
|
+
transformed.properties = {};
|
|
61
|
+
for (const propKey in schema.properties) {
|
|
62
|
+
transformed.properties[propKey] = transformSchemaForGoogle(schema.properties[propKey]);
|
|
63
|
+
}
|
|
64
|
+
} else if (key === 'items' && schema.items) {
|
|
65
|
+
// Recursively transform array items schema
|
|
66
|
+
transformed.items = transformSchemaForGoogle(schema.items);
|
|
67
|
+
} else if (key === 'anyOf' || key === 'oneOf' || key === 'allOf') {
|
|
68
|
+
// Recursively transform union/intersection schemas
|
|
69
|
+
transformed[key] = Array.isArray(schema[key])
|
|
70
|
+
? schema[key].map(transformSchemaForGoogle)
|
|
71
|
+
: transformSchemaForGoogle(schema[key]);
|
|
72
|
+
} else {
|
|
73
|
+
// Copy other properties as-is
|
|
74
|
+
transformed[key] = schema[key];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return transformed;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
describe('transformSchemaForGoogle', () => {
|
|
82
|
+
describe('const to enum conversion', () => {
|
|
83
|
+
it('should convert const to enum with single value', () => {
|
|
84
|
+
const schema = {
|
|
85
|
+
type: 'string',
|
|
86
|
+
const: 'active',
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const result = transformSchemaForGoogle(schema);
|
|
90
|
+
|
|
91
|
+
expect(result).toEqual({
|
|
92
|
+
type: 'string',
|
|
93
|
+
enum: ['active'],
|
|
94
|
+
});
|
|
95
|
+
expect(result).not.toHaveProperty('const');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should convert const number to enum', () => {
|
|
99
|
+
const schema = {
|
|
100
|
+
type: 'number',
|
|
101
|
+
const: 42,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const result = transformSchemaForGoogle(schema);
|
|
105
|
+
|
|
106
|
+
expect(result).toEqual({
|
|
107
|
+
type: 'number',
|
|
108
|
+
enum: [42],
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should convert const boolean to enum', () => {
|
|
113
|
+
const schema = {
|
|
114
|
+
type: 'boolean',
|
|
115
|
+
const: true,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const result = transformSchemaForGoogle(schema);
|
|
119
|
+
|
|
120
|
+
expect(result).toEqual({
|
|
121
|
+
type: 'boolean',
|
|
122
|
+
enum: [true],
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('should preserve other properties when converting const', () => {
|
|
127
|
+
const schema = {
|
|
128
|
+
type: 'string',
|
|
129
|
+
const: 'value',
|
|
130
|
+
description: 'A constant value',
|
|
131
|
+
title: 'Constant Field',
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const result = transformSchemaForGoogle(schema);
|
|
135
|
+
|
|
136
|
+
expect(result).toEqual({
|
|
137
|
+
type: 'string',
|
|
138
|
+
enum: ['value'],
|
|
139
|
+
description: 'A constant value',
|
|
140
|
+
title: 'Constant Field',
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe('anyOf with const values to enum conversion', () => {
|
|
146
|
+
it('should convert anyOf with const values to enum', () => {
|
|
147
|
+
const schema = {
|
|
148
|
+
anyOf: [
|
|
149
|
+
{ const: 'active' },
|
|
150
|
+
{ const: 'inactive' },
|
|
151
|
+
{ const: 'pending' },
|
|
152
|
+
],
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const result = transformSchemaForGoogle(schema);
|
|
156
|
+
|
|
157
|
+
expect(result).toEqual({
|
|
158
|
+
enum: ['active', 'inactive', 'pending'],
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('should convert anyOf with const and type to enum with type', () => {
|
|
163
|
+
const schema = {
|
|
164
|
+
anyOf: [
|
|
165
|
+
{ type: 'string', const: 'red' },
|
|
166
|
+
{ type: 'string', const: 'green' },
|
|
167
|
+
{ type: 'string', const: 'blue' },
|
|
168
|
+
],
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const result = transformSchemaForGoogle(schema);
|
|
172
|
+
|
|
173
|
+
expect(result).toEqual({
|
|
174
|
+
type: 'string',
|
|
175
|
+
enum: ['red', 'green', 'blue'],
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('should preserve parent schema properties', () => {
|
|
180
|
+
const schema = {
|
|
181
|
+
description: 'Status field',
|
|
182
|
+
anyOf: [
|
|
183
|
+
{ const: 'active' },
|
|
184
|
+
{ const: 'inactive' },
|
|
185
|
+
],
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const result = transformSchemaForGoogle(schema);
|
|
189
|
+
|
|
190
|
+
expect(result).toEqual({
|
|
191
|
+
description: 'Status field',
|
|
192
|
+
enum: ['active', 'inactive'],
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('should not convert anyOf without all const values', () => {
|
|
197
|
+
const schema = {
|
|
198
|
+
anyOf: [
|
|
199
|
+
{ const: 'active' },
|
|
200
|
+
{ type: 'number' }, // Not a const
|
|
201
|
+
],
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const result = transformSchemaForGoogle(schema);
|
|
205
|
+
|
|
206
|
+
// Should recursively transform but not convert to enum
|
|
207
|
+
expect(result).toHaveProperty('anyOf');
|
|
208
|
+
expect(result.anyOf).toHaveLength(2);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it('should handle anyOf with mixed types in const values', () => {
|
|
212
|
+
const schema = {
|
|
213
|
+
anyOf: [
|
|
214
|
+
{ const: 'string_value' },
|
|
215
|
+
{ const: 42 },
|
|
216
|
+
{ const: true },
|
|
217
|
+
],
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const result = transformSchemaForGoogle(schema);
|
|
221
|
+
|
|
222
|
+
expect(result).toEqual({
|
|
223
|
+
enum: ['string_value', 42, true],
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
describe('Nested object transformation', () => {
|
|
229
|
+
it('should recursively transform nested object properties', () => {
|
|
230
|
+
const schema = {
|
|
231
|
+
type: 'object',
|
|
232
|
+
properties: {
|
|
233
|
+
status: {
|
|
234
|
+
const: 'active',
|
|
235
|
+
},
|
|
236
|
+
priority: {
|
|
237
|
+
anyOf: [
|
|
238
|
+
{ const: 'high' },
|
|
239
|
+
{ const: 'low' },
|
|
240
|
+
],
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
const result = transformSchemaForGoogle(schema);
|
|
246
|
+
|
|
247
|
+
expect(result.properties.status).toEqual({
|
|
248
|
+
enum: ['active'],
|
|
249
|
+
});
|
|
250
|
+
expect(result.properties.priority).toEqual({
|
|
251
|
+
enum: ['high', 'low'],
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('should handle deeply nested objects', () => {
|
|
256
|
+
const schema = {
|
|
257
|
+
type: 'object',
|
|
258
|
+
properties: {
|
|
259
|
+
user: {
|
|
260
|
+
type: 'object',
|
|
261
|
+
properties: {
|
|
262
|
+
role: {
|
|
263
|
+
const: 'admin',
|
|
264
|
+
},
|
|
265
|
+
permissions: {
|
|
266
|
+
type: 'object',
|
|
267
|
+
properties: {
|
|
268
|
+
level: {
|
|
269
|
+
anyOf: [
|
|
270
|
+
{ const: 'read' },
|
|
271
|
+
{ const: 'write' },
|
|
272
|
+
],
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
const result = transformSchemaForGoogle(schema);
|
|
282
|
+
|
|
283
|
+
expect(result.properties.user.properties.role).toEqual({
|
|
284
|
+
enum: ['admin'],
|
|
285
|
+
});
|
|
286
|
+
expect(result.properties.user.properties.permissions.properties.level).toEqual({
|
|
287
|
+
enum: ['read', 'write'],
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it('should preserve non-const properties unchanged', () => {
|
|
292
|
+
const schema = {
|
|
293
|
+
type: 'object',
|
|
294
|
+
properties: {
|
|
295
|
+
name: {
|
|
296
|
+
type: 'string',
|
|
297
|
+
minLength: 1,
|
|
298
|
+
maxLength: 100,
|
|
299
|
+
},
|
|
300
|
+
status: {
|
|
301
|
+
const: 'active',
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const result = transformSchemaForGoogle(schema);
|
|
307
|
+
|
|
308
|
+
expect(result.properties.name).toEqual({
|
|
309
|
+
type: 'string',
|
|
310
|
+
minLength: 1,
|
|
311
|
+
maxLength: 100,
|
|
312
|
+
});
|
|
313
|
+
expect(result.properties.status).toEqual({
|
|
314
|
+
enum: ['active'],
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
describe('Array items transformation', () => {
|
|
320
|
+
it('should recursively transform array items schema', () => {
|
|
321
|
+
const schema = {
|
|
322
|
+
type: 'array',
|
|
323
|
+
items: {
|
|
324
|
+
const: 'option',
|
|
325
|
+
},
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
const result = transformSchemaForGoogle(schema);
|
|
329
|
+
|
|
330
|
+
expect(result).toEqual({
|
|
331
|
+
type: 'array',
|
|
332
|
+
items: {
|
|
333
|
+
enum: ['option'],
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it('should handle array of objects with const fields', () => {
|
|
339
|
+
const schema = {
|
|
340
|
+
type: 'array',
|
|
341
|
+
items: {
|
|
342
|
+
type: 'object',
|
|
343
|
+
properties: {
|
|
344
|
+
type: {
|
|
345
|
+
const: 'item',
|
|
346
|
+
},
|
|
347
|
+
value: {
|
|
348
|
+
type: 'string',
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
const result = transformSchemaForGoogle(schema);
|
|
355
|
+
|
|
356
|
+
expect(result.items.properties.type).toEqual({
|
|
357
|
+
enum: ['item'],
|
|
358
|
+
});
|
|
359
|
+
expect(result.items.properties.value).toEqual({
|
|
360
|
+
type: 'string',
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
it('should handle array items with anyOf', () => {
|
|
365
|
+
const schema = {
|
|
366
|
+
type: 'array',
|
|
367
|
+
items: {
|
|
368
|
+
anyOf: [
|
|
369
|
+
{ const: 'a' },
|
|
370
|
+
{ const: 'b' },
|
|
371
|
+
],
|
|
372
|
+
},
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
const result = transformSchemaForGoogle(schema);
|
|
376
|
+
|
|
377
|
+
expect(result.items).toEqual({
|
|
378
|
+
enum: ['a', 'b'],
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
describe('Complex union transformations', () => {
|
|
384
|
+
it('should recursively transform anyOf schemas', () => {
|
|
385
|
+
const schema = {
|
|
386
|
+
anyOf: [
|
|
387
|
+
{
|
|
388
|
+
type: 'object',
|
|
389
|
+
properties: {
|
|
390
|
+
mode: { const: 'auto' },
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
type: 'object',
|
|
395
|
+
properties: {
|
|
396
|
+
mode: { const: 'manual' },
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
],
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
const result = transformSchemaForGoogle(schema);
|
|
403
|
+
|
|
404
|
+
expect(result.anyOf[0].properties.mode).toEqual({ enum: ['auto'] });
|
|
405
|
+
expect(result.anyOf[1].properties.mode).toEqual({ enum: ['manual'] });
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it('should recursively transform oneOf schemas', () => {
|
|
409
|
+
const schema = {
|
|
410
|
+
oneOf: [
|
|
411
|
+
{ const: 'option1' },
|
|
412
|
+
{ const: 'option2' },
|
|
413
|
+
],
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
const result = transformSchemaForGoogle(schema);
|
|
417
|
+
|
|
418
|
+
expect(result.oneOf).toEqual([
|
|
419
|
+
{ enum: ['option1'] },
|
|
420
|
+
{ enum: ['option2'] },
|
|
421
|
+
]);
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
it('should recursively transform allOf schemas', () => {
|
|
425
|
+
const schema = {
|
|
426
|
+
allOf: [
|
|
427
|
+
{
|
|
428
|
+
type: 'object',
|
|
429
|
+
properties: {
|
|
430
|
+
status: { const: 'active' },
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
],
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
const result = transformSchemaForGoogle(schema);
|
|
437
|
+
|
|
438
|
+
expect(result.allOf[0].properties.status).toEqual({ enum: ['active'] });
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
describe('TypeBox schema transformation', () => {
|
|
443
|
+
it('should transform TypeBox Literal to enum', () => {
|
|
444
|
+
const schema = Type.Literal('active');
|
|
445
|
+
|
|
446
|
+
const result = transformSchemaForGoogle(schema);
|
|
447
|
+
|
|
448
|
+
expect(result).toMatchObject({
|
|
449
|
+
enum: ['active'],
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
it('should transform TypeBox Union with Literals', () => {
|
|
454
|
+
const schema = Type.Union([
|
|
455
|
+
Type.Literal('active'),
|
|
456
|
+
Type.Literal('inactive'),
|
|
457
|
+
Type.Literal('pending'),
|
|
458
|
+
]);
|
|
459
|
+
|
|
460
|
+
const result = transformSchemaForGoogle(schema);
|
|
461
|
+
|
|
462
|
+
expect(result).toMatchObject({
|
|
463
|
+
enum: ['active', 'inactive', 'pending'],
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
it('should transform TypeBox Object with Literal properties', () => {
|
|
468
|
+
const schema = Type.Object({
|
|
469
|
+
status: Type.Literal('active'),
|
|
470
|
+
type: Type.Literal('user'),
|
|
471
|
+
name: Type.String(),
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
const result = transformSchemaForGoogle(schema);
|
|
475
|
+
|
|
476
|
+
expect(result.properties.status).toMatchObject({ enum: ['active'] });
|
|
477
|
+
expect(result.properties.type).toMatchObject({ enum: ['user'] });
|
|
478
|
+
expect(result.properties.name.type).toBe('string');
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
describe('Edge cases', () => {
|
|
483
|
+
it('should handle null input', () => {
|
|
484
|
+
const result = transformSchemaForGoogle(null);
|
|
485
|
+
expect(result).toBeNull();
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
it('should handle undefined input', () => {
|
|
489
|
+
const result = transformSchemaForGoogle(undefined);
|
|
490
|
+
expect(result).toBeUndefined();
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
it('should handle primitive values', () => {
|
|
494
|
+
expect(transformSchemaForGoogle('string')).toBe('string');
|
|
495
|
+
expect(transformSchemaForGoogle(42)).toBe(42);
|
|
496
|
+
expect(transformSchemaForGoogle(true)).toBe(true);
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
it('should handle empty object', () => {
|
|
500
|
+
const result = transformSchemaForGoogle({});
|
|
501
|
+
expect(result).toEqual({});
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
it('should handle empty array', () => {
|
|
505
|
+
const result = transformSchemaForGoogle([]);
|
|
506
|
+
expect(result).toEqual([]);
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
it('should handle schema without const or anyOf', () => {
|
|
510
|
+
const schema = {
|
|
511
|
+
type: 'string',
|
|
512
|
+
minLength: 1,
|
|
513
|
+
maxLength: 100,
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
const result = transformSchemaForGoogle(schema);
|
|
517
|
+
|
|
518
|
+
expect(result).toEqual(schema);
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
it('should handle anyOf with empty array', () => {
|
|
522
|
+
const schema = {
|
|
523
|
+
anyOf: [],
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
const result = transformSchemaForGoogle(schema);
|
|
527
|
+
|
|
528
|
+
expect(result).toMatchObject({ anyOf: [] });
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
it('should handle const with null value', () => {
|
|
532
|
+
const schema = {
|
|
533
|
+
const: null,
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
const result = transformSchemaForGoogle(schema);
|
|
537
|
+
|
|
538
|
+
expect(result).toEqual({
|
|
539
|
+
enum: [null],
|
|
540
|
+
});
|
|
541
|
+
});
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
describe('Real-world tool schemas', () => {
|
|
545
|
+
it('should transform calculator tool schema', () => {
|
|
546
|
+
const schema = {
|
|
547
|
+
type: 'object',
|
|
548
|
+
properties: {
|
|
549
|
+
expression: {
|
|
550
|
+
type: 'string',
|
|
551
|
+
description: 'Mathematical expression to evaluate',
|
|
552
|
+
},
|
|
553
|
+
format: {
|
|
554
|
+
anyOf: [
|
|
555
|
+
{ const: 'decimal' },
|
|
556
|
+
{ const: 'fraction' },
|
|
557
|
+
{ const: 'scientific' },
|
|
558
|
+
],
|
|
559
|
+
description: 'Output format',
|
|
560
|
+
},
|
|
561
|
+
},
|
|
562
|
+
required: ['expression'],
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
const result = transformSchemaForGoogle(schema);
|
|
566
|
+
|
|
567
|
+
expect(result.properties.expression.type).toBe('string');
|
|
568
|
+
expect(result.properties.format).toEqual({
|
|
569
|
+
enum: ['decimal', 'fraction', 'scientific'],
|
|
570
|
+
description: 'Output format',
|
|
571
|
+
});
|
|
572
|
+
expect(result.required).toEqual(['expression']);
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
it('should transform search tool schema with filters', () => {
|
|
576
|
+
const schema = {
|
|
577
|
+
type: 'object',
|
|
578
|
+
properties: {
|
|
579
|
+
query: {
|
|
580
|
+
type: 'string',
|
|
581
|
+
},
|
|
582
|
+
filters: {
|
|
583
|
+
type: 'object',
|
|
584
|
+
properties: {
|
|
585
|
+
category: {
|
|
586
|
+
anyOf: [
|
|
587
|
+
{ const: 'tech' },
|
|
588
|
+
{ const: 'science' },
|
|
589
|
+
{ const: 'art' },
|
|
590
|
+
],
|
|
591
|
+
},
|
|
592
|
+
sort: {
|
|
593
|
+
const: 'relevance',
|
|
594
|
+
},
|
|
595
|
+
},
|
|
596
|
+
},
|
|
597
|
+
},
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
const result = transformSchemaForGoogle(schema);
|
|
601
|
+
|
|
602
|
+
expect(result.properties.filters.properties.category).toEqual({
|
|
603
|
+
enum: ['tech', 'science', 'art'],
|
|
604
|
+
});
|
|
605
|
+
expect(result.properties.filters.properties.sort).toEqual({
|
|
606
|
+
enum: ['relevance'],
|
|
607
|
+
});
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
it('should transform complex nested tool schema', () => {
|
|
611
|
+
const schema = {
|
|
612
|
+
type: 'object',
|
|
613
|
+
properties: {
|
|
614
|
+
action: {
|
|
615
|
+
anyOf: [
|
|
616
|
+
{ const: 'create' },
|
|
617
|
+
{ const: 'update' },
|
|
618
|
+
{ const: 'delete' },
|
|
619
|
+
],
|
|
620
|
+
},
|
|
621
|
+
data: {
|
|
622
|
+
type: 'object',
|
|
623
|
+
properties: {
|
|
624
|
+
items: {
|
|
625
|
+
type: 'array',
|
|
626
|
+
items: {
|
|
627
|
+
type: 'object',
|
|
628
|
+
properties: {
|
|
629
|
+
status: {
|
|
630
|
+
const: 'pending',
|
|
631
|
+
},
|
|
632
|
+
},
|
|
633
|
+
},
|
|
634
|
+
},
|
|
635
|
+
},
|
|
636
|
+
},
|
|
637
|
+
},
|
|
638
|
+
};
|
|
639
|
+
|
|
640
|
+
const result = transformSchemaForGoogle(schema);
|
|
641
|
+
|
|
642
|
+
expect(result.properties.action).toEqual({
|
|
643
|
+
enum: ['create', 'update', 'delete'],
|
|
644
|
+
});
|
|
645
|
+
expect(result.properties.data.properties.items.items.properties.status).toEqual({
|
|
646
|
+
enum: ['pending'],
|
|
647
|
+
});
|
|
648
|
+
});
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
describe('Array schema handling', () => {
|
|
652
|
+
it('should transform array of schemas', () => {
|
|
653
|
+
const schemas = [
|
|
654
|
+
{ const: 'a' },
|
|
655
|
+
{ const: 'b' },
|
|
656
|
+
{ type: 'string' },
|
|
657
|
+
];
|
|
658
|
+
|
|
659
|
+
const result = transformSchemaForGoogle(schemas);
|
|
660
|
+
|
|
661
|
+
expect(result[0]).toEqual({ enum: ['a'] });
|
|
662
|
+
expect(result[1]).toEqual({ enum: ['b'] });
|
|
663
|
+
expect(result[2]).toEqual({ type: 'string' });
|
|
664
|
+
});
|
|
665
|
+
});
|
|
666
|
+
});
|