@ai-sdk/google 3.0.110 → 3.0.111
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/CHANGELOG.md +6 -0
- package/dist/index.js +115 -25
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +110 -18
- package/dist/index.mjs.map +1 -1
- package/dist/internal/index.js +107 -17
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/index.mjs +109 -17
- package/dist/internal/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/convert-json-schema-to-openapi-schema.ts +175 -15
package/package.json
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
UnsupportedFunctionalityError,
|
|
3
|
+
type JSONSchema7,
|
|
4
|
+
type JSONSchema7Definition,
|
|
5
|
+
} from '@ai-sdk/provider';
|
|
6
|
+
|
|
7
|
+
type JSONSchema7WithDefinitions = JSONSchema7 & {
|
|
8
|
+
$defs?: Record<string, JSONSchema7Definition>;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type ReferenceContext = {
|
|
12
|
+
definitions: Record<string, JSONSchema7Definition> | undefined;
|
|
13
|
+
dollarDefinitions: Record<string, JSONSchema7Definition> | undefined;
|
|
14
|
+
resolvingReferences: ReadonlySet<string>;
|
|
15
|
+
};
|
|
2
16
|
|
|
3
17
|
/**
|
|
4
18
|
* Converts JSON Schema 7 to OpenAPI Schema 3.0
|
|
@@ -7,26 +21,52 @@ export function convertJSONSchemaToOpenAPISchema(
|
|
|
7
21
|
jsonSchema: JSONSchema7Definition | undefined,
|
|
8
22
|
isRoot = true,
|
|
9
23
|
): unknown {
|
|
10
|
-
|
|
24
|
+
const rootSchema =
|
|
25
|
+
typeof jsonSchema === 'object'
|
|
26
|
+
? (jsonSchema as JSONSchema7WithDefinitions)
|
|
27
|
+
: undefined;
|
|
28
|
+
|
|
29
|
+
return convertJSONSchemaDefinition(jsonSchema, isRoot, {
|
|
30
|
+
definitions: rootSchema?.definitions,
|
|
31
|
+
dollarDefinitions: rootSchema?.$defs,
|
|
32
|
+
resolvingReferences: new Set(),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function convertJSONSchemaDefinition(
|
|
37
|
+
jsonSchema: JSONSchema7Definition | undefined,
|
|
38
|
+
isRoot: boolean,
|
|
39
|
+
referenceContext: ReferenceContext,
|
|
40
|
+
): unknown {
|
|
11
41
|
if (jsonSchema == null) {
|
|
12
42
|
return undefined;
|
|
13
43
|
}
|
|
14
44
|
|
|
45
|
+
if (typeof jsonSchema === 'boolean') {
|
|
46
|
+
return { type: 'boolean', properties: {} };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (jsonSchema.$ref != null) {
|
|
50
|
+
return convertJSONSchemaReference({
|
|
51
|
+
jsonSchema,
|
|
52
|
+
reference: jsonSchema.$ref,
|
|
53
|
+
isRoot,
|
|
54
|
+
referenceContext,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Handle empty object schemas: undefined at root, preserved when nested
|
|
15
59
|
if (isEmptyObjectSchema(jsonSchema)) {
|
|
16
60
|
if (isRoot) {
|
|
17
61
|
return undefined;
|
|
18
62
|
}
|
|
19
63
|
|
|
20
|
-
if (
|
|
64
|
+
if (jsonSchema.description) {
|
|
21
65
|
return { type: 'object', description: jsonSchema.description };
|
|
22
66
|
}
|
|
23
67
|
return { type: 'object' };
|
|
24
68
|
}
|
|
25
69
|
|
|
26
|
-
if (typeof jsonSchema === 'boolean') {
|
|
27
|
-
return { type: 'boolean', properties: {} };
|
|
28
|
-
}
|
|
29
|
-
|
|
30
70
|
const {
|
|
31
71
|
type,
|
|
32
72
|
description,
|
|
@@ -81,7 +121,7 @@ export function convertJSONSchemaToOpenAPISchema(
|
|
|
81
121
|
if (properties != null) {
|
|
82
122
|
result.properties = Object.entries(properties).reduce(
|
|
83
123
|
(acc, [key, value]) => {
|
|
84
|
-
acc[key] =
|
|
124
|
+
acc[key] = convertJSONSchemaDefinition(value, false, referenceContext);
|
|
85
125
|
return acc;
|
|
86
126
|
},
|
|
87
127
|
{} as Record<string, unknown>,
|
|
@@ -90,13 +130,15 @@ export function convertJSONSchemaToOpenAPISchema(
|
|
|
90
130
|
|
|
91
131
|
if (items) {
|
|
92
132
|
result.items = Array.isArray(items)
|
|
93
|
-
? items.map(item =>
|
|
94
|
-
|
|
133
|
+
? items.map(item =>
|
|
134
|
+
convertJSONSchemaDefinition(item, false, referenceContext),
|
|
135
|
+
)
|
|
136
|
+
: convertJSONSchemaDefinition(items, false, referenceContext);
|
|
95
137
|
}
|
|
96
138
|
|
|
97
139
|
if (allOf) {
|
|
98
140
|
result.allOf = allOf.map(item =>
|
|
99
|
-
|
|
141
|
+
convertJSONSchemaDefinition(item, false, referenceContext),
|
|
100
142
|
);
|
|
101
143
|
}
|
|
102
144
|
if (anyOf) {
|
|
@@ -112,9 +154,10 @@ export function convertJSONSchemaToOpenAPISchema(
|
|
|
112
154
|
|
|
113
155
|
if (nonNullSchemas.length === 1) {
|
|
114
156
|
// If there's only one non-null schema, convert it and make it nullable
|
|
115
|
-
const converted =
|
|
157
|
+
const converted = convertJSONSchemaDefinition(
|
|
116
158
|
nonNullSchemas[0],
|
|
117
159
|
false,
|
|
160
|
+
referenceContext,
|
|
118
161
|
);
|
|
119
162
|
if (typeof converted === 'object') {
|
|
120
163
|
result.nullable = true;
|
|
@@ -123,19 +166,19 @@ export function convertJSONSchemaToOpenAPISchema(
|
|
|
123
166
|
} else {
|
|
124
167
|
// If there are multiple non-null schemas, keep them in anyOf
|
|
125
168
|
result.anyOf = nonNullSchemas.map(item =>
|
|
126
|
-
|
|
169
|
+
convertJSONSchemaDefinition(item, false, referenceContext),
|
|
127
170
|
);
|
|
128
171
|
result.nullable = true;
|
|
129
172
|
}
|
|
130
173
|
} else {
|
|
131
174
|
result.anyOf = anyOf.map(item =>
|
|
132
|
-
|
|
175
|
+
convertJSONSchemaDefinition(item, false, referenceContext),
|
|
133
176
|
);
|
|
134
177
|
}
|
|
135
178
|
}
|
|
136
179
|
if (oneOf) {
|
|
137
180
|
result.oneOf = oneOf.map(item =>
|
|
138
|
-
|
|
181
|
+
convertJSONSchemaDefinition(item, false, referenceContext),
|
|
139
182
|
);
|
|
140
183
|
}
|
|
141
184
|
|
|
@@ -146,6 +189,123 @@ export function convertJSONSchemaToOpenAPISchema(
|
|
|
146
189
|
return result;
|
|
147
190
|
}
|
|
148
191
|
|
|
192
|
+
function convertJSONSchemaReference({
|
|
193
|
+
jsonSchema,
|
|
194
|
+
reference,
|
|
195
|
+
isRoot,
|
|
196
|
+
referenceContext,
|
|
197
|
+
}: {
|
|
198
|
+
jsonSchema: JSONSchema7;
|
|
199
|
+
reference: string;
|
|
200
|
+
isRoot: boolean;
|
|
201
|
+
referenceContext: ReferenceContext;
|
|
202
|
+
}): unknown {
|
|
203
|
+
const { definition, referenceKey } = getReferencedDefinition(
|
|
204
|
+
reference,
|
|
205
|
+
referenceContext,
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
if (referenceContext.resolvingReferences.has(referenceKey)) {
|
|
209
|
+
throw new UnsupportedFunctionalityError({
|
|
210
|
+
functionality: `recursive JSON Schema reference: ${reference}`,
|
|
211
|
+
message:
|
|
212
|
+
'Google schema conversion does not support recursive JSON Schema references.',
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const resolvingReferences = new Set(referenceContext.resolvingReferences);
|
|
217
|
+
resolvingReferences.add(referenceKey);
|
|
218
|
+
|
|
219
|
+
// Inline references instead of emitting Google's `ref` / `defs` fields.
|
|
220
|
+
// Those fields are supported by Vertex AI's Schema representation but are
|
|
221
|
+
// rejected by the Gemini Developer API representation used by this shared
|
|
222
|
+
// converter.
|
|
223
|
+
const { $ref: _reference, ...siblingSchema } = jsonSchema;
|
|
224
|
+
const resolvedSchema =
|
|
225
|
+
typeof definition === 'boolean'
|
|
226
|
+
? definition
|
|
227
|
+
? siblingSchema
|
|
228
|
+
: false
|
|
229
|
+
: { ...definition, ...siblingSchema };
|
|
230
|
+
|
|
231
|
+
return convertJSONSchemaDefinition(resolvedSchema, isRoot, {
|
|
232
|
+
...referenceContext,
|
|
233
|
+
resolvingReferences,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function getReferencedDefinition(
|
|
238
|
+
reference: string,
|
|
239
|
+
referenceContext: ReferenceContext,
|
|
240
|
+
): {
|
|
241
|
+
definition: JSONSchema7Definition;
|
|
242
|
+
referenceKey: string;
|
|
243
|
+
} {
|
|
244
|
+
const definitionSources = [
|
|
245
|
+
{
|
|
246
|
+
prefix: '#/$defs/',
|
|
247
|
+
definitions: referenceContext.dollarDefinitions,
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
prefix: '#/definitions/',
|
|
251
|
+
definitions: referenceContext.definitions,
|
|
252
|
+
},
|
|
253
|
+
];
|
|
254
|
+
|
|
255
|
+
const source = definitionSources.find(({ prefix }) =>
|
|
256
|
+
reference.startsWith(prefix),
|
|
257
|
+
);
|
|
258
|
+
const encodedDefinitionName = source
|
|
259
|
+
? reference.slice(source.prefix.length)
|
|
260
|
+
: undefined;
|
|
261
|
+
|
|
262
|
+
if (
|
|
263
|
+
source == null ||
|
|
264
|
+
encodedDefinitionName == null ||
|
|
265
|
+
encodedDefinitionName.length === 0 ||
|
|
266
|
+
encodedDefinitionName.includes('/')
|
|
267
|
+
) {
|
|
268
|
+
throwUnsupportedReference(reference);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
let decodedDefinitionName: string;
|
|
272
|
+
try {
|
|
273
|
+
decodedDefinitionName = decodeURIComponent(encodedDefinitionName);
|
|
274
|
+
} catch {
|
|
275
|
+
throwUnsupportedReference(reference);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (
|
|
279
|
+
decodedDefinitionName.includes('/') ||
|
|
280
|
+
/~(?![01])/u.test(decodedDefinitionName) ||
|
|
281
|
+
source.definitions == null
|
|
282
|
+
) {
|
|
283
|
+
throwUnsupportedReference(reference);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const definitionName = decodedDefinitionName.replace(/~[01]/g, match =>
|
|
287
|
+
match === '~1' ? '/' : '~',
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
if (
|
|
291
|
+
!Object.prototype.hasOwnProperty.call(source.definitions, definitionName)
|
|
292
|
+
) {
|
|
293
|
+
throwUnsupportedReference(reference);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return {
|
|
297
|
+
definition: source.definitions[definitionName],
|
|
298
|
+
referenceKey: `${source.prefix}${definitionName}`,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function throwUnsupportedReference(reference: string): never {
|
|
303
|
+
throw new UnsupportedFunctionalityError({
|
|
304
|
+
functionality: `JSON Schema reference: ${reference}`,
|
|
305
|
+
message:
|
|
306
|
+
'Google schema conversion only supports references to direct children of root-level $defs or definitions.',
|
|
307
|
+
});
|
|
308
|
+
}
|
|
149
309
|
function isEmptyObjectSchema(jsonSchema: JSONSchema7Definition): boolean {
|
|
150
310
|
return (
|
|
151
311
|
jsonSchema != null &&
|