File tree Expand file tree Collapse file tree 2 files changed +44
-2
lines changed
spring-ai-client-chat/src
main/java/org/springframework/ai/chat/client
test/java/org/springframework/ai/chat/client Expand file tree Collapse file tree 2 files changed +44
-2
lines changed Original file line number Diff line number Diff line change @@ -521,10 +521,21 @@ private ChatClientResponse doGetObservableChatClientResponse(ChatClientRequest c
521521
522522 @ Nullable
523523 private static String getContentFromChatResponse (@ Nullable ChatResponse chatResponse ) {
524- return Optional .ofNullable (chatResponse )
525- .map (ChatResponse ::getResult )
524+ if (chatResponse == null || CollectionUtils .isEmpty (chatResponse .getResults ())) {
525+ return null ;
526+ }
527+ // Iterate through all generations to find the first one with non-null content
528+ // This handles cases where models return multiple generations (e.g., Bedrock
529+ // Converse API
530+ // with openai.gpt-oss models may return reasoning output first with null
531+ // content,
532+ // followed by the actual response)
533+ return chatResponse .getResults ()
534+ .stream ()
526535 .map (Generation ::getOutput )
527536 .map (AbstractMessage ::getText )
537+ .filter (text -> text != null )
538+ .findFirst ()
528539 .orElse (null );
529540 }
530541
Original file line number Diff line number Diff line change @@ -969,6 +969,37 @@ void whenChatResponseContentIsNull() {
969969 assertThat (content ).isNull ();
970970 }
971971
972+ @ Test
973+ void whenMultipleGenerationsWithFirstContentNull () {
974+ // Test case for Bedrock Converse API with openai.gpt-oss models
975+ // which return multiple generations where the first one has null content
976+ // (reasoning output)
977+ // and the second one contains the actual response
978+ ChatModel chatModel = mock (ChatModel .class );
979+ ArgumentCaptor <Prompt > promptCaptor = ArgumentCaptor .forClass (Prompt .class );
980+ given (chatModel .call (promptCaptor .capture ()))
981+ .willReturn (new ChatResponse (List .of (new Generation (new AssistantMessage (null )), // First
982+ // generation
983+ // with
984+ // null
985+ // content
986+ new Generation (new AssistantMessage ("Hello! How can I help you today?" )) // Second
987+ // generation
988+ // with
989+ // actual
990+ // content
991+ )));
992+
993+ ChatClient chatClient = new DefaultChatClientBuilder (chatModel ).build ();
994+ DefaultChatClient .DefaultChatClientRequestSpec chatClientRequestSpec = (DefaultChatClient .DefaultChatClientRequestSpec ) chatClient
995+ .prompt ("Hello" );
996+ DefaultChatClient .DefaultCallResponseSpec spec = (DefaultChatClient .DefaultCallResponseSpec ) chatClientRequestSpec
997+ .call ();
998+
999+ String content = spec .content ();
1000+ assertThat (content ).isEqualTo ("Hello! How can I help you today?" );
1001+ }
1002+
9721003 @ Test
9731004 void whenResponseEntityWithParameterizedTypeIsNull () {
9741005 ChatClient chatClient = new DefaultChatClientBuilder (mock (ChatModel .class )).build ();
You can’t perform that action at this time.
0 commit comments