@aigne/openai 0.14.2 → 0.14.3
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
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.14.3](https://github.com/AIGNE-io/aigne-framework/compare/openai-v0.14.2...openai-v0.14.3) (2025-09-08)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* support optional field sturectured output for gemini ([#468](https://github.com/AIGNE-io/aigne-framework/issues/468)) ([70c6279](https://github.com/AIGNE-io/aigne-framework/commit/70c62795039a2862e3333f26707329489bf938de))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @aigne/core bumped to 1.58.3
|
|
16
|
+
* devDependencies
|
|
17
|
+
* @aigne/test-utils bumped to 0.5.47
|
|
18
|
+
|
|
3
19
|
## [0.14.2](https://github.com/AIGNE-io/aigne-framework/compare/openai-v0.14.1...openai-v0.14.2) (2025-09-05)
|
|
4
20
|
|
|
5
21
|
|
|
@@ -151,6 +151,13 @@ export declare class OpenAIChatModel extends ChatModel {
|
|
|
151
151
|
private getRunResponseFormat;
|
|
152
152
|
private requestStructuredOutput;
|
|
153
153
|
private extractResultFromStream;
|
|
154
|
+
/**
|
|
155
|
+
* Controls how optional fields are handled in JSON schema conversion
|
|
156
|
+
* - "anyOf": All fields are required but can be null (default)
|
|
157
|
+
* - "optional": Fields marked as optional in schema remain optional
|
|
158
|
+
*/
|
|
159
|
+
protected optionalFieldMode?: "anyOf" | "optional";
|
|
160
|
+
protected jsonSchemaToOpenAIJsonSchema(schema: Record<string, unknown>): Record<string, unknown>;
|
|
154
161
|
}
|
|
155
162
|
/**
|
|
156
163
|
* @hidden
|
|
@@ -162,7 +169,3 @@ export declare function contentsFromInputMessages(messages: ChatModelInputMessag
|
|
|
162
169
|
export declare function toolsFromInputTools(tools?: ChatModelInputTool[], options?: {
|
|
163
170
|
addTypeToEmptyParameters?: boolean;
|
|
164
171
|
}): ChatCompletionTool[] | undefined;
|
|
165
|
-
/**
|
|
166
|
-
* @hidden
|
|
167
|
-
*/
|
|
168
|
-
export declare function jsonSchemaToOpenAIJsonSchema(schema: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.OpenAIChatModel = exports.openAIChatModelOptionsSchema = void 0;
|
|
4
4
|
exports.contentsFromInputMessages = contentsFromInputMessages;
|
|
5
5
|
exports.toolsFromInputTools = toolsFromInputTools;
|
|
6
|
-
exports.jsonSchemaToOpenAIJsonSchema = jsonSchemaToOpenAIJsonSchema;
|
|
7
6
|
const core_1 = require("@aigne/core");
|
|
8
7
|
const logger_js_1 = require("@aigne/core/utils/logger.js");
|
|
9
8
|
const model_utils_js_1 = require("@aigne/core/utils/model-utils.js");
|
|
@@ -196,7 +195,7 @@ class OpenAIChatModel extends core_1.ChatModel {
|
|
|
196
195
|
type: "json_schema",
|
|
197
196
|
json_schema: {
|
|
198
197
|
...input.responseFormat.jsonSchema,
|
|
199
|
-
schema: jsonSchemaToOpenAIJsonSchema(input.responseFormat.jsonSchema.schema),
|
|
198
|
+
schema: this.jsonSchemaToOpenAIJsonSchema(input.responseFormat.jsonSchema.schema),
|
|
200
199
|
},
|
|
201
200
|
},
|
|
202
201
|
};
|
|
@@ -312,6 +311,40 @@ class OpenAIChatModel extends core_1.ChatModel {
|
|
|
312
311
|
});
|
|
313
312
|
return streaming ? result : await (0, stream_utils_js_1.agentResponseStreamToObject)(result);
|
|
314
313
|
}
|
|
314
|
+
/**
|
|
315
|
+
* Controls how optional fields are handled in JSON schema conversion
|
|
316
|
+
* - "anyOf": All fields are required but can be null (default)
|
|
317
|
+
* - "optional": Fields marked as optional in schema remain optional
|
|
318
|
+
*/
|
|
319
|
+
optionalFieldMode = "anyOf";
|
|
320
|
+
jsonSchemaToOpenAIJsonSchema(schema) {
|
|
321
|
+
if (schema?.type === "object") {
|
|
322
|
+
const s = schema;
|
|
323
|
+
const required = this.optionalFieldMode === "anyOf" ? Object.keys(s.properties) : s.required;
|
|
324
|
+
return {
|
|
325
|
+
...schema,
|
|
326
|
+
properties: Object.fromEntries(Object.entries(s.properties).map(([key, value]) => {
|
|
327
|
+
const valueSchema = this.jsonSchemaToOpenAIJsonSchema(value);
|
|
328
|
+
// NOTE: All fields must be required https://platform.openai.com/docs/guides/structured-outputs/all-fields-must-be-required
|
|
329
|
+
return [
|
|
330
|
+
key,
|
|
331
|
+
this.optionalFieldMode === "optional" || s.required?.includes(key)
|
|
332
|
+
? valueSchema
|
|
333
|
+
: { anyOf: [valueSchema, { type: ["null"] }] },
|
|
334
|
+
];
|
|
335
|
+
})),
|
|
336
|
+
required,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
if (schema?.type === "array") {
|
|
340
|
+
const { items } = schema;
|
|
341
|
+
return {
|
|
342
|
+
...schema,
|
|
343
|
+
items: this.jsonSchemaToOpenAIJsonSchema(items),
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
return schema;
|
|
347
|
+
}
|
|
315
348
|
}
|
|
316
349
|
exports.OpenAIChatModel = OpenAIChatModel;
|
|
317
350
|
// Create role mapper for OpenAI (uses standard mapping)
|
|
@@ -373,34 +406,6 @@ function toolsFromInputTools(tools, options) {
|
|
|
373
406
|
})
|
|
374
407
|
: undefined;
|
|
375
408
|
}
|
|
376
|
-
/**
|
|
377
|
-
* @hidden
|
|
378
|
-
*/
|
|
379
|
-
function jsonSchemaToOpenAIJsonSchema(schema) {
|
|
380
|
-
if (schema?.type === "object") {
|
|
381
|
-
const { required, properties } = schema;
|
|
382
|
-
return {
|
|
383
|
-
...schema,
|
|
384
|
-
properties: Object.fromEntries(Object.entries(properties).map(([key, value]) => {
|
|
385
|
-
const valueSchema = jsonSchemaToOpenAIJsonSchema(value);
|
|
386
|
-
// NOTE: All fields must be required https://platform.openai.com/docs/guides/structured-outputs/all-fields-must-be-required
|
|
387
|
-
return [
|
|
388
|
-
key,
|
|
389
|
-
required?.includes(key) ? valueSchema : { anyOf: [valueSchema, { type: ["null"] }] },
|
|
390
|
-
];
|
|
391
|
-
})),
|
|
392
|
-
required: Object.keys(properties),
|
|
393
|
-
};
|
|
394
|
-
}
|
|
395
|
-
if (schema?.type === "array") {
|
|
396
|
-
const { items } = schema;
|
|
397
|
-
return {
|
|
398
|
-
...schema,
|
|
399
|
-
items: jsonSchemaToOpenAIJsonSchema(items),
|
|
400
|
-
};
|
|
401
|
-
}
|
|
402
|
-
return schema;
|
|
403
|
-
}
|
|
404
409
|
function handleToolCallDelta(toolCalls, call) {
|
|
405
410
|
toolCalls[call.index] ??= {
|
|
406
411
|
id: call.id || (0, uuid_1.v7)(),
|
|
@@ -151,6 +151,13 @@ export declare class OpenAIChatModel extends ChatModel {
|
|
|
151
151
|
private getRunResponseFormat;
|
|
152
152
|
private requestStructuredOutput;
|
|
153
153
|
private extractResultFromStream;
|
|
154
|
+
/**
|
|
155
|
+
* Controls how optional fields are handled in JSON schema conversion
|
|
156
|
+
* - "anyOf": All fields are required but can be null (default)
|
|
157
|
+
* - "optional": Fields marked as optional in schema remain optional
|
|
158
|
+
*/
|
|
159
|
+
protected optionalFieldMode?: "anyOf" | "optional";
|
|
160
|
+
protected jsonSchemaToOpenAIJsonSchema(schema: Record<string, unknown>): Record<string, unknown>;
|
|
154
161
|
}
|
|
155
162
|
/**
|
|
156
163
|
* @hidden
|
|
@@ -162,7 +169,3 @@ export declare function contentsFromInputMessages(messages: ChatModelInputMessag
|
|
|
162
169
|
export declare function toolsFromInputTools(tools?: ChatModelInputTool[], options?: {
|
|
163
170
|
addTypeToEmptyParameters?: boolean;
|
|
164
171
|
}): ChatCompletionTool[] | undefined;
|
|
165
|
-
/**
|
|
166
|
-
* @hidden
|
|
167
|
-
*/
|
|
168
|
-
export declare function jsonSchemaToOpenAIJsonSchema(schema: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -151,6 +151,13 @@ export declare class OpenAIChatModel extends ChatModel {
|
|
|
151
151
|
private getRunResponseFormat;
|
|
152
152
|
private requestStructuredOutput;
|
|
153
153
|
private extractResultFromStream;
|
|
154
|
+
/**
|
|
155
|
+
* Controls how optional fields are handled in JSON schema conversion
|
|
156
|
+
* - "anyOf": All fields are required but can be null (default)
|
|
157
|
+
* - "optional": Fields marked as optional in schema remain optional
|
|
158
|
+
*/
|
|
159
|
+
protected optionalFieldMode?: "anyOf" | "optional";
|
|
160
|
+
protected jsonSchemaToOpenAIJsonSchema(schema: Record<string, unknown>): Record<string, unknown>;
|
|
154
161
|
}
|
|
155
162
|
/**
|
|
156
163
|
* @hidden
|
|
@@ -162,7 +169,3 @@ export declare function contentsFromInputMessages(messages: ChatModelInputMessag
|
|
|
162
169
|
export declare function toolsFromInputTools(tools?: ChatModelInputTool[], options?: {
|
|
163
170
|
addTypeToEmptyParameters?: boolean;
|
|
164
171
|
}): ChatCompletionTool[] | undefined;
|
|
165
|
-
/**
|
|
166
|
-
* @hidden
|
|
167
|
-
*/
|
|
168
|
-
export declare function jsonSchemaToOpenAIJsonSchema(schema: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -190,7 +190,7 @@ export class OpenAIChatModel extends ChatModel {
|
|
|
190
190
|
type: "json_schema",
|
|
191
191
|
json_schema: {
|
|
192
192
|
...input.responseFormat.jsonSchema,
|
|
193
|
-
schema: jsonSchemaToOpenAIJsonSchema(input.responseFormat.jsonSchema.schema),
|
|
193
|
+
schema: this.jsonSchemaToOpenAIJsonSchema(input.responseFormat.jsonSchema.schema),
|
|
194
194
|
},
|
|
195
195
|
},
|
|
196
196
|
};
|
|
@@ -306,6 +306,40 @@ export class OpenAIChatModel extends ChatModel {
|
|
|
306
306
|
});
|
|
307
307
|
return streaming ? result : await agentResponseStreamToObject(result);
|
|
308
308
|
}
|
|
309
|
+
/**
|
|
310
|
+
* Controls how optional fields are handled in JSON schema conversion
|
|
311
|
+
* - "anyOf": All fields are required but can be null (default)
|
|
312
|
+
* - "optional": Fields marked as optional in schema remain optional
|
|
313
|
+
*/
|
|
314
|
+
optionalFieldMode = "anyOf";
|
|
315
|
+
jsonSchemaToOpenAIJsonSchema(schema) {
|
|
316
|
+
if (schema?.type === "object") {
|
|
317
|
+
const s = schema;
|
|
318
|
+
const required = this.optionalFieldMode === "anyOf" ? Object.keys(s.properties) : s.required;
|
|
319
|
+
return {
|
|
320
|
+
...schema,
|
|
321
|
+
properties: Object.fromEntries(Object.entries(s.properties).map(([key, value]) => {
|
|
322
|
+
const valueSchema = this.jsonSchemaToOpenAIJsonSchema(value);
|
|
323
|
+
// NOTE: All fields must be required https://platform.openai.com/docs/guides/structured-outputs/all-fields-must-be-required
|
|
324
|
+
return [
|
|
325
|
+
key,
|
|
326
|
+
this.optionalFieldMode === "optional" || s.required?.includes(key)
|
|
327
|
+
? valueSchema
|
|
328
|
+
: { anyOf: [valueSchema, { type: ["null"] }] },
|
|
329
|
+
];
|
|
330
|
+
})),
|
|
331
|
+
required,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
if (schema?.type === "array") {
|
|
335
|
+
const { items } = schema;
|
|
336
|
+
return {
|
|
337
|
+
...schema,
|
|
338
|
+
items: this.jsonSchemaToOpenAIJsonSchema(items),
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
return schema;
|
|
342
|
+
}
|
|
309
343
|
}
|
|
310
344
|
// Create role mapper for OpenAI (uses standard mapping)
|
|
311
345
|
const mapRole = createRoleMapper(STANDARD_ROLE_MAP);
|
|
@@ -366,34 +400,6 @@ export function toolsFromInputTools(tools, options) {
|
|
|
366
400
|
})
|
|
367
401
|
: undefined;
|
|
368
402
|
}
|
|
369
|
-
/**
|
|
370
|
-
* @hidden
|
|
371
|
-
*/
|
|
372
|
-
export function jsonSchemaToOpenAIJsonSchema(schema) {
|
|
373
|
-
if (schema?.type === "object") {
|
|
374
|
-
const { required, properties } = schema;
|
|
375
|
-
return {
|
|
376
|
-
...schema,
|
|
377
|
-
properties: Object.fromEntries(Object.entries(properties).map(([key, value]) => {
|
|
378
|
-
const valueSchema = jsonSchemaToOpenAIJsonSchema(value);
|
|
379
|
-
// NOTE: All fields must be required https://platform.openai.com/docs/guides/structured-outputs/all-fields-must-be-required
|
|
380
|
-
return [
|
|
381
|
-
key,
|
|
382
|
-
required?.includes(key) ? valueSchema : { anyOf: [valueSchema, { type: ["null"] }] },
|
|
383
|
-
];
|
|
384
|
-
})),
|
|
385
|
-
required: Object.keys(properties),
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
|
-
if (schema?.type === "array") {
|
|
389
|
-
const { items } = schema;
|
|
390
|
-
return {
|
|
391
|
-
...schema,
|
|
392
|
-
items: jsonSchemaToOpenAIJsonSchema(items),
|
|
393
|
-
};
|
|
394
|
-
}
|
|
395
|
-
return schema;
|
|
396
|
-
}
|
|
397
403
|
function handleToolCallDelta(toolCalls, call) {
|
|
398
404
|
toolCalls[call.index] ??= {
|
|
399
405
|
id: call.id || v7(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/openai",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.3",
|
|
4
4
|
"description": "AIGNE OpenAI SDK for integrating with OpenAI's GPT models and API services",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"openai": "^5.8.3",
|
|
40
40
|
"uuid": "^11.1.0",
|
|
41
41
|
"zod": "^3.25.67",
|
|
42
|
-
"@aigne/core": "^1.58.
|
|
42
|
+
"@aigne/core": "^1.58.3",
|
|
43
43
|
"@aigne/platform-helpers": "^0.6.2"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"npm-run-all": "^4.1.5",
|
|
49
49
|
"rimraf": "^6.0.1",
|
|
50
50
|
"typescript": "^5.8.3",
|
|
51
|
-
"@aigne/test-utils": "^0.5.
|
|
51
|
+
"@aigne/test-utils": "^0.5.47"
|
|
52
52
|
},
|
|
53
53
|
"scripts": {
|
|
54
54
|
"lint": "tsc --noEmit",
|