Skip to content

Commit 2049b2f

Browse files
committed
fix: enhance content extraction from chat response to handle multiple generations with null content
Signed-off-by: liugddx <liugddx@gmail.com>
1 parent 34a291a commit 2049b2f

File tree

2 files changed

+33
-22
lines changed

2 files changed

+33
-22
lines changed

spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/DefaultChatClient.java

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -519,23 +519,25 @@ private ChatClientResponse doGetObservableChatClientResponse(ChatClientRequest c
519519
return chatClientResponse != null ? chatClientResponse : ChatClientResponse.builder().build();
520520
}
521521

522-
@Nullable
523-
private static String getContentFromChatResponse(@Nullable ChatResponse chatResponse) {
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 Converse API
529-
// with openai.gpt-oss models may return reasoning output first with null content,
530-
// followed by the actual response)
531-
return chatResponse.getResults()
532-
.stream()
533-
.map(Generation::getOutput)
534-
.map(AbstractMessage::getText)
535-
.filter(text -> text != null)
536-
.findFirst()
537-
.orElse(null);
538-
}
522+
@Nullable
523+
private static String getContentFromChatResponse(@Nullable ChatResponse chatResponse) {
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()
535+
.map(Generation::getOutput)
536+
.map(AbstractMessage::getText)
537+
.filter(text -> text != null)
538+
.findFirst()
539+
.orElse(null);
540+
}
539541

540542
}
541543

spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/DefaultChatClientTests.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -972,14 +972,23 @@ void whenChatResponseContentIsNull() {
972972
@Test
973973
void whenMultipleGenerationsWithFirstContentNull() {
974974
// Test case for Bedrock Converse API with openai.gpt-oss models
975-
// which return multiple generations where the first one has null content (reasoning output)
975+
// which return multiple generations where the first one has null content
976+
// (reasoning output)
976977
// and the second one contains the actual response
977978
ChatModel chatModel = mock(ChatModel.class);
978979
ArgumentCaptor<Prompt> promptCaptor = ArgumentCaptor.forClass(Prompt.class);
979-
given(chatModel.call(promptCaptor.capture())).willReturn(new ChatResponse(List.of(
980-
new Generation(new AssistantMessage(null)), // First generation with null content
981-
new Generation(new AssistantMessage("Hello! How can I help you today?")) // Second generation with actual content
982-
)));
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+
)));
983992

984993
ChatClient chatClient = new DefaultChatClientBuilder(chatModel).build();
985994
DefaultChatClient.DefaultChatClientRequestSpec chatClientRequestSpec = (DefaultChatClient.DefaultChatClientRequestSpec) chatClient

0 commit comments

Comments
 (0)