2929import com .azure .ai .openai .OpenAIAsyncClient ;
3030import com .azure .ai .openai .OpenAIClient ;
3131import com .azure .ai .openai .OpenAIClientBuilder ;
32+ import com .azure .ai .openai .implementation .accesshelpers .ChatCompletionsOptionsAccessHelper ;
3233import com .azure .ai .openai .models .ChatChoice ;
3334import com .azure .ai .openai .models .ChatCompletions ;
3435import com .azure .ai .openai .models .ChatCompletionsFunctionToolCall ;
@@ -206,7 +207,7 @@ public ChatResponse call(Prompt prompt) {
206207 this .observationRegistry )
207208 .observe (() -> {
208209 ChatCompletionsOptions options = toAzureChatCompletionsOptions (prompt );
209- options .setStream (false );
210+ ChatCompletionsOptionsAccessHelper .setStream (options , false );
210211
211212 ChatCompletions chatCompletions = this .openAIClient .getChatCompletions (options .getModel (), options );
212213 ChatResponse chatResponse = toChatResponse (chatCompletions );
@@ -230,7 +231,7 @@ public Flux<ChatResponse> stream(Prompt prompt) {
230231
231232 return Flux .deferContextual (contextView -> {
232233 ChatCompletionsOptions options = toAzureChatCompletionsOptions (prompt );
233- options .setStream (true );
234+ ChatCompletionsOptionsAccessHelper .setStream (options , true );
234235
235236 Flux <ChatCompletions > chatCompletionsStream = this .openAIAsyncClient
236237 .getChatCompletionsStream (options .getModel (), options );
@@ -252,10 +253,14 @@ public Flux<ChatResponse> stream(Prompt prompt) {
252253 final Flux <ChatCompletions > accessibleChatCompletionsFlux = chatCompletionsStream
253254 // Note: the first chat completions can be ignored when using Azure OpenAI
254255 // service which is a known service bug.
255- .filter (chatCompletions -> !CollectionUtils .isEmpty (chatCompletions .getChoices ()))
256+ // The last element, when using stream_options will contain the usage data
257+ .filter (chatCompletions -> !CollectionUtils .isEmpty (chatCompletions .getChoices ())
258+ || chatCompletions .getUsage () != null )
256259 .map (chatCompletions -> {
257- final var toolCalls = chatCompletions .getChoices ().get (0 ).getDelta ().getToolCalls ();
258- isFunctionCall .set (toolCalls != null && !toolCalls .isEmpty ());
260+ if (!chatCompletions .getChoices ().isEmpty ()) {
261+ final var toolCalls = chatCompletions .getChoices ().get (0 ).getDelta ().getToolCalls ();
262+ isFunctionCall .set (toolCalls != null && !toolCalls .isEmpty ());
263+ }
259264 return chatCompletions ;
260265 })
261266 .windowUntil (chatCompletions -> {
@@ -493,7 +498,13 @@ private ChatCompletionsOptions merge(ChatCompletionsOptions fromAzureOptions,
493498 }
494499
495500 ChatCompletionsOptions mergedAzureOptions = new ChatCompletionsOptions (fromAzureOptions .getMessages ());
496- mergedAzureOptions .setStream (fromAzureOptions .isStream ());
501+
502+ ChatCompletionsOptionsAccessHelper .setStream (mergedAzureOptions ,
503+ fromAzureOptions .isStream () != null ? fromAzureOptions .isStream () : false );
504+
505+ ChatCompletionsOptionsAccessHelper .setStreamOptions (mergedAzureOptions ,
506+ fromAzureOptions .getStreamOptions () != null ? fromAzureOptions .getStreamOptions ()
507+ : toSpringAiOptions .getStreamOptions ());
497508
498509 mergedAzureOptions .setMaxTokens ((fromAzureOptions .getMaxTokens () != null ) ? fromAzureOptions .getMaxTokens ()
499510 : toSpringAiOptions .getMaxTokens ());
@@ -629,6 +640,15 @@ private ChatCompletionsOptions merge(AzureOpenAiChatOptions fromSpringAiOptions,
629640 mergedAzureOptions .setEnhancements (fromSpringAiOptions .getEnhancements ());
630641 }
631642
643+ if (fromSpringAiOptions .getStreamOptions () != null ) {
644+ ChatCompletionsOptionsAccessHelper .setStreamOptions (mergedAzureOptions ,
645+ fromSpringAiOptions .getStreamOptions ());
646+ }
647+
648+ if (fromSpringAiOptions .getEnhancements () != null ) {
649+ mergedAzureOptions .setEnhancements (fromSpringAiOptions .getEnhancements ());
650+ }
651+
632652 return mergedAzureOptions ;
633653 }
634654
@@ -640,8 +660,13 @@ private ChatCompletionsOptions merge(AzureOpenAiChatOptions fromSpringAiOptions,
640660 private ChatCompletionsOptions copy (ChatCompletionsOptions fromOptions ) {
641661
642662 ChatCompletionsOptions copyOptions = new ChatCompletionsOptions (fromOptions .getMessages ());
643- copyOptions .setStream (fromOptions .isStream ());
644663
664+ if (fromOptions .isStream () != null ) {
665+ ChatCompletionsOptionsAccessHelper .setStream (copyOptions , fromOptions .isStream ());
666+ }
667+ if (fromOptions .getStreamOptions () != null ) {
668+ ChatCompletionsOptionsAccessHelper .setStreamOptions (copyOptions , fromOptions .getStreamOptions ());
669+ }
645670 if (fromOptions .getMaxTokens () != null ) {
646671 copyOptions .setMaxTokens (fromOptions .getMaxTokens ());
647672 }
0 commit comments