From 877b691cafd65ea80b06c352221ab1c5bf3e8caf Mon Sep 17 00:00:00 2001 From: markstuart-oai <323302876+markstuart-oai@users.noreply.github.com> Date: Wed, 2 Sep 2026 21:17:25 -0700 Subject: [PATCH] feat(api): allow omitted function-call argument event names Castiron-Internal-PR: https://github.com/openai/openai-java-internal/pull/62 Castiron-Source-SHA: cb386b222ff7aa86293f5e9ac678c20e3851044f Castiron-Public-Base-SHA: d3191b0db2f456882fd2e2edc3dce126f85505e1 --- .castiron.stats.yml | 12 +-- api_reference/openapi.transformed.yml | 4 - ...aResponseFunctionCallArgumentsDoneEvent.kt | 78 +++++++++--------- .../ResponseFunctionCallArgumentsDoneEvent.kt | 81 ++++++++++--------- ...ponseFunctionCallArgumentsDoneEventTest.kt | 6 +- .../responses/BetaResponseStreamEventTest.kt | 4 +- .../responses/BetaResponsesServerEventTest.kt | 4 +- ...ponseFunctionCallArgumentsDoneEventTest.kt | 6 +- .../responses/ResponseStreamEventTest.kt | 4 +- .../responses/ResponsesServerEventTest.kt | 4 +- .../ResponseStreamEventValidationTest.kt | 51 ++++++++++-- 11 files changed, 143 insertions(+), 111 deletions(-) diff --git a/.castiron.stats.yml b/.castiron.stats.yml index 38faa80ab..36ba0f68d 100644 --- a/.castiron.stats.yml +++ b/.castiron.stats.yml @@ -1,8 +1,8 @@ schema_version: 1 -generation_id: a2e15f59-94b2-41a7-83a2-0aa28ffd7091 -openapi_spec_hash: 0ba3e4acd88b521d832e2a42d5471e00 -openapi_transformed_spec_hash: 0a6002520553b981f4c0bf6555a0a623 +generation_id: fef4406c-d79d-4929-be42-636e065492e3 +openapi_spec_hash: e20c8c5d5ffad89da6fbb14b57d894f1 +openapi_transformed_spec_hash: 174a43233549b09ebc982daba97832fa config_hash: d8813efd847d1966dd7f03bb648c41dc -codegen_sha: 23fe5abcd01bf9d6dd1c1ee49b6244f9d2d078ce -codegen_hash: 2c513214ca2f30afc9ae2724d5b78c068dac45d959bc1c4f1d8b4706f507f3ca -public_codegen_sha: 0c208e28bddcefe8be7b5a0b94be94b8b973ed4e +codegen_sha: 46f1ea420fa56168af5784e690d21edab330f5d9 +codegen_hash: 1639bed1e5f83245883989fd6fd2aa83e1e346ebbde41244abd09f121037fc42 +public_codegen_sha: cbd5150d543315558ec70410c987c98e39d7edb4 diff --git a/api_reference/openapi.transformed.yml b/api_reference/openapi.transformed.yml index 272cbeaf2..a006d55c1 100644 --- a/api_reference/openapi.transformed.yml +++ b/api_reference/openapi.transformed.yml @@ -53305,7 +53305,6 @@ components: required: - type - item_id - - name - output_index - arguments - sequence_number @@ -53316,7 +53315,6 @@ components: { "type": "response.function_call_arguments.done", "item_id": "item-abc", - "name": "get_weather", "output_index": 1, "arguments": "{ \"arg\": 123 }", "sequence_number": 1 @@ -76336,7 +76334,6 @@ components: required: - type - item_id - - name - output_index - arguments - sequence_number @@ -76347,7 +76344,6 @@ components: { "type": "response.function_call_arguments.done", "item_id": "item-abc", - "name": "get_weather", "output_index": 1, "arguments": "{ \"arg\": 123 }", "sequence_number": 1 diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/responses/BetaResponseFunctionCallArgumentsDoneEvent.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/responses/BetaResponseFunctionCallArgumentsDoneEvent.kt index 21d63f0ef..87e2a7373 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/responses/BetaResponseFunctionCallArgumentsDoneEvent.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/responses/BetaResponseFunctionCallArgumentsDoneEvent.kt @@ -23,11 +23,11 @@ class BetaResponseFunctionCallArgumentsDoneEvent private constructor( private val arguments: JsonField, private val itemId: JsonField, - private val name: JsonField, private val outputIndex: JsonField, private val sequenceNumber: JsonField, private val type: JsonValue, private val agent: JsonField, + private val name: JsonField, private val additionalProperties: MutableMap, ) { @@ -35,7 +35,6 @@ private constructor( private constructor( @JsonProperty("arguments") @ExcludeMissing arguments: JsonField = JsonMissing.of(), @JsonProperty("item_id") @ExcludeMissing itemId: JsonField = JsonMissing.of(), - @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), @JsonProperty("output_index") @ExcludeMissing outputIndex: JsonField = JsonMissing.of(), @@ -44,7 +43,8 @@ private constructor( sequenceNumber: JsonField = JsonMissing.of(), @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), @JsonProperty("agent") @ExcludeMissing agent: JsonField = JsonMissing.of(), - ) : this(arguments, itemId, name, outputIndex, sequenceNumber, type, agent, mutableMapOf()) + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(arguments, itemId, outputIndex, sequenceNumber, type, agent, name, mutableMapOf()) /** * The function-call arguments. @@ -62,14 +62,6 @@ private constructor( */ fun itemId(): String = itemId.getRequired("item_id") - /** - * The name of the function that was called. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun name(): String = name.getRequired("name") - /** * The index of the output item. * @@ -105,6 +97,14 @@ private constructor( */ fun agent(): Optional = agent.getOptional("agent") + /** + * The name of the function that was called. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + /** * Returns the raw JSON value of [arguments]. * @@ -119,13 +119,6 @@ private constructor( */ @JsonProperty("item_id") @ExcludeMissing fun _itemId(): JsonField = itemId - /** - * Returns the raw JSON value of [name]. - * - * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - /** * Returns the raw JSON value of [outputIndex]. * @@ -149,6 +142,13 @@ private constructor( */ @JsonProperty("agent") @ExcludeMissing fun _agent(): JsonField = agent + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -171,7 +171,6 @@ private constructor( * ```java * .arguments() * .itemId() - * .name() * .outputIndex() * .sequenceNumber() * ``` @@ -184,11 +183,11 @@ private constructor( private var arguments: JsonField? = null private var itemId: JsonField? = null - private var name: JsonField? = null private var outputIndex: JsonField? = null private var sequenceNumber: JsonField? = null private var type: JsonValue = JsonValue.from("response.function_call_arguments.done") private var agent: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -197,11 +196,11 @@ private constructor( ) = apply { arguments = betaResponseFunctionCallArgumentsDoneEvent.arguments itemId = betaResponseFunctionCallArgumentsDoneEvent.itemId - name = betaResponseFunctionCallArgumentsDoneEvent.name outputIndex = betaResponseFunctionCallArgumentsDoneEvent.outputIndex sequenceNumber = betaResponseFunctionCallArgumentsDoneEvent.sequenceNumber type = betaResponseFunctionCallArgumentsDoneEvent.type agent = betaResponseFunctionCallArgumentsDoneEvent.agent + name = betaResponseFunctionCallArgumentsDoneEvent.name additionalProperties = betaResponseFunctionCallArgumentsDoneEvent.additionalProperties.toMutableMap() } @@ -229,17 +228,6 @@ private constructor( */ fun itemId(itemId: JsonField) = apply { this.itemId = itemId } - /** The name of the function that was called. */ - fun name(name: String) = name(JsonField.of(name)) - - /** - * Sets [Builder.name] to an arbitrary JSON value. - * - * You should usually call [Builder.name] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun name(name: JsonField) = apply { this.name = name } - /** The index of the output item. */ fun outputIndex(outputIndex: Long) = outputIndex(JsonField.of(outputIndex)) @@ -294,6 +282,17 @@ private constructor( */ fun agent(agent: JsonField) = apply { this.agent = agent } + /** The name of the function that was called. */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -322,7 +321,6 @@ private constructor( * ```java * .arguments() * .itemId() - * .name() * .outputIndex() * .sequenceNumber() * ``` @@ -333,11 +331,11 @@ private constructor( BetaResponseFunctionCallArgumentsDoneEvent( checkRequired("arguments", arguments), checkRequired("itemId", itemId), - checkRequired("name", name), checkRequired("outputIndex", outputIndex), checkRequired("sequenceNumber", sequenceNumber), type, agent, + name, additionalProperties.toMutableMap(), ) } @@ -359,7 +357,6 @@ private constructor( arguments() itemId() - name() outputIndex() sequenceNumber() _type().let { @@ -368,6 +365,7 @@ private constructor( } } agent().ifPresent { it.validate() } + name() validated = true } @@ -388,13 +386,13 @@ private constructor( internal fun validity(): Int = (if (arguments.asKnown().isPresent) 1 else 0) + (if (itemId.asKnown().isPresent) 1 else 0) + - (if (name.asKnown().isPresent) 1 else 0) + (if (outputIndex.asKnown().isPresent) 1 else 0) + (if (sequenceNumber.asKnown().isPresent) 1 else 0) + type.let { if (it == JsonValue.from("response.function_call_arguments.done")) 1 else 0 } + - (agent.asKnown().getOrNull()?.validity() ?: 0) + (agent.asKnown().getOrNull()?.validity() ?: 0) + + (if (name.asKnown().isPresent) 1 else 0) /** The agent that owns this multi-agent streaming event. */ class Agent @@ -572,11 +570,11 @@ private constructor( return other is BetaResponseFunctionCallArgumentsDoneEvent && arguments == other.arguments && itemId == other.itemId && - name == other.name && outputIndex == other.outputIndex && sequenceNumber == other.sequenceNumber && type == other.type && agent == other.agent && + name == other.name && additionalProperties == other.additionalProperties } @@ -584,11 +582,11 @@ private constructor( Objects.hash( arguments, itemId, - name, outputIndex, sequenceNumber, type, agent, + name, additionalProperties, ) } @@ -596,5 +594,5 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "BetaResponseFunctionCallArgumentsDoneEvent{arguments=$arguments, itemId=$itemId, name=$name, outputIndex=$outputIndex, sequenceNumber=$sequenceNumber, type=$type, agent=$agent, additionalProperties=$additionalProperties}" + "BetaResponseFunctionCallArgumentsDoneEvent{arguments=$arguments, itemId=$itemId, outputIndex=$outputIndex, sequenceNumber=$sequenceNumber, type=$type, agent=$agent, name=$name, additionalProperties=$additionalProperties}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseFunctionCallArgumentsDoneEvent.kt b/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseFunctionCallArgumentsDoneEvent.kt index 7e1362090..38715944a 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseFunctionCallArgumentsDoneEvent.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseFunctionCallArgumentsDoneEvent.kt @@ -14,6 +14,7 @@ import com.openai.core.checkRequired import com.openai.errors.OpenAIInvalidDataException import java.util.Collections import java.util.Objects +import java.util.Optional /** Emitted when function-call arguments are finalized. */ class ResponseFunctionCallArgumentsDoneEvent @@ -21,10 +22,10 @@ class ResponseFunctionCallArgumentsDoneEvent private constructor( private val arguments: JsonField, private val itemId: JsonField, - private val name: JsonField, private val outputIndex: JsonField, private val sequenceNumber: JsonField, private val type: JsonValue, + private val name: JsonField, private val additionalProperties: MutableMap, ) { @@ -32,7 +33,6 @@ private constructor( private constructor( @JsonProperty("arguments") @ExcludeMissing arguments: JsonField = JsonMissing.of(), @JsonProperty("item_id") @ExcludeMissing itemId: JsonField = JsonMissing.of(), - @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), @JsonProperty("output_index") @ExcludeMissing outputIndex: JsonField = JsonMissing.of(), @@ -40,7 +40,8 @@ private constructor( @ExcludeMissing sequenceNumber: JsonField = JsonMissing.of(), @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), - ) : this(arguments, itemId, name, outputIndex, sequenceNumber, type, mutableMapOf()) + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(arguments, itemId, outputIndex, sequenceNumber, type, name, mutableMapOf()) /** * The function-call arguments. @@ -58,14 +59,6 @@ private constructor( */ fun itemId(): String = itemId.getRequired("item_id") - /** - * The name of the function that was called. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun name(): String = name.getRequired("name") - /** * The index of the output item. * @@ -93,6 +86,14 @@ private constructor( */ @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type + /** + * The name of the function that was called. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + /** * Returns the raw JSON value of [arguments]. * @@ -107,13 +108,6 @@ private constructor( */ @JsonProperty("item_id") @ExcludeMissing fun _itemId(): JsonField = itemId - /** - * Returns the raw JSON value of [name]. - * - * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - /** * Returns the raw JSON value of [outputIndex]. * @@ -130,6 +124,13 @@ private constructor( @ExcludeMissing fun _sequenceNumber(): JsonField = sequenceNumber + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -152,7 +153,6 @@ private constructor( * ```java * .arguments() * .itemId() - * .name() * .outputIndex() * .sequenceNumber() * ``` @@ -165,10 +165,10 @@ private constructor( private var arguments: JsonField? = null private var itemId: JsonField? = null - private var name: JsonField? = null private var outputIndex: JsonField? = null private var sequenceNumber: JsonField? = null private var type: JsonValue = JsonValue.from("response.function_call_arguments.done") + private var name: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -177,10 +177,10 @@ private constructor( ) = apply { arguments = responseFunctionCallArgumentsDoneEvent.arguments itemId = responseFunctionCallArgumentsDoneEvent.itemId - name = responseFunctionCallArgumentsDoneEvent.name outputIndex = responseFunctionCallArgumentsDoneEvent.outputIndex sequenceNumber = responseFunctionCallArgumentsDoneEvent.sequenceNumber type = responseFunctionCallArgumentsDoneEvent.type + name = responseFunctionCallArgumentsDoneEvent.name additionalProperties = responseFunctionCallArgumentsDoneEvent.additionalProperties.toMutableMap() } @@ -208,17 +208,6 @@ private constructor( */ fun itemId(itemId: JsonField) = apply { this.itemId = itemId } - /** The name of the function that was called. */ - fun name(name: String) = name(JsonField.of(name)) - - /** - * Sets [Builder.name] to an arbitrary JSON value. - * - * You should usually call [Builder.name] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun name(name: JsonField) = apply { this.name = name } - /** The index of the output item. */ fun outputIndex(outputIndex: Long) = outputIndex(JsonField.of(outputIndex)) @@ -259,6 +248,17 @@ private constructor( */ fun type(type: JsonValue) = apply { this.type = type } + /** The name of the function that was called. */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -287,7 +287,6 @@ private constructor( * ```java * .arguments() * .itemId() - * .name() * .outputIndex() * .sequenceNumber() * ``` @@ -298,10 +297,10 @@ private constructor( ResponseFunctionCallArgumentsDoneEvent( checkRequired("arguments", arguments), checkRequired("itemId", itemId), - checkRequired("name", name), checkRequired("outputIndex", outputIndex), checkRequired("sequenceNumber", sequenceNumber), type, + name, additionalProperties.toMutableMap(), ) } @@ -323,7 +322,6 @@ private constructor( arguments() itemId() - name() outputIndex() sequenceNumber() _type().let { @@ -331,6 +329,7 @@ private constructor( throw OpenAIInvalidDataException("'type' is invalid, received $it") } } + name() validated = true } @@ -351,10 +350,12 @@ private constructor( internal fun validity(): Int = (if (arguments.asKnown().isPresent) 1 else 0) + (if (itemId.asKnown().isPresent) 1 else 0) + - (if (name.asKnown().isPresent) 1 else 0) + (if (outputIndex.asKnown().isPresent) 1 else 0) + (if (sequenceNumber.asKnown().isPresent) 1 else 0) + - type.let { if (it == JsonValue.from("response.function_call_arguments.done")) 1 else 0 } + type.let { + if (it == JsonValue.from("response.function_call_arguments.done")) 1 else 0 + } + + (if (name.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { @@ -364,10 +365,10 @@ private constructor( return other is ResponseFunctionCallArgumentsDoneEvent && arguments == other.arguments && itemId == other.itemId && - name == other.name && outputIndex == other.outputIndex && sequenceNumber == other.sequenceNumber && type == other.type && + name == other.name && additionalProperties == other.additionalProperties } @@ -375,10 +376,10 @@ private constructor( Objects.hash( arguments, itemId, - name, outputIndex, sequenceNumber, type, + name, additionalProperties, ) } @@ -386,5 +387,5 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "ResponseFunctionCallArgumentsDoneEvent{arguments=$arguments, itemId=$itemId, name=$name, outputIndex=$outputIndex, sequenceNumber=$sequenceNumber, type=$type, additionalProperties=$additionalProperties}" + "ResponseFunctionCallArgumentsDoneEvent{arguments=$arguments, itemId=$itemId, outputIndex=$outputIndex, sequenceNumber=$sequenceNumber, type=$type, name=$name, additionalProperties=$additionalProperties}" } diff --git a/openai-java-core/src/test/kotlin/com/openai/models/beta/responses/BetaResponseFunctionCallArgumentsDoneEventTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/beta/responses/BetaResponseFunctionCallArgumentsDoneEventTest.kt index 757cb520b..59e7b1833 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/beta/responses/BetaResponseFunctionCallArgumentsDoneEventTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/beta/responses/BetaResponseFunctionCallArgumentsDoneEventTest.kt @@ -15,7 +15,6 @@ internal class BetaResponseFunctionCallArgumentsDoneEventTest { BetaResponseFunctionCallArgumentsDoneEvent.builder() .arguments("arguments") .itemId("item_id") - .name("name") .outputIndex(0L) .sequenceNumber(0L) .agent( @@ -23,11 +22,11 @@ internal class BetaResponseFunctionCallArgumentsDoneEventTest { .agentName("agent_name") .build() ) + .name("name") .build() assertThat(betaResponseFunctionCallArgumentsDoneEvent.arguments()).isEqualTo("arguments") assertThat(betaResponseFunctionCallArgumentsDoneEvent.itemId()).isEqualTo("item_id") - assertThat(betaResponseFunctionCallArgumentsDoneEvent.name()).isEqualTo("name") assertThat(betaResponseFunctionCallArgumentsDoneEvent.outputIndex()).isEqualTo(0L) assertThat(betaResponseFunctionCallArgumentsDoneEvent.sequenceNumber()).isEqualTo(0L) assertThat(betaResponseFunctionCallArgumentsDoneEvent.agent()) @@ -36,6 +35,7 @@ internal class BetaResponseFunctionCallArgumentsDoneEventTest { .agentName("agent_name") .build() ) + assertThat(betaResponseFunctionCallArgumentsDoneEvent.name()).contains("name") } @Test @@ -45,7 +45,6 @@ internal class BetaResponseFunctionCallArgumentsDoneEventTest { BetaResponseFunctionCallArgumentsDoneEvent.builder() .arguments("arguments") .itemId("item_id") - .name("name") .outputIndex(0L) .sequenceNumber(0L) .agent( @@ -53,6 +52,7 @@ internal class BetaResponseFunctionCallArgumentsDoneEventTest { .agentName("agent_name") .build() ) + .name("name") .build() val roundtrippedBetaResponseFunctionCallArgumentsDoneEvent = diff --git a/openai-java-core/src/test/kotlin/com/openai/models/beta/responses/BetaResponseStreamEventTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/beta/responses/BetaResponseStreamEventTest.kt index d96049361..5b442face 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/beta/responses/BetaResponseStreamEventTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/beta/responses/BetaResponseStreamEventTest.kt @@ -2831,7 +2831,6 @@ internal class BetaResponseStreamEventTest { BetaResponseFunctionCallArgumentsDoneEvent.builder() .arguments("arguments") .itemId("item_id") - .name("name") .outputIndex(0L) .sequenceNumber(0L) .agent( @@ -2839,6 +2838,7 @@ internal class BetaResponseStreamEventTest { .agentName("agent_name") .build() ) + .name("name") .build() val betaResponseStreamEvent = @@ -2915,7 +2915,6 @@ internal class BetaResponseStreamEventTest { BetaResponseFunctionCallArgumentsDoneEvent.builder() .arguments("arguments") .itemId("item_id") - .name("name") .outputIndex(0L) .sequenceNumber(0L) .agent( @@ -2923,6 +2922,7 @@ internal class BetaResponseStreamEventTest { .agentName("agent_name") .build() ) + .name("name") .build() ) diff --git a/openai-java-core/src/test/kotlin/com/openai/models/beta/responses/BetaResponsesServerEventTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/beta/responses/BetaResponsesServerEventTest.kt index 616f2cb84..6fe165e2b 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/beta/responses/BetaResponsesServerEventTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/beta/responses/BetaResponsesServerEventTest.kt @@ -2826,7 +2826,6 @@ internal class BetaResponsesServerEventTest { BetaResponseFunctionCallArgumentsDoneEvent.builder() .arguments("arguments") .itemId("item_id") - .name("name") .outputIndex(0L) .sequenceNumber(0L) .agent( @@ -2834,6 +2833,7 @@ internal class BetaResponsesServerEventTest { .agentName("agent_name") .build() ) + .name("name") .build() val betaResponsesServerEvent = @@ -2912,7 +2912,6 @@ internal class BetaResponsesServerEventTest { BetaResponseFunctionCallArgumentsDoneEvent.builder() .arguments("arguments") .itemId("item_id") - .name("name") .outputIndex(0L) .sequenceNumber(0L) .agent( @@ -2920,6 +2919,7 @@ internal class BetaResponsesServerEventTest { .agentName("agent_name") .build() ) + .name("name") .build() ) diff --git a/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseFunctionCallArgumentsDoneEventTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseFunctionCallArgumentsDoneEventTest.kt index 3e4d33008..bb744545a 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseFunctionCallArgumentsDoneEventTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseFunctionCallArgumentsDoneEventTest.kt @@ -15,16 +15,16 @@ internal class ResponseFunctionCallArgumentsDoneEventTest { ResponseFunctionCallArgumentsDoneEvent.builder() .arguments("arguments") .itemId("item_id") - .name("name") .outputIndex(0L) .sequenceNumber(0L) + .name("name") .build() assertThat(responseFunctionCallArgumentsDoneEvent.arguments()).isEqualTo("arguments") assertThat(responseFunctionCallArgumentsDoneEvent.itemId()).isEqualTo("item_id") - assertThat(responseFunctionCallArgumentsDoneEvent.name()).isEqualTo("name") assertThat(responseFunctionCallArgumentsDoneEvent.outputIndex()).isEqualTo(0L) assertThat(responseFunctionCallArgumentsDoneEvent.sequenceNumber()).isEqualTo(0L) + assertThat(responseFunctionCallArgumentsDoneEvent.name()).contains("name") } @Test @@ -34,9 +34,9 @@ internal class ResponseFunctionCallArgumentsDoneEventTest { ResponseFunctionCallArgumentsDoneEvent.builder() .arguments("arguments") .itemId("item_id") - .name("name") .outputIndex(0L) .sequenceNumber(0L) + .name("name") .build() val roundtrippedResponseFunctionCallArgumentsDoneEvent = diff --git a/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseStreamEventTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseStreamEventTest.kt index e57ad78b3..cc1daac62 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseStreamEventTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseStreamEventTest.kt @@ -2615,9 +2615,9 @@ internal class ResponseStreamEventTest { ResponseFunctionCallArgumentsDoneEvent.builder() .arguments("arguments") .itemId("item_id") - .name("name") .outputIndex(0L) .sequenceNumber(0L) + .name("name") .build() val responseStreamEvent = @@ -2692,9 +2692,9 @@ internal class ResponseStreamEventTest { ResponseFunctionCallArgumentsDoneEvent.builder() .arguments("arguments") .itemId("item_id") - .name("name") .outputIndex(0L) .sequenceNumber(0L) + .name("name") .build() ) diff --git a/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponsesServerEventTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponsesServerEventTest.kt index 714353bf6..0a7532b64 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponsesServerEventTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponsesServerEventTest.kt @@ -2594,9 +2594,9 @@ internal class ResponsesServerEventTest { ResponseFunctionCallArgumentsDoneEvent.builder() .arguments("arguments") .itemId("item_id") - .name("name") .outputIndex(0L) .sequenceNumber(0L) + .name("name") .build() val responsesServerEvent = @@ -2673,9 +2673,9 @@ internal class ResponsesServerEventTest { ResponseFunctionCallArgumentsDoneEvent.builder() .arguments("arguments") .itemId("item_id") - .name("name") .outputIndex(0L) .sequenceNumber(0L) + .name("name") .build() ) diff --git a/openai-java-core/src/test/kotlin/com/openai/services/ResponseStreamEventValidationTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/ResponseStreamEventValidationTest.kt index cc0edae2d..6b292caf4 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/ResponseStreamEventValidationTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/ResponseStreamEventValidationTest.kt @@ -26,7 +26,12 @@ internal class ResponseStreamEventValidationTest { @ParameterizedTest @EnumSource(StreamingCall::class) fun keepaliveDoesNotBreakValidatedStreams(streamingCall: StreamingCall) { - val result = consume(streamingCall, responseValidation = true, middleType = "keepalive") + val result = + consume( + streamingCall, + responseValidation = true, + middleEvent = """{"type":"keepalive","sequence_number":2}""", + ) assertThat(result.error).isNull() assertThat(result.events.map(::eventType)) @@ -41,7 +46,12 @@ internal class ResponseStreamEventValidationTest { @ParameterizedTest @EnumSource(StreamingCall::class) fun otherUnknownEventsStillFailValidation(streamingCall: StreamingCall) { - val result = consume(streamingCall, responseValidation = true, middleType = "future.event") + val result = + consume( + streamingCall, + responseValidation = true, + middleEvent = """{"type":"future.event","sequence_number":2}""", + ) assertThat(result.error) .isInstanceOf(OpenAIInvalidDataException::class.java) @@ -57,7 +67,7 @@ internal class ResponseStreamEventValidationTest { consume( StreamingCall.ASYNC_CREATE, responseValidation = false, - middleType = "future.event", + middleEvent = """{"type":"future.event","sequence_number":2}""", ) assertThat(result.error).isNull() @@ -70,14 +80,41 @@ internal class ResponseStreamEventValidationTest { assertThat(result.outputTextDeltas()).containsExactly("before", "after") } + @ParameterizedTest + @EnumSource(StreamingCall::class) + fun functionCallArgumentsDoneWithoutNameKeepsValidatedStreamUsable( + streamingCall: StreamingCall + ) { + val result = + consume( + streamingCall, + responseValidation = true, + middleEvent = + """{"type":"response.function_call_arguments.done","item_id":"item_function","output_index":0,"arguments":"{}","sequence_number":2}""", + ) + + assertThat(result.error).isNull() + assertThat(result.events.map(::eventType)) + .containsExactly( + "response.output_text.delta", + "response.function_call_arguments.done", + "response.output_text.delta", + ) + val event = result.events[1].asFunctionCallArgumentsDone() + assertThat(event.name()).isEmpty() + assertThat(event.arguments()).isEqualTo("{}") + assertThat(event.itemId()).isEqualTo("item_function") + assertThat(result.outputTextDeltas()).containsExactly("before", "after") + } + private fun consume( streamingCall: StreamingCall, responseValidation: Boolean, - middleType: String, + middleEvent: String, ): ConsumeResult { val clientOptions = ClientOptions.builder() - .httpClient(FakeSseHttpClient(sseBody(middleType))) + .httpClient(FakeSseHttpClient(sseBody(middleEvent))) .apiKey("test-api-key") .responseValidation(responseValidation) .streamHandlerExecutor(Executor(Runnable::run)) @@ -164,11 +201,11 @@ internal class ResponseStreamEventValidationTest { fun Throwable.unwrapCompletionException(): Throwable = if (this is CompletionException && cause != null) cause!! else this - fun sseBody(middleType: String): String = + fun sseBody(middleEvent: String): String = """ data: {"type":"response.output_text.delta","content_index":0,"delta":"before","item_id":"item_1","logprobs":[],"output_index":0,"sequence_number":1} - data: {"type":"$middleType","sequence_number":2} + data: $middleEvent data: {"type":"response.output_text.delta","content_index":0,"delta":"after","item_id":"item_1","logprobs":[],"output_index":0,"sequence_number":3}