Skip to content

Commit 3b809df

Browse files
release: 2.18.2 (#551)
* fix(client): support structured outputs in async requests (#548). (#550) * release: 2.18.2 --------- Co-authored-by: D Gardner <[email protected]> Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com>
1 parent f380c56 commit 3b809df

File tree

9 files changed

+281
-11
lines changed

9 files changed

+281
-11
lines changed

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "2.18.1"
2+
".": "2.18.2"
33
}

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## 2.18.2 (2025-07-22)
4+
5+
Full Changelog: [v2.18.1...v2.18.2](https://github.com/openai/openai-java/compare/v2.18.1...v2.18.2)
6+
7+
### Bug Fixes
8+
9+
* **client:** support structured outputs in async requests ([#548](https://github.com/openai/openai-java/issues/548)). ([#550](https://github.com/openai/openai-java/issues/550)) ([b9d52cf](https://github.com/openai/openai-java/commit/b9d52cf6e03c886dcdd5e0da3f16ea436220f09c))
10+
311
## 2.18.1 (2025-07-22)
412

513
Full Changelog: [v2.18.0...v2.18.1](https://github.com/openai/openai-java/compare/v2.18.0...v2.18.1)

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@
22

33
<!-- x-release-please-start-version -->
44

5-
[![Maven Central](https://img.shields.io/maven-central/v/com.openai/openai-java)](https://central.sonatype.com/artifact/com.openai/openai-java/2.18.1)
6-
[![javadoc](https://javadoc.io/badge2/com.openai/openai-java/2.18.1/javadoc.svg)](https://javadoc.io/doc/com.openai/openai-java/2.18.1)
5+
[![Maven Central](https://img.shields.io/maven-central/v/com.openai/openai-java)](https://central.sonatype.com/artifact/com.openai/openai-java/2.18.2)
6+
[![javadoc](https://javadoc.io/badge2/com.openai/openai-java/2.18.2/javadoc.svg)](https://javadoc.io/doc/com.openai/openai-java/2.18.2)
77

88
<!-- x-release-please-end -->
99

1010
The OpenAI Java SDK provides convenient access to the [OpenAI REST API](https://platform.openai.com/docs) from applications written in Java.
1111

1212
<!-- x-release-please-start-version -->
1313

14-
The REST API documentation can be found on [platform.openai.com](https://platform.openai.com/docs). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.openai/openai-java/2.18.1).
14+
The REST API documentation can be found on [platform.openai.com](https://platform.openai.com/docs). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.openai/openai-java/2.18.2).
1515

1616
<!-- x-release-please-end -->
1717

@@ -24,7 +24,7 @@ The REST API documentation can be found on [platform.openai.com](https://platfor
2424
### Gradle
2525

2626
```kotlin
27-
implementation("com.openai:openai-java:2.18.1")
27+
implementation("com.openai:openai-java:2.18.2")
2828
```
2929

3030
### Maven
@@ -33,7 +33,7 @@ implementation("com.openai:openai-java:2.18.1")
3333
<dependency>
3434
<groupId>com.openai</groupId>
3535
<artifactId>openai-java</artifactId>
36-
<version>2.18.1</version>
36+
<version>2.18.2</version>
3737
</dependency>
3838
```
3939

@@ -1321,7 +1321,7 @@ If you're using Spring Boot, then you can use the SDK's [Spring Boot starter](ht
13211321
#### Gradle
13221322

13231323
```kotlin
1324-
implementation("com.openai:openai-java-spring-boot-starter:2.18.1")
1324+
implementation("com.openai:openai-java-spring-boot-starter:2.18.2")
13251325
```
13261326

13271327
#### Maven
@@ -1330,7 +1330,7 @@ implementation("com.openai:openai-java-spring-boot-starter:2.18.1")
13301330
<dependency>
13311331
<groupId>com.openai</groupId>
13321332
<artifactId>openai-java-spring-boot-starter</artifactId>
1333-
<version>2.18.1</version>
1333+
<version>2.18.2</version>
13341334
</dependency>
13351335
```
13361336

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ repositories {
88

99
allprojects {
1010
group = "com.openai"
11-
version = "2.18.1" // x-release-please-version
11+
version = "2.18.2" // x-release-please-version
1212
}
1313

1414
subprojects {

openai-java-core/src/main/kotlin/com/openai/services/async/ResponseServiceAsync.kt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import com.openai.models.responses.ResponseCreateParams
1515
import com.openai.models.responses.ResponseDeleteParams
1616
import com.openai.models.responses.ResponseRetrieveParams
1717
import com.openai.models.responses.ResponseStreamEvent
18+
import com.openai.models.responses.StructuredResponse
19+
import com.openai.models.responses.StructuredResponseCreateParams
1820
import com.openai.services.async.responses.InputItemServiceAsync
1921
import java.util.concurrent.CompletableFuture
2022
import java.util.function.Consumer
@@ -63,6 +65,30 @@ interface ResponseServiceAsync {
6365
fun create(requestOptions: RequestOptions): CompletableFuture<Response> =
6466
create(ResponseCreateParams.none(), requestOptions)
6567

68+
/**
69+
* Creates a model response. The model's structured output in JSON form will be deserialized
70+
* automatically into an instance of the class `T`. See the SDK documentation for more details.
71+
*
72+
* @see create
73+
*/
74+
fun <T : Any> create(
75+
params: StructuredResponseCreateParams<T>
76+
): CompletableFuture<StructuredResponse<T>> = create(params, RequestOptions.none())
77+
78+
/**
79+
* Creates a model response. The model's structured output in JSON form will be deserialized
80+
* automatically into an instance of the class `T`. See the SDK documentation for more details.
81+
*
82+
* @see create
83+
*/
84+
fun <T : Any> create(
85+
params: StructuredResponseCreateParams<T>,
86+
requestOptions: RequestOptions = RequestOptions.none(),
87+
): CompletableFuture<StructuredResponse<T>> =
88+
create(params.rawParams, requestOptions).thenApply {
89+
StructuredResponse<T>(params.responseType, it)
90+
}
91+
6692
/**
6793
* Creates a model response. Provide [text](https://platform.openai.com/docs/guides/text) or
6894
* [image](https://platform.openai.com/docs/guides/images) inputs to generate
@@ -92,6 +118,26 @@ interface ResponseServiceAsync {
92118
fun createStreaming(requestOptions: RequestOptions): AsyncStreamResponse<ResponseStreamEvent> =
93119
createStreaming(ResponseCreateParams.none(), requestOptions)
94120

121+
/**
122+
* Creates a streaming model response for the given response conversation. The input parameters
123+
* can define a JSON schema derived automatically from an arbitrary class to request a
124+
* structured output in JSON form. However, that structured output is split over multiple
125+
* streamed events, so it will not be deserialized automatically into an instance of that class.
126+
* To deserialize the output, first use a helper class to accumulate the stream of events into a
127+
* single output value. See the
128+
* [SDK documentation](https://github.com/openai/openai-java/#usage-with-streaming) for full
129+
* details.
130+
*/
131+
fun createStreaming(
132+
params: StructuredResponseCreateParams<*>
133+
): AsyncStreamResponse<ResponseStreamEvent> = createStreaming(params, RequestOptions.none())
134+
135+
/** @see [createStreaming] */
136+
fun createStreaming(
137+
params: StructuredResponseCreateParams<*>,
138+
requestOptions: RequestOptions = RequestOptions.none(),
139+
): AsyncStreamResponse<ResponseStreamEvent> = createStreaming(params.rawParams, requestOptions)
140+
95141
/** Retrieves a model response with the given ID. */
96142
fun retrieve(responseId: String): CompletableFuture<Response> =
97143
retrieve(responseId, ResponseRetrieveParams.none())

openai-java-core/src/main/kotlin/com/openai/services/async/chat/ChatCompletionServiceAsync.kt

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import com.openai.models.chat.completions.ChatCompletionListPageAsync
1717
import com.openai.models.chat.completions.ChatCompletionListParams
1818
import com.openai.models.chat.completions.ChatCompletionRetrieveParams
1919
import com.openai.models.chat.completions.ChatCompletionUpdateParams
20+
import com.openai.models.chat.completions.StructuredChatCompletion
21+
import com.openai.models.chat.completions.StructuredChatCompletionCreateParams
2022
import com.openai.services.async.chat.completions.MessageServiceAsync
2123
import java.util.concurrent.CompletableFuture
2224
import java.util.function.Consumer
@@ -64,6 +66,32 @@ interface ChatCompletionServiceAsync {
6466
requestOptions: RequestOptions = RequestOptions.none(),
6567
): CompletableFuture<ChatCompletion>
6668

69+
/**
70+
* Creates a model response for the given chat conversation. The model's structured output in
71+
* JSON form will be deserialized automatically into an instance of the class `T`. See the SDK
72+
* documentation for more details.
73+
*
74+
* @see create
75+
*/
76+
fun <T : Any> create(
77+
params: StructuredChatCompletionCreateParams<T>
78+
): CompletableFuture<StructuredChatCompletion<T>> = create(params, RequestOptions.none())
79+
80+
/**
81+
* Creates a model response for the given chat conversation. The model's structured output in
82+
* JSON form will be deserialized automatically into an instance of the class `T`. See the SDK
83+
* documentation for more details.
84+
*
85+
* @see create
86+
*/
87+
fun <T : Any> create(
88+
params: StructuredChatCompletionCreateParams<T>,
89+
requestOptions: RequestOptions = RequestOptions.none(),
90+
): CompletableFuture<StructuredChatCompletion<T>> =
91+
create(params.rawParams, requestOptions).thenApply {
92+
StructuredChatCompletion<T>(params.responseType, it)
93+
}
94+
6795
/**
6896
* **Starting a new project?** We recommend trying
6997
* [Responses](https://platform.openai.com/docs/api-reference/responses) to take advantage of
@@ -92,6 +120,26 @@ interface ChatCompletionServiceAsync {
92120
requestOptions: RequestOptions = RequestOptions.none(),
93121
): AsyncStreamResponse<ChatCompletionChunk>
94122

123+
/**
124+
* Creates a streaming model response for the given chat conversation. The input parameters can
125+
* define a JSON schema derived automatically from an arbitrary class to request a structured
126+
* output in JSON form. However, that structured output is split over multiple streamed events,
127+
* so it will not be deserialized automatically into an instance of that class. To deserialize
128+
* the output, first use a helper class to accumulate the stream of events into a single output
129+
* value. See the
130+
* [SDK documentation](https://github.com/openai/openai-java/#usage-with-streaming) for full
131+
* details.
132+
*/
133+
fun createStreaming(
134+
params: StructuredChatCompletionCreateParams<*>
135+
): AsyncStreamResponse<ChatCompletionChunk> = createStreaming(params, RequestOptions.none())
136+
137+
/** @see [createStreaming] */
138+
fun createStreaming(
139+
params: StructuredChatCompletionCreateParams<*>,
140+
requestOptions: RequestOptions = RequestOptions.none(),
141+
): AsyncStreamResponse<ChatCompletionChunk> = createStreaming(params.rawParams, requestOptions)
142+
95143
/**
96144
* Get a stored chat completion. Only Chat Completions that have been created with the `store`
97145
* parameter set to `true` will be returned.

openai-java-core/src/main/kotlin/com/openai/services/blocking/ResponseService.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,10 @@ interface ResponseService {
121121
* can define a JSON schema derived automatically from an arbitrary class to request a
122122
* structured output in JSON form. However, that structured output is split over multiple
123123
* streamed events, so it will not be deserialized automatically into an instance of that class.
124-
* See the [SDK documentation](https://github.com/openai/openai-java/#usage-with-streaming) for
125-
* full details.
124+
* To deserialize the output, first use a helper class to accumulate the stream of events into a
125+
* single output value. See the
126+
* [SDK documentation](https://github.com/openai/openai-java/#usage-with-streaming) for full
127+
* details.
126128
*/
127129
@MustBeClosed
128130
fun createStreaming(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package com.openai.example;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnore;
4+
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
5+
import com.openai.client.OpenAIClientAsync;
6+
import com.openai.client.okhttp.OpenAIOkHttpClientAsync;
7+
import com.openai.helpers.ResponseAccumulator;
8+
import com.openai.models.ChatModel;
9+
import com.openai.models.responses.ResponseCreateParams;
10+
import com.openai.models.responses.StructuredResponseCreateParams;
11+
import java.util.List;
12+
13+
public final class ResponsesStructuredOutputsStreamingAsyncExample {
14+
15+
public static class Person {
16+
@JsonPropertyDescription("The first name and surname of the person.")
17+
public String name;
18+
19+
public int birthYear;
20+
21+
@JsonPropertyDescription("The year the person died, or 'present' if the person is living.")
22+
public String deathYear;
23+
24+
@Override
25+
public String toString() {
26+
return name + " (" + birthYear + '-' + deathYear + ')';
27+
}
28+
}
29+
30+
public static class Book {
31+
public String title;
32+
33+
public Person author;
34+
35+
@JsonPropertyDescription("The year in which the book was first published.")
36+
public int publicationYear;
37+
38+
public String genre;
39+
40+
@JsonIgnore
41+
public String isbn;
42+
43+
@Override
44+
public String toString() {
45+
return '"' + title + "\" (" + publicationYear + ") [" + genre + "] by " + author;
46+
}
47+
}
48+
49+
public static class BookList {
50+
public List<Book> books;
51+
}
52+
53+
private ResponsesStructuredOutputsStreamingAsyncExample() {}
54+
55+
public static void main(String[] args) {
56+
// Configure using one of:
57+
// - The `OPENAI_API_KEY` environment variable
58+
// - The `OPENAI_BASE_URL` and `AZURE_OPENAI_KEY` environment variables
59+
OpenAIClientAsync client = OpenAIOkHttpClientAsync.fromEnv();
60+
61+
StructuredResponseCreateParams<BookList> createParams = ResponseCreateParams.builder()
62+
.input("List some famous late twentieth century novels.")
63+
.text(BookList.class)
64+
.model(ChatModel.GPT_4O)
65+
.build();
66+
67+
ResponseAccumulator accumulator = ResponseAccumulator.create();
68+
69+
client.responses()
70+
.createStreaming(createParams)
71+
.subscribe(event -> accumulator
72+
.accumulate(event)
73+
.outputTextDelta()
74+
.ifPresent(textEvent -> System.out.print(textEvent.delta())))
75+
.onCompleteFuture()
76+
.join();
77+
System.out.println();
78+
79+
accumulator.response(BookList.class).output().stream()
80+
.flatMap(item -> item.message().stream())
81+
.flatMap(message -> message.content().stream())
82+
.flatMap(content -> content.outputText().stream())
83+
.flatMap(bookList -> bookList.books.stream())
84+
.forEach(book -> System.out.println(" - " + book));
85+
}
86+
}

0 commit comments

Comments
 (0)