@aigne/openai 0.14.2 → 0.15.0

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,37 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.15.0](https://github.com/AIGNE-io/aigne-framework/compare/openai-v0.14.3...openai-v0.15.0) (2025-09-09)
4
+
5
+
6
+ ### Features
7
+
8
+ * support custom prefer input file type ([#469](https://github.com/AIGNE-io/aigne-framework/issues/469)) ([db0161b](https://github.com/AIGNE-io/aigne-framework/commit/db0161bbac52542c771ee2f40f361636b0668075))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @aigne/core bumped to 1.59.0
16
+ * devDependencies
17
+ * @aigne/test-utils bumped to 0.5.48
18
+
19
+ ## [0.14.3](https://github.com/AIGNE-io/aigne-framework/compare/openai-v0.14.2...openai-v0.14.3) (2025-09-08)
20
+
21
+
22
+ ### Bug Fixes
23
+
24
+ * 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))
25
+
26
+
27
+ ### Dependencies
28
+
29
+ * The following workspace dependencies were updated
30
+ * dependencies
31
+ * @aigne/core bumped to 1.58.3
32
+ * devDependencies
33
+ * @aigne/test-utils bumped to 0.5.47
34
+
3
35
  ## [0.14.2](https://github.com/AIGNE-io/aigne-framework/compare/openai-v0.14.1...openai-v0.14.2) (2025-09-05)
4
36
 
5
37
 
@@ -15,7 +15,7 @@ export interface OpenAIChatModelCapabilities {
15
15
  /**
16
16
  * Configuration options for OpenAI Chat Model
17
17
  */
18
- export interface OpenAIChatModelOptions {
18
+ export interface OpenAIChatModelOptions extends ChatModelOptions {
19
19
  /**
20
20
  * API key for OpenAI API
21
21
  *
@@ -28,16 +28,6 @@ export interface OpenAIChatModelOptions {
28
28
  * Useful for proxies or alternate endpoints
29
29
  */
30
30
  baseURL?: string;
31
- /**
32
- * OpenAI model to use
33
- *
34
- * Defaults to 'gpt-4o-mini'
35
- */
36
- model?: string;
37
- /**
38
- * Additional model options to control behavior
39
- */
40
- modelOptions?: ChatModelOptions;
41
31
  /**
42
32
  * Client options for OpenAI API
43
33
  */
@@ -137,7 +127,7 @@ export declare class OpenAIChatModel extends ChatModel {
137
127
  apiKey: string | undefined;
138
128
  model: string;
139
129
  };
140
- get modelOptions(): ChatModelOptions | undefined;
130
+ get modelOptions(): Omit<import("@aigne/core").ModelOptions, "model"> | undefined;
141
131
  /**
142
132
  * Process the input and generate a response
143
133
  * @param input The input to process
@@ -151,6 +141,13 @@ export declare class OpenAIChatModel extends ChatModel {
151
141
  private getRunResponseFormat;
152
142
  private requestStructuredOutput;
153
143
  private extractResultFromStream;
144
+ /**
145
+ * Controls how optional fields are handled in JSON schema conversion
146
+ * - "anyOf": All fields are required but can be null (default)
147
+ * - "optional": Fields marked as optional in schema remain optional
148
+ */
149
+ protected optionalFieldMode?: "anyOf" | "optional";
150
+ protected jsonSchemaToOpenAIJsonSchema(schema: Record<string, unknown>): Record<string, unknown>;
154
151
  }
155
152
  /**
156
153
  * @hidden
@@ -162,7 +159,3 @@ export declare function contentsFromInputMessages(messages: ChatModelInputMessag
162
159
  export declare function toolsFromInputTools(tools?: ChatModelInputTool[], options?: {
163
160
  addTypeToEmptyParameters?: boolean;
164
161
  }): 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)(),
@@ -15,7 +15,7 @@ export interface OpenAIChatModelCapabilities {
15
15
  /**
16
16
  * Configuration options for OpenAI Chat Model
17
17
  */
18
- export interface OpenAIChatModelOptions {
18
+ export interface OpenAIChatModelOptions extends ChatModelOptions {
19
19
  /**
20
20
  * API key for OpenAI API
21
21
  *
@@ -28,16 +28,6 @@ export interface OpenAIChatModelOptions {
28
28
  * Useful for proxies or alternate endpoints
29
29
  */
30
30
  baseURL?: string;
31
- /**
32
- * OpenAI model to use
33
- *
34
- * Defaults to 'gpt-4o-mini'
35
- */
36
- model?: string;
37
- /**
38
- * Additional model options to control behavior
39
- */
40
- modelOptions?: ChatModelOptions;
41
31
  /**
42
32
  * Client options for OpenAI API
43
33
  */
@@ -137,7 +127,7 @@ export declare class OpenAIChatModel extends ChatModel {
137
127
  apiKey: string | undefined;
138
128
  model: string;
139
129
  };
140
- get modelOptions(): ChatModelOptions | undefined;
130
+ get modelOptions(): Omit<import("@aigne/core").ModelOptions, "model"> | undefined;
141
131
  /**
142
132
  * Process the input and generate a response
143
133
  * @param input The input to process
@@ -151,6 +141,13 @@ export declare class OpenAIChatModel extends ChatModel {
151
141
  private getRunResponseFormat;
152
142
  private requestStructuredOutput;
153
143
  private extractResultFromStream;
144
+ /**
145
+ * Controls how optional fields are handled in JSON schema conversion
146
+ * - "anyOf": All fields are required but can be null (default)
147
+ * - "optional": Fields marked as optional in schema remain optional
148
+ */
149
+ protected optionalFieldMode?: "anyOf" | "optional";
150
+ protected jsonSchemaToOpenAIJsonSchema(schema: Record<string, unknown>): Record<string, unknown>;
154
151
  }
155
152
  /**
156
153
  * @hidden
@@ -162,7 +159,3 @@ export declare function contentsFromInputMessages(messages: ChatModelInputMessag
162
159
  export declare function toolsFromInputTools(tools?: ChatModelInputTool[], options?: {
163
160
  addTypeToEmptyParameters?: boolean;
164
161
  }): ChatCompletionTool[] | undefined;
165
- /**
166
- * @hidden
167
- */
168
- export declare function jsonSchemaToOpenAIJsonSchema(schema: Record<string, unknown>): Record<string, unknown>;
@@ -15,7 +15,7 @@ export interface OpenAIChatModelCapabilities {
15
15
  /**
16
16
  * Configuration options for OpenAI Chat Model
17
17
  */
18
- export interface OpenAIChatModelOptions {
18
+ export interface OpenAIChatModelOptions extends ChatModelOptions {
19
19
  /**
20
20
  * API key for OpenAI API
21
21
  *
@@ -28,16 +28,6 @@ export interface OpenAIChatModelOptions {
28
28
  * Useful for proxies or alternate endpoints
29
29
  */
30
30
  baseURL?: string;
31
- /**
32
- * OpenAI model to use
33
- *
34
- * Defaults to 'gpt-4o-mini'
35
- */
36
- model?: string;
37
- /**
38
- * Additional model options to control behavior
39
- */
40
- modelOptions?: ChatModelOptions;
41
31
  /**
42
32
  * Client options for OpenAI API
43
33
  */
@@ -137,7 +127,7 @@ export declare class OpenAIChatModel extends ChatModel {
137
127
  apiKey: string | undefined;
138
128
  model: string;
139
129
  };
140
- get modelOptions(): ChatModelOptions | undefined;
130
+ get modelOptions(): Omit<import("@aigne/core").ModelOptions, "model"> | undefined;
141
131
  /**
142
132
  * Process the input and generate a response
143
133
  * @param input The input to process
@@ -151,6 +141,13 @@ export declare class OpenAIChatModel extends ChatModel {
151
141
  private getRunResponseFormat;
152
142
  private requestStructuredOutput;
153
143
  private extractResultFromStream;
144
+ /**
145
+ * Controls how optional fields are handled in JSON schema conversion
146
+ * - "anyOf": All fields are required but can be null (default)
147
+ * - "optional": Fields marked as optional in schema remain optional
148
+ */
149
+ protected optionalFieldMode?: "anyOf" | "optional";
150
+ protected jsonSchemaToOpenAIJsonSchema(schema: Record<string, unknown>): Record<string, unknown>;
154
151
  }
155
152
  /**
156
153
  * @hidden
@@ -162,7 +159,3 @@ export declare function contentsFromInputMessages(messages: ChatModelInputMessag
162
159
  export declare function toolsFromInputTools(tools?: ChatModelInputTool[], options?: {
163
160
  addTypeToEmptyParameters?: boolean;
164
161
  }): 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.2",
3
+ "version": "0.15.0",
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.2",
42
+ "@aigne/core": "^1.59.0",
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.46"
51
+ "@aigne/test-utils": "^0.5.48"
52
52
  },
53
53
  "scripts": {
54
54
  "lint": "tsc --noEmit",