diff --git a/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/ConverseApiUtils.java b/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/ConverseApiUtils.java index a19de831a7e..d58fdbad8cf 100644 --- a/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/ConverseApiUtils.java +++ b/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/ConverseApiUtils.java @@ -421,8 +421,7 @@ public List toolUseEntries() { } public boolean isEmpty() { - return (this.index == null || this.id == null || this.name == null - || !StringUtils.hasText(this.partialJson)); + return (this.index == null || this.id == null || this.name == null || this.partialJson == null); } ToolUseAggregationEvent withIndex(Integer index) { @@ -451,7 +450,9 @@ ToolUseAggregationEvent appendPartialJson(String partialJson) { } void squashIntoContentBlock() { - this.toolUseEntries.add(new ToolUseEntry(this.index, this.id, this.name, this.partialJson, this.usage)); + // Workaround to handle streaming tool calling with no input arguments. + String json = StringUtils.hasText(this.partialJson) ? this.partialJson : "{}"; + this.toolUseEntries.add(new ToolUseEntry(this.index, this.id, this.name, json, this.usage)); this.index = null; this.id = null; this.name = null; diff --git a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/client/BedrockNovaChatClientIT.java b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/client/BedrockNovaChatClientIT.java index d582d676833..61d3b1da882 100644 --- a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/client/BedrockNovaChatClientIT.java +++ b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/client/BedrockNovaChatClientIT.java @@ -23,6 +23,8 @@ import java.util.stream.Collectors; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.publisher.Flux; @@ -186,12 +188,15 @@ void toolAnnotationWeatherForecast() { assertThat(response).contains("20 degrees"); } - @Test - void toolAnnotationWeatherForecastStreaming() { + // https://github.com/spring-projects/spring-ai/issues/1878 + @ParameterizedTest + @ValueSource(strings = { "amazon.nova-pro-v1:0", "us.anthropic.claude-3-7-sonnet-20250219-v1:0" }) + void toolAnnotationWeatherForecastStreaming(String modelName) { ChatClient chatClient = ChatClient.builder(this.chatModel).build(); Flux responses = chatClient.prompt() + .options(ToolCallingChatOptions.builder().model(modelName).build()) .tools(new DummyWeatherForecastTools()) .user("Get current weather in Amsterdam") .stream() @@ -257,6 +262,7 @@ public static class Config { public BedrockProxyChatModel bedrockConverseChatModel() { String modelId = "amazon.nova-pro-v1:0"; + // String modelId = "us.anthropic.claude-3-7-sonnet-20250219-v1:0"; return BedrockProxyChatModel.builder() .credentialsProvider(EnvironmentVariableCredentialsProvider.create()) diff --git a/pom.xml b/pom.xml index f215c4f6605..a555ea45419 100644 --- a/pom.xml +++ b/pom.xml @@ -264,8 +264,8 @@ 1.9.25 - 2.31.26 - 2.29.29 + 2.31.65 + 2.31.65 0.32.0 1.19.2