Skip to content

Commit d58091b

Browse files
feat(api): Support images and files for function call outputs in responses, BatchUsage
This release introduces a major version change to reflect a breaking modification in the `ResponseFunctionToolCallOutputItem` and `ResponseCustomToolCallOutput` schemas. Specifically, the `output` field, which previously accepted only a `string` value, has been expanded to support multiple structured types: ``` Before: output: string After: output: string | Array<ResponseInputText | ResponseInputImage | ResponseInputFile> ``` This change allows custom tool calls to return images, files, and rich text content in addition to plain strings, aligning `ResponseCustomToolCallOutput` with the broader `ResponseInput` type system. Because this alters the type and shape of the field, it may break existing callsites that only accept strings. BREAKING CHANGE: `ResponseFunctionToolCallOutputItem.output` and `ResponseCustomToolCallOutput.output` now return `string | Array<ResponseInputText | ResponseInputImage | ResponseInputFile>` instead of `string` only. This may break existing callsites that assume `output` is always a string.
1 parent 422d07b commit d58091b

25 files changed

+3678
-60
lines changed

.stats.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
configured_endpoints: 118
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-410219ea680089f02bb55163c673919703f946c3d6ad7ff5d6f607121d5287d5.yml
3-
openapi_spec_hash: 2b3eee95d3f6796c7a61dfddf694a59a
4-
config_hash: 666d6bb4b564f0d9d431124b5d1a0665
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-49233088b5e73dbb96bf7af27be3d4547632e3db1c2b00f14184900613325bbc.yml
3+
openapi_spec_hash: b34f14b141d5019244112901c5c7c2d8
4+
config_hash: 94e9ba08201c3d1ca46e093e6a0138fa

openai-java-core/src/main/kotlin/com/openai/models/batches/Batch.kt

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ private constructor(
4141
private val finalizingAt: JsonField<Long>,
4242
private val inProgressAt: JsonField<Long>,
4343
private val metadata: JsonField<Metadata>,
44+
private val model: JsonField<String>,
4445
private val outputFileId: JsonField<String>,
4546
private val requestCounts: JsonField<BatchRequestCounts>,
47+
private val usage: JsonField<BatchUsage>,
4648
private val additionalProperties: MutableMap<String, JsonValue>,
4749
) {
4850

@@ -82,12 +84,14 @@ private constructor(
8284
@ExcludeMissing
8385
inProgressAt: JsonField<Long> = JsonMissing.of(),
8486
@JsonProperty("metadata") @ExcludeMissing metadata: JsonField<Metadata> = JsonMissing.of(),
87+
@JsonProperty("model") @ExcludeMissing model: JsonField<String> = JsonMissing.of(),
8588
@JsonProperty("output_file_id")
8689
@ExcludeMissing
8790
outputFileId: JsonField<String> = JsonMissing.of(),
8891
@JsonProperty("request_counts")
8992
@ExcludeMissing
9093
requestCounts: JsonField<BatchRequestCounts> = JsonMissing.of(),
94+
@JsonProperty("usage") @ExcludeMissing usage: JsonField<BatchUsage> = JsonMissing.of(),
9195
) : this(
9296
id,
9397
completionWindow,
@@ -107,8 +111,10 @@ private constructor(
107111
finalizingAt,
108112
inProgressAt,
109113
metadata,
114+
model,
110115
outputFileId,
111116
requestCounts,
117+
usage,
112118
mutableMapOf(),
113119
)
114120

@@ -262,6 +268,17 @@ private constructor(
262268
*/
263269
fun metadata(): Optional<Metadata> = metadata.getOptional("metadata")
264270

271+
/**
272+
* Model ID used to process the batch, like `gpt-5-2025-08-07`. OpenAI offers a wide range of
273+
* models with different capabilities, performance characteristics, and price points. Refer to
274+
* the [model guide](https://platform.openai.com/docs/models) to browse and compare available
275+
* models.
276+
*
277+
* @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the
278+
* server responded with an unexpected value).
279+
*/
280+
fun model(): Optional<String> = model.getOptional("model")
281+
265282
/**
266283
* The ID of the file containing the outputs of successfully executed requests.
267284
*
@@ -278,6 +295,15 @@ private constructor(
278295
*/
279296
fun requestCounts(): Optional<BatchRequestCounts> = requestCounts.getOptional("request_counts")
280297

298+
/**
299+
* Represents token usage details including input tokens, output tokens, a breakdown of output
300+
* tokens, and the total tokens used. Only populated on batches created after September 7, 2025.
301+
*
302+
* @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the
303+
* server responded with an unexpected value).
304+
*/
305+
fun usage(): Optional<BatchUsage> = usage.getOptional("usage")
306+
281307
/**
282308
* Returns the raw JSON value of [id].
283309
*
@@ -410,6 +436,13 @@ private constructor(
410436
*/
411437
@JsonProperty("metadata") @ExcludeMissing fun _metadata(): JsonField<Metadata> = metadata
412438

439+
/**
440+
* Returns the raw JSON value of [model].
441+
*
442+
* Unlike [model], this method doesn't throw if the JSON field has an unexpected type.
443+
*/
444+
@JsonProperty("model") @ExcludeMissing fun _model(): JsonField<String> = model
445+
413446
/**
414447
* Returns the raw JSON value of [outputFileId].
415448
*
@@ -428,6 +461,13 @@ private constructor(
428461
@ExcludeMissing
429462
fun _requestCounts(): JsonField<BatchRequestCounts> = requestCounts
430463

464+
/**
465+
* Returns the raw JSON value of [usage].
466+
*
467+
* Unlike [usage], this method doesn't throw if the JSON field has an unexpected type.
468+
*/
469+
@JsonProperty("usage") @ExcludeMissing fun _usage(): JsonField<BatchUsage> = usage
470+
431471
@JsonAnySetter
432472
private fun putAdditionalProperty(key: String, value: JsonValue) {
433473
additionalProperties.put(key, value)
@@ -479,8 +519,10 @@ private constructor(
479519
private var finalizingAt: JsonField<Long> = JsonMissing.of()
480520
private var inProgressAt: JsonField<Long> = JsonMissing.of()
481521
private var metadata: JsonField<Metadata> = JsonMissing.of()
522+
private var model: JsonField<String> = JsonMissing.of()
482523
private var outputFileId: JsonField<String> = JsonMissing.of()
483524
private var requestCounts: JsonField<BatchRequestCounts> = JsonMissing.of()
525+
private var usage: JsonField<BatchUsage> = JsonMissing.of()
484526
private var additionalProperties: MutableMap<String, JsonValue> = mutableMapOf()
485527

486528
@JvmSynthetic
@@ -503,8 +545,10 @@ private constructor(
503545
finalizingAt = batch.finalizingAt
504546
inProgressAt = batch.inProgressAt
505547
metadata = batch.metadata
548+
model = batch.model
506549
outputFileId = batch.outputFileId
507550
requestCounts = batch.requestCounts
551+
usage = batch.usage
508552
additionalProperties = batch.additionalProperties.toMutableMap()
509553
}
510554

@@ -729,6 +773,22 @@ private constructor(
729773
*/
730774
fun metadata(metadata: JsonField<Metadata>) = apply { this.metadata = metadata }
731775

776+
/**
777+
* Model ID used to process the batch, like `gpt-5-2025-08-07`. OpenAI offers a wide range
778+
* of models with different capabilities, performance characteristics, and price points.
779+
* Refer to the [model guide](https://platform.openai.com/docs/models) to browse and compare
780+
* available models.
781+
*/
782+
fun model(model: String) = model(JsonField.of(model))
783+
784+
/**
785+
* Sets [Builder.model] to an arbitrary JSON value.
786+
*
787+
* You should usually call [Builder.model] with a well-typed [String] value instead. This
788+
* method is primarily for setting the field to an undocumented or not yet supported value.
789+
*/
790+
fun model(model: JsonField<String>) = apply { this.model = model }
791+
732792
/** The ID of the file containing the outputs of successfully executed requests. */
733793
fun outputFileId(outputFileId: String) = outputFileId(JsonField.of(outputFileId))
734794

@@ -758,6 +818,22 @@ private constructor(
758818
this.requestCounts = requestCounts
759819
}
760820

821+
/**
822+
* Represents token usage details including input tokens, output tokens, a breakdown of
823+
* output tokens, and the total tokens used. Only populated on batches created after
824+
* September 7, 2025.
825+
*/
826+
fun usage(usage: BatchUsage) = usage(JsonField.of(usage))
827+
828+
/**
829+
* Sets [Builder.usage] to an arbitrary JSON value.
830+
*
831+
* You should usually call [Builder.usage] with a well-typed [BatchUsage] value instead.
832+
* This method is primarily for setting the field to an undocumented or not yet supported
833+
* value.
834+
*/
835+
fun usage(usage: JsonField<BatchUsage>) = apply { this.usage = usage }
836+
761837
fun additionalProperties(additionalProperties: Map<String, JsonValue>) = apply {
762838
this.additionalProperties.clear()
763839
putAllAdditionalProperties(additionalProperties)
@@ -814,8 +890,10 @@ private constructor(
814890
finalizingAt,
815891
inProgressAt,
816892
metadata,
893+
model,
817894
outputFileId,
818895
requestCounts,
896+
usage,
819897
additionalProperties.toMutableMap(),
820898
)
821899
}
@@ -849,8 +927,10 @@ private constructor(
849927
finalizingAt()
850928
inProgressAt()
851929
metadata().ifPresent { it.validate() }
930+
model()
852931
outputFileId()
853932
requestCounts().ifPresent { it.validate() }
933+
usage().ifPresent { it.validate() }
854934
validated = true
855935
}
856936

@@ -887,8 +967,10 @@ private constructor(
887967
(if (finalizingAt.asKnown().isPresent) 1 else 0) +
888968
(if (inProgressAt.asKnown().isPresent) 1 else 0) +
889969
(metadata.asKnown().getOrNull()?.validity() ?: 0) +
970+
(if (model.asKnown().isPresent) 1 else 0) +
890971
(if (outputFileId.asKnown().isPresent) 1 else 0) +
891-
(requestCounts.asKnown().getOrNull()?.validity() ?: 0)
972+
(requestCounts.asKnown().getOrNull()?.validity() ?: 0) +
973+
(usage.asKnown().getOrNull()?.validity() ?: 0)
892974

893975
/** The current status of the batch. */
894976
class Status @JsonCreator private constructor(private val value: JsonField<String>) : Enum {
@@ -1378,8 +1460,10 @@ private constructor(
13781460
finalizingAt == other.finalizingAt &&
13791461
inProgressAt == other.inProgressAt &&
13801462
metadata == other.metadata &&
1463+
model == other.model &&
13811464
outputFileId == other.outputFileId &&
13821465
requestCounts == other.requestCounts &&
1466+
usage == other.usage &&
13831467
additionalProperties == other.additionalProperties
13841468
}
13851469

@@ -1403,14 +1487,16 @@ private constructor(
14031487
finalizingAt,
14041488
inProgressAt,
14051489
metadata,
1490+
model,
14061491
outputFileId,
14071492
requestCounts,
1493+
usage,
14081494
additionalProperties,
14091495
)
14101496
}
14111497

14121498
override fun hashCode(): Int = hashCode
14131499

14141500
override fun toString() =
1415-
"Batch{id=$id, completionWindow=$completionWindow, createdAt=$createdAt, endpoint=$endpoint, inputFileId=$inputFileId, object_=$object_, status=$status, cancelledAt=$cancelledAt, cancellingAt=$cancellingAt, completedAt=$completedAt, errorFileId=$errorFileId, errors=$errors, expiredAt=$expiredAt, expiresAt=$expiresAt, failedAt=$failedAt, finalizingAt=$finalizingAt, inProgressAt=$inProgressAt, metadata=$metadata, outputFileId=$outputFileId, requestCounts=$requestCounts, additionalProperties=$additionalProperties}"
1501+
"Batch{id=$id, completionWindow=$completionWindow, createdAt=$createdAt, endpoint=$endpoint, inputFileId=$inputFileId, object_=$object_, status=$status, cancelledAt=$cancelledAt, cancellingAt=$cancellingAt, completedAt=$completedAt, errorFileId=$errorFileId, errors=$errors, expiredAt=$expiredAt, expiresAt=$expiresAt, failedAt=$failedAt, finalizingAt=$finalizingAt, inProgressAt=$inProgressAt, metadata=$metadata, model=$model, outputFileId=$outputFileId, requestCounts=$requestCounts, usage=$usage, additionalProperties=$additionalProperties}"
14161502
}

0 commit comments

Comments
 (0)