1
1
package com.openai.helpers
2
2
3
+ import com.openai.errors.OpenAIInvalidDataException
3
4
import com.openai.models.responses.Response
4
5
import com.openai.models.responses.ResponseAudioDeltaEvent
5
6
import com.openai.models.responses.ResponseAudioDoneEvent
@@ -21,19 +22,41 @@ import com.openai.models.responses.ResponseFileSearchCallInProgressEvent
21
22
import com.openai.models.responses.ResponseFileSearchCallSearchingEvent
22
23
import com.openai.models.responses.ResponseFunctionCallArgumentsDeltaEvent
23
24
import com.openai.models.responses.ResponseFunctionCallArgumentsDoneEvent
25
+ import com.openai.models.responses.ResponseImageGenCallCompletedEvent
26
+ import com.openai.models.responses.ResponseImageGenCallGeneratingEvent
27
+ import com.openai.models.responses.ResponseImageGenCallInProgressEvent
28
+ import com.openai.models.responses.ResponseImageGenCallPartialImageEvent
24
29
import com.openai.models.responses.ResponseInProgressEvent
25
30
import com.openai.models.responses.ResponseIncompleteEvent
31
+ import com.openai.models.responses.ResponseMcpCallArgumentsDeltaEvent
32
+ import com.openai.models.responses.ResponseMcpCallArgumentsDoneEvent
33
+ import com.openai.models.responses.ResponseMcpCallCompletedEvent
34
+ import com.openai.models.responses.ResponseMcpCallFailedEvent
35
+ import com.openai.models.responses.ResponseMcpCallInProgressEvent
36
+ import com.openai.models.responses.ResponseMcpListToolsCompletedEvent
37
+ import com.openai.models.responses.ResponseMcpListToolsFailedEvent
38
+ import com.openai.models.responses.ResponseMcpListToolsInProgressEvent
26
39
import com.openai.models.responses.ResponseOutputItemAddedEvent
27
40
import com.openai.models.responses.ResponseOutputItemDoneEvent
41
+ import com.openai.models.responses.ResponseOutputTextAnnotationAddedEvent
42
+ import com.openai.models.responses.ResponseQueuedEvent
43
+ import com.openai.models.responses.ResponseReasoningDeltaEvent
44
+ import com.openai.models.responses.ResponseReasoningDoneEvent
45
+ import com.openai.models.responses.ResponseReasoningSummaryDeltaEvent
46
+ import com.openai.models.responses.ResponseReasoningSummaryDoneEvent
47
+ import com.openai.models.responses.ResponseReasoningSummaryPartAddedEvent
48
+ import com.openai.models.responses.ResponseReasoningSummaryPartDoneEvent
49
+ import com.openai.models.responses.ResponseReasoningSummaryTextDeltaEvent
50
+ import com.openai.models.responses.ResponseReasoningSummaryTextDoneEvent
28
51
import com.openai.models.responses.ResponseRefusalDeltaEvent
29
52
import com.openai.models.responses.ResponseRefusalDoneEvent
30
53
import com.openai.models.responses.ResponseStreamEvent
31
- import com.openai.models.responses.ResponseTextAnnotationDeltaEvent
32
54
import com.openai.models.responses.ResponseTextDeltaEvent
33
55
import com.openai.models.responses.ResponseTextDoneEvent
34
56
import com.openai.models.responses.ResponseWebSearchCallCompletedEvent
35
57
import com.openai.models.responses.ResponseWebSearchCallInProgressEvent
36
58
import com.openai.models.responses.ResponseWebSearchCallSearchingEvent
59
+ import com.openai.models.responses.StructuredResponse
37
60
38
61
/* *
39
62
* An accumulator that constructs a [Response] from a sequence of streamed events. Pass all events
@@ -64,9 +87,28 @@ class ResponseAccumulator private constructor() {
64
87
*/
65
88
fun response () = checkNotNull(response) { " Completed response is not yet received." }
66
89
90
+ /* *
91
+ * Gets the final accumulated response with support for structured outputs. Until the last event
92
+ * has been accumulated, a [StructuredResponse] will not be available. Wait until all events
93
+ * have been handled by [accumulate] before calling this method. See that method for more
94
+ * details on how the last event is detected. See the
95
+ * [SDK documentation](https://github.com/openai/openai-java/#usage-with-streaming) for more
96
+ * details and example code.
97
+ *
98
+ * @param responseType The Java class from which the JSON schema in the request was derived. The
99
+ * output JSON conforming to that schema can be converted automatically back to an instance of
100
+ * that Java class by the [StructuredResponse].
101
+ * @throws IllegalStateException If called before the last event has been accumulated.
102
+ * @throws OpenAIInvalidDataException If the JSON data cannot be parsed to an instance of the
103
+ * [responseType] class.
104
+ */
105
+ fun <T : Any > response (responseType : Class <T >) = StructuredResponse (responseType, response())
106
+
67
107
/* *
68
108
* Accumulates a streamed event and uses it to construct a [Response]. When all events have been
69
- * accumulated, the response can be retrieved by calling [response].
109
+ * accumulated, the response can be retrieved by calling [response]. The last event is detected
110
+ * if one of `ResponseCompletedEvent`, `ResponseIncompleteEvent`, or `ResponseFailedEvent` is
111
+ * accumulated. After that event, no more events are expected.
70
112
*
71
113
* @return The given [event] for convenience, such as when chaining method calls.
72
114
* @throws IllegalStateException If [accumulate] is called again after the last event has been
@@ -78,64 +120,93 @@ class ResponseAccumulator private constructor() {
78
120
event.accept(
79
121
object : ResponseStreamEvent .Visitor <Unit > {
80
122
// --------------------------------------------------------------------------------
81
- // The following events _all_ have a `Response ` property.
123
+ // The following events _all_ have a `response ` property.
82
124
83
125
override fun visitCreated (created : ResponseCreatedEvent ) {
84
- // TODO: Taking not action here on the assumption that there is no need to store
85
- // the initial `Response` (devoid of any content), as it will be replaced
86
- // later by one of the "terminal" events. OTOH, this could be useful if the
87
- // events stop suddenly before any further response details can be recorded.
126
+ // The initial response (on creation) has no content, so it is not stored.
127
+ }
128
+
129
+ override fun visitCompleted (completed : ResponseCompletedEvent ) {
130
+ response = completed.response()
88
131
}
89
132
90
133
override fun visitInProgress (inProgress : ResponseInProgressEvent ) {
91
- // TODO: Taking no action here on the assumption that this is just some sort of
92
- // "keep-alive" event that carries no new data that needs to be accumulated.
93
- // OTOH, if the events stop suddenly, this could be used as a "partial"
94
- // response, or an ongoing "story so far".
134
+ // An in-progress response is not complete, so it is not stored.
95
135
}
96
136
97
- override fun visitCompleted (completed : ResponseCompletedEvent ) {
98
- response = completed.response()
137
+ override fun visitQueued (queued : ResponseQueuedEvent ) {
138
+ // A queued response that is awaiting processing is not complete, so it is not
139
+ // stored.
99
140
}
100
141
101
142
override fun visitFailed (failed : ResponseFailedEvent ) {
102
143
// TODO: Confirm that this is a "terminal" event and will occur _instead of_
103
- // `ResponseCompletedEvent`.
144
+ // `ResponseCompletedEvent` or `ResponseIncompleteEvent`.
145
+ // Store the response so the reason for the failure can be interrogated.
104
146
response = failed.response()
105
147
}
106
148
107
149
override fun visitIncomplete (incomplete : ResponseIncompleteEvent ) {
108
150
// TODO: Confirm that this is a "terminal" event and will occur _instead of_
109
- // `ResponseCompletedEvent`.
151
+ // `ResponseCompletedEvent` or `ResponseFailedEvent`.
152
+ // Store the response so the reason for the incompleteness can be interrogated.
110
153
response = incomplete.response()
111
154
}
112
155
113
156
// --------------------------------------------------------------------------------
114
157
// The following events do _not_ have a `Response` property.
115
158
116
- override fun visitError ( error : ResponseErrorEvent ) {}
159
+ override fun visitAudioDelta ( audioDelta : ResponseAudioDeltaEvent ) {}
117
160
118
- override fun visitOutputItemAdded ( outputItemAdded : ResponseOutputItemAddedEvent ) {}
161
+ override fun visitAudioDone ( audioDone : ResponseAudioDoneEvent ) {}
119
162
120
- override fun visitOutputItemDone (outputItemDone : ResponseOutputItemDoneEvent ) {}
163
+ override fun visitAudioTranscriptDelta (
164
+ audioTranscriptDelta : ResponseAudioTranscriptDeltaEvent
165
+ ) {}
166
+
167
+ override fun visitAudioTranscriptDone (
168
+ audioTranscriptDone : ResponseAudioTranscriptDoneEvent
169
+ ) {}
170
+
171
+ override fun visitCodeInterpreterCallCodeDelta (
172
+ codeInterpreterCallCodeDelta : ResponseCodeInterpreterCallCodeDeltaEvent
173
+ ) {}
174
+
175
+ override fun visitCodeInterpreterCallCodeDone (
176
+ codeInterpreterCallCodeDone : ResponseCodeInterpreterCallCodeDoneEvent
177
+ ) {}
178
+
179
+ override fun visitCodeInterpreterCallCompleted (
180
+ codeInterpreterCallCompleted : ResponseCodeInterpreterCallCompletedEvent
181
+ ) {}
182
+
183
+ override fun visitCodeInterpreterCallInProgress (
184
+ codeInterpreterCallInProgress : ResponseCodeInterpreterCallInProgressEvent
185
+ ) {}
186
+
187
+ override fun visitCodeInterpreterCallInterpreting (
188
+ codeInterpreterCallInterpreting : ResponseCodeInterpreterCallInterpretingEvent
189
+ ) {}
121
190
122
191
override fun visitContentPartAdded (
123
192
contentPartAdded : ResponseContentPartAddedEvent
124
193
) {}
125
194
126
195
override fun visitContentPartDone (contentPartDone : ResponseContentPartDoneEvent ) {}
127
196
128
- override fun visitOutputTextDelta ( outputTextDelta : ResponseTextDeltaEvent ) {}
197
+ override fun visitError ( error : ResponseErrorEvent ) {}
129
198
130
- override fun visitOutputTextAnnotationAdded (
131
- outputTextAnnotationAdded : ResponseTextAnnotationDeltaEvent
199
+ override fun visitFileSearchCallCompleted (
200
+ fileSearchCallCompleted : ResponseFileSearchCallCompletedEvent
132
201
) {}
133
202
134
- override fun visitOutputTextDone ( outputTextDone : ResponseTextDoneEvent ) {}
135
-
136
- override fun visitRefusalDelta ( refusalDelta : ResponseRefusalDeltaEvent ) {}
203
+ override fun visitFileSearchCallInProgress (
204
+ fileSearchCallInProgress : ResponseFileSearchCallInProgressEvent
205
+ ) {}
137
206
138
- override fun visitRefusalDone (refusalDone : ResponseRefusalDoneEvent ) {}
207
+ override fun visitFileSearchCallSearching (
208
+ fileSearchCallSearching : ResponseFileSearchCallSearchingEvent
209
+ ) {}
139
210
140
211
override fun visitFunctionCallArgumentsDelta (
141
212
functionCallArgumentsDelta : ResponseFunctionCallArgumentsDeltaEvent
@@ -145,16 +216,36 @@ class ResponseAccumulator private constructor() {
145
216
functionCallArgumentsDone : ResponseFunctionCallArgumentsDoneEvent
146
217
) {}
147
218
148
- override fun visitFileSearchCallInProgress (
149
- fileSearchCallInProgress : ResponseFileSearchCallInProgressEvent
219
+ override fun visitOutputItemAdded (outputItemAdded : ResponseOutputItemAddedEvent ) {}
220
+
221
+ override fun visitOutputItemDone (outputItemDone : ResponseOutputItemDoneEvent ) {}
222
+
223
+ override fun visitReasoningSummaryPartAdded (
224
+ reasoningSummaryPartAdded : ResponseReasoningSummaryPartAddedEvent
150
225
) {}
151
226
152
- override fun visitFileSearchCallSearching (
153
- fileSearchCallSearching : ResponseFileSearchCallSearchingEvent
227
+ override fun visitReasoningSummaryPartDone (
228
+ reasoningSummaryPartDone : ResponseReasoningSummaryPartDoneEvent
154
229
) {}
155
230
156
- override fun visitFileSearchCallCompleted (
157
- fileSearchCallCompleted : ResponseFileSearchCallCompletedEvent
231
+ override fun visitReasoningSummaryTextDelta (
232
+ reasoningSummaryTextDelta : ResponseReasoningSummaryTextDeltaEvent
233
+ ) {}
234
+
235
+ override fun visitReasoningSummaryTextDone (
236
+ reasoningSummaryTextDone : ResponseReasoningSummaryTextDoneEvent
237
+ ) {}
238
+
239
+ override fun visitRefusalDelta (refusalDelta : ResponseRefusalDeltaEvent ) {}
240
+
241
+ override fun visitRefusalDone (refusalDone : ResponseRefusalDoneEvent ) {}
242
+
243
+ override fun visitOutputTextDelta (outputTextDelta : ResponseTextDeltaEvent ) {}
244
+
245
+ override fun visitOutputTextDone (outputTextDone : ResponseTextDoneEvent ) {}
246
+
247
+ override fun visitWebSearchCallCompleted (
248
+ webSearchCallCompleted : ResponseWebSearchCallCompletedEvent
158
249
) {}
159
250
160
251
override fun visitWebSearchCallInProgress (
@@ -165,40 +256,66 @@ class ResponseAccumulator private constructor() {
165
256
webSearchCallSearching : ResponseWebSearchCallSearchingEvent
166
257
) {}
167
258
168
- override fun visitWebSearchCallCompleted (
169
- webSearchCallCompleted : ResponseWebSearchCallCompletedEvent
259
+ override fun visitImageGenerationCallCompleted (
260
+ imageGenerationCallCompleted : ResponseImageGenCallCompletedEvent
170
261
) {}
171
262
172
- override fun visitAudioDelta (audioDelta : ResponseAudioDeltaEvent ) {}
263
+ override fun visitImageGenerationCallGenerating (
264
+ imageGenerationCallGenerating : ResponseImageGenCallGeneratingEvent
265
+ ) {}
173
266
174
- override fun visitAudioDone (audioDone : ResponseAudioDoneEvent ) {}
267
+ override fun visitImageGenerationCallInProgress (
268
+ imageGenerationCallInProgress : ResponseImageGenCallInProgressEvent
269
+ ) {}
175
270
176
- override fun visitAudioTranscriptDelta (
177
- audioTranscriptDelta : ResponseAudioTranscriptDeltaEvent
271
+ override fun visitImageGenerationCallPartialImage (
272
+ imageGenerationCallPartialImage : ResponseImageGenCallPartialImageEvent
178
273
) {}
179
274
180
- override fun visitAudioTranscriptDone (
181
- audioTranscriptDone : ResponseAudioTranscriptDoneEvent
275
+ override fun visitMcpCallArgumentsDelta (
276
+ mcpCallArgumentsDelta : ResponseMcpCallArgumentsDeltaEvent
182
277
) {}
183
278
184
- override fun visitCodeInterpreterCallCodeDelta (
185
- codeInterpreterCallCodeDelta : ResponseCodeInterpreterCallCodeDeltaEvent
279
+ override fun visitMcpCallArgumentsDone (
280
+ mcpCallArgumentsDone : ResponseMcpCallArgumentsDoneEvent
186
281
) {}
187
282
188
- override fun visitCodeInterpreterCallCodeDone (
189
- codeInterpreterCallCodeDone : ResponseCodeInterpreterCallCodeDoneEvent
283
+ override fun visitMcpCallCompleted (
284
+ mcpCallCompleted : ResponseMcpCallCompletedEvent
190
285
) {}
191
286
192
- override fun visitCodeInterpreterCallInProgress (
193
- codeInterpreterCallInProgress : ResponseCodeInterpreterCallInProgressEvent
287
+ override fun visitMcpCallFailed (mcpCallFailed : ResponseMcpCallFailedEvent ) {}
288
+
289
+ override fun visitMcpCallInProgress (
290
+ mcpCallInProgress : ResponseMcpCallInProgressEvent
194
291
) {}
195
292
196
- override fun visitCodeInterpreterCallInterpreting (
197
- codeInterpreterCallInterpreting : ResponseCodeInterpreterCallInterpretingEvent
293
+ override fun visitMcpListToolsCompleted (
294
+ mcpListToolsCompleted : ResponseMcpListToolsCompletedEvent
198
295
) {}
199
296
200
- override fun visitCodeInterpreterCallCompleted (
201
- codeInterpreterCallCompleted : ResponseCodeInterpreterCallCompletedEvent
297
+ override fun visitMcpListToolsFailed (
298
+ mcpListToolsFailed : ResponseMcpListToolsFailedEvent
299
+ ) {}
300
+
301
+ override fun visitMcpListToolsInProgress (
302
+ mcpListToolsInProgress : ResponseMcpListToolsInProgressEvent
303
+ ) {}
304
+
305
+ override fun visitOutputTextAnnotationAdded (
306
+ outputTextAnnotationAdded : ResponseOutputTextAnnotationAddedEvent
307
+ ) {}
308
+
309
+ override fun visitReasoningDelta (reasoningDelta : ResponseReasoningDeltaEvent ) {}
310
+
311
+ override fun visitReasoningDone (reasoningDone : ResponseReasoningDoneEvent ) {}
312
+
313
+ override fun visitReasoningSummaryDelta (
314
+ reasoningSummaryDelta : ResponseReasoningSummaryDeltaEvent
315
+ ) {}
316
+
317
+ override fun visitReasoningSummaryDone (
318
+ reasoningSummaryDone : ResponseReasoningSummaryDoneEvent
202
319
) {}
203
320
}
204
321
)
0 commit comments