diff --git a/auto-configurations/common/spring-ai-autoconfigure-retry/pom.xml b/auto-configurations/common/spring-ai-autoconfigure-retry/pom.xml index 4fcb9371d82..f7b3d39d83f 100644 --- a/auto-configurations/common/spring-ai-autoconfigure-retry/pom.xml +++ b/auto-configurations/common/spring-ai-autoconfigure-retry/pom.xml @@ -62,6 +62,12 @@ test + + org.springframework.boot + spring-boot-starter-restclient + test + + org.mockito mockito-core diff --git a/auto-configurations/common/spring-ai-autoconfigure-retry/src/main/java/org/springframework/ai/retry/autoconfigure/SpringAiRetryAutoConfiguration.java b/auto-configurations/common/spring-ai-autoconfigure-retry/src/main/java/org/springframework/ai/retry/autoconfigure/SpringAiRetryAutoConfiguration.java index 36d212c8d8a..8409ada52be 100644 --- a/auto-configurations/common/spring-ai-autoconfigure-retry/src/main/java/org/springframework/ai/retry/autoconfigure/SpringAiRetryAutoConfiguration.java +++ b/auto-configurations/common/spring-ai-autoconfigure-retry/src/main/java/org/springframework/ai/retry/autoconfigure/SpringAiRetryAutoConfiguration.java @@ -17,7 +17,9 @@ package org.springframework.ai.retry.autoconfigure; import java.io.IOException; +import java.net.URI; import java.nio.charset.StandardCharsets; +import java.util.concurrent.atomic.AtomicInteger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,12 +32,13 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.core.retry.RetryListener; +import org.springframework.core.retry.RetryPolicy; +import org.springframework.core.retry.RetryTemplate; +import org.springframework.core.retry.Retryable; +import org.springframework.http.HttpMethod; import org.springframework.http.client.ClientHttpResponse; import org.springframework.lang.NonNull; -import org.springframework.retry.RetryCallback; -import org.springframework.retry.RetryContext; -import org.springframework.retry.RetryListener; -import org.springframework.retry.support.RetryTemplate; import org.springframework.util.CollectionUtils; import org.springframework.util.StreamUtils; import org.springframework.web.client.ResponseErrorHandler; @@ -58,21 +61,25 @@ public class SpringAiRetryAutoConfiguration { @Bean @ConditionalOnMissingBean public RetryTemplate retryTemplate(SpringAiRetryProperties properties) { - return RetryTemplate.builder() + RetryPolicy retryPolicy = RetryPolicy.builder() .maxAttempts(properties.getMaxAttempts()) - .retryOn(TransientAiException.class) - .exponentialBackoff(properties.getBackoff().getInitialInterval(), properties.getBackoff().getMultiplier(), - properties.getBackoff().getMaxInterval()) - .withListener(new RetryListener() { - - @Override - public void onError(RetryContext context, RetryCallback callback, - Throwable throwable) { - logger.warn("Retry error. Retry count: {}, Exception: {}", context.getRetryCount(), - throwable.getMessage(), throwable); - } - }) + .includes(TransientAiException.class) + .delay(properties.getBackoff().getInitialInterval()) + .multiplier(properties.getBackoff().getMultiplier()) + .maxDelay(properties.getBackoff().getMaxInterval()) .build(); + + RetryTemplate retryTemplate = new RetryTemplate(retryPolicy); + retryTemplate.setRetryListener(new RetryListener() { + private final AtomicInteger retryCount = new AtomicInteger(0); + + @Override + public void onRetryFailure(RetryPolicy policy, Retryable retryable, Throwable throwable) { + int currentRetries = retryCount.incrementAndGet(); + logger.warn("Retry error. Retry count:{}", currentRetries, throwable); + } + }); + return retryTemplate; } @Bean @@ -87,7 +94,8 @@ public boolean hasError(@NonNull ClientHttpResponse response) throws IOException } @Override - public void handleError(@NonNull ClientHttpResponse response) throws IOException { + public void handleError(URI url, HttpMethod method, @NonNull ClientHttpResponse response) + throws IOException { if (!response.getStatusCode().isError()) { return; } diff --git a/auto-configurations/common/spring-ai-autoconfigure-retry/src/test/java/org/springframework/ai/retry/autoconfigure/SpringAiRetryAutoConfigurationIT.java b/auto-configurations/common/spring-ai-autoconfigure-retry/src/test/java/org/springframework/ai/retry/autoconfigure/SpringAiRetryAutoConfigurationIT.java index 4b712f0507e..dd4004dbb6b 100644 --- a/auto-configurations/common/spring-ai-autoconfigure-retry/src/test/java/org/springframework/ai/retry/autoconfigure/SpringAiRetryAutoConfigurationIT.java +++ b/auto-configurations/common/spring-ai-autoconfigure-retry/src/test/java/org/springframework/ai/retry/autoconfigure/SpringAiRetryAutoConfigurationIT.java @@ -19,9 +19,9 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.web.client.ResponseErrorHandler; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfigurationTests.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfigurationTests.java index 72fcafbcec6..b47b3e0984c 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfigurationTests.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfigurationTests.java @@ -16,17 +16,17 @@ package org.springframework.ai.mcp.server.autoconfigure; -import com.fasterxml.jackson.databind.ObjectMapper; import io.modelcontextprotocol.server.transport.WebFluxSseServerTransportProvider; import org.junit.jupiter.api.Test; import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerProperties; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; +import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Configuration; import org.springframework.web.reactive.function.server.RouterFunction; +import tools.jackson.databind.ObjectMapper; import static org.assertj.core.api.Assertions.assertThat; @@ -46,8 +46,8 @@ void shouldConfigureWebFluxTransportWithCustomObjectMapper() { ObjectMapper objectMapper = context.getBean(ObjectMapper.class); // Verify that the ObjectMapper is configured to ignore unknown properties - assertThat(objectMapper.getDeserializationConfig() - .isEnabled(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)).isFalse(); + assertThat(objectMapper.deserializationConfig() + .isEnabled(tools.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)).isFalse(); // Test with a JSON payload containing unknown fields // CHECKSTYLE:OFF diff --git a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cassandra/pom.xml b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cassandra/pom.xml index 9f13c6f89e9..4dcbb0abc39 100644 --- a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cassandra/pom.xml +++ b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cassandra/pom.xml @@ -53,6 +53,11 @@ true + + org.springframework.boot + spring-boot-cassandra + + org.springframework.ai diff --git a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cassandra/src/main/java/org/springframework/ai/model/chat/memory/repository/cassandra/autoconfigure/CassandraChatMemoryRepositoryAutoConfiguration.java b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cassandra/src/main/java/org/springframework/ai/model/chat/memory/repository/cassandra/autoconfigure/CassandraChatMemoryRepositoryAutoConfiguration.java index e55bc82cea5..ff1964f83c2 100644 --- a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cassandra/src/main/java/org/springframework/ai/model/chat/memory/repository/cassandra/autoconfigure/CassandraChatMemoryRepositoryAutoConfiguration.java +++ b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cassandra/src/main/java/org/springframework/ai/model/chat/memory/repository/cassandra/autoconfigure/CassandraChatMemoryRepositoryAutoConfiguration.java @@ -22,7 +22,7 @@ import org.springframework.ai.chat.memory.repository.cassandra.CassandraChatMemoryRepositoryConfig; import org.springframework.ai.model.chat.memory.autoconfigure.ChatMemoryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; +import org.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; diff --git a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cassandra/src/test/java/org/springframework/ai/model/chat/memory/repository/cassandra/autoconfigure/CassandraChatMemoryRepositoryAutoConfigurationIT.java b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cassandra/src/test/java/org/springframework/ai/model/chat/memory/repository/cassandra/autoconfigure/CassandraChatMemoryRepositoryAutoConfigurationIT.java index 9b619ce9039..50d04eaa3ea 100644 --- a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cassandra/src/test/java/org/springframework/ai/model/chat/memory/repository/cassandra/autoconfigure/CassandraChatMemoryRepositoryAutoConfigurationIT.java +++ b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cassandra/src/test/java/org/springframework/ai/model/chat/memory/repository/cassandra/autoconfigure/CassandraChatMemoryRepositoryAutoConfigurationIT.java @@ -31,7 +31,7 @@ import org.springframework.ai.chat.messages.MessageType; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; +import org.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cosmos-db/pom.xml b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cosmos-db/pom.xml index 535fd9f44ed..da7cb85c488 100644 --- a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cosmos-db/pom.xml +++ b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cosmos-db/pom.xml @@ -81,6 +81,11 @@ ${azure-identity.version} + + org.slf4j + jcl-over-slf4j + + org.springframework.boot diff --git a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/pom.xml b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/pom.xml index 1ffcc2f324f..fbaf44ad6a1 100644 --- a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/pom.xml +++ b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/pom.xml @@ -53,6 +53,11 @@ true + + org.springframework.boot + spring-boot-jdbc + + org.springframework.boot @@ -60,6 +65,12 @@ test + + org.springframework.boot + spring-boot-starter-jdbc + test + + org.postgresql postgresql diff --git a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositoryAutoConfiguration.java b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositoryAutoConfiguration.java index 17bed069754..f6abfb91454 100644 --- a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositoryAutoConfiguration.java +++ b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositoryAutoConfiguration.java @@ -24,8 +24,8 @@ import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; -import org.springframework.boot.autoconfigure.sql.init.OnDatabaseInitializationCondition; +import org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration; +import org.springframework.boot.sql.autoconfigure.init.OnDatabaseInitializationCondition; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; diff --git a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositoryHsqldbAutoConfigurationIT.java b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositoryHsqldbAutoConfigurationIT.java index abfd6927a46..f9b10f48f5f 100644 --- a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositoryHsqldbAutoConfigurationIT.java +++ b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositoryHsqldbAutoConfigurationIT.java @@ -29,7 +29,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ApplicationContext; @@ -52,9 +51,8 @@ @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.ANY) @ImportAutoConfiguration({ org.springframework.ai.model.chat.memory.autoconfigure.ChatMemoryAutoConfiguration.class, JdbcChatMemoryRepositoryAutoConfiguration.class, - org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration.class, - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.class, - SqlInitializationAutoConfiguration.class }) + org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration.class, + org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration.class }) public class JdbcChatMemoryRepositoryHsqldbAutoConfigurationIT { @Autowired diff --git a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositoryPostgresqlAutoConfigurationIT.java b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositoryPostgresqlAutoConfigurationIT.java index c6bde91fff4..2f7217c6710 100644 --- a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositoryPostgresqlAutoConfigurationIT.java +++ b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositoryPostgresqlAutoConfigurationIT.java @@ -28,8 +28,8 @@ import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.model.chat.memory.autoconfigure.ChatMemoryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositorySchemaInitializerPostgresqlTests.java b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositorySchemaInitializerPostgresqlTests.java index 03542a87d98..7845ef2fa95 100644 --- a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositorySchemaInitializerPostgresqlTests.java +++ b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositorySchemaInitializerPostgresqlTests.java @@ -25,8 +25,8 @@ import org.testcontainers.utility.DockerImageName; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositorySqlServerAutoConfigurationIT.java b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositorySqlServerAutoConfigurationIT.java index a3bf69410ac..77095de4216 100644 --- a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositorySqlServerAutoConfigurationIT.java +++ b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositorySqlServerAutoConfigurationIT.java @@ -33,8 +33,8 @@ import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.model.chat.memory.autoconfigure.ChatMemoryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-neo4j/pom.xml b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-neo4j/pom.xml index dc0e1ef9373..e4df7ded982 100644 --- a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-neo4j/pom.xml +++ b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-neo4j/pom.xml @@ -53,6 +53,11 @@ true + + org.springframework.boot + spring-boot-neo4j + + org.springframework.ai diff --git a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-neo4j/src/main/java/org/springframework/ai/model/chat/memory/repository/neo4j/autoconfigure/Neo4jChatMemoryRepositoryAutoConfiguration.java b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-neo4j/src/main/java/org/springframework/ai/model/chat/memory/repository/neo4j/autoconfigure/Neo4jChatMemoryRepositoryAutoConfiguration.java index 970cb6be91c..5371f4f7587 100644 --- a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-neo4j/src/main/java/org/springframework/ai/model/chat/memory/repository/neo4j/autoconfigure/Neo4jChatMemoryRepositoryAutoConfiguration.java +++ b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-neo4j/src/main/java/org/springframework/ai/model/chat/memory/repository/neo4j/autoconfigure/Neo4jChatMemoryRepositoryAutoConfiguration.java @@ -24,7 +24,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; +import org.springframework.boot.neo4j.autoconfigure.Neo4jAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; diff --git a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-neo4j/src/test/java/org/springframework/ai/model/chat/memory/repository/neo4j/autoconfigure/Neo4jChatMemoryRepositoryAutoConfigurationIT.java b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-neo4j/src/test/java/org/springframework/ai/model/chat/memory/repository/neo4j/autoconfigure/Neo4jChatMemoryRepositoryAutoConfigurationIT.java index f60f6f61320..0ba45f83161 100644 --- a/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-neo4j/src/test/java/org/springframework/ai/model/chat/memory/repository/neo4j/autoconfigure/Neo4jChatMemoryRepositoryAutoConfigurationIT.java +++ b/auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-neo4j/src/test/java/org/springframework/ai/model/chat/memory/repository/neo4j/autoconfigure/Neo4jChatMemoryRepositoryAutoConfigurationIT.java @@ -39,7 +39,7 @@ import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.content.Media; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; +import org.springframework.boot.neo4j.autoconfigure.Neo4jAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.util.MimeType; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-anthropic/pom.xml b/auto-configurations/models/spring-ai-autoconfigure-model-anthropic/pom.xml index 3835531828c..f39662355aa 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-anthropic/pom.xml +++ b/auto-configurations/models/spring-ai-autoconfigure-model-anthropic/pom.xml @@ -72,6 +72,18 @@ true + + org.springframework.boot + spring-boot-restclient + true + + + + org.springframework.boot + spring-boot-webclient + true + + org.springframework.ai diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-anthropic/src/main/java/org/springframework/ai/model/anthropic/autoconfigure/AnthropicChatAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-anthropic/src/main/java/org/springframework/ai/model/anthropic/autoconfigure/AnthropicChatAutoConfiguration.java index 3233dd1eee1..17e2cc8edb6 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-anthropic/src/main/java/org/springframework/ai/model/anthropic/autoconfigure/AnthropicChatAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-anthropic/src/main/java/org/springframework/ai/model/anthropic/autoconfigure/AnthropicChatAutoConfiguration.java @@ -33,12 +33,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.core.retry.RetryTemplate; import org.springframework.context.annotation.Import; -import org.springframework.retry.support.RetryTemplate; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; import org.springframework.web.reactive.function.client.WebClient; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-anthropic/src/test/java/org/springframework/ai/model/anthropic/autoconfigure/AnthropicPropertiesTests.java b/auto-configurations/models/spring-ai-autoconfigure-model-anthropic/src/test/java/org/springframework/ai/model/anthropic/autoconfigure/AnthropicPropertiesTests.java index f87eb430dfe..20af04ded1c 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-anthropic/src/test/java/org/springframework/ai/model/anthropic/autoconfigure/AnthropicPropertiesTests.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-anthropic/src/test/java/org/springframework/ai/model/anthropic/autoconfigure/AnthropicPropertiesTests.java @@ -22,7 +22,7 @@ import org.springframework.ai.anthropic.api.AnthropicApi.ToolChoiceTool; import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-anthropic/src/test/java/org/springframework/ai/model/anthropic/autoconfigure/BaseAnthropicIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-anthropic/src/test/java/org/springframework/ai/model/anthropic/autoconfigure/BaseAnthropicIT.java index c68d9188e10..44282b3614d 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-anthropic/src/test/java/org/springframework/ai/model/anthropic/autoconfigure/BaseAnthropicIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-anthropic/src/test/java/org/springframework/ai/model/anthropic/autoconfigure/BaseAnthropicIT.java @@ -22,8 +22,8 @@ import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; public abstract class BaseAnthropicIT { diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/pom.xml b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/pom.xml index 2f36a8c976e..e772e156453 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/pom.xml +++ b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/pom.xml @@ -72,6 +72,16 @@ true + + org.springframework.boot + spring-boot-starter-restclient + + + + org.springframework.boot + spring-boot-starter-webclient + + org.springframework.ai diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/main/java/org/springframework/ai/model/deepseek/autoconfigure/DeepSeekChatAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/main/java/org/springframework/ai/model/deepseek/autoconfigure/DeepSeekChatAutoConfiguration.java index 98aae30a232..1c11d4b84ec 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/main/java/org/springframework/ai/model/deepseek/autoconfigure/DeepSeekChatAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/main/java/org/springframework/ai/model/deepseek/autoconfigure/DeepSeekChatAutoConfiguration.java @@ -34,11 +34,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.client.ResponseErrorHandler; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/BaseDeepSeekIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/BaseDeepSeekIT.java index 9423542a624..1ea7baf7292 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/BaseDeepSeekIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/BaseDeepSeekIT.java @@ -22,8 +22,8 @@ import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; /** * Base utility class for DeepSeek integration tests. diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/pom.xml b/auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/pom.xml index bc09ef1f5b4..cb02bb344b4 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/pom.xml +++ b/auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/pom.xml @@ -66,6 +66,18 @@ true + + org.springframework.boot + spring-boot-restclient + true + + + + org.springframework.boot + spring-boot-webclient + true + + org.springframework.ai diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/src/main/java/org/springframework/ai/model/elevenlabs/autoconfigure/ElevenLabsAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/src/main/java/org/springframework/ai/model/elevenlabs/autoconfigure/ElevenLabsAutoConfiguration.java index bbff2dcf71e..dd21a339914 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/src/main/java/org/springframework/ai/model/elevenlabs/autoconfigure/ElevenLabsAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/src/main/java/org/springframework/ai/model/elevenlabs/autoconfigure/ElevenLabsAutoConfiguration.java @@ -24,11 +24,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; import org.springframework.web.reactive.function.client.WebClient; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/src/test/java/org/springframework/ai/model/elevenlabs/autoconfigure/ElevenLabsITUtil.java b/auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/src/test/java/org/springframework/ai/model/elevenlabs/autoconfigure/ElevenLabsITUtil.java index 9cd2b178856..86debc54233 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/src/test/java/org/springframework/ai/model/elevenlabs/autoconfigure/ElevenLabsITUtil.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/src/test/java/org/springframework/ai/model/elevenlabs/autoconfigure/ElevenLabsITUtil.java @@ -18,8 +18,8 @@ import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; /** * Utility class for ElevenLabs integration tests. diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/pom.xml b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/pom.xml index 8bed6c0ea18..6b644a60b6e 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/pom.xml +++ b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/pom.xml @@ -101,6 +101,18 @@ test + + org.springframework.boot + spring-boot-starter-restclient + test + + + + org.springframework.boot + spring-boot-starter-webclient + test + + org.mockito mockito-core diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/main/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiChatAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/main/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiChatAutoConfiguration.java index e8c9b8ea2d1..664b1e3b9be 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/main/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiChatAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/main/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiChatAutoConfiguration.java @@ -42,7 +42,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/main/java/org/springframework/ai/model/google/genai/autoconfigure/embedding/GoogleGenAiTextEmbeddingAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/main/java/org/springframework/ai/model/google/genai/autoconfigure/embedding/GoogleGenAiTextEmbeddingAutoConfiguration.java index 6fd62c663e4..d3825836171 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/main/java/org/springframework/ai/model/google/genai/autoconfigure/embedding/GoogleGenAiTextEmbeddingAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/main/java/org/springframework/ai/model/google/genai/autoconfigure/embedding/GoogleGenAiTextEmbeddingAutoConfiguration.java @@ -31,7 +31,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; /** * Auto-configuration for Google GenAI Text Embedding. diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/tool/FunctionCallWithFunctionBeanIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/tool/FunctionCallWithFunctionBeanIT.java index 328e742fcfa..84d5bf71cc7 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/tool/FunctionCallWithFunctionBeanIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/tool/FunctionCallWithFunctionBeanIT.java @@ -30,7 +30,7 @@ import org.springframework.ai.model.google.genai.autoconfigure.BaseGoogleGenAiIT; import org.springframework.ai.tool.ToolCallback; import org.springframework.ai.tool.function.FunctionToolCallback; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/pom.xml b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/pom.xml index 62eff8604f9..4233826e890 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/pom.xml +++ b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/pom.xml @@ -78,6 +78,16 @@ true + + org.springframework.boot + spring-boot-restclient + + + + org.springframework.boot + spring-boot-webclient + + org.springframework.ai diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/main/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxChatAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/main/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxChatAutoConfiguration.java index b51445491f5..6ab4d2bf11d 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/main/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxChatAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/main/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxChatAutoConfiguration.java @@ -33,10 +33,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.client.ResponseErrorHandler; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/main/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxEmbeddingAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/main/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxEmbeddingAutoConfiguration.java index e7098339cc2..e87fd22a979 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/main/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxEmbeddingAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/main/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxEmbeddingAutoConfiguration.java @@ -29,10 +29,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.client.ResponseErrorHandler; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/FunctionCallbackInPromptIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/FunctionCallbackInPromptIT.java index dcf772a0bf7..16b5f011ee5 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/FunctionCallbackInPromptIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/FunctionCallbackInPromptIT.java @@ -36,7 +36,7 @@ import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.ai.tool.function.FunctionToolCallback; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/FunctionCallbackWithPlainFunctionBeanIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/FunctionCallbackWithPlainFunctionBeanIT.java index 0cb23c746a9..94f0678789c 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/FunctionCallbackWithPlainFunctionBeanIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/FunctionCallbackWithPlainFunctionBeanIT.java @@ -37,7 +37,7 @@ import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxAutoConfigurationIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxAutoConfigurationIT.java index 543ad444578..723e800e0c2 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxAutoConfigurationIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxAutoConfigurationIT.java @@ -34,7 +34,7 @@ import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxFunctionCallbackIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxFunctionCallbackIT.java index 8e41a0641dd..956c3dcedd1 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxFunctionCallbackIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxFunctionCallbackIT.java @@ -36,7 +36,7 @@ import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.ai.tool.function.FunctionToolCallback; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxPropertiesTests.java b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxPropertiesTests.java index c0751d5e334..44df03c8b7a 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxPropertiesTests.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxPropertiesTests.java @@ -27,7 +27,7 @@ import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/MinimaxModelConfigurationTests.java b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/MinimaxModelConfigurationTests.java index cf1b622d1ff..6fa8ac46c54 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/MinimaxModelConfigurationTests.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/MinimaxModelConfigurationTests.java @@ -23,7 +23,7 @@ import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/pom.xml b/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/pom.xml index d4642a87308..c787ea91713 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/pom.xml +++ b/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/pom.xml @@ -84,6 +84,16 @@ true + + org.springframework.boot + spring-boot-restclient + + + + org.springframework.boot + spring-boot-webclient + + org.springframework.ai diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiChatAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiChatAutoConfiguration.java index 9044e82cbbd..6732bbdafde 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiChatAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiChatAutoConfiguration.java @@ -33,11 +33,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.client.ResponseErrorHandler; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiEmbeddingAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiEmbeddingAutoConfiguration.java index ad8a8632ccd..3937029d39c 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiEmbeddingAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiEmbeddingAutoConfiguration.java @@ -29,10 +29,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.client.ResponseErrorHandler; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiModerationAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiModerationAutoConfiguration.java index 778d267019e..932023787bc 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiModerationAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiModerationAutoConfiguration.java @@ -27,11 +27,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.client.ResponseErrorHandler; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiOcrAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiOcrAutoConfiguration.java index 8a247672507..49e26378f13 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiOcrAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiOcrAutoConfiguration.java @@ -24,7 +24,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.util.Assert; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/test/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiOcrPropertiesTests.java b/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/test/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiOcrPropertiesTests.java index 3b494c7f713..1a2ec9a34e5 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/test/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiOcrPropertiesTests.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/test/java/org/springframework/ai/model/mistralai/autoconfigure/MistralAiOcrPropertiesTests.java @@ -21,7 +21,7 @@ import org.springframework.ai.mistralai.ocr.MistralOcrApi; import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-ollama/pom.xml b/auto-configurations/models/spring-ai-autoconfigure-model-ollama/pom.xml index ecb49ce4c23..38c163ee13e 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-ollama/pom.xml +++ b/auto-configurations/models/spring-ai-autoconfigure-model-ollama/pom.xml @@ -86,6 +86,18 @@ test + + + org.springframework.boot + spring-boot-starter-restclient + + + + + org.springframework.boot + spring-boot-starter-webclient + + org.springframework.boot spring-boot-starter-test diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-ollama/src/main/java/org/springframework/ai/model/ollama/autoconfigure/OllamaApiAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-ollama/src/main/java/org/springframework/ai/model/ollama/autoconfigure/OllamaApiAutoConfiguration.java index ed30d787021..3df440cdc3f 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-ollama/src/main/java/org/springframework/ai/model/ollama/autoconfigure/OllamaApiAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-ollama/src/main/java/org/springframework/ai/model/ollama/autoconfigure/OllamaApiAutoConfiguration.java @@ -22,9 +22,9 @@ import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-ollama/src/main/java/org/springframework/ai/model/ollama/autoconfigure/OllamaChatAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-ollama/src/main/java/org/springframework/ai/model/ollama/autoconfigure/OllamaChatAutoConfiguration.java index 34b9ad58346..67bdae15714 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-ollama/src/main/java/org/springframework/ai/model/ollama/autoconfigure/OllamaChatAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-ollama/src/main/java/org/springframework/ai/model/ollama/autoconfigure/OllamaChatAutoConfiguration.java @@ -36,7 +36,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; /** * {@link AutoConfiguration Auto-configuration} for Ollama Chat model. diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-ollama/src/test/java/org/springframework/ai/model/ollama/autoconfigure/BaseOllamaIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-ollama/src/test/java/org/springframework/ai/model/ollama/autoconfigure/BaseOllamaIT.java index 9a3bc2527f4..b4bd3fb8403 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-ollama/src/test/java/org/springframework/ai/model/ollama/autoconfigure/BaseOllamaIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-ollama/src/test/java/org/springframework/ai/model/ollama/autoconfigure/BaseOllamaIT.java @@ -20,6 +20,7 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.ollama.OllamaContainer; @@ -30,7 +31,6 @@ import org.springframework.ai.ollama.management.PullModelStrategy; import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; import org.springframework.util.Assert; @Testcontainers diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/pom.xml b/auto-configurations/models/spring-ai-autoconfigure-model-openai/pom.xml index ed37e511925..a388f7299bd 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/pom.xml +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/pom.xml @@ -83,6 +83,16 @@ true + + org.springframework.boot + spring-boot-restclient + + + + org.springframework.boot + spring-boot-webclient + + diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAIAutoConfigurationUtil.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAIAutoConfigurationUtil.java index 7eff1898fa4..398c4566184 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAIAutoConfigurationUtil.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAIAutoConfigurationUtil.java @@ -20,10 +20,9 @@ import java.util.List; import java.util.Map; +import org.springframework.http.HttpHeaders; import org.springframework.lang.NonNull; import org.springframework.util.Assert; -import org.springframework.util.CollectionUtils; -import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; public final class OpenAIAutoConfigurationUtil { @@ -44,12 +43,12 @@ private OpenAIAutoConfigurationUtil() { String organizationId = StringUtils.hasText(modelProperties.getOrganizationId()) ? modelProperties.getOrganizationId() : commonProperties.getOrganizationId(); - Map> connectionHeaders = new HashMap<>(); + HttpHeaders connectionHeaders = new HttpHeaders(); if (StringUtils.hasText(projectId)) { - connectionHeaders.put("OpenAI-Project", List.of(projectId)); + connectionHeaders.add("OpenAI-Project", projectId); } if (StringUtils.hasText(organizationId)) { - connectionHeaders.put("OpenAI-Organization", List.of(organizationId)); + connectionHeaders.add("OpenAI-Organization", organizationId); } Assert.hasText(baseUrl, @@ -59,10 +58,10 @@ private OpenAIAutoConfigurationUtil() { "OpenAI API key must be set. Use the connection property: spring.ai.openai.api-key or spring.ai.openai." + modelType + ".api-key property."); - return new ResolvedConnectionProperties(baseUrl, apiKey, CollectionUtils.toMultiValueMap(connectionHeaders)); + return new ResolvedConnectionProperties(baseUrl, apiKey, connectionHeaders); } - public record ResolvedConnectionProperties(String baseUrl, String apiKey, MultiValueMap headers) { + public record ResolvedConnectionProperties(String baseUrl, String apiKey, HttpHeaders headers) { } diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiAudioSpeechAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiAudioSpeechAutoConfiguration.java index 4d197904e5d..73b6228a19f 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiAudioSpeechAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiAudioSpeechAutoConfiguration.java @@ -28,11 +28,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; import org.springframework.web.reactive.function.client.WebClient; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiAudioTranscriptionAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiAudioTranscriptionAutoConfiguration.java index 7e9b67c70ca..f350e49536e 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiAudioTranscriptionAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiAudioTranscriptionAutoConfiguration.java @@ -28,11 +28,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; import org.springframework.web.reactive.function.client.WebClient; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiChatAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiChatAutoConfiguration.java index f1c1e4ea618..5fde6a55ff0 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiChatAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiChatAutoConfiguration.java @@ -34,11 +34,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; import org.springframework.web.reactive.function.client.WebClient; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiEmbeddingAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiEmbeddingAutoConfiguration.java index bf9b40e7a65..cefc31f2cbf 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiEmbeddingAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiEmbeddingAutoConfiguration.java @@ -30,11 +30,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; import org.springframework.web.reactive.function.client.WebClient; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiImageAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiImageAutoConfiguration.java index 07da6969a70..69522f8091a 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiImageAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiImageAutoConfiguration.java @@ -31,11 +31,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiModerationAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiModerationAutoConfiguration.java index bf74afe8fdc..f5e4a2ece45 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiModerationAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiModerationAutoConfiguration.java @@ -28,11 +28,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/ChatClientAutoConfigurationIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/ChatClientAutoConfigurationIT.java index 46dec5cb44c..89bd4f3e373 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/ChatClientAutoConfigurationIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/ChatClientAutoConfigurationIT.java @@ -29,7 +29,7 @@ import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiAutoConfigurationIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiAutoConfigurationIT.java index 78e920f7f08..39f8fdcf86f 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiAutoConfigurationIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiAutoConfigurationIT.java @@ -42,8 +42,8 @@ import org.springframework.ai.openai.api.OpenAiApi; import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiModelConfigurationTests.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiModelConfigurationTests.java index b5797172932..bfd4b992a47 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiModelConfigurationTests.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiModelConfigurationTests.java @@ -28,8 +28,8 @@ import org.springframework.ai.openai.api.OpenAiApi; import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiPropertiesTests.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiPropertiesTests.java index 28378329628..cfcbf798ead 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiPropertiesTests.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiPropertiesTests.java @@ -32,8 +32,8 @@ import org.springframework.ai.openai.api.OpenAiAudioApi; import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiResponseFormatPropertiesTests.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiResponseFormatPropertiesTests.java index 04c2b5813f4..b8fb05b4f78 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiResponseFormatPropertiesTests.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/OpenAiResponseFormatPropertiesTests.java @@ -28,8 +28,8 @@ import org.springframework.ai.openai.api.ResponseFormat; import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/FunctionCallbackInPrompt2IT.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/FunctionCallbackInPrompt2IT.java index d7b90d853ff..6797d39afa0 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/FunctionCallbackInPrompt2IT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/FunctionCallbackInPrompt2IT.java @@ -33,7 +33,7 @@ import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.ai.tool.function.FunctionToolCallback; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/FunctionCallbackInPromptIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/FunctionCallbackInPromptIT.java index 06510dfcdbe..60d47c834ce 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/FunctionCallbackInPromptIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/FunctionCallbackInPromptIT.java @@ -38,7 +38,7 @@ import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.ai.tool.function.FunctionToolCallback; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/FunctionCallbackWithPlainFunctionBeanIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/FunctionCallbackWithPlainFunctionBeanIT.java index 75debfb1069..fccf6708afd 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/FunctionCallbackWithPlainFunctionBeanIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/FunctionCallbackWithPlainFunctionBeanIT.java @@ -47,7 +47,7 @@ import org.springframework.ai.openai.api.OpenAiApi.ChatModel; import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/OpenAiFunctionCallback2IT.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/OpenAiFunctionCallback2IT.java index a996c4c3e5a..4d7ed8a7459 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/OpenAiFunctionCallback2IT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/OpenAiFunctionCallback2IT.java @@ -32,7 +32,7 @@ import org.springframework.ai.tool.ToolCallback; import org.springframework.ai.tool.function.FunctionToolCallback; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/OpenAiFunctionCallbackIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/OpenAiFunctionCallbackIT.java index 9c917b25fdc..0d74ddc297b 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/OpenAiFunctionCallbackIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/test/java/org/springframework/ai/model/openai/autoconfigure/tool/OpenAiFunctionCallbackIT.java @@ -39,7 +39,7 @@ import org.springframework.ai.tool.ToolCallback; import org.springframework.ai.tool.function.FunctionToolCallback; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-postgresml-embedding/pom.xml b/auto-configurations/models/spring-ai-autoconfigure-model-postgresml-embedding/pom.xml index 5ff82851c32..b56e490687b 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-postgresml-embedding/pom.xml +++ b/auto-configurations/models/spring-ai-autoconfigure-model-postgresml-embedding/pom.xml @@ -66,6 +66,11 @@ true + + org.springframework.boot + spring-boot-jdbc + + org.springframework.ai diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-postgresml-embedding/src/main/java/org/springframework/ai/model/postgresml/autoconfigure/PostgresMlEmbeddingAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-postgresml-embedding/src/main/java/org/springframework/ai/model/postgresml/autoconfigure/PostgresMlEmbeddingAutoConfiguration.java index 6fcbb4f2949..2daaa872552 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-postgresml-embedding/src/main/java/org/springframework/ai/model/postgresml/autoconfigure/PostgresMlEmbeddingAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-postgresml-embedding/src/main/java/org/springframework/ai/model/postgresml/autoconfigure/PostgresMlEmbeddingAutoConfiguration.java @@ -23,7 +23,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.core.JdbcTemplate; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-stability-ai/pom.xml b/auto-configurations/models/spring-ai-autoconfigure-model-stability-ai/pom.xml index 38f9f644b8c..479306a826a 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-stability-ai/pom.xml +++ b/auto-configurations/models/spring-ai-autoconfigure-model-stability-ai/pom.xml @@ -66,6 +66,16 @@ true + + org.springframework.boot + spring-boot-restclient + + + + org.springframework.boot + spring-boot-webclient + + org.springframework.ai diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-stability-ai/src/main/java/org/springframework/ai/model/stabilityai/autoconfigure/StabilityAiImageAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-stability-ai/src/main/java/org/springframework/ai/model/stabilityai/autoconfigure/StabilityAiImageAutoConfiguration.java index b38df31325e..a082bb2cf3c 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-stability-ai/src/main/java/org/springframework/ai/model/stabilityai/autoconfigure/StabilityAiImageAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-stability-ai/src/main/java/org/springframework/ai/model/stabilityai/autoconfigure/StabilityAiImageAutoConfiguration.java @@ -25,7 +25,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.util.Assert; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-vertex-ai/src/main/java/org/springframework/ai/model/vertexai/autoconfigure/embedding/VertexAiTextEmbeddingAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-vertex-ai/src/main/java/org/springframework/ai/model/vertexai/autoconfigure/embedding/VertexAiTextEmbeddingAutoConfiguration.java index 56e253dc2d2..8c0370ec84d 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-vertex-ai/src/main/java/org/springframework/ai/model/vertexai/autoconfigure/embedding/VertexAiTextEmbeddingAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-vertex-ai/src/main/java/org/springframework/ai/model/vertexai/autoconfigure/embedding/VertexAiTextEmbeddingAutoConfiguration.java @@ -31,7 +31,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; /** * Auto-configuration for Vertex AI Gemini Chat. diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-vertex-ai/src/main/java/org/springframework/ai/model/vertexai/autoconfigure/gemini/VertexAiGeminiChatAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-vertex-ai/src/main/java/org/springframework/ai/model/vertexai/autoconfigure/gemini/VertexAiGeminiChatAutoConfiguration.java index edb7057c1e6..79b4865ca8e 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-vertex-ai/src/main/java/org/springframework/ai/model/vertexai/autoconfigure/gemini/VertexAiGeminiChatAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-vertex-ai/src/main/java/org/springframework/ai/model/vertexai/autoconfigure/gemini/VertexAiGeminiChatAutoConfiguration.java @@ -39,7 +39,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/pom.xml b/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/pom.xml index eafc77142fa..4b83577ff5b 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/pom.xml +++ b/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/pom.xml @@ -84,6 +84,16 @@ true + + org.springframework.boot + spring-boot-starter-restclient + + + + org.springframework.boot + spring-boot-starter-webclient + + org.springframework.ai diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/main/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiChatAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/main/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiChatAutoConfiguration.java index ba9468e5c4f..002236e5ecc 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/main/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiChatAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/main/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiChatAutoConfiguration.java @@ -34,10 +34,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.client.ResponseErrorHandler; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/main/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiEmbeddingAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/main/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiEmbeddingAutoConfiguration.java index a80913cdd3d..b78c9139de9 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/main/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiEmbeddingAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/main/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiEmbeddingAutoConfiguration.java @@ -30,10 +30,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.client.ResponseErrorHandler; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/main/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiImageAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/main/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiImageAutoConfiguration.java index ea89f6198cb..2ae307f4cb7 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/main/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiImageAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/main/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiImageAutoConfiguration.java @@ -27,10 +27,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.client.ResponseErrorHandler; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/test/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiITUtil.java b/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/test/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiITUtil.java index 6c4c0833602..4df8c382ac5 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/test/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiITUtil.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-zhipuai/src/test/java/org/springframework/ai/model/zhipuai/autoconfigure/ZhiPuAiITUtil.java @@ -19,7 +19,7 @@ import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; /** * Utility class for ZhiPuAI integration tests. diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/pom.xml b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/pom.xml index dfed881e4de..68690649c63 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/pom.xml +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/pom.xml @@ -59,6 +59,12 @@ spring-boot-autoconfigure-processor true + + + org.springframework.boot + spring-boot-cassandra + + org.springframework.ai diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/src/main/java/org/springframework/ai/vectorstore/cassandra/autoconfigure/CassandraVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/src/main/java/org/springframework/ai/vectorstore/cassandra/autoconfigure/CassandraVectorStoreAutoConfiguration.java index e58ef033ce9..0173b9afd80 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/src/main/java/org/springframework/ai/vectorstore/cassandra/autoconfigure/CassandraVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/src/main/java/org/springframework/ai/vectorstore/cassandra/autoconfigure/CassandraVectorStoreAutoConfiguration.java @@ -30,8 +30,8 @@ import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; -import org.springframework.boot.autoconfigure.cassandra.DriverConfigLoaderBuilderCustomizer; +import org.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration; +import org.springframework.boot.cassandra.autoconfigure.DriverConfigLoaderBuilderCustomizer; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/src/test/java/org/springframework/ai/vectorstore/cassandra/autoconfigure/CassandraVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/src/test/java/org/springframework/ai/vectorstore/cassandra/autoconfigure/CassandraVectorStoreAutoConfigurationIT.java index 0ad388a5b60..7669a6266b5 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/src/test/java/org/springframework/ai/vectorstore/cassandra/autoconfigure/CassandraVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/src/test/java/org/springframework/ai/vectorstore/cassandra/autoconfigure/CassandraVectorStoreAutoConfigurationIT.java @@ -37,7 +37,7 @@ import org.springframework.ai.vectorstore.cassandra.CassandraVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; +import org.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-couchbase/pom.xml b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-couchbase/pom.xml index 11e93742d7e..74f8aa0e8d7 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-couchbase/pom.xml +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-couchbase/pom.xml @@ -59,6 +59,11 @@ spring-boot-autoconfigure-processor true + + + org.springframework.boot + spring-boot-couchbase + org.springframework.ai diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-couchbase/src/main/java/org/springframework/ai/vectorstore/couchbase/autoconfigure/CouchbaseSearchVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-couchbase/src/main/java/org/springframework/ai/vectorstore/couchbase/autoconfigure/CouchbaseSearchVectorStoreAutoConfiguration.java index 25aa0617930..82bfaf8cfc0 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-couchbase/src/main/java/org/springframework/ai/vectorstore/couchbase/autoconfigure/CouchbaseSearchVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-couchbase/src/main/java/org/springframework/ai/vectorstore/couchbase/autoconfigure/CouchbaseSearchVectorStoreAutoConfiguration.java @@ -23,7 +23,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration; +import org.springframework.boot.couchbase.autoconfigure.CouchbaseAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.context.annotation.Bean; @@ -49,9 +49,9 @@ public CouchbaseSearchVectorStore vectorStore(CouchbaseSearchVectorStoreProperti mapper.from(properties::getBucketName).whenHasText().to(builder::bucketName); mapper.from(properties::getScopeName).whenHasText().to(builder::scopeName); mapper.from(properties::getCollectionName).whenHasText().to(builder::collectionName); - mapper.from(properties::getDimensions).whenNonNull().to(builder::dimensions); - mapper.from(properties::getSimilarity).whenNonNull().to(builder::similarityFunction); - mapper.from(properties::getOptimization).whenNonNull().to(builder::indexOptimization); + mapper.from(properties::getDimensions).to(builder::dimensions); + mapper.from(properties::getSimilarity).to(builder::similarityFunction); + mapper.from(properties::getOptimization).to(builder::indexOptimization); return builder.initializeSchema(properties.isInitializeSchema()).build(); } diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-couchbase/src/test/java/org/springframework/ai/vectorstore/couchbase/autoconfigure/CouchbaseSearchVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-couchbase/src/test/java/org/springframework/ai/vectorstore/couchbase/autoconfigure/CouchbaseSearchVectorStoreAutoConfigurationIT.java index bb8cc8b646c..279c58a498e 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-couchbase/src/test/java/org/springframework/ai/vectorstore/couchbase/autoconfigure/CouchbaseSearchVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-couchbase/src/test/java/org/springframework/ai/vectorstore/couchbase/autoconfigure/CouchbaseSearchVectorStoreAutoConfigurationIT.java @@ -36,8 +36,8 @@ import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.couchbase.autoconfigure.CouchbaseAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/pom.xml b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/pom.xml index 30ab3d801c4..988b7a5f749 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/pom.xml +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/pom.xml @@ -59,6 +59,11 @@ spring-boot-autoconfigure-processor true + + + org.springframework.boot + spring-boot-elasticsearch + org.springframework.ai diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/main/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/main/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfiguration.java index 2c780c94f54..8e59f814f8e 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/main/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/main/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfiguration.java @@ -16,8 +16,8 @@ package org.springframework.ai.vectorstore.elasticsearch.autoconfigure; +import co.elastic.clients.transport.rest5_client.low_level.Rest5Client; import io.micrometer.observation.ObservationRegistry; -import org.elasticsearch.client.RestClient; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; @@ -31,7 +31,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration; +import org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.context.annotation.Bean; @@ -49,7 +49,7 @@ * @since 1.0.0 */ @AutoConfiguration(after = ElasticsearchRestClientAutoConfiguration.class) -@ConditionalOnClass({ ElasticsearchVectorStore.class, EmbeddingModel.class, RestClient.class }) +@ConditionalOnClass({ ElasticsearchVectorStore.class, EmbeddingModel.class, Rest5Client.class }) @EnableConfigurationProperties(ElasticsearchVectorStoreProperties.class) @ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.ELASTICSEARCH, matchIfMissing = true) @@ -63,7 +63,7 @@ BatchingStrategy batchingStrategy() { @Bean @ConditionalOnMissingBean - ElasticsearchVectorStore vectorStore(ElasticsearchVectorStoreProperties properties, RestClient restClient, + ElasticsearchVectorStore vectorStore(ElasticsearchVectorStoreProperties properties, Rest5Client restClient, EmbeddingModel embeddingModel, ObjectProvider observationRegistry, ObjectProvider customObservationConvention, BatchingStrategy batchingStrategy) { @@ -71,8 +71,8 @@ ElasticsearchVectorStore vectorStore(ElasticsearchVectorStoreProperties properti PropertyMapper mapper = PropertyMapper.get(); mapper.from(properties::getIndexName).whenHasText().to(elasticsearchVectorStoreOptions::setIndexName); - mapper.from(properties::getDimensions).whenNonNull().to(elasticsearchVectorStoreOptions::setDimensions); - mapper.from(properties::getSimilarity).whenNonNull().to(elasticsearchVectorStoreOptions::setSimilarity); + mapper.from(properties::getDimensions).to(elasticsearchVectorStoreOptions::setDimensions); + mapper.from(properties::getSimilarity).to(elasticsearchVectorStoreOptions::setSimilarity); mapper.from(properties::getEmbeddingFieldName) .whenHasText() .to(elasticsearchVectorStoreOptions::setEmbeddingFieldName); diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/test/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/test/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfigurationIT.java index 48e5191a171..3066e503e9d 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/test/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/test/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfigurationIT.java @@ -42,8 +42,8 @@ import org.springframework.ai.vectorstore.elasticsearch.SimilarityFunction; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/pom.xml b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/pom.xml index d773cc1773f..8971473f7e0 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/pom.xml +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/pom.xml @@ -59,6 +59,11 @@ spring-boot-autoconfigure-processor true + + + org.springframework.boot + spring-boot-jdbc + org.springframework.ai diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/src/main/java/org/springframework/ai/vectorstore/mariadb/autoconfigure/MariaDbStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/src/main/java/org/springframework/ai/vectorstore/mariadb/autoconfigure/MariaDbStoreAutoConfiguration.java index 0c9606646f5..951b2c9e854 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/src/main/java/org/springframework/ai/vectorstore/mariadb/autoconfigure/MariaDbStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/src/main/java/org/springframework/ai/vectorstore/mariadb/autoconfigure/MariaDbStoreAutoConfiguration.java @@ -31,7 +31,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.core.JdbcTemplate; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/src/test/java/org/springframework/ai/vectorstore/mariadb/autoconfigure/MariaDbStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/src/test/java/org/springframework/ai/vectorstore/mariadb/autoconfigure/MariaDbStoreAutoConfigurationIT.java index 09fbfd6ad0b..b708eb559ac 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/src/test/java/org/springframework/ai/vectorstore/mariadb/autoconfigure/MariaDbStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/src/test/java/org/springframework/ai/vectorstore/mariadb/autoconfigure/MariaDbStoreAutoConfigurationIT.java @@ -39,8 +39,8 @@ import org.springframework.ai.vectorstore.mariadb.MariaDBVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas/pom.xml b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas/pom.xml index 6d283e019ca..a6d6a55273f 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas/pom.xml +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas/pom.xml @@ -126,5 +126,9 @@ ${project.parent.version} test + + org.springframework.boot + spring-boot-starter-mongodb + diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas/src/test/java/org/springframework/ai/vectorstore/mongodb/autoconfigure/MongoDBAtlasVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas/src/test/java/org/springframework/ai/vectorstore/mongodb/autoconfigure/MongoDBAtlasVectorStoreAutoConfigurationIT.java index afd2723b452..ef630530496 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas/src/test/java/org/springframework/ai/vectorstore/mongodb/autoconfigure/MongoDBAtlasVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas/src/test/java/org/springframework/ai/vectorstore/mongodb/autoconfigure/MongoDBAtlasVectorStoreAutoConfigurationIT.java @@ -38,9 +38,8 @@ import org.springframework.ai.vectorstore.mongodb.atlas.MongoDBAtlasVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; -import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.mongodb.autoconfigure.MongoAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -63,7 +62,7 @@ class MongoDBAtlasVectorStoreAutoConfigurationIT { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withUserConfiguration(Config.class) - .withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, + .withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, MongoDBAtlasVectorStoreAutoConfiguration.class, RestClientAutoConfiguration.class, SpringAiRetryAutoConfiguration.class, OpenAiEmbeddingAutoConfiguration.class)) .withPropertyValues("spring.data.mongodb.database=springaisample", diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/pom.xml b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/pom.xml index 94654167324..1ca5ba63668 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/pom.xml +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/pom.xml @@ -59,6 +59,10 @@ spring-boot-autoconfigure-processor true + + org.springframework.boot + spring-boot-neo4j + org.springframework.ai @@ -71,6 +75,11 @@ spring-boot-starter-test test + + org.springframework.boot + spring-boot-starter-neo4j + test + org.springframework.boot spring-boot-testcontainers diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/src/main/java/org/springframework/ai/vectorstore/neo4j/autoconfigure/Neo4jVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/src/main/java/org/springframework/ai/vectorstore/neo4j/autoconfigure/Neo4jVectorStoreAutoConfiguration.java index 245a36e7deb..7cc2f3b86be 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/src/main/java/org/springframework/ai/vectorstore/neo4j/autoconfigure/Neo4jVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/src/main/java/org/springframework/ai/vectorstore/neo4j/autoconfigure/Neo4jVectorStoreAutoConfiguration.java @@ -30,7 +30,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; +import org.springframework.boot.neo4j.autoconfigure.Neo4jAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/src/test/java/org/springframework/ai/vectorstore/neo4j/autoconfigure/Neo4jVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/src/test/java/org/springframework/ai/vectorstore/neo4j/autoconfigure/Neo4jVectorStoreAutoConfigurationIT.java index fd9077d6c73..47ff53d9987 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/src/test/java/org/springframework/ai/vectorstore/neo4j/autoconfigure/Neo4jVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/src/test/java/org/springframework/ai/vectorstore/neo4j/autoconfigure/Neo4jVectorStoreAutoConfigurationIT.java @@ -37,7 +37,7 @@ import org.springframework.ai.vectorstore.neo4j.Neo4jVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; +import org.springframework.boot.neo4j.autoconfigure.Neo4jAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/pom.xml b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/pom.xml index 66c6202bd82..c157df942ac 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/pom.xml +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/pom.xml @@ -59,6 +59,10 @@ spring-boot-autoconfigure-processor true + + org.springframework.boot + spring-boot-jdbc + org.springframework.ai diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/src/main/java/org/springframework/ai/vectorstore/oracle/autoconfigure/OracleVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/src/main/java/org/springframework/ai/vectorstore/oracle/autoconfigure/OracleVectorStoreAutoConfiguration.java index eb31a4dda94..f08715feda5 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/src/main/java/org/springframework/ai/vectorstore/oracle/autoconfigure/OracleVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/src/main/java/org/springframework/ai/vectorstore/oracle/autoconfigure/OracleVectorStoreAutoConfiguration.java @@ -31,7 +31,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.core.JdbcTemplate; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/src/test/java/org/springframework/ai/vectorstore/oracle/autoconfigure/OracleVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/src/test/java/org/springframework/ai/vectorstore/oracle/autoconfigure/OracleVectorStoreAutoConfigurationIT.java index 1e1261389bd..61ca7179ae8 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/src/test/java/org/springframework/ai/vectorstore/oracle/autoconfigure/OracleVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/src/test/java/org/springframework/ai/vectorstore/oracle/autoconfigure/OracleVectorStoreAutoConfigurationIT.java @@ -38,8 +38,8 @@ import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; import org.springframework.ai.vectorstore.oracle.OracleVectorStore; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/pom.xml b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/pom.xml index 9bc06e4b948..20c394f9a4c 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/pom.xml +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/pom.xml @@ -59,6 +59,10 @@ spring-boot-autoconfigure-processor true + + org.springframework.boot + spring-boot-jdbc + org.springframework.ai diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/main/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/main/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfiguration.java index 839d88a37e9..a79d3f9d54e 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/main/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/main/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfiguration.java @@ -31,7 +31,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.core.JdbcTemplate; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/test/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/test/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfigurationIT.java index 3958c109cdb..efca91bf3f7 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/test/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/test/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfigurationIT.java @@ -39,8 +39,8 @@ import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; import org.springframework.ai.vectorstore.pgvector.PgVectorStore; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/pom.xml b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/pom.xml index a01969180e1..de67582edd6 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/pom.xml +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/pom.xml @@ -56,8 +56,7 @@ org.springframework.boot - spring-boot-autoconfigure-processor - true + spring-boot-data-redis @@ -71,6 +70,11 @@ spring-boot-starter-test test + + org.springframework.boot + spring-boot-starter-data-redis + test + org.springframework.boot spring-boot-testcontainers diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/main/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/main/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfiguration.java index abb5b629bb4..b63dda5dd44 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/main/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/main/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfiguration.java @@ -34,7 +34,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.data.redis.autoconfigure.RedisAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/test/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/test/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfigurationIT.java index 40d3bce6e93..20dd28aa9be 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/test/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/test/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfigurationIT.java @@ -36,7 +36,7 @@ import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; import org.springframework.ai.vectorstore.redis.RedisVectorStore; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.data.redis.autoconfigure.RedisAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/memory/repository/spring-ai-model-chat-memory-repository-cassandra/pom.xml b/memory/repository/spring-ai-model-chat-memory-repository-cassandra/pom.xml index 99a26be2e85..f5a6dc9fc44 100644 --- a/memory/repository/spring-ai-model-chat-memory-repository-cassandra/pom.xml +++ b/memory/repository/spring-ai-model-chat-memory-repository-cassandra/pom.xml @@ -50,6 +50,12 @@ java-driver-query-builder + + org.springframework.boot + spring-boot-jdbc + test + + org.springframework.boot spring-boot-starter-test diff --git a/memory/repository/spring-ai-model-chat-memory-repository-cassandra/src/test/java/org/springframework/ai/chat/memory/repository/cassandra/CassandraChatMemoryRepositoryIT.java b/memory/repository/spring-ai-model-chat-memory-repository-cassandra/src/test/java/org/springframework/ai/chat/memory/repository/cassandra/CassandraChatMemoryRepositoryIT.java index b16f28d31e0..c570f7d864c 100644 --- a/memory/repository/spring-ai-model-chat-memory-repository-cassandra/src/test/java/org/springframework/ai/chat/memory/repository/cassandra/CassandraChatMemoryRepositoryIT.java +++ b/memory/repository/spring-ai-model-chat-memory-repository-cassandra/src/test/java/org/springframework/ai/chat/memory/repository/cassandra/CassandraChatMemoryRepositoryIT.java @@ -39,7 +39,7 @@ import org.springframework.ai.chat.messages.UserMessage; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; diff --git a/memory/repository/spring-ai-model-chat-memory-repository-jdbc/pom.xml b/memory/repository/spring-ai-model-chat-memory-repository-jdbc/pom.xml index e2271ea6dc0..e9e310ddee5 100644 --- a/memory/repository/spring-ai-model-chat-memory-repository-jdbc/pom.xml +++ b/memory/repository/spring-ai-model-chat-memory-repository-jdbc/pom.xml @@ -91,6 +91,12 @@ test + + org.springframework.boot + spring-boot-jdbc + test + + org.testcontainers testcontainers diff --git a/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/chat/memory/repository/jdbc/AbstractJdbcChatMemoryRepositoryIT.java b/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/chat/memory/repository/jdbc/AbstractJdbcChatMemoryRepositoryIT.java index c26dd69049d..db58f060a17 100644 --- a/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/chat/memory/repository/jdbc/AbstractJdbcChatMemoryRepositoryIT.java +++ b/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/chat/memory/repository/jdbc/AbstractJdbcChatMemoryRepositoryIT.java @@ -35,8 +35,8 @@ import org.springframework.ai.chat.messages.UserMessage; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.ContextConfiguration; diff --git a/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicChatModel.java b/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicChatModel.java index f8091eee212..bc547f65037 100644 --- a/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicChatModel.java +++ b/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicChatModel.java @@ -30,6 +30,8 @@ import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.retry.RetryException; +import org.springframework.http.HttpHeaders; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; @@ -78,7 +80,7 @@ import org.springframework.ai.tool.definition.ToolDefinition; import org.springframework.ai.util.json.JsonParser; import org.springframework.http.ResponseEntity; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.MultiValueMap; @@ -192,8 +194,19 @@ public ChatResponse internalCall(Prompt prompt, ChatResponse previousChatRespons this.observationRegistry) .observe(() -> { - ResponseEntity completionEntity = this.retryTemplate.execute( - ctx -> this.anthropicApi.chatCompletionEntity(request, this.getAdditionalHttpHeaders(prompt))); + ResponseEntity completionEntity = null; + try { + completionEntity = this.retryTemplate.execute(() -> this.anthropicApi.chatCompletionEntity(request, + this.getAdditionalHttpHeaders(prompt))); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); + } + } AnthropicApi.ChatCompletionResponse completionResponse = completionEntity.getBody(); AnthropicApi.Usage usage = completionResponse.usage(); @@ -427,14 +440,15 @@ else if (mimeType.contains("pdf")) { + ". Supported types are: images (image/*) and PDF documents (application/pdf)"); } - private MultiValueMap getAdditionalHttpHeaders(Prompt prompt) { + private HttpHeaders getAdditionalHttpHeaders(Prompt prompt) { Map headers = new HashMap<>(this.defaultOptions.getHttpHeaders()); if (prompt.getOptions() != null && prompt.getOptions() instanceof AnthropicChatOptions chatOptions) { headers.putAll(chatOptions.getHttpHeaders()); } - return CollectionUtils.toMultiValueMap( - headers.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> List.of(e.getValue())))); + HttpHeaders httpHeaders = new HttpHeaders(); + headers.forEach(httpHeaders::add); + return httpHeaders; } Prompt buildRequestPrompt(Prompt prompt) { diff --git a/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/api/AnthropicApi.java b/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/api/AnthropicApi.java index cdd1a4fef51..e84aff29464 100644 --- a/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/api/AnthropicApi.java +++ b/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/api/AnthropicApi.java @@ -48,8 +48,6 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; @@ -157,7 +155,7 @@ private AnthropicApi(String baseUrl, String completionsPath, ApiKey anthropicApi * status code and headers. */ public ResponseEntity chatCompletionEntity(ChatCompletionRequest chatRequest) { - return chatCompletionEntity(chatRequest, new LinkedMultiValueMap<>()); + return chatCompletionEntity(chatRequest, new HttpHeaders()); } /** @@ -168,7 +166,7 @@ public ResponseEntity chatCompletionEntity(ChatCompletio * status code and headers. */ public ResponseEntity chatCompletionEntity(ChatCompletionRequest chatRequest, - MultiValueMap additionalHttpHeader) { + HttpHeaders additionalHttpHeader) { Assert.notNull(chatRequest, "The request body can not be null."); Assert.isTrue(!chatRequest.stream(), "Request must set the stream property to false."); @@ -194,7 +192,7 @@ public ResponseEntity chatCompletionEntity(ChatCompletio * @return Returns a {@link Flux} stream from chat completion chunks. */ public Flux chatCompletionStream(ChatCompletionRequest chatRequest) { - return chatCompletionStream(chatRequest, new LinkedMultiValueMap<>()); + return chatCompletionStream(chatRequest, new HttpHeaders()); } /** @@ -205,7 +203,7 @@ public Flux chatCompletionStream(ChatCompletionRequest c * @return Returns a {@link Flux} stream from chat completion chunks. */ public Flux chatCompletionStream(ChatCompletionRequest chatRequest, - MultiValueMap additionalHttpHeader) { + HttpHeaders additionalHttpHeader) { Assert.notNull(chatRequest, "The request body can not be null."); Assert.isTrue(chatRequest.stream(), "Request must set the stream property to true."); @@ -258,7 +256,7 @@ public Flux chatCompletionStream(ChatCompletionRequest c } private void addDefaultHeadersIfMissing(HttpHeaders headers) { - if (!headers.containsKey(HEADER_X_API_KEY)) { + if (!headers.containsHeader(HEADER_X_API_KEY)) { String apiKeyValue = this.apiKey.getValue(); if (StringUtils.hasText(apiKeyValue)) { headers.add(HEADER_X_API_KEY, apiKeyValue); diff --git a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/AnthropicChatModelObservationIT.java b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/AnthropicChatModelObservationIT.java index 910f572d208..382dbe6f64f 100644 --- a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/AnthropicChatModelObservationIT.java +++ b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/AnthropicChatModelObservationIT.java @@ -40,7 +40,7 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; @@ -171,7 +171,7 @@ public AnthropicApi anthropicApi() { public AnthropicChatModel anthropicChatModel(AnthropicApi anthropicApi, TestObservationRegistry observationRegistry) { return new AnthropicChatModel(anthropicApi, AnthropicChatOptions.builder().build(), - ToolCallingManager.builder().build(), RetryTemplate.defaultInstance(), observationRegistry); + ToolCallingManager.builder().build(), new RetryTemplate(), observationRegistry); } } diff --git a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/api/AnthropicApiBuilderTests.java b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/api/AnthropicApiBuilderTests.java index 8a89ea306c7..08eb75ffaca 100644 --- a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/api/AnthropicApiBuilderTests.java +++ b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/api/AnthropicApiBuilderTests.java @@ -229,7 +229,7 @@ void dynamicApiKeyRestClientWithAdditionalApiKeyHeader() throws InterruptedExcep .temperature(0.8) .messages(List.of(chatCompletionMessage)) .build(); - MultiValueMap additionalHeaders = new LinkedMultiValueMap<>(); + var additionalHeaders = new HttpHeaders(); additionalHeaders.add("x-api-key", "additional-key"); ResponseEntity response = api.chatCompletionEntity(request, additionalHeaders); @@ -328,7 +328,7 @@ void dynamicApiKeyWebClientWithAdditionalApiKey() throws InterruptedException { .messages(List.of(chatCompletionMessage)) .stream(true) .build(); - MultiValueMap additionalHeaders = new LinkedMultiValueMap<>(); + var additionalHeaders = new HttpHeaders(); additionalHeaders.add("x-api-key", "additional-key"); api.chatCompletionStream(request, additionalHeaders).collectList().block(); diff --git a/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/DeepSeekChatModel.java b/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/DeepSeekChatModel.java index fba44ffd4ce..bd8581cde97 100644 --- a/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/DeepSeekChatModel.java +++ b/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/DeepSeekChatModel.java @@ -25,6 +25,8 @@ import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.retry.RetryException; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; @@ -67,7 +69,7 @@ import org.springframework.ai.support.UsageCalculator; import org.springframework.ai.tool.definition.ToolDefinition; import org.springframework.http.ResponseEntity; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -165,8 +167,18 @@ public ChatResponse internalCall(Prompt prompt, ChatResponse previousChatRespons this.observationRegistry) .observe(() -> { - ResponseEntity completionEntity = this.retryTemplate - .execute(ctx -> this.deepSeekApi.chatCompletionEntity(request)); + ResponseEntity completionEntity = null; + try { + completionEntity = this.retryTemplate.execute(() -> this.deepSeekApi.chatCompletionEntity(request)); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); + } + } var chatCompletion = completionEntity.getBody(); diff --git a/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/api/DeepSeekApi.java b/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/api/DeepSeekApi.java index 13415829854..d6b36d554f8 100644 --- a/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/api/DeepSeekApi.java +++ b/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/api/DeepSeekApi.java @@ -41,8 +41,6 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; import org.springframework.web.reactive.function.client.WebClient; @@ -80,7 +78,7 @@ public class DeepSeekApi { * @param webClientBuilder WebClient builder. * @param responseErrorHandler Response error handler. */ - public DeepSeekApi(String baseUrl, ApiKey apiKey, MultiValueMap headers, String completionsPath, + public DeepSeekApi(String baseUrl, ApiKey apiKey, HttpHeaders headers, String completionsPath, String betaPrefixPath, RestClient.Builder restClientBuilder, WebClient.Builder webClientBuilder, ResponseErrorHandler responseErrorHandler) { @@ -132,7 +130,7 @@ public ResponseEntity chatCompletionEntity(ChatCompletionRequest * @return Returns a {@link Flux} stream from chat completion chunks. */ public Flux chatCompletionStream(ChatCompletionRequest chatRequest) { - return chatCompletionStream(chatRequest, new LinkedMultiValueMap<>()); + return chatCompletionStream(chatRequest, new HttpHeaders()); } /** @@ -144,7 +142,7 @@ public Flux chatCompletionStream(ChatCompletionRequest chat * @return Returns a {@link Flux} stream from chat completion chunks. */ public Flux chatCompletionStream(ChatCompletionRequest chatRequest, - MultiValueMap additionalHttpHeader) { + HttpHeaders additionalHttpHeader) { Assert.notNull(chatRequest, "The request body can not be null."); Assert.isTrue(chatRequest.stream(), "Request must set the stream property to true."); @@ -911,7 +909,7 @@ public static final class Builder { private ApiKey apiKey; - private MultiValueMap headers = new LinkedMultiValueMap<>(); + private HttpHeaders headers = new HttpHeaders(); private String completionsPath = org.springframework.ai.deepseek.api.common.DeepSeekConstants.DEFAULT_COMPLETIONS_PATH; @@ -941,7 +939,7 @@ public Builder apiKey(String simpleApiKey) { return this; } - public Builder headers(MultiValueMap headers) { + public Builder headers(HttpHeaders headers) { Assert.notNull(headers, "headers cannot be null"); this.headers = headers; return this; diff --git a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/DeepSeekRetryTests.java b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/DeepSeekRetryTests.java index 35f24eaadeb..895a393260e 100644 --- a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/DeepSeekRetryTests.java +++ b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/DeepSeekRetryTests.java @@ -35,10 +35,10 @@ import org.springframework.ai.retry.RetryUtils; import org.springframework.ai.retry.TransientAiException; import org.springframework.http.ResponseEntity; -import org.springframework.retry.RetryCallback; -import org.springframework.retry.RetryContext; -import org.springframework.retry.RetryListener; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryListener; +import org.springframework.core.retry.RetryPolicy; +import org.springframework.core.retry.Retryable; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -62,7 +62,7 @@ public class DeepSeekRetryTests { public void beforeEach() { RetryTemplate retryTemplate = RetryUtils.SHORT_RETRY_TEMPLATE; this.retryListener = new TestRetryListener(); - retryTemplate.registerListener(this.retryListener); + retryTemplate.setRetryListener(this.retryListener); this.chatModel = DeepSeekChatModel.builder() .deepSeekApi(this.deepSeekApi) @@ -88,7 +88,7 @@ public void deepSeekChatTransientError() { assertThat(result).isNotNull(); assertThat(result.getResult().getOutput().getText()).isSameAs("Response"); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); } @@ -116,7 +116,7 @@ public void deepSeekChatStreamTransientError() { assertThat(result).isNotNull(); assertThat(result.getResult().getOutput().getText()).isSameAs("Response"); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); } @@ -134,14 +134,15 @@ private static class TestRetryListener implements RetryListener { int onSuccessRetryCount = 0; @Override - public void onSuccess(RetryContext context, RetryCallback callback, T result) { - this.onSuccessRetryCount = context.getRetryCount(); + public void beforeRetry(final RetryPolicy retryPolicy, final Retryable retryable) { + // Count each retry attempt + this.onErrorRetryCount++; } @Override - public void onError(RetryContext context, RetryCallback callback, - Throwable throwable) { - this.onErrorRetryCount = context.getRetryCount(); + public void onRetrySuccess(final RetryPolicy retryPolicy, final Retryable retryable, final Object result) { + // Count successful retries - we increment when we succeed after a failure + this.onSuccessRetryCount++; } } diff --git a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/chat/DeepSeekChatModelObservationIT.java b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/chat/DeepSeekChatModelObservationIT.java index 00e8732dade..b2900e479cb 100644 --- a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/chat/DeepSeekChatModelObservationIT.java +++ b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/chat/DeepSeekChatModelObservationIT.java @@ -40,7 +40,7 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.ai.chat.observation.ChatModelObservationDocumentation.HighCardinalityKeyNames; @@ -172,7 +172,7 @@ public DeepSeekApi deepSeekApi() { public DeepSeekChatModel deepSeekChatModel(DeepSeekApi deepSeekApi, TestObservationRegistry observationRegistry) { return new DeepSeekChatModel(deepSeekApi, DeepSeekChatOptions.builder().build(), - ToolCallingManager.builder().build(), RetryTemplate.defaultInstance(), observationRegistry); + ToolCallingManager.builder().build(), new RetryTemplate(), observationRegistry); } } diff --git a/models/spring-ai-elevenlabs/src/main/java/org/springframework/ai/elevenlabs/ElevenLabsTextToSpeechModel.java b/models/spring-ai-elevenlabs/src/main/java/org/springframework/ai/elevenlabs/ElevenLabsTextToSpeechModel.java index 68ed07568a8..7f4a5a98621 100644 --- a/models/spring-ai-elevenlabs/src/main/java/org/springframework/ai/elevenlabs/ElevenLabsTextToSpeechModel.java +++ b/models/spring-ai-elevenlabs/src/main/java/org/springframework/ai/elevenlabs/ElevenLabsTextToSpeechModel.java @@ -20,6 +20,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.retry.RetryException; import reactor.core.publisher.Flux; import org.springframework.ai.audio.tts.Speech; @@ -29,7 +30,7 @@ import org.springframework.ai.audio.tts.TextToSpeechResponse; import org.springframework.ai.elevenlabs.api.ElevenLabsApi; import org.springframework.ai.retry.RetryUtils; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; @@ -73,15 +74,26 @@ public static Builder builder() { public TextToSpeechResponse call(TextToSpeechPrompt prompt) { RequestContext requestContext = prepareRequest(prompt); - byte[] audioData = this.retryTemplate.execute(context -> { - var response = this.elevenLabsApi.textToSpeech(requestContext.request, requestContext.voiceId, - requestContext.queryParameters); - if (response.getBody() == null) { - logger.warn("No speech response returned for request: {}", requestContext.request); - return new byte[0]; + byte[] audioData = null; + try { + audioData = this.retryTemplate.execute(() -> { + var response = this.elevenLabsApi.textToSpeech(requestContext.request, requestContext.voiceId, + requestContext.queryParameters); + if (response.getBody() == null) { + logger.warn("No speech response returned for request: {}", requestContext.request); + return new byte[0]; + } + return response.getBody(); + }); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); } - return response.getBody(); - }); + } return new TextToSpeechResponse(List.of(new Speech(audioData))); } @@ -90,9 +102,19 @@ public TextToSpeechResponse call(TextToSpeechPrompt prompt) { public Flux stream(TextToSpeechPrompt prompt) { RequestContext requestContext = prepareRequest(prompt); - return this.retryTemplate.execute(context -> this.elevenLabsApi - .textToSpeechStream(requestContext.request, requestContext.voiceId, requestContext.queryParameters) - .map(entity -> new TextToSpeechResponse(List.of(new Speech(entity.getBody()))))); + try { + return this.retryTemplate.execute(() -> this.elevenLabsApi + .textToSpeechStream(requestContext.request, requestContext.voiceId, requestContext.queryParameters) + .map(entity -> new TextToSpeechResponse(List.of(new Speech(entity.getBody()))))); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); + } + } } private RequestContext prepareRequest(TextToSpeechPrompt prompt) { diff --git a/models/spring-ai-elevenlabs/src/main/java/org/springframework/ai/elevenlabs/api/ElevenLabsApi.java b/models/spring-ai-elevenlabs/src/main/java/org/springframework/ai/elevenlabs/api/ElevenLabsApi.java index 10ce0349070..a6879b4f43b 100644 --- a/models/spring-ai-elevenlabs/src/main/java/org/springframework/ai/elevenlabs/api/ElevenLabsApi.java +++ b/models/spring-ai-elevenlabs/src/main/java/org/springframework/ai/elevenlabs/api/ElevenLabsApi.java @@ -33,7 +33,6 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; -import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; @@ -62,9 +61,8 @@ public final class ElevenLabsApi { * @param webClientBuilder A builder for the Spring WebClient. * @param responseErrorHandler A custom error handler for API responses. */ - private ElevenLabsApi(String baseUrl, ApiKey apiKey, MultiValueMap headers, - RestClient.Builder restClientBuilder, WebClient.Builder webClientBuilder, - ResponseErrorHandler responseErrorHandler) { + private ElevenLabsApi(String baseUrl, ApiKey apiKey, HttpHeaders headers, RestClient.Builder restClientBuilder, + WebClient.Builder webClientBuilder, ResponseErrorHandler responseErrorHandler) { Consumer jsonContentHeaders = h -> { if (!(apiKey instanceof NoopApiKey)) { @@ -331,7 +329,7 @@ public static final class Builder { private ApiKey apiKey; - private MultiValueMap headers = new LinkedMultiValueMap<>(); + private HttpHeaders headers = new HttpHeaders(); private RestClient.Builder restClientBuilder = RestClient.builder(); @@ -357,7 +355,7 @@ public Builder apiKey(String simpleApiKey) { return this; } - public Builder headers(MultiValueMap headers) { + public Builder headers(HttpHeaders headers) { Assert.notNull(headers, "headers cannot be null"); this.headers = headers; return this; diff --git a/models/spring-ai-elevenlabs/src/main/java/org/springframework/ai/elevenlabs/api/ElevenLabsVoicesApi.java b/models/spring-ai-elevenlabs/src/main/java/org/springframework/ai/elevenlabs/api/ElevenLabsVoicesApi.java index 3f6f6377937..e501ca98864 100644 --- a/models/spring-ai-elevenlabs/src/main/java/org/springframework/ai/elevenlabs/api/ElevenLabsVoicesApi.java +++ b/models/spring-ai-elevenlabs/src/main/java/org/springframework/ai/elevenlabs/api/ElevenLabsVoicesApi.java @@ -32,8 +32,6 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; @@ -56,8 +54,8 @@ public class ElevenLabsVoicesApi { * @param restClientBuilder A builder for the Spring RestClient. * @param responseErrorHandler A custom error handler for API responses. */ - public ElevenLabsVoicesApi(String baseUrl, ApiKey apiKey, MultiValueMap headers, - RestClient.Builder restClientBuilder, ResponseErrorHandler responseErrorHandler) { + public ElevenLabsVoicesApi(String baseUrl, ApiKey apiKey, HttpHeaders headers, RestClient.Builder restClientBuilder, + ResponseErrorHandler responseErrorHandler) { Consumer jsonContentHeaders = h -> { if (!(apiKey instanceof NoopApiKey)) { h.set("xi-api-key", apiKey.getValue()); @@ -399,7 +397,7 @@ public static final class Builder { private ApiKey apiKey; - private MultiValueMap headers = new LinkedMultiValueMap<>(); + private HttpHeaders headers = new HttpHeaders(); private RestClient.Builder restClientBuilder = RestClient.builder(); @@ -423,7 +421,7 @@ public Builder apiKey(String simpleApiKey) { return this; } - public Builder headers(MultiValueMap headers) { + public Builder headers(HttpHeaders headers) { Assert.notNull(headers, "headers cannot be null"); this.headers = headers; return this; diff --git a/models/spring-ai-google-genai-embedding/src/main/java/org/springframework/ai/google/genai/text/GoogleGenAiTextEmbeddingModel.java b/models/spring-ai-google-genai-embedding/src/main/java/org/springframework/ai/google/genai/text/GoogleGenAiTextEmbeddingModel.java index 46c87cd6862..049720082bf 100644 --- a/models/spring-ai-google-genai-embedding/src/main/java/org/springframework/ai/google/genai/text/GoogleGenAiTextEmbeddingModel.java +++ b/models/spring-ai-google-genai-embedding/src/main/java/org/springframework/ai/google/genai/text/GoogleGenAiTextEmbeddingModel.java @@ -46,7 +46,8 @@ import org.springframework.ai.model.ModelOptionsUtils; import org.springframework.ai.observation.conventions.AiProvider; import org.springframework.ai.retry.RetryUtils; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryException; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -168,8 +169,19 @@ public EmbeddingResponse call(EmbeddingRequest request) { } // Call the embedding API with retry - EmbedContentResponse embeddingResponse = this.retryTemplate - .execute(context -> this.genAiClient.models.embedContent(modelName, validTexts, config)); + EmbedContentResponse embeddingResponse = null; + try { + embeddingResponse = this.retryTemplate + .execute(() -> this.genAiClient.models.embedContent(modelName, validTexts, config)); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); + } + } // Process the response // Note: We need to handle the case where some texts were filtered out diff --git a/models/spring-ai-google-genai-embedding/src/test/java/org/springframework/ai/google/genai/text/GoogleGenAiTextEmbeddingRetryTests.java b/models/spring-ai-google-genai-embedding/src/test/java/org/springframework/ai/google/genai/text/GoogleGenAiTextEmbeddingRetryTests.java index 4dc9fce14c5..08ea9a8af07 100644 --- a/models/spring-ai-google-genai-embedding/src/test/java/org/springframework/ai/google/genai/text/GoogleGenAiTextEmbeddingRetryTests.java +++ b/models/spring-ai-google-genai-embedding/src/test/java/org/springframework/ai/google/genai/text/GoogleGenAiTextEmbeddingRetryTests.java @@ -36,10 +36,10 @@ import org.springframework.ai.google.genai.GoogleGenAiEmbeddingConnectionDetails; import org.springframework.ai.retry.RetryUtils; import org.springframework.ai.retry.TransientAiException; -import org.springframework.retry.RetryCallback; -import org.springframework.retry.RetryContext; -import org.springframework.retry.RetryListener; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryListener; +import org.springframework.core.retry.RetryPolicy; +import org.springframework.core.retry.Retryable; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; @@ -75,7 +75,7 @@ public class GoogleGenAiTextEmbeddingRetryTests { public void setUp() throws Exception { this.retryTemplate = RetryUtils.SHORT_RETRY_TEMPLATE; this.retryListener = new TestRetryListener(); - this.retryTemplate.registerListener(this.retryListener); + this.retryTemplate.setRetryListener(this.retryListener); // Create a mock Client and use reflection to set the models field this.mockGenAiClient = mock(Client.class); @@ -114,7 +114,7 @@ public void vertexAiEmbeddingTransientError() { assertThat(result).isNotNull(); assertThat(result.getResults()).hasSize(1); assertThat(result.getResults().get(0).getOutput()).isEqualTo(new float[] { 9.9f, 8.8f }); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); verify(this.mockModels, times(3)).embedContent(anyString(), any(List.class), any(EmbedContentConfig.class)); @@ -143,14 +143,15 @@ private static class TestRetryListener implements RetryListener { int onSuccessRetryCount = 0; @Override - public void onSuccess(RetryContext context, RetryCallback callback, T result) { - this.onSuccessRetryCount = context.getRetryCount(); + public void beforeRetry(final RetryPolicy retryPolicy, final Retryable retryable) { + // Count each retry attempt + this.onErrorRetryCount++; } @Override - public void onError(RetryContext context, RetryCallback callback, - Throwable throwable) { - this.onErrorRetryCount = context.getRetryCount(); + public void onRetrySuccess(final RetryPolicy retryPolicy, final Retryable retryable, final Object result) { + // Count successful retries - we increment when we succeed after a failure + this.onSuccessRetryCount++; } } diff --git a/models/spring-ai-google-genai-embedding/src/test/java/org/springframework/ai/google/genai/text/TestGoogleGenAiTextEmbeddingModel.java b/models/spring-ai-google-genai-embedding/src/test/java/org/springframework/ai/google/genai/text/TestGoogleGenAiTextEmbeddingModel.java index 44a06031afc..9836f63ec30 100644 --- a/models/spring-ai-google-genai-embedding/src/test/java/org/springframework/ai/google/genai/text/TestGoogleGenAiTextEmbeddingModel.java +++ b/models/spring-ai-google-genai-embedding/src/test/java/org/springframework/ai/google/genai/text/TestGoogleGenAiTextEmbeddingModel.java @@ -17,7 +17,7 @@ package org.springframework.ai.google.genai.text; import org.springframework.ai.google.genai.GoogleGenAiEmbeddingConnectionDetails; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; /** * Test implementation of GoogleGenAiTextEmbeddingModel that uses a mock connection for diff --git a/models/spring-ai-google-genai/src/main/java/org/springframework/ai/google/genai/GoogleGenAiChatModel.java b/models/spring-ai-google-genai/src/main/java/org/springframework/ai/google/genai/GoogleGenAiChatModel.java index 8e38008e859..7411d085c65 100644 --- a/models/spring-ai-google-genai/src/main/java/org/springframework/ai/google/genai/GoogleGenAiChatModel.java +++ b/models/spring-ai-google-genai/src/main/java/org/springframework/ai/google/genai/GoogleGenAiChatModel.java @@ -46,6 +46,7 @@ import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.retry.RetryException; import reactor.core.publisher.Flux; import reactor.core.scheduler.Schedulers; @@ -88,7 +89,7 @@ import org.springframework.ai.tool.definition.ToolDefinition; import org.springframework.beans.factory.DisposableBean; import org.springframework.lang.NonNull; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -404,30 +405,41 @@ private ChatResponse internalCall(Prompt prompt, ChatResponse previousChatRespon ChatResponse response = ChatModelObservationDocumentation.CHAT_MODEL_OPERATION .observation(this.observationConvention, DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, this.observationRegistry) - .observe(() -> this.retryTemplate.execute(context -> { - - var geminiRequest = createGeminiRequest(prompt); - - GenerateContentResponse generateContentResponse = this.getContentResponse(geminiRequest); + .observe(() -> { + try { + return this.retryTemplate.execute(() -> { + + var geminiRequest = createGeminiRequest(prompt); + + GenerateContentResponse generateContentResponse = this.getContentResponse(geminiRequest); + + List generations = generateContentResponse.candidates() + .orElse(List.of()) + .stream() + .map(this::responseCandidateToGeneration) + .flatMap(List::stream) + .toList(); + + var usage = generateContentResponse.usageMetadata(); + GoogleGenAiChatOptions options = (GoogleGenAiChatOptions) prompt.getOptions(); + Usage currentUsage = (usage.isPresent()) ? getDefaultUsage(usage.get(), options) + : getDefaultUsage(null, options); + Usage cumulativeUsage = UsageCalculator.getCumulativeUsage(currentUsage, previousChatResponse); + ChatResponse chatResponse = new ChatResponse(generations, + toChatResponseMetadata(cumulativeUsage, generateContentResponse.modelVersion().get())); + + observationContext.setResponse(chatResponse); + return chatResponse; + }); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } - List generations = generateContentResponse.candidates() - .orElse(List.of()) - .stream() - .map(this::responseCandidateToGeneration) - .flatMap(List::stream) - .toList(); - - var usage = generateContentResponse.usageMetadata(); - GoogleGenAiChatOptions options = (GoogleGenAiChatOptions) prompt.getOptions(); - Usage currentUsage = (usage.isPresent()) ? getDefaultUsage(usage.get(), options) - : getDefaultUsage(null, options); - Usage cumulativeUsage = UsageCalculator.getCumulativeUsage(currentUsage, previousChatResponse); - ChatResponse chatResponse = new ChatResponse(generations, - toChatResponseMetadata(cumulativeUsage, generateContentResponse.modelVersion().get())); - - observationContext.setResponse(chatResponse); - return chatResponse; - })); + throw new RuntimeException(e); + } + }); if (this.toolExecutionEligibilityPredicate.isToolExecutionRequired(prompt.getOptions(), response)) { var toolExecutionResult = this.toolCallingManager.executeToolCalls(prompt, response); diff --git a/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/GoogleGenAiChatModelCachedContentTests.java b/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/GoogleGenAiChatModelCachedContentTests.java index af4ea6679e0..f2340cc79d6 100644 --- a/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/GoogleGenAiChatModelCachedContentTests.java +++ b/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/GoogleGenAiChatModelCachedContentTests.java @@ -36,7 +36,7 @@ import org.springframework.ai.google.genai.cache.GoogleGenAiCachedContent; import org.springframework.ai.google.genai.cache.GoogleGenAiCachedContentService; import org.springframework.ai.retry.RetryUtils; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; diff --git a/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/GoogleGenAiChatModelExtendedUsageTests.java b/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/GoogleGenAiChatModelExtendedUsageTests.java index 27e3ccf24a5..1b75b991a3a 100644 --- a/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/GoogleGenAiChatModelExtendedUsageTests.java +++ b/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/GoogleGenAiChatModelExtendedUsageTests.java @@ -41,7 +41,7 @@ import org.springframework.ai.google.genai.metadata.GoogleGenAiTrafficType; import org.springframework.ai.google.genai.metadata.GoogleGenAiUsage; import org.springframework.ai.retry.RetryUtils; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; diff --git a/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/GoogleGenAiRetryTests.java b/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/GoogleGenAiRetryTests.java index 4170c992c64..85c570a7c3c 100644 --- a/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/GoogleGenAiRetryTests.java +++ b/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/GoogleGenAiRetryTests.java @@ -27,10 +27,10 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.ai.retry.RetryUtils; -import org.springframework.retry.RetryCallback; -import org.springframework.retry.RetryContext; -import org.springframework.retry.RetryListener; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryListener; +import org.springframework.core.retry.RetryPolicy; +import org.springframework.core.retry.Retryable; +import org.springframework.core.retry.RetryTemplate; /** * @author Mark Pollack @@ -55,7 +55,7 @@ public class GoogleGenAiRetryTests { public void setUp() { this.retryTemplate = RetryUtils.SHORT_RETRY_TEMPLATE; this.retryListener = new TestRetryListener(); - this.retryTemplate.registerListener(this.retryListener); + this.retryTemplate.setRetryListener(this.retryListener); this.chatModel = new org.springframework.ai.google.genai.TestGoogleGenAiGeminiChatModel(this.genAiClient, GoogleGenAiChatOptions.builder() @@ -95,14 +95,15 @@ private static class TestRetryListener implements RetryListener { int onSuccessRetryCount = 0; @Override - public void onSuccess(RetryContext context, RetryCallback callback, T result) { - this.onSuccessRetryCount = context.getRetryCount(); + public void beforeRetry(final RetryPolicy retryPolicy, final Retryable retryable) { + // Count each retry attempt + this.onErrorRetryCount++; } @Override - public void onError(RetryContext context, RetryCallback callback, - Throwable throwable) { - this.onErrorRetryCount = context.getRetryCount(); + public void onRetrySuccess(final RetryPolicy retryPolicy, final Retryable retryable, final Object result) { + // Count successful retries - we increment when we succeed after a failure + this.onSuccessRetryCount++; } } diff --git a/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/TestGoogleGenAiGeminiChatModel.java b/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/TestGoogleGenAiGeminiChatModel.java index 6c63133fd1f..2730b73e501 100644 --- a/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/TestGoogleGenAiGeminiChatModel.java +++ b/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/TestGoogleGenAiGeminiChatModel.java @@ -20,7 +20,7 @@ import com.google.genai.types.GenerateContentResponse; import org.springframework.ai.model.tool.ToolCallingManager; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; /** * @author Mark Pollack diff --git a/models/spring-ai-huggingface/pom.xml b/models/spring-ai-huggingface/pom.xml index fae8ecbd802..9bb8329a1f3 100644 --- a/models/spring-ai-huggingface/pom.xml +++ b/models/spring-ai-huggingface/pom.xml @@ -90,7 +90,7 @@ io.swagger.codegen.v3 swagger-codegen-maven-plugin - 3.0.64 + 3.0.74 diff --git a/models/spring-ai-minimax/src/main/java/org/springframework/ai/minimax/MiniMaxChatModel.java b/models/spring-ai-minimax/src/main/java/org/springframework/ai/minimax/MiniMaxChatModel.java index 5c771b2f5db..5e9af943676 100644 --- a/models/spring-ai-minimax/src/main/java/org/springframework/ai/minimax/MiniMaxChatModel.java +++ b/models/spring-ai-minimax/src/main/java/org/springframework/ai/minimax/MiniMaxChatModel.java @@ -26,6 +26,7 @@ import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.retry.RetryException; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; @@ -69,7 +70,7 @@ import org.springframework.ai.retry.RetryUtils; import org.springframework.ai.tool.definition.ToolDefinition; import org.springframework.http.ResponseEntity; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -253,8 +254,18 @@ public ChatResponse call(Prompt prompt) { this.observationRegistry) .observe(() -> { - ResponseEntity completionEntity = this.retryTemplate - .execute(ctx -> this.miniMaxApi.chatCompletionEntity(request)); + ResponseEntity completionEntity = null; + try { + completionEntity = this.retryTemplate.execute(() -> this.miniMaxApi.chatCompletionEntity(request)); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); + } + } var chatCompletion = completionEntity.getBody(); @@ -328,8 +339,18 @@ public Flux stream(Prompt prompt) { return Flux.deferContextual(contextView -> { ChatCompletionRequest request = createRequest(requestPrompt, true); - Flux completionChunks = this.retryTemplate - .execute(ctx -> this.miniMaxApi.chatCompletionStream(request)); + Flux completionChunks = null; + try { + completionChunks = this.retryTemplate.execute(() -> this.miniMaxApi.chatCompletionStream(request)); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); + } + } // For chunked responses, only the first chunk contains the choice role. // The rest of the chunks with same ID share the same role. diff --git a/models/spring-ai-minimax/src/main/java/org/springframework/ai/minimax/MiniMaxEmbeddingModel.java b/models/spring-ai-minimax/src/main/java/org/springframework/ai/minimax/MiniMaxEmbeddingModel.java index 5dd0077fed3..944e7a40f04 100644 --- a/models/spring-ai-minimax/src/main/java/org/springframework/ai/minimax/MiniMaxEmbeddingModel.java +++ b/models/spring-ai-minimax/src/main/java/org/springframework/ai/minimax/MiniMaxEmbeddingModel.java @@ -22,6 +22,7 @@ import io.micrometer.observation.ObservationRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.retry.RetryException; import org.springframework.ai.chat.metadata.DefaultUsage; import org.springframework.ai.document.Document; @@ -40,7 +41,7 @@ import org.springframework.ai.minimax.api.MiniMaxApiConstants; import org.springframework.ai.model.ModelOptionsUtils; import org.springframework.ai.retry.RetryUtils; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -165,8 +166,19 @@ public EmbeddingResponse call(EmbeddingRequest request) { .observation(this.observationConvention, DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, this.observationRegistry) .observe(() -> { - MiniMaxApi.EmbeddingList apiEmbeddingResponse = this.retryTemplate - .execute(ctx -> this.miniMaxApi.embeddings(apiRequest).getBody()); + MiniMaxApi.EmbeddingList apiEmbeddingResponse = null; + try { + apiEmbeddingResponse = this.retryTemplate + .execute(() -> this.miniMaxApi.embeddings(apiRequest).getBody()); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); + } + } if (apiEmbeddingResponse == null) { logger.warn("No embeddings returned for request: {}", request); diff --git a/models/spring-ai-minimax/src/test/java/org/springframework/ai/minimax/api/MiniMaxRetryTests.java b/models/spring-ai-minimax/src/test/java/org/springframework/ai/minimax/api/MiniMaxRetryTests.java index 9f165e27c0d..db3acd39525 100644 --- a/models/spring-ai-minimax/src/test/java/org/springframework/ai/minimax/api/MiniMaxRetryTests.java +++ b/models/spring-ai-minimax/src/test/java/org/springframework/ai/minimax/api/MiniMaxRetryTests.java @@ -46,10 +46,10 @@ import org.springframework.ai.retry.RetryUtils; import org.springframework.ai.retry.TransientAiException; import org.springframework.http.ResponseEntity; -import org.springframework.retry.RetryCallback; -import org.springframework.retry.RetryContext; -import org.springframework.retry.RetryListener; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryListener; +import org.springframework.core.retry.RetryPolicy; +import org.springframework.core.retry.RetryTemplate; +import org.springframework.core.retry.Retryable; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -78,7 +78,7 @@ public class MiniMaxRetryTests { public void beforeEach() { this.retryTemplate = RetryUtils.SHORT_RETRY_TEMPLATE; this.retryListener = new TestRetryListener(); - this.retryTemplate.registerListener(this.retryListener); + this.retryTemplate.setRetryListener(this.retryListener); this.chatModel = new MiniMaxChatModel(this.miniMaxApi, MiniMaxChatOptions.builder().build(), ToolCallingManager.builder().build(), this.retryTemplate); @@ -103,7 +103,7 @@ public void miniMaxChatTransientError() { assertThat(result).isNotNull(); assertThat(result.getResult().getOutput().getText()).isSameAs("Response"); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); } @@ -131,7 +131,7 @@ public void miniMaxChatStreamTransientError() { assertThat(result).isNotNull(); assertThat(result.collectList().block().get(0).getResult().getOutput().getText()).isSameAs("Response"); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); } @@ -158,7 +158,7 @@ public void miniMaxEmbeddingTransientError() { assertThat(result).isNotNull(); assertThat(result.getResult().getOutput()).isEqualTo(new float[] { 9.9f, 8.8f }); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); } @@ -171,21 +171,22 @@ public void miniMaxEmbeddingNonTransientError() { .call(new org.springframework.ai.embedding.EmbeddingRequest(List.of("text1", "text2"), options))); } - private class TestRetryListener implements RetryListener { + private static class TestRetryListener implements RetryListener { int onErrorRetryCount = 0; int onSuccessRetryCount = 0; @Override - public void onSuccess(RetryContext context, RetryCallback callback, T result) { - this.onSuccessRetryCount = context.getRetryCount(); + public void beforeRetry(final RetryPolicy retryPolicy, final Retryable retryable) { + // Count each retry attempt + this.onErrorRetryCount++; } @Override - public void onError(RetryContext context, RetryCallback callback, - Throwable throwable) { - this.onErrorRetryCount = context.getRetryCount(); + public void onRetrySuccess(final RetryPolicy retryPolicy, final Retryable retryable, final Object result) { + // Count successful retries - we increment when we succeed after a failure + this.onSuccessRetryCount++; } } diff --git a/models/spring-ai-minimax/src/test/java/org/springframework/ai/minimax/embedding/MiniMaxEmbeddingModelObservationIT.java b/models/spring-ai-minimax/src/test/java/org/springframework/ai/minimax/embedding/MiniMaxEmbeddingModelObservationIT.java index 0b5df195dd3..b502515ae15 100644 --- a/models/spring-ai-minimax/src/test/java/org/springframework/ai/minimax/embedding/MiniMaxEmbeddingModelObservationIT.java +++ b/models/spring-ai-minimax/src/test/java/org/springframework/ai/minimax/embedding/MiniMaxEmbeddingModelObservationIT.java @@ -37,7 +37,7 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.ai.embedding.observation.EmbeddingModelObservationDocumentation.HighCardinalityKeyNames; @@ -106,7 +106,7 @@ public MiniMaxApi minimaxApi() { public MiniMaxEmbeddingModel minimaxEmbeddingModel(MiniMaxApi minimaxApi, TestObservationRegistry observationRegistry) { return new MiniMaxEmbeddingModel(minimaxApi, MetadataMode.EMBED, MiniMaxEmbeddingOptions.builder().build(), - RetryTemplate.defaultInstance(), observationRegistry); + new RetryTemplate(), observationRegistry); } } diff --git a/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/MistralAiChatModel.java b/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/MistralAiChatModel.java index f7314603ec3..035630c6982 100644 --- a/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/MistralAiChatModel.java +++ b/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/MistralAiChatModel.java @@ -28,6 +28,8 @@ import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.retry.RetryException; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; @@ -70,7 +72,7 @@ import org.springframework.ai.support.UsageCalculator; import org.springframework.ai.tool.definition.ToolDefinition; import org.springframework.http.ResponseEntity; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.MimeType; @@ -199,8 +201,19 @@ public ChatResponse internalCall(Prompt prompt, ChatResponse previousChatRespons this.observationRegistry) .observe(() -> { - ResponseEntity completionEntity = this.retryTemplate - .execute(ctx -> this.mistralAiApi.chatCompletionEntity(request)); + ResponseEntity completionEntity = null; + try { + completionEntity = this.retryTemplate + .execute(() -> this.mistralAiApi.chatCompletionEntity(request)); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); + } + } ChatCompletion chatCompletion = completionEntity.getBody(); @@ -272,8 +285,18 @@ public Flux internalStream(Prompt prompt, ChatResponse previousCha observation.parentObservation(contextView.getOrDefault(ObservationThreadLocalAccessor.KEY, null)).start(); - Flux completionChunks = this.retryTemplate - .execute(ctx -> this.mistralAiApi.chatCompletionStream(request)); + Flux completionChunks = null; + try { + completionChunks = this.retryTemplate.execute(() -> this.mistralAiApi.chatCompletionStream(request)); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); + } + } // For chunked responses, only the first chunk contains the choice role. // The rest of the chunks with same ID share the same role. diff --git a/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/MistralAiEmbeddingModel.java b/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/MistralAiEmbeddingModel.java index b60c95d1bae..b5c93a8c951 100644 --- a/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/MistralAiEmbeddingModel.java +++ b/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/MistralAiEmbeddingModel.java @@ -21,6 +21,7 @@ import io.micrometer.observation.ObservationRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.retry.RetryException; import org.springframework.ai.chat.metadata.DefaultUsage; import org.springframework.ai.document.Document; @@ -38,7 +39,7 @@ import org.springframework.ai.mistralai.api.MistralAiApi; import org.springframework.ai.model.ModelOptionsUtils; import org.springframework.ai.retry.RetryUtils; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; /** @@ -129,8 +130,19 @@ public EmbeddingResponse call(EmbeddingRequest request) { .observation(this.observationConvention, DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, this.observationRegistry) .observe(() -> { - var apiEmbeddingResponse = this.retryTemplate - .execute(ctx -> this.mistralAiApi.embeddings(apiRequest).getBody()); + MistralAiApi.EmbeddingList apiEmbeddingResponse = null; + try { + apiEmbeddingResponse = this.retryTemplate + .execute(() -> this.mistralAiApi.embeddings(apiRequest).getBody()); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); + } + } if (apiEmbeddingResponse == null) { logger.warn("No embeddings returned for request: {}", request); diff --git a/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/moderation/MistralAiModerationModel.java b/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/moderation/MistralAiModerationModel.java index 0717520d766..e0aaab16099 100644 --- a/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/moderation/MistralAiModerationModel.java +++ b/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/moderation/MistralAiModerationModel.java @@ -21,6 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.retry.RetryException; import org.springframework.ai.mistralai.api.MistralAiModerationApi; import org.springframework.ai.model.ModelOptionsUtils; @@ -35,7 +36,7 @@ import org.springframework.ai.moderation.ModerationResult; import org.springframework.ai.retry.RetryUtils; import org.springframework.http.ResponseEntity; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import static org.springframework.ai.mistralai.api.MistralAiModerationApi.MistralAiModerationRequest; @@ -81,27 +82,39 @@ public MistralAiModerationModel(MistralAiModerationApi mistralAiModerationApi, R @Override public ModerationResponse call(ModerationPrompt moderationPrompt) { - return this.retryTemplate.execute(ctx -> { + try { + return this.retryTemplate.execute(() -> { - var instructions = moderationPrompt.getInstructions().getText(); + var instructions = moderationPrompt.getInstructions().getText(); - var moderationRequest = new MistralAiModerationRequest(instructions); + var moderationRequest = new MistralAiModerationRequest(instructions); - if (this.defaultOptions != null) { - moderationRequest = ModelOptionsUtils.merge(this.defaultOptions, moderationRequest, - MistralAiModerationRequest.class); + if (this.defaultOptions != null) { + moderationRequest = ModelOptionsUtils.merge(this.defaultOptions, moderationRequest, + MistralAiModerationRequest.class); + } + else { + // moderationPrompt.getOptions() never null but model can be empty, + // cause + // by ModerationPrompt constructor + moderationRequest = ModelOptionsUtils.merge( + toMistralAiModerationOptions(moderationPrompt.getOptions()), moderationRequest, + MistralAiModerationRequest.class); + } + + var moderationResponseEntity = this.mistralAiModerationApi.moderate(moderationRequest); + + return convertResponse(moderationResponseEntity, moderationRequest); + }); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; } else { - // moderationPrompt.getOptions() never null but model can be empty, cause - // by ModerationPrompt constructor - moderationRequest = ModelOptionsUtils.merge(toMistralAiModerationOptions(moderationPrompt.getOptions()), - moderationRequest, MistralAiModerationRequest.class); + throw new RuntimeException(e.getCause()); } - - var moderationResponseEntity = this.mistralAiModerationApi.moderate(moderationRequest); - - return convertResponse(moderationResponseEntity, moderationRequest); - }); + } } private ModerationResponse convertResponse(ResponseEntity moderationResponseEntity, diff --git a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatModelObservationIT.java b/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatModelObservationIT.java index 5d8a30d309c..03ac09d993c 100644 --- a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatModelObservationIT.java +++ b/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatModelObservationIT.java @@ -38,7 +38,7 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -190,7 +190,7 @@ public MistralAiChatModel mistralAiChatModel(MistralAiApi mistralAiApi, return MistralAiChatModel.builder() .mistralAiApi(mistralAiApi) .defaultOptions(MistralAiChatOptions.builder().build()) - .retryTemplate(RetryTemplate.defaultInstance()) + .retryTemplate(new RetryTemplate()) .observationRegistry(observationRegistry) .build(); } diff --git a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiEmbeddingModelObservationIT.java b/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiEmbeddingModelObservationIT.java index 8341c0fa22e..f3287c9fc3e 100644 --- a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiEmbeddingModelObservationIT.java +++ b/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiEmbeddingModelObservationIT.java @@ -34,7 +34,7 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.ai.embedding.observation.EmbeddingModelObservationDocumentation.HighCardinalityKeyNames; @@ -110,7 +110,7 @@ public MistralAiEmbeddingModel mistralAiEmbeddingModel(MistralAiApi mistralAiApi return MistralAiEmbeddingModel.builder() .mistralAiApi(mistralAiApi) .options(MistralAiEmbeddingOptions.builder().build()) - .retryTemplate(RetryTemplate.defaultInstance()) + .retryTemplate(new RetryTemplate()) .observationRegistry(observationRegistry) .build(); } diff --git a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiRetryTests.java b/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiRetryTests.java index 9709a3783ca..d608e1bab1a 100644 --- a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiRetryTests.java +++ b/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiRetryTests.java @@ -41,10 +41,10 @@ import org.springframework.ai.retry.RetryUtils; import org.springframework.ai.retry.TransientAiException; import org.springframework.http.ResponseEntity; -import org.springframework.retry.RetryCallback; -import org.springframework.retry.RetryContext; -import org.springframework.retry.RetryListener; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryListener; +import org.springframework.core.retry.RetryPolicy; +import org.springframework.core.retry.Retryable; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -75,7 +75,7 @@ public class MistralAiRetryTests { public void beforeEach() { this.retryTemplate = RetryUtils.SHORT_RETRY_TEMPLATE; this.retryListener = new TestRetryListener(); - this.retryTemplate.registerListener(this.retryListener); + this.retryTemplate.setRetryListener(this.retryListener); this.chatModel = MistralAiChatModel.builder() .mistralAiApi(this.mistralAiApi) @@ -110,7 +110,7 @@ public void mistralAiChatTransientError() { assertThat(result).isNotNull(); assertThat(result.getResult().getOutput().getText()).isSameAs("Response"); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); } @@ -139,7 +139,7 @@ public void mistralAiChatStreamTransientError() { assertThat(result).isNotNull(); assertThat(result.collectList().block().get(0).getResult().getOutput().getText()).isSameAs("Response"); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); } @@ -167,7 +167,7 @@ public void mistralAiEmbeddingTransientError() { assertThat(result).isNotNull(); assertThat(result.getResult().getOutput()).isEqualTo(new float[] { 9.9f, 8.8f }); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); } @@ -189,7 +189,7 @@ public void mistralAiChatMixedTransientAndNonTransientErrors() { assertThrows(RuntimeException.class, () -> this.chatModel.call(new Prompt("text"))); // Should have 1 retry attempt before hitting non-transient error - assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); + assertThat(this.retryListener.onErrorRetryCount).isEqualTo(1); } private static class TestRetryListener implements RetryListener { @@ -199,14 +199,15 @@ private static class TestRetryListener implements RetryListener { int onSuccessRetryCount = 0; @Override - public void onSuccess(RetryContext context, RetryCallback callback, T result) { - this.onSuccessRetryCount = context.getRetryCount(); + public void beforeRetry(final RetryPolicy retryPolicy, final Retryable retryable) { + // Count each retry attempt + this.onErrorRetryCount++; } @Override - public void onError(RetryContext context, RetryCallback callback, - Throwable throwable) { - this.onErrorRetryCount = context.getRetryCount(); + public void onRetrySuccess(final RetryPolicy retryPolicy, final Retryable retryable, final Object result) { + // Count successful retries - we increment when we succeed after a failure + this.onSuccessRetryCount++; } } diff --git a/models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/OllamaChatModel.java b/models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/OllamaChatModel.java index 7cb87eb8f3b..b17837e07c4 100644 --- a/models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/OllamaChatModel.java +++ b/models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/OllamaChatModel.java @@ -28,6 +28,7 @@ import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.retry.RetryException; import reactor.core.publisher.Flux; import reactor.core.scheduler.Schedulers; @@ -70,7 +71,7 @@ import org.springframework.ai.retry.RetryUtils; import org.springframework.ai.tool.definition.ToolDefinition; import org.springframework.ai.util.json.JsonParser; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -246,7 +247,18 @@ private ChatResponse internalCall(Prompt prompt, ChatResponse previousChatRespon this.observationRegistry) .observe(() -> { - OllamaApi.ChatResponse ollamaResponse = this.retryTemplate.execute(ctx -> this.chatApi.chat(request)); + OllamaApi.ChatResponse ollamaResponse = null; + try { + ollamaResponse = this.retryTemplate.execute(() -> this.chatApi.chat(request)); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); + } + } List toolCalls = ollamaResponse.message().toolCalls() == null ? List.of() : ollamaResponse.message() diff --git a/models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaChatModelMultimodalIT.java b/models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaChatModelMultimodalIT.java index 693f892e940..232269fa97f 100644 --- a/models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaChatModelMultimodalIT.java +++ b/models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaChatModelMultimodalIT.java @@ -35,10 +35,10 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.core.io.ClassPathResource; -import org.springframework.retry.RetryCallback; -import org.springframework.retry.RetryContext; -import org.springframework.retry.RetryListener; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryListener; +import org.springframework.core.retry.RetryPolicy; +import org.springframework.core.retry.RetryTemplate; +import org.springframework.core.retry.Retryable; import org.springframework.util.MimeTypeUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -93,19 +93,21 @@ public OllamaApi ollamaApi() { @Bean public OllamaChatModel ollamaChat(OllamaApi ollamaApi) { - RetryTemplate retryTemplate = RetryTemplate.builder() + RetryPolicy retryPolicy = RetryPolicy.builder() .maxAttempts(1) - .retryOn(TransientAiException.class) - .fixedBackoff(Duration.ofSeconds(1)) - .withListener(new RetryListener() { - - @Override - public void onError(RetryContext context, - RetryCallback callback, Throwable throwable) { - logger.warn("Retry error. Retry count:" + context.getRetryCount(), throwable); - } - }) + .includes(TransientAiException.class) + .delay(Duration.ofSeconds(1)) .build(); + + RetryTemplate retryTemplate = new RetryTemplate(retryPolicy); + retryTemplate.setRetryListener(new RetryListener() { + + @Override + public void onRetryFailure(final RetryPolicy policy, final Retryable retryable, + final Throwable throwable) { + logger.warn("Retry error. Retry count:" + (throwable.getSuppressed().length + 1), throwable); + } + }); return OllamaChatModel.builder() .ollamaApi(ollamaApi) .defaultOptions(OllamaChatOptions.builder().model(MODEL).temperature(0.9).build()) diff --git a/models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaRetryTests.java b/models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaRetryTests.java index 323c969c6fa..a744aead9d1 100644 --- a/models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaRetryTests.java +++ b/models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaRetryTests.java @@ -35,10 +35,10 @@ import org.springframework.ai.retry.NonTransientAiException; import org.springframework.ai.retry.RetryUtils; import org.springframework.ai.retry.TransientAiException; -import org.springframework.retry.RetryCallback; -import org.springframework.retry.RetryContext; -import org.springframework.retry.RetryListener; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryListener; +import org.springframework.core.retry.RetryPolicy; +import org.springframework.core.retry.RetryTemplate; +import org.springframework.core.retry.Retryable; import org.springframework.web.client.ResourceAccessException; import static org.assertj.core.api.Assertions.assertThat; @@ -71,7 +71,7 @@ class OllamaRetryTests { public void beforeEach() { this.retryTemplate = RetryUtils.SHORT_RETRY_TEMPLATE; this.retryListener = new TestRetryListener(); - this.retryTemplate.registerListener(this.retryListener); + this.retryTemplate.setRetryListener(this.retryListener); this.chatModel = OllamaChatModel.builder() .ollamaApi(this.ollamaApi) @@ -96,7 +96,7 @@ void ollamaChatTransientError() { assertThat(result).isNotNull(); assertThat(result.getResult().getOutput().getText()).isSameAs("Response"); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); } @@ -130,7 +130,7 @@ void ollamaChatNonTransientErrorShouldNotRetry() { .hasMessage("Model not found"); assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(0); - assertThat(this.retryListener.onErrorRetryCount).isEqualTo(1); + assertThat(this.retryListener.onErrorRetryCount).isEqualTo(0); verify(this.ollamaApi, times(1)).chat(isA(OllamaApi.ChatRequest.class)); } @@ -202,14 +202,15 @@ private static class TestRetryListener implements RetryListener { int onSuccessRetryCount = 0; @Override - public void onSuccess(RetryContext context, RetryCallback callback, T result) { - this.onSuccessRetryCount = context.getRetryCount(); + public void beforeRetry(final RetryPolicy retryPolicy, final Retryable retryable) { + // Count each retry attempt + this.onErrorRetryCount++; } @Override - public void onError(RetryContext context, RetryCallback callback, - Throwable throwable) { - this.onErrorRetryCount = context.getRetryCount(); + public void onRetrySuccess(final RetryPolicy retryPolicy, final Retryable retryable, final Object result) { + // Count successful retries - we increment when we succeed after a failure + this.onSuccessRetryCount++; } } diff --git a/models/spring-ai-openai/pom.xml b/models/spring-ai-openai/pom.xml index 3f9adec528e..07558446367 100644 --- a/models/spring-ai-openai/pom.xml +++ b/models/spring-ai-openai/pom.xml @@ -87,6 +87,28 @@ test + + org.springframework.boot + spring-boot-starter-jackson + test + + + + + org.springframework.boot + spring-boot-starter-restclient + ${spring-boot.version} + test + + + + + org.springframework.boot + spring-boot-starter-webclient + ${spring-boot.version} + test + + io.micrometer micrometer-observation-test diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiAudioSpeechModel.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiAudioSpeechModel.java index f9fcd006cb6..a106ce5383b 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiAudioSpeechModel.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiAudioSpeechModel.java @@ -32,7 +32,7 @@ import org.springframework.ai.openai.metadata.support.OpenAiResponseHeaderExtractor; import org.springframework.ai.retry.RetryUtils; import org.springframework.http.ResponseEntity; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -127,8 +127,13 @@ public SpeechResponse call(SpeechPrompt speechPrompt) { OpenAiAudioApi.SpeechRequest speechRequest = createRequest(speechPrompt); - ResponseEntity speechEntity = this.retryTemplate - .execute(ctx -> this.audioApi.createSpeech(speechRequest)); + ResponseEntity speechEntity; + try { + speechEntity = this.retryTemplate.execute(() -> this.audioApi.createSpeech(speechRequest)); + } + catch (Exception e) { + throw new RuntimeException("Error calling OpenAI audio speech API", e); + } var speech = speechEntity.getBody(); @@ -154,8 +159,13 @@ public Flux stream(SpeechPrompt speechPrompt) { OpenAiAudioApi.SpeechRequest speechRequest = createRequest(speechPrompt); - Flux> speechEntity = this.retryTemplate - .execute(ctx -> this.audioApi.stream(speechRequest)); + Flux> speechEntity; + try { + speechEntity = this.retryTemplate.execute(() -> this.audioApi.stream(speechRequest)); + } + catch (Exception e) { + throw new RuntimeException("Error calling OpenAI audio speech streaming API", e); + } return speechEntity.map(entity -> new SpeechResponse(new Speech(entity.getBody()), new OpenAiAudioSpeechResponseMetadata(OpenAiResponseHeaderExtractor.extractAiResponseHeaders(entity)))); diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiAudioTranscriptionModel.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiAudioTranscriptionModel.java index 8fbd75d4d39..dd2395f4ecd 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiAudioTranscriptionModel.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiAudioTranscriptionModel.java @@ -31,7 +31,7 @@ import org.springframework.ai.retry.RetryUtils; import org.springframework.core.io.Resource; import org.springframework.http.ResponseEntity; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; /** @@ -112,8 +112,14 @@ public AudioTranscriptionResponse call(AudioTranscriptionPrompt transcriptionPro if (request.responseFormat().isJsonType()) { - ResponseEntity transcriptionEntity = this.retryTemplate - .execute(ctx -> this.audioApi.createTranscription(request, StructuredResponse.class)); + ResponseEntity transcriptionEntity; + try { + transcriptionEntity = this.retryTemplate + .execute(() -> this.audioApi.createTranscription(request, StructuredResponse.class)); + } + catch (Exception e) { + throw new RuntimeException("Error calling OpenAI transcription API", e); + } var transcription = transcriptionEntity.getBody(); @@ -133,8 +139,14 @@ public AudioTranscriptionResponse call(AudioTranscriptionPrompt transcriptionPro } else { - ResponseEntity transcriptionEntity = this.retryTemplate - .execute(ctx -> this.audioApi.createTranscription(request, String.class)); + ResponseEntity transcriptionEntity; + try { + transcriptionEntity = this.retryTemplate + .execute(() -> this.audioApi.createTranscription(request, String.class)); + } + catch (Exception e) { + throw new RuntimeException("Error calling OpenAI transcription API", e); + } var transcription = transcriptionEntity.getBody(); diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatModel.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatModel.java index 246b7893c4a..b3dc2497954 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatModel.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatModel.java @@ -22,7 +22,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationRegistry; @@ -78,13 +77,13 @@ import org.springframework.ai.tool.definition.ToolDefinition; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.MimeType; import org.springframework.util.MimeTypeUtils; -import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; /** @@ -196,8 +195,14 @@ public ChatResponse internalCall(Prompt prompt, ChatResponse previousChatRespons this.observationRegistry) .observe(() -> { - ResponseEntity completionEntity = this.retryTemplate - .execute(ctx -> this.openAiApi.chatCompletionEntity(request, getAdditionalHttpHeaders(prompt))); + ResponseEntity completionEntity; + try { + completionEntity = this.retryTemplate + .execute(() -> this.openAiApi.chatCompletionEntity(request, getAdditionalHttpHeaders(prompt))); + } + catch (Exception e) { + throw new RuntimeException("Error calling OpenAI chat completion API", e); + } var chatCompletion = completionEntity.getBody(); @@ -402,14 +407,15 @@ public Flux internalStream(Prompt prompt, ChatResponse previousCha }); } - private MultiValueMap getAdditionalHttpHeaders(Prompt prompt) { + private HttpHeaders getAdditionalHttpHeaders(Prompt prompt) { Map headers = new HashMap<>(this.defaultOptions.getHttpHeaders()); if (prompt.getOptions() != null && prompt.getOptions() instanceof OpenAiChatOptions chatOptions) { headers.putAll(chatOptions.getHttpHeaders()); } - return CollectionUtils.toMultiValueMap( - headers.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> List.of(e.getValue())))); + HttpHeaders httpHeaders = new HttpHeaders(); + headers.forEach(httpHeaders::add); + return httpHeaders; } private Generation buildGeneration(Choice choice, Map metadata, ChatCompletionRequest request) { diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiEmbeddingModel.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiEmbeddingModel.java index 47c06ac5a72..d5c3cb347d4 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiEmbeddingModel.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiEmbeddingModel.java @@ -42,7 +42,7 @@ import org.springframework.ai.openai.api.OpenAiApi.EmbeddingList; import org.springframework.ai.openai.api.common.OpenAiApiConstants; import org.springframework.ai.retry.RetryUtils; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; /** @@ -164,8 +164,14 @@ public EmbeddingResponse call(EmbeddingRequest request) { .observation(this.observationConvention, DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, this.observationRegistry) .observe(() -> { - EmbeddingList apiEmbeddingResponse = this.retryTemplate - .execute(ctx -> this.openAiApi.embeddings(apiRequest).getBody()); + EmbeddingList apiEmbeddingResponse; + try { + apiEmbeddingResponse = this.retryTemplate + .execute(() -> this.openAiApi.embeddings(apiRequest).getBody()); + } + catch (Exception e) { + throw new RuntimeException("Error calling OpenAI embedding API", e); + } if (apiEmbeddingResponse == null) { logger.warn("No embeddings returned for request: {}", request); diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiImageModel.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiImageModel.java index 68354662548..c6d1a0cffe4 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiImageModel.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiImageModel.java @@ -39,7 +39,7 @@ import org.springframework.ai.openai.metadata.OpenAiImageGenerationMetadata; import org.springframework.ai.retry.RetryUtils; import org.springframework.http.ResponseEntity; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; /** @@ -141,8 +141,14 @@ public ImageResponse call(ImagePrompt imagePrompt) { .observation(this.observationConvention, DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, this.observationRegistry) .observe(() -> { - ResponseEntity imageResponseEntity = this.retryTemplate - .execute(ctx -> this.openAiImageApi.createImage(imageRequest)); + ResponseEntity imageResponseEntity; + try { + imageResponseEntity = this.retryTemplate + .execute(() -> this.openAiImageApi.createImage(imageRequest)); + } + catch (Exception e) { + throw new RuntimeException("Error calling OpenAI image API", e); + } ImageResponse imageResponse = convertResponse(imageResponseEntity, imageRequest); diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiModerationModel.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiModerationModel.java index 8e00c24b430..02e6f833bbf 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiModerationModel.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiModerationModel.java @@ -35,7 +35,7 @@ import org.springframework.ai.openai.api.OpenAiModerationApi; import org.springframework.ai.retry.RetryUtils; import org.springframework.http.ResponseEntity; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; /** @@ -77,28 +77,34 @@ public OpenAiModerationModel withDefaultOptions(OpenAiModerationOptions defaultO @Override public ModerationResponse call(ModerationPrompt moderationPrompt) { - return this.retryTemplate.execute(ctx -> { + try { + return this.retryTemplate.execute(() -> { - String instructions = moderationPrompt.getInstructions().getText(); + String instructions = moderationPrompt.getInstructions().getText(); - OpenAiModerationApi.OpenAiModerationRequest moderationRequest = new OpenAiModerationApi.OpenAiModerationRequest( - instructions); + OpenAiModerationApi.OpenAiModerationRequest moderationRequest = new OpenAiModerationApi.OpenAiModerationRequest( + instructions); - if (this.defaultOptions != null) { - moderationRequest = ModelOptionsUtils.merge(this.defaultOptions, moderationRequest, - OpenAiModerationApi.OpenAiModerationRequest.class); - } + if (this.defaultOptions != null) { + moderationRequest = ModelOptionsUtils.merge(this.defaultOptions, moderationRequest, + OpenAiModerationApi.OpenAiModerationRequest.class); + } - if (moderationPrompt.getOptions() != null) { - moderationRequest = ModelOptionsUtils.merge(toOpenAiModerationOptions(moderationPrompt.getOptions()), - moderationRequest, OpenAiModerationApi.OpenAiModerationRequest.class); - } + if (moderationPrompt.getOptions() != null) { + moderationRequest = ModelOptionsUtils.merge( + toOpenAiModerationOptions(moderationPrompt.getOptions()), moderationRequest, + OpenAiModerationApi.OpenAiModerationRequest.class); + } - ResponseEntity moderationResponseEntity = this.openAiModerationApi - .createModeration(moderationRequest); + ResponseEntity moderationResponseEntity = this.openAiModerationApi + .createModeration(moderationRequest); - return convertResponse(moderationResponseEntity, moderationRequest); - }); + return convertResponse(moderationResponseEntity, moderationRequest); + }); + } + catch (Exception e) { + throw new RuntimeException("Error calling OpenAI moderation API", e); + } } private ModerationResponse convertResponse( diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java index 49d42b1e1aa..ba7ae46ac18 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java @@ -48,8 +48,6 @@ import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; import org.springframework.web.reactive.function.client.WebClient; @@ -98,7 +96,7 @@ public static Builder builder() { private final ApiKey apiKey; - private final MultiValueMap headers; + private final HttpHeaders headers; private final String completionsPath; @@ -123,8 +121,8 @@ public static Builder builder() { * @param webClientBuilder WebClient builder. * @param responseErrorHandler Response error handler. */ - public OpenAiApi(String baseUrl, ApiKey apiKey, MultiValueMap headers, String completionsPath, - String embeddingsPath, RestClient.Builder restClientBuilder, WebClient.Builder webClientBuilder, + public OpenAiApi(String baseUrl, ApiKey apiKey, HttpHeaders headers, String completionsPath, String embeddingsPath, + RestClient.Builder restClientBuilder, WebClient.Builder webClientBuilder, ResponseErrorHandler responseErrorHandler) { this.baseUrl = baseUrl; this.apiKey = apiKey; @@ -177,7 +175,7 @@ public static String getTextContent(List con * and headers. */ public ResponseEntity chatCompletionEntity(ChatCompletionRequest chatRequest) { - return chatCompletionEntity(chatRequest, new LinkedMultiValueMap<>()); + return chatCompletionEntity(chatRequest, new HttpHeaders()); } /** @@ -189,7 +187,7 @@ public ResponseEntity chatCompletionEntity(ChatCompletionRequest * and headers. */ public ResponseEntity chatCompletionEntity(ChatCompletionRequest chatRequest, - MultiValueMap additionalHttpHeader) { + HttpHeaders additionalHttpHeader) { Assert.notNull(chatRequest, REQUEST_BODY_NULL_MESSAGE); Assert.isTrue(!chatRequest.stream(), STREAM_FALSE_MESSAGE); @@ -215,7 +213,7 @@ public ResponseEntity chatCompletionEntity(ChatCompletionRequest * @return Returns a {@link Flux} stream from chat completion chunks. */ public Flux chatCompletionStream(ChatCompletionRequest chatRequest) { - return chatCompletionStream(chatRequest, new LinkedMultiValueMap<>()); + return chatCompletionStream(chatRequest, new HttpHeaders()); } /** @@ -227,7 +225,7 @@ public Flux chatCompletionStream(ChatCompletionRequest chat * @return Returns a {@link Flux} stream from chat completion chunks. */ public Flux chatCompletionStream(ChatCompletionRequest chatRequest, - MultiValueMap additionalHttpHeader) { + HttpHeaders additionalHttpHeader) { Assert.notNull(chatRequest, REQUEST_BODY_NULL_MESSAGE); Assert.isTrue(chatRequest.stream(), "Request must set the stream property to true."); @@ -323,7 +321,7 @@ public ResponseEntity> embeddings(EmbeddingRequest< } private void addDefaultHeadersIfMissing(HttpHeaders headers) { - if (!headers.containsKey(HttpHeaders.AUTHORIZATION) && !(this.apiKey instanceof NoopApiKey)) { + if (headers.get(HttpHeaders.AUTHORIZATION) == null && !(this.apiKey instanceof NoopApiKey)) { headers.setBearerAuth(this.apiKey.getValue()); } } @@ -337,7 +335,7 @@ ApiKey getApiKey() { return this.apiKey; } - MultiValueMap getHeaders() { + HttpHeaders getHeaders() { return this.headers; } @@ -1995,7 +1993,8 @@ public Builder() { public Builder(OpenAiApi api) { this.baseUrl = api.getBaseUrl(); this.apiKey = api.getApiKey(); - this.headers = new LinkedMultiValueMap<>(api.getHeaders()); + this.headers = new HttpHeaders(); + this.headers.addAll(api.getHeaders()); this.completionsPath = api.getCompletionsPath(); this.embeddingsPath = api.getEmbeddingsPath(); this.restClientBuilder = api.restClient != null ? api.restClient.mutate() : RestClient.builder(); @@ -2007,7 +2006,7 @@ public Builder(OpenAiApi api) { private ApiKey apiKey; - private MultiValueMap headers = new LinkedMultiValueMap<>(); + private HttpHeaders headers = new HttpHeaders(); private String completionsPath = "/v1/chat/completions"; @@ -2036,7 +2035,7 @@ public Builder apiKey(String simpleApiKey) { return this; } - public Builder headers(MultiValueMap headers) { + public Builder headers(HttpHeaders headers) { Assert.notNull(headers, "headers cannot be null"); this.headers = headers; return this; diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiAudioApi.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiAudioApi.java index cd5b3e89d8f..49026e96f2c 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiAudioApi.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiAudioApi.java @@ -67,9 +67,8 @@ public class OpenAiAudioApi { * @param webClientBuilder WebClient builder. * @param responseErrorHandler Response error handler. */ - public OpenAiAudioApi(String baseUrl, ApiKey apiKey, MultiValueMap headers, - RestClient.Builder restClientBuilder, WebClient.Builder webClientBuilder, - ResponseErrorHandler responseErrorHandler) { + public OpenAiAudioApi(String baseUrl, ApiKey apiKey, HttpHeaders headers, RestClient.Builder restClientBuilder, + WebClient.Builder webClientBuilder, ResponseErrorHandler responseErrorHandler) { Consumer authHeaders = h -> h.addAll(headers); @@ -796,7 +795,7 @@ public static final class Builder { private ApiKey apiKey; - private MultiValueMap headers = new LinkedMultiValueMap<>(); + private HttpHeaders headers = new HttpHeaders(); private RestClient.Builder restClientBuilder = RestClient.builder(); @@ -822,7 +821,7 @@ public Builder apiKey(String simpleApiKey) { return this; } - public Builder headers(MultiValueMap headers) { + public Builder headers(HttpHeaders headers) { Assert.notNull(headers, "headers cannot be null"); this.headers = headers; return this; diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiFileApi.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiFileApi.java index 535b6a9a043..29ec58de969 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiFileApi.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiFileApi.java @@ -49,8 +49,8 @@ public class OpenAiFileApi { private final RestClient restClient; - public OpenAiFileApi(String baseUrl, ApiKey apiKey, MultiValueMap headers, - RestClient.Builder restClientBuilder, ResponseErrorHandler responseErrorHandler) { + public OpenAiFileApi(String baseUrl, ApiKey apiKey, HttpHeaders headers, RestClient.Builder restClientBuilder, + ResponseErrorHandler responseErrorHandler) { Consumer authHeaders = h -> h.addAll(headers); this.restClient = restClientBuilder.clone() @@ -360,7 +360,7 @@ public static final class Builder { private ApiKey apiKey; - private MultiValueMap headers = new LinkedMultiValueMap<>(); + private HttpHeaders headers = new HttpHeaders(); private RestClient.Builder restClientBuilder = RestClient.builder(); @@ -384,7 +384,7 @@ public Builder apiKey(String simpleApiKey) { return this; } - public Builder headers(MultiValueMap headers) { + public Builder headers(HttpHeaders headers) { Assert.notNull(headers, "headers cannot be null"); this.headers = headers; return this; diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiImageApi.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiImageApi.java index fe82e30e56b..bb20891ef80 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiImageApi.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiImageApi.java @@ -31,8 +31,6 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; @@ -60,7 +58,7 @@ public class OpenAiImageApi { * @param restClientBuilder the rest client builder to use. * @param responseErrorHandler the response error handler to use. */ - public OpenAiImageApi(String baseUrl, ApiKey apiKey, MultiValueMap headers, String imagesPath, + public OpenAiImageApi(String baseUrl, ApiKey apiKey, HttpHeaders headers, String imagesPath, RestClient.Builder restClientBuilder, ResponseErrorHandler responseErrorHandler) { // @formatter:off @@ -168,7 +166,7 @@ public static final class Builder { private ApiKey apiKey; - private MultiValueMap headers = new LinkedMultiValueMap<>(); + private HttpHeaders headers = new HttpHeaders(); private RestClient.Builder restClientBuilder = RestClient.builder(); @@ -200,7 +198,7 @@ public Builder apiKey(String simpleApiKey) { return this; } - public Builder headers(MultiValueMap headers) { + public Builder headers(HttpHeaders headers) { Assert.notNull(headers, "headers cannot be null"); this.headers = headers; return this; diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiModerationApi.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiModerationApi.java index fc05811c5bb..615392206e1 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiModerationApi.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiModerationApi.java @@ -31,8 +31,6 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; @@ -61,8 +59,8 @@ public class OpenAiModerationApi { * @param apiKey OpenAI apiKey. * @param restClientBuilder the rest client builder to use. */ - public OpenAiModerationApi(String baseUrl, ApiKey apiKey, MultiValueMap headers, - RestClient.Builder restClientBuilder, ResponseErrorHandler responseErrorHandler) { + public OpenAiModerationApi(String baseUrl, ApiKey apiKey, HttpHeaders headers, RestClient.Builder restClientBuilder, + ResponseErrorHandler responseErrorHandler) { this.objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); @@ -178,7 +176,7 @@ public static final class Builder { private ApiKey apiKey; - private MultiValueMap headers = new LinkedMultiValueMap<>(); + private HttpHeaders headers = new HttpHeaders(); private RestClient.Builder restClientBuilder = RestClient.builder(); @@ -202,7 +200,7 @@ public Builder apiKey(String simpleApiKey) { return this; } - public Builder headers(MultiValueMap headers) { + public Builder headers(HttpHeaders headers) { Assert.notNull(headers, "headers cannot be null"); this.headers = headers; return this; diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/metadata/support/OpenAiResponseHeaderExtractor.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/metadata/support/OpenAiResponseHeaderExtractor.java index 7a4d344755d..b7ad61960a3 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/metadata/support/OpenAiResponseHeaderExtractor.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/metadata/support/OpenAiResponseHeaderExtractor.java @@ -71,22 +71,18 @@ public static RateLimit extractAiResponseHeaders(ResponseEntity response) { private static Duration getHeaderAsDuration(ResponseEntity response, String headerName) { var headers = response.getHeaders(); - if (headers.containsKey(headerName)) { - var values = headers.get(headerName); - if (!CollectionUtils.isEmpty(values)) { - return DurationFormatter.TIME_UNIT.parse(values.get(0)); - } + var values = headers.get(headerName); + if (!CollectionUtils.isEmpty(values)) { + return DurationFormatter.TIME_UNIT.parse(values.get(0)); } return null; } private static Long getHeaderAsLong(ResponseEntity response, String headerName) { var headers = response.getHeaders(); - if (headers.containsKey(headerName)) { - var values = headers.get(headerName); - if (!CollectionUtils.isEmpty(values)) { - return parseLong(headerName, values.get(0)); - } + var values = headers.get(headerName); + if (!CollectionUtils.isEmpty(values)) { + return parseLong(headerName, values.get(0)); } return null; } diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/OpenAiApiBuilderTests.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/OpenAiApiBuilderTests.java index e2858c9e46d..5697ff6f64e 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/OpenAiApiBuilderTests.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/OpenAiApiBuilderTests.java @@ -37,8 +37,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; import org.springframework.web.reactive.function.client.WebClient; @@ -66,7 +64,7 @@ void testMinimalBuilder() { @Test void testFullBuilder() { - MultiValueMap headers = new LinkedMultiValueMap<>(); + HttpHeaders headers = new HttpHeaders(); headers.add("Custom-Header", "test-value"); RestClient.Builder restClientBuilder = RestClient.builder(); WebClient.Builder webClientBuilder = WebClient.builder(); @@ -192,7 +190,7 @@ void testNullApiKeyValue() { @Test void testBuilderMethodChaining() { - MultiValueMap headers = new LinkedMultiValueMap<>(); + HttpHeaders headers = new HttpHeaders(); headers.add("Test-Header", "test-value"); OpenAiApi api = OpenAiApi.builder() @@ -211,7 +209,7 @@ void testBuilderMethodChaining() { @Test void testCustomHeadersPreservation() { - MultiValueMap customHeaders = new LinkedMultiValueMap<>(); + HttpHeaders customHeaders = new HttpHeaders(); customHeaders.add("X-Custom-Header", "custom-value"); customHeaders.add("X-Organization", "org-123"); customHeaders.add("User-Agent", "Custom-Client/1.0"); @@ -223,7 +221,7 @@ void testCustomHeadersPreservation() { @Test void testComplexMultiValueHeaders() { - MultiValueMap multiHeaders = new LinkedMultiValueMap<>(); + HttpHeaders multiHeaders = new HttpHeaders(); multiHeaders.add("Accept", "application/json"); multiHeaders.add("Accept", "text/plain"); multiHeaders.add("Cache-Control", "no-cache"); @@ -381,7 +379,7 @@ void dynamicApiKeyRestClientWithAdditionalAuthorizationHeader() throws Interrupt OpenAiApi.ChatCompletionRequest request = new OpenAiApi.ChatCompletionRequest( List.of(chatCompletionMessage), "gpt-3.5-turbo", 0.8, false); - MultiValueMap additionalHeaders = new LinkedMultiValueMap<>(); + HttpHeaders additionalHeaders = new HttpHeaders(); additionalHeaders.add(HttpHeaders.AUTHORIZATION, "Bearer additional-key"); ResponseEntity response = api.chatCompletionEntity(request, additionalHeaders); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); @@ -478,7 +476,7 @@ void dynamicApiKeyWebClientWithAdditionalAuthorizationHeader() throws Interrupte OpenAiApi.ChatCompletionMessage.Role.USER); OpenAiApi.ChatCompletionRequest request = new OpenAiApi.ChatCompletionRequest( List.of(chatCompletionMessage), "gpt-3.5-turbo", 0.8, true); - MultiValueMap additionalHeaders = new LinkedMultiValueMap<>(); + HttpHeaders additionalHeaders = new HttpHeaders(); additionalHeaders.add(HttpHeaders.AUTHORIZATION, "Bearer additional-key"); List response = api.chatCompletionStream(request, additionalHeaders) .collectList() diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/OpenAiChatModelMutateTests.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/OpenAiChatModelMutateTests.java index 36ca255710e..cd549a9bebb 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/OpenAiChatModelMutateTests.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/OpenAiChatModelMutateTests.java @@ -20,7 +20,7 @@ import org.springframework.ai.openai.OpenAiChatModel; import org.springframework.ai.openai.OpenAiChatOptions; -import org.springframework.util.LinkedMultiValueMap; +import org.springframework.http.HttpHeaders; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; @@ -88,12 +88,12 @@ void mutateDoesNotAffectOriginal() { @Test void mutateHeadersCreatesDistinctHeaders() { - OpenAiApi mutatedApi = this.baseApi.mutate() - .headers(new LinkedMultiValueMap<>(java.util.Map.of("X-Test", java.util.List.of("value")))) - .build(); + HttpHeaders headers = new HttpHeaders(); + headers.add("X-Test", "value"); + OpenAiApi mutatedApi = this.baseApi.mutate().headers(headers).build(); - assertThat(mutatedApi.getHeaders()).containsKey("X-Test"); - assertThat(this.baseApi.getHeaders()).doesNotContainKey("X-Test"); + assertThat(mutatedApi.getHeaders().get("X-Test")).isNotNull(); + assertThat(this.baseApi.getHeaders().get("X-Test")).isNull(); } @Test @@ -129,7 +129,7 @@ void mutateAndCloneAreEquivalent() { @Test void testApiMutateWithComplexHeaders() { - LinkedMultiValueMap complexHeaders = new LinkedMultiValueMap<>(); + HttpHeaders complexHeaders = new HttpHeaders(); complexHeaders.add("Authorization", "Bearer custom-token"); complexHeaders.add("X-Custom-Header", "value1"); complexHeaders.add("X-Custom-Header", "value2"); @@ -137,9 +137,9 @@ void testApiMutateWithComplexHeaders() { OpenAiApi mutatedApi = this.baseApi.mutate().headers(complexHeaders).build(); - assertThat(mutatedApi.getHeaders()).containsKey("Authorization"); - assertThat(mutatedApi.getHeaders()).containsKey("X-Custom-Header"); - assertThat(mutatedApi.getHeaders()).containsKey("User-Agent"); + assertThat(mutatedApi.getHeaders().get("Authorization")).isNotNull(); + assertThat(mutatedApi.getHeaders().get("X-Custom-Header")).isNotNull(); + assertThat(mutatedApi.getHeaders().get("User-Agent")).isNotNull(); assertThat(mutatedApi.getHeaders().get("X-Custom-Header")).hasSize(2); } @@ -155,11 +155,11 @@ void testMutateWithEmptyOptions() { @Test void testApiMutateWithEmptyHeaders() { - LinkedMultiValueMap emptyHeaders = new LinkedMultiValueMap<>(); + HttpHeaders emptyHeaders = new HttpHeaders(); OpenAiApi mutatedApi = this.baseApi.mutate().headers(emptyHeaders).build(); - assertThat(mutatedApi.getHeaders()).isEmpty(); + assertThat(mutatedApi.getHeaders().isEmpty()).isTrue(); } @Test diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/OpenAiFileApiBuilderTests.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/OpenAiFileApiBuilderTests.java index 143fd9eaa68..0bcbf856db9 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/OpenAiFileApiBuilderTests.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/OpenAiFileApiBuilderTests.java @@ -36,8 +36,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; @@ -65,7 +63,7 @@ void testMinimalBuilder() { @Test void testFullBuilder() { - MultiValueMap headers = new LinkedMultiValueMap<>(); + HttpHeaders headers = new HttpHeaders(); headers.add("Custom-Header", "test-value"); RestClient.Builder restClientBuilder = RestClient.builder(); ResponseErrorHandler errorHandler = mock(ResponseErrorHandler.class); diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/audio/api/OpenAiAudioApiBuilderTests.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/audio/api/OpenAiAudioApiBuilderTests.java index ecd506277d3..2d567807abc 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/audio/api/OpenAiAudioApiBuilderTests.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/audio/api/OpenAiAudioApiBuilderTests.java @@ -37,8 +37,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; import org.springframework.web.reactive.function.client.WebClient; @@ -65,7 +63,7 @@ void testMinimalBuilder() { @Test void testFullBuilder() { - MultiValueMap headers = new LinkedMultiValueMap<>(); + HttpHeaders headers = new HttpHeaders(); headers.add("Custom-Header", "test-value"); RestClient.Builder restClientBuilder = RestClient.builder(); WebClient.Builder webClientBuilder = WebClient.builder(); diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/audio/transcription/OpenAiAudioTranscriptionModelTests.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/audio/transcription/OpenAiAudioTranscriptionModelTests.java index ea9b3d930c3..51a4b52a53d 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/audio/transcription/OpenAiAudioTranscriptionModelTests.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/audio/transcription/OpenAiAudioTranscriptionModelTests.java @@ -32,10 +32,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.test.web.client.MockRestServiceServer; -import org.springframework.util.LinkedMultiValueMap; import org.springframework.web.client.RestClient; import org.springframework.web.reactive.function.client.WebClient; @@ -123,9 +123,8 @@ static class Config { @Bean public OpenAiAudioApi openAiAudioApi(RestClient.Builder builder) { - return new OpenAiAudioApi("https://api.openai.com", new SimpleApiKey("test-api-key"), - new LinkedMultiValueMap<>(), builder, WebClient.builder(), - RetryUtils.DEFAULT_RESPONSE_ERROR_HANDLER); + return new OpenAiAudioApi("https://api.openai.com", new SimpleApiKey("test-api-key"), new HttpHeaders(), + builder, WebClient.builder(), RetryUtils.DEFAULT_RESPONSE_ERROR_HANDLER); } @Bean diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/MessageTypeContentTests.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/MessageTypeContentTests.java index 0c949a15f71..3a176ffaef4 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/MessageTypeContentTests.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/MessageTypeContentTests.java @@ -41,10 +41,10 @@ import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionChunk; import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionRequest; import org.springframework.core.io.ByteArrayResource; +import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.util.MimeType; import org.springframework.util.MimeTypeUtils; -import org.springframework.util.MultiValueMap; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; @@ -66,7 +66,7 @@ public class MessageTypeContentTests { ArgumentCaptor pomptCaptor; @Captor - ArgumentCaptor> headersCaptor; + ArgumentCaptor headersCaptor; Flux fluxResponse = Flux.generate( () -> new ChatCompletionChunk("id", List.of(), 0L, "model", null, "fp", "object", null), (state, sink) -> { @@ -89,7 +89,7 @@ public void systemMessageSimpleContentType() { this.chatModel.call(new Prompt(List.of(new SystemMessage("test message")))); validateStringContent(this.pomptCaptor.getValue()); - assertThat(this.headersCaptor.getValue()).isEmpty(); + assertThat(this.headersCaptor.getValue().isEmpty()).isTrue(); } @Test @@ -112,7 +112,7 @@ public void streamUserMessageSimpleContentType() { this.chatModel.stream(new Prompt(List.of(new UserMessage("test message")))).subscribe(); validateStringContent(this.pomptCaptor.getValue()); - assertThat(this.headersCaptor.getValue()).isEmpty(); + assertThat(this.headersCaptor.getValue().isEmpty()).isTrue(); } private void validateStringContent(ChatCompletionRequest chatCompletionRequest) { @@ -207,7 +207,7 @@ public void userMessageWithEmptyMediaList() { .build()))); validateStringContent(this.pomptCaptor.getValue()); - assertThat(this.headersCaptor.getValue()).isEmpty(); + assertThat(this.headersCaptor.getValue().isEmpty()).isTrue(); } @Test @@ -308,7 +308,7 @@ public void streamWithMultipleMessagesAndMedia() { // User message should be complex assertThat(request.messages().get(1).rawContent()).isInstanceOf(List.class); - assertThat(this.headersCaptor.getValue()).isEmpty(); + assertThat(this.headersCaptor.getValue().isEmpty()).isTrue(); } // Helper method for testing different image formats diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiChatModelObservationIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiChatModelObservationIT.java index 3b73adf7f0b..fa2daa3962f 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiChatModelObservationIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiChatModelObservationIT.java @@ -40,7 +40,8 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryPolicy; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.ai.chat.observation.ChatModelObservationDocumentation.HighCardinalityKeyNames; @@ -175,7 +176,8 @@ public OpenAiApi openAiApi() { @Bean public OpenAiChatModel openAiChatModel(OpenAiApi openAiApi, TestObservationRegistry observationRegistry) { return new OpenAiChatModel(openAiApi, OpenAiChatOptions.builder().build(), - ToolCallingManager.builder().build(), RetryTemplate.defaultInstance(), observationRegistry); + ToolCallingManager.builder().build(), new RetryTemplate(RetryPolicy.withDefaults()), + observationRegistry); } } diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiChatModelWithChatResponseMetadataTests.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiChatModelWithChatResponseMetadataTests.java index 1e9815513c3..08aa5e07ff9 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiChatModelWithChatResponseMetadataTests.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiChatModelWithChatResponseMetadataTests.java @@ -35,7 +35,10 @@ import org.springframework.ai.openai.metadata.support.OpenAiApiResponseHeaders; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.autoconfigure.web.client.AutoConfigureWebClient; import org.springframework.boot.test.autoconfigure.web.client.RestClientTest; +import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -55,7 +58,11 @@ * @author Christian Tzolov * @since 0.7.0 */ -@RestClientTest(OpenAiChatModelWithChatResponseMetadataTests.Config.class) +@RestClientTest(value = OpenAiChatModelWithChatResponseMetadataTests.Config.class, properties = "debug=true") +@AutoConfigureWebClient + +// TODO: Remove after Spring Boot 4 RC1 +@ImportAutoConfiguration(WebClientAutoConfiguration.class) public class OpenAiChatModelWithChatResponseMetadataTests { private static String TEST_API_KEY = "sk-1234567890"; diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiRetryTests.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiRetryTests.java index e19e82640b2..4d70dc6e97e 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiRetryTests.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiRetryTests.java @@ -65,11 +65,11 @@ import org.springframework.ai.retry.RetryUtils; import org.springframework.ai.retry.TransientAiException; import org.springframework.core.io.ClassPathResource; +import org.springframework.core.retry.RetryListener; +import org.springframework.core.retry.RetryPolicy; +import org.springframework.core.retry.RetryTemplate; +import org.springframework.core.retry.Retryable; import org.springframework.http.ResponseEntity; -import org.springframework.retry.RetryCallback; -import org.springframework.retry.RetryContext; -import org.springframework.retry.RetryListener; -import org.springframework.retry.support.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -109,7 +109,7 @@ public class OpenAiRetryTests { public void beforeEach() { this.retryTemplate = RetryUtils.SHORT_RETRY_TEMPLATE; this.retryListener = new TestRetryListener(); - this.retryTemplate.registerListener(this.retryListener); + this.retryTemplate.setRetryListener(this.retryListener); this.chatModel = OpenAiChatModel.builder() .openAiApi(this.openAiApi) @@ -145,8 +145,8 @@ public void openAiChatTransientError() { assertThat(result).isNotNull(); assertThat(result.getResult().getOutput().getText()).isSameAs("Response"); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); - assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); + assertThat(this.retryListener.retryCount).isEqualTo(2); } @Test @@ -174,8 +174,8 @@ public void openAiChatStreamTransientError() { assertThat(result).isNotNull(); assertThat(result.collectList().block().get(0).getResult().getOutput().getText()).isSameAs("Response"); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); - assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); + assertThat(this.retryListener.retryCount).isEqualTo(2); } @Test @@ -202,8 +202,8 @@ public void openAiEmbeddingTransientError() { assertThat(result).isNotNull(); assertThat(result.getResult().getOutput()).isEqualTo(new float[] { 9.9f, 8.8f }); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); - assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); + assertThat(this.retryListener.retryCount).isEqualTo(2); } @Test @@ -229,8 +229,8 @@ public void openAiAudioTranscriptionTransientError() { assertThat(result).isNotNull(); assertThat(result.getResult().getOutput()).isEqualTo(expectedResponse.text()); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); - assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); + assertThat(this.retryListener.retryCount).isEqualTo(2); } @Test @@ -256,8 +256,8 @@ public void openAiImageTransientError() { assertThat(result).isNotNull(); assertThat(result.getResult().getOutput().getUrl()).isEqualTo("url678"); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); - assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); + assertThat(this.retryListener.retryCount).isEqualTo(2); } @Test @@ -270,19 +270,19 @@ public void openAiImageNonTransientError() { private static class TestRetryListener implements RetryListener { - int onErrorRetryCount = 0; + int retryCount = 0; int onSuccessRetryCount = 0; @Override - public void onSuccess(RetryContext context, RetryCallback callback, T result) { - this.onSuccessRetryCount = context.getRetryCount(); + public void onRetrySuccess(final RetryPolicy retryPolicy, final Retryable retryable, final Object result) { + // Count successful retries - we increment when we succeed after a failure + this.onSuccessRetryCount++; } @Override - public void onError(RetryContext context, RetryCallback callback, - Throwable throwable) { - this.onErrorRetryCount = context.getRetryCount(); + public void beforeRetry(RetryPolicy retryPolicy, Retryable retryable) { + retryCount++; } } diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiStreamingFinishReasonTests.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiStreamingFinishReasonTests.java index 3dc59444e82..d1f8dee4929 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiStreamingFinishReasonTests.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiStreamingFinishReasonTests.java @@ -40,7 +40,7 @@ import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionMessage.Role; import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionRequest; import org.springframework.ai.retry.RetryUtils; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/embedding/OpenAiEmbeddingModelObservationIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/embedding/OpenAiEmbeddingModelObservationIT.java index aa76a67f7a5..5d3cd477653 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/embedding/OpenAiEmbeddingModelObservationIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/embedding/OpenAiEmbeddingModelObservationIT.java @@ -37,7 +37,8 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryPolicy; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.ai.embedding.observation.EmbeddingModelObservationDocumentation.HighCardinalityKeyNames; @@ -111,7 +112,7 @@ public OpenAiApi openAiApi() { public OpenAiEmbeddingModel openAiEmbeddingModel(OpenAiApi openAiApi, TestObservationRegistry observationRegistry) { return new OpenAiEmbeddingModel(openAiApi, MetadataMode.EMBED, OpenAiEmbeddingOptions.builder().build(), - RetryTemplate.defaultInstance(), observationRegistry); + new RetryTemplate(RetryPolicy.withDefaults()), observationRegistry); } } diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelNoOpApiKeysIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelNoOpApiKeysIT.java index 61160a08a1f..bbd3373f826 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelNoOpApiKeysIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelNoOpApiKeysIT.java @@ -31,7 +31,8 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryPolicy; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; @@ -70,7 +71,7 @@ public OpenAiImageApi openAiImageApi() { @Bean public OpenAiImageModel openAiImageModel(OpenAiImageApi openAiImageApi) { return new OpenAiImageModel(openAiImageApi, OpenAiImageOptions.builder().build(), - RetryTemplate.defaultInstance(), TestObservationRegistry.create()); + new RetryTemplate(RetryPolicy.withDefaults()), TestObservationRegistry.create()); } } diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelObservationIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelObservationIT.java index 37dc7abcdba..8a6fb12b13b 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelObservationIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelObservationIT.java @@ -34,7 +34,8 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryPolicy; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.ai.image.observation.ImageModelObservationDocumentation.HighCardinalityKeyNames; @@ -105,7 +106,7 @@ public OpenAiImageApi openAiImageApi() { public OpenAiImageModel openAiImageModel(OpenAiImageApi openAiImageApi, TestObservationRegistry observationRegistry) { return new OpenAiImageModel(openAiImageApi, OpenAiImageOptions.builder().build(), - RetryTemplate.defaultInstance(), observationRegistry); + new RetryTemplate(RetryPolicy.withDefaults()), observationRegistry); } } diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/api/OpenAiImageApiBuilderTests.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/api/OpenAiImageApiBuilderTests.java index 50bfd71fef3..6121893973a 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/api/OpenAiImageApiBuilderTests.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/api/OpenAiImageApiBuilderTests.java @@ -37,8 +37,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; @@ -64,7 +62,7 @@ void testMinimalBuilder() { @Test void testFullBuilder() { - MultiValueMap headers = new LinkedMultiValueMap<>(); + HttpHeaders headers = new HttpHeaders(); headers.add("Custom-Header", "test-value"); RestClient.Builder restClientBuilder = RestClient.builder(); ResponseErrorHandler errorHandler = mock(ResponseErrorHandler.class); diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/moderation/api/OpenAiModerationApiBuilderTests.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/moderation/api/OpenAiModerationApiBuilderTests.java index 262eb21e05b..e7712e97d97 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/moderation/api/OpenAiModerationApiBuilderTests.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/moderation/api/OpenAiModerationApiBuilderTests.java @@ -37,8 +37,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; @@ -64,7 +62,7 @@ void testMinimalBuilder() { @Test void testFullBuilder() { - MultiValueMap headers = new LinkedMultiValueMap<>(); + HttpHeaders headers = new HttpHeaders(); headers.add("Custom-Header", "test-value"); RestClient.Builder restClientBuilder = RestClient.builder(); ResponseErrorHandler errorHandler = mock(ResponseErrorHandler.class); diff --git a/models/spring-ai-vertex-ai-embedding/src/main/java/org/springframework/ai/vertexai/embedding/text/VertexAiTextEmbeddingModel.java b/models/spring-ai-vertex-ai-embedding/src/main/java/org/springframework/ai/vertexai/embedding/text/VertexAiTextEmbeddingModel.java index 4bef9d1145b..380ed5035ae 100644 --- a/models/spring-ai-vertex-ai-embedding/src/main/java/org/springframework/ai/vertexai/embedding/text/VertexAiTextEmbeddingModel.java +++ b/models/spring-ai-vertex-ai-embedding/src/main/java/org/springframework/ai/vertexai/embedding/text/VertexAiTextEmbeddingModel.java @@ -50,7 +50,8 @@ import org.springframework.ai.vertexai.embedding.VertexAiEmbeddingUtils; import org.springframework.ai.vertexai.embedding.VertexAiEmbeddingUtils.TextInstanceBuilder; import org.springframework.ai.vertexai.embedding.VertexAiEmbeddingUtils.TextParametersBuilder; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryException; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -139,7 +140,7 @@ public EmbeddingResponse call(EmbeddingRequest request) { (VertexAiTextEmbeddingOptions) options); PredictResponse embeddingResponse = this.retryTemplate - .execute(context -> getPredictResponse(client, predictRequestBuilder)); + .execute(() -> getPredictResponse(client, predictRequestBuilder)); int index = 0; int totalTokenCount = 0; @@ -163,6 +164,14 @@ public EmbeddingResponse call(EmbeddingRequest request) { return response; } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); + } + } }); } diff --git a/models/spring-ai-vertex-ai-embedding/src/test/java/org/springframework/ai/vertexai/embedding/text/TestVertexAiTextEmbeddingModel.java b/models/spring-ai-vertex-ai-embedding/src/test/java/org/springframework/ai/vertexai/embedding/text/TestVertexAiTextEmbeddingModel.java index e8627f3d625..36853d0bca7 100644 --- a/models/spring-ai-vertex-ai-embedding/src/test/java/org/springframework/ai/vertexai/embedding/text/TestVertexAiTextEmbeddingModel.java +++ b/models/spring-ai-vertex-ai-embedding/src/test/java/org/springframework/ai/vertexai/embedding/text/TestVertexAiTextEmbeddingModel.java @@ -23,7 +23,7 @@ import org.springframework.ai.embedding.EmbeddingRequest; import org.springframework.ai.vertexai.embedding.VertexAiEmbeddingConnectionDetails; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; public class TestVertexAiTextEmbeddingModel extends VertexAiTextEmbeddingModel { diff --git a/models/spring-ai-vertex-ai-embedding/src/test/java/org/springframework/ai/vertexai/embedding/text/VertexAiTextEmbeddingRetryTests.java b/models/spring-ai-vertex-ai-embedding/src/test/java/org/springframework/ai/vertexai/embedding/text/VertexAiTextEmbeddingRetryTests.java index 6d88ef6e958..08f4295dbcd 100644 --- a/models/spring-ai-vertex-ai-embedding/src/test/java/org/springframework/ai/vertexai/embedding/text/VertexAiTextEmbeddingRetryTests.java +++ b/models/spring-ai-vertex-ai-embedding/src/test/java/org/springframework/ai/vertexai/embedding/text/VertexAiTextEmbeddingRetryTests.java @@ -36,10 +36,10 @@ import org.springframework.ai.retry.RetryUtils; import org.springframework.ai.retry.TransientAiException; import org.springframework.ai.vertexai.embedding.VertexAiEmbeddingConnectionDetails; -import org.springframework.retry.RetryCallback; -import org.springframework.retry.RetryContext; -import org.springframework.retry.RetryListener; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryListener; +import org.springframework.core.retry.RetryPolicy; +import org.springframework.core.retry.RetryTemplate; +import org.springframework.core.retry.Retryable; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; @@ -76,7 +76,7 @@ public class VertexAiTextEmbeddingRetryTests { public void setUp() { this.retryTemplate = RetryUtils.SHORT_RETRY_TEMPLATE; this.retryListener = new TestRetryListener(); - this.retryTemplate.registerListener(this.retryListener); + this.retryTemplate.setRetryListener(this.retryListener); this.embeddingModel = new TestVertexAiTextEmbeddingModel(this.mockConnectionDetails, VertexAiTextEmbeddingOptions.builder().build(), this.retryTemplate); @@ -123,7 +123,7 @@ public void vertexAiEmbeddingTransientError() { assertThat(result).isNotNull(); assertThat(result.getResults()).hasSize(1); assertThat(result.getResults().get(0).getOutput()).isEqualTo(new float[] { 9.9f, 8.8f }); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); verify(this.mockPredictRequestBuilder, times(3)).build(); @@ -163,14 +163,15 @@ private static class TestRetryListener implements RetryListener { int onSuccessRetryCount = 0; @Override - public void onSuccess(RetryContext context, RetryCallback callback, T result) { - this.onSuccessRetryCount = context.getRetryCount(); + public void beforeRetry(final RetryPolicy retryPolicy, final Retryable retryable) { + // Count each retry attempt + this.onErrorRetryCount++; } @Override - public void onError(RetryContext context, RetryCallback callback, - Throwable throwable) { - this.onErrorRetryCount = context.getRetryCount(); + public void onRetrySuccess(final RetryPolicy retryPolicy, final Retryable retryable, final Object result) { + // Count successful retries - we increment when we succeed after a failure + this.onSuccessRetryCount++; } } diff --git a/models/spring-ai-vertex-ai-gemini/src/main/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiChatModel.java b/models/spring-ai-vertex-ai-gemini/src/main/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiChatModel.java index 3a55ee58611..957ff8cc959 100644 --- a/models/spring-ai-vertex-ai-gemini/src/main/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiChatModel.java +++ b/models/spring-ai-vertex-ai-gemini/src/main/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiChatModel.java @@ -49,6 +49,7 @@ import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.retry.RetryException; import reactor.core.publisher.Flux; import reactor.core.scheduler.Schedulers; @@ -92,7 +93,7 @@ import org.springframework.ai.vertexai.gemini.schema.VertexToolCallingManager; import org.springframework.beans.factory.DisposableBean; import org.springframework.lang.NonNull; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -389,28 +390,45 @@ private ChatResponse internalCall(Prompt prompt, ChatResponse previousChatRespon ChatResponse response = ChatModelObservationDocumentation.CHAT_MODEL_OPERATION .observation(this.observationConvention, DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, this.observationRegistry) - .observe(() -> this.retryTemplate.execute(context -> { - - var geminiRequest = createGeminiRequest(prompt); - - GenerateContentResponse generateContentResponse = this.getContentResponse(geminiRequest); + .observe(() -> { + try { + return this.retryTemplate.execute(() -> { + + var geminiRequest = createGeminiRequest(prompt); + + GenerateContentResponse generateContentResponse = this.getContentResponse(geminiRequest); + + List generations = generateContentResponse.getCandidatesList() + .stream() + .map(this::responseCandidateToGeneration) + .flatMap(List::stream) + .toList(); + + GenerateContentResponse.UsageMetadata usage = generateContentResponse.getUsageMetadata(); + Usage currentUsage = (usage != null) + ? new DefaultUsage(usage.getPromptTokenCount(), usage.getCandidatesTokenCount()) + : new EmptyUsage(); + Usage cumulativeUsage = UsageCalculator.getCumulativeUsage(currentUsage, previousChatResponse); + ChatResponse chatResponse = new ChatResponse(generations, + toChatResponseMetadata(cumulativeUsage)); + + observationContext.setResponse(chatResponse); + return chatResponse; + }); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } - List generations = generateContentResponse.getCandidatesList() - .stream() - .map(this::responseCandidateToGeneration) - .flatMap(List::stream) - .toList(); - - GenerateContentResponse.UsageMetadata usage = generateContentResponse.getUsageMetadata(); - Usage currentUsage = (usage != null) - ? new DefaultUsage(usage.getPromptTokenCount(), usage.getCandidatesTokenCount()) - : new EmptyUsage(); - Usage cumulativeUsage = UsageCalculator.getCumulativeUsage(currentUsage, previousChatResponse); - ChatResponse chatResponse = new ChatResponse(generations, toChatResponseMetadata(cumulativeUsage)); - - observationContext.setResponse(chatResponse); - return chatResponse; - })); + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); + } + } + }); if (this.toolExecutionEligibilityPredicate.isToolExecutionRequired(prompt.getOptions(), response)) { var toolExecutionResult = this.toolCallingManager.executeToolCalls(prompt, response); diff --git a/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/TestVertexAiGeminiChatModel.java b/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/TestVertexAiGeminiChatModel.java index 33af68c57d2..e19e39fccb0 100644 --- a/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/TestVertexAiGeminiChatModel.java +++ b/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/TestVertexAiGeminiChatModel.java @@ -23,7 +23,7 @@ import com.google.cloud.vertexai.generativeai.GenerativeModel; import org.springframework.ai.model.tool.ToolCallingManager; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; /** * @author Mark Pollack diff --git a/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiRetryTests.java b/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiRetryTests.java index 79ac33982c3..5c5610c7524 100644 --- a/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiRetryTests.java +++ b/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiRetryTests.java @@ -35,10 +35,10 @@ import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.retry.RetryUtils; import org.springframework.ai.retry.TransientAiException; -import org.springframework.retry.RetryCallback; -import org.springframework.retry.RetryContext; -import org.springframework.retry.RetryListener; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryListener; +import org.springframework.core.retry.RetryPolicy; +import org.springframework.core.retry.Retryable; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -68,7 +68,7 @@ public class VertexAiGeminiRetryTests { public void setUp() { this.retryTemplate = RetryUtils.SHORT_RETRY_TEMPLATE; this.retryListener = new TestRetryListener(); - this.retryTemplate.registerListener(this.retryListener); + this.retryTemplate.setRetryListener(this.retryListener); this.chatModel = new TestVertexAiGeminiChatModel(this.vertexAI, VertexAiGeminiChatOptions.builder() @@ -101,7 +101,7 @@ public void vertexAiGeminiChatTransientError() throws IOException { // Assertions assertThat(result).isNotNull(); assertThat(result.getResult().getOutput().getText()).isEqualTo("Response"); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); } @@ -168,7 +168,6 @@ public void vertexAiGeminiChatMaxRetriesExceeded() throws Exception { // Should throw the last TransientAiException after exhausting retries assertThrows(TransientAiException.class, () -> this.chatModel.call(new Prompt("test prompt"))); - // Verify retry attempts were made assertThat(this.retryListener.onErrorRetryCount).isGreaterThan(0); } @@ -249,7 +248,7 @@ public void vertexAiGeminiChatAlternatingErrorsAndSuccess() throws Exception { assertThat(result).isNotNull(); assertThat(result.getResult().getOutput().getText()).isEqualTo("Success after alternating errors"); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); } @@ -260,14 +259,15 @@ private static class TestRetryListener implements RetryListener { int onSuccessRetryCount = 0; @Override - public void onSuccess(RetryContext context, RetryCallback callback, T result) { - this.onSuccessRetryCount = context.getRetryCount(); + public void beforeRetry(final RetryPolicy retryPolicy, final Retryable retryable) { + // Count each retry attempt + this.onErrorRetryCount++; } @Override - public void onError(RetryContext context, RetryCallback callback, - Throwable throwable) { - this.onErrorRetryCount = context.getRetryCount(); + public void onRetrySuccess(final RetryPolicy retryPolicy, final Retryable retryable, final Object result) { + // Count successful retries - we increment when we succeed after a failure + this.onSuccessRetryCount++; } } diff --git a/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/ZhiPuAiChatModel.java b/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/ZhiPuAiChatModel.java index 2c9ff3e54ff..9090e73d912 100644 --- a/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/ZhiPuAiChatModel.java +++ b/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/ZhiPuAiChatModel.java @@ -27,6 +27,7 @@ import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.retry.RetryException; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; @@ -71,7 +72,7 @@ import org.springframework.ai.zhipuai.api.ZhiPuAiApi.ChatCompletionRequest; import org.springframework.ai.zhipuai.api.ZhiPuApiConstants; import org.springframework.http.ResponseEntity; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.MimeType; @@ -260,8 +261,18 @@ public ChatResponse call(Prompt prompt) { this.observationRegistry) .observe(() -> { - ResponseEntity completionEntity = this.retryTemplate - .execute(ctx -> this.zhiPuAiApi.chatCompletionEntity(request)); + ResponseEntity completionEntity = null; + try { + completionEntity = this.retryTemplate.execute(() -> this.zhiPuAiApi.chatCompletionEntity(request)); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); + } + } var chatCompletion = completionEntity.getBody(); @@ -319,8 +330,18 @@ public Flux stream(Prompt prompt) { Prompt requestPrompt = buildRequestPrompt(prompt); ChatCompletionRequest request = createRequest(requestPrompt, true); - Flux completionChunks = this.retryTemplate - .execute(ctx -> this.zhiPuAiApi.chatCompletionStream(request)); + Flux completionChunks = null; + try { + completionChunks = this.retryTemplate.execute(() -> this.zhiPuAiApi.chatCompletionStream(request)); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); + } + } // For chunked responses, only the first chunk contains the choice role. // The rest of the chunks with same ID share the same role. diff --git a/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/ZhiPuAiEmbeddingModel.java b/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/ZhiPuAiEmbeddingModel.java index c1ec94262e1..2415ee34ae7 100644 --- a/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/ZhiPuAiEmbeddingModel.java +++ b/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/ZhiPuAiEmbeddingModel.java @@ -21,6 +21,7 @@ import io.micrometer.observation.ObservationRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.retry.RetryException; import org.springframework.ai.chat.metadata.DefaultUsage; import org.springframework.ai.chat.metadata.EmptyUsage; @@ -41,7 +42,8 @@ import org.springframework.ai.retry.RetryUtils; import org.springframework.ai.zhipuai.api.ZhiPuAiApi; import org.springframework.ai.zhipuai.api.ZhiPuApiConstants; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; +import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -165,8 +167,19 @@ public EmbeddingResponse call(EmbeddingRequest request) { .observation(this.observationConvention, DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, this.observationRegistry) .observe(() -> { - var embeddingResponse = this.retryTemplate - .execute(ctx -> this.zhiPuAiApi.embeddings(zhipuEmbeddingRequest)); + ResponseEntity> embeddingResponse = null; + try { + embeddingResponse = this.retryTemplate + .execute(() -> this.zhiPuAiApi.embeddings(zhipuEmbeddingRequest)); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); + } + } if (embeddingResponse == null || embeddingResponse.getBody() == null || CollectionUtils.isEmpty(embeddingResponse.getBody().data())) { diff --git a/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/ZhiPuAiImageModel.java b/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/ZhiPuAiImageModel.java index 406221e7d8a..ad1e13746af 100644 --- a/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/ZhiPuAiImageModel.java +++ b/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/ZhiPuAiImageModel.java @@ -20,6 +20,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.retry.RetryException; import org.springframework.ai.image.Image; import org.springframework.ai.image.ImageGeneration; @@ -31,7 +32,7 @@ import org.springframework.ai.retry.RetryUtils; import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi; import org.springframework.http.ResponseEntity; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import org.springframework.util.Assert; /** @@ -71,30 +72,40 @@ public ZhiPuAiImageOptions getDefaultOptions() { @Override public ImageResponse call(ImagePrompt imagePrompt) { - return this.retryTemplate.execute(ctx -> { + try { + return this.retryTemplate.execute(() -> { - String instructions = imagePrompt.getInstructions().get(0).getText(); + String instructions = imagePrompt.getInstructions().get(0).getText(); - ZhiPuAiImageApi.ZhiPuAiImageRequest imageRequest = new ZhiPuAiImageApi.ZhiPuAiImageRequest(instructions, - ZhiPuAiImageApi.DEFAULT_IMAGE_MODEL); + ZhiPuAiImageApi.ZhiPuAiImageRequest imageRequest = new ZhiPuAiImageApi.ZhiPuAiImageRequest(instructions, + ZhiPuAiImageApi.DEFAULT_IMAGE_MODEL); - if (this.defaultOptions != null) { - imageRequest = ModelOptionsUtils.merge(this.defaultOptions, imageRequest, - ZhiPuAiImageApi.ZhiPuAiImageRequest.class); - } + if (this.defaultOptions != null) { + imageRequest = ModelOptionsUtils.merge(this.defaultOptions, imageRequest, + ZhiPuAiImageApi.ZhiPuAiImageRequest.class); + } - if (imagePrompt.getOptions() != null) { - imageRequest = ModelOptionsUtils.merge(toZhiPuAiImageOptions(imagePrompt.getOptions()), imageRequest, - ZhiPuAiImageApi.ZhiPuAiImageRequest.class); - } + if (imagePrompt.getOptions() != null) { + imageRequest = ModelOptionsUtils.merge(toZhiPuAiImageOptions(imagePrompt.getOptions()), + imageRequest, ZhiPuAiImageApi.ZhiPuAiImageRequest.class); + } - // Make the request - ResponseEntity imageResponseEntity = this.zhiPuAiImageApi - .createImage(imageRequest); + // Make the request + ResponseEntity imageResponseEntity = this.zhiPuAiImageApi + .createImage(imageRequest); - // Convert to org.springframework.ai.model derived ImageResponse data type - return convertResponse(imageResponseEntity, imageRequest); - }); + // Convert to org.springframework.ai.model derived ImageResponse data type + return convertResponse(imageResponseEntity, imageRequest); + }); + } + catch (RetryException e) { + if (e.getCause() instanceof RuntimeException r) { + throw r; + } + else { + throw new RuntimeException(e.getCause()); + } + } } private ImageResponse convertResponse(ResponseEntity imageResponseEntity, diff --git a/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/api/ZhiPuAiApi.java b/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/api/ZhiPuAiApi.java index c5a99f99eb3..fb0d55d72c6 100644 --- a/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/api/ZhiPuAiApi.java +++ b/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/api/ZhiPuAiApi.java @@ -42,8 +42,6 @@ import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestClient; import org.springframework.web.reactive.function.client.WebClient; @@ -85,7 +83,7 @@ public static Builder builder() { private final ApiKey apiKey; - private final MultiValueMap headers; + private final HttpHeaders headers; private final String completionsPath; @@ -143,7 +141,7 @@ public ZhiPuAiApi(String baseUrl, String zhiPuAiToken, RestClient.Builder restCl @Deprecated public ZhiPuAiApi(String baseUrl, String zhiPuAiToken, RestClient.Builder restClientBuilder, ResponseErrorHandler responseErrorHandler) { - this(baseUrl, new SimpleApiKey(zhiPuAiToken), new LinkedMultiValueMap<>(), DEFAULT_COMPLETIONS_PATH, + this(baseUrl, new SimpleApiKey(zhiPuAiToken), new HttpHeaders(), DEFAULT_COMPLETIONS_PATH, DEFAULT_EMBEDDINGS_PATH, restClientBuilder, WebClient.builder(), responseErrorHandler); } @@ -158,7 +156,7 @@ public ZhiPuAiApi(String baseUrl, String zhiPuAiToken, RestClient.Builder restCl * @param webClientBuilder WebClient builder. * @param responseErrorHandler Response error handler. */ - private ZhiPuAiApi(String baseUrl, ApiKey apiKey, MultiValueMap headers, String completionsPath, + private ZhiPuAiApi(String baseUrl, ApiKey apiKey, HttpHeaders headers, String completionsPath, String embeddingsPath, RestClient.Builder restClientBuilder, WebClient.Builder webClientBuilder, ResponseErrorHandler responseErrorHandler) { Assert.hasText(completionsPath, "Completions Path must not be null"); @@ -204,7 +202,7 @@ public static String getTextContent(List con * and headers. */ public ResponseEntity chatCompletionEntity(ChatCompletionRequest chatRequest) { - return chatCompletionEntity(chatRequest, new LinkedMultiValueMap<>()); + return chatCompletionEntity(chatRequest, new HttpHeaders()); } /** @@ -214,7 +212,7 @@ public ResponseEntity chatCompletionEntity(ChatCompletionRequest * and headers. */ public ResponseEntity chatCompletionEntity(ChatCompletionRequest chatRequest, - MultiValueMap additionalHttpHeader) { + HttpHeaders additionalHttpHeader) { Assert.notNull(chatRequest, "The request body can not be null."); Assert.isTrue(!chatRequest.stream(), "Request must set the stream property to false."); @@ -239,7 +237,7 @@ public ResponseEntity chatCompletionEntity(ChatCompletionRequest * @return Returns a {@link Flux} stream from chat completion chunks. */ public Flux chatCompletionStream(ChatCompletionRequest chatRequest) { - return chatCompletionStream(chatRequest, new LinkedMultiValueMap<>()); + return chatCompletionStream(chatRequest, new HttpHeaders()); } /** @@ -249,7 +247,7 @@ public Flux chatCompletionStream(ChatCompletionRequest chat * @return Returns a {@link Flux} stream from chat completion chunks. */ public Flux chatCompletionStream(ChatCompletionRequest chatRequest, - MultiValueMap additionalHttpHeader) { + HttpHeaders additionalHttpHeader) { Assert.notNull(chatRequest, "The request body can not be null."); Assert.isTrue(chatRequest.stream(), "Request must set the stream property to true."); @@ -330,7 +328,7 @@ public ResponseEntity> embeddings(EmbeddingRequest< } private void addDefaultHeadersIfMissing(HttpHeaders headers) { - if (!headers.containsKey(HttpHeaders.AUTHORIZATION) && !(this.apiKey instanceof NoopApiKey)) { + if (headers.get(HttpHeaders.AUTHORIZATION) == null && !(this.apiKey instanceof NoopApiKey)) { headers.setBearerAuth(this.apiKey.getValue()); } } @@ -344,7 +342,7 @@ ApiKey getApiKey() { return this.apiKey; } - MultiValueMap getHeaders() { + HttpHeaders getHeaders() { return this.headers; } @@ -1215,7 +1213,8 @@ private Builder() { public Builder(ZhiPuAiApi api) { this.baseUrl = api.getBaseUrl(); this.apiKey = api.getApiKey(); - this.headers = new LinkedMultiValueMap<>(api.getHeaders()); + this.headers = new HttpHeaders(); + this.headers.addAll(api.getHeaders()); this.completionsPath = api.getCompletionsPath(); this.embeddingsPath = api.getEmbeddingsPath(); this.restClientBuilder = api.restClient != null ? api.restClient.mutate() : RestClient.builder(); @@ -1227,7 +1226,7 @@ public Builder(ZhiPuAiApi api) { private ApiKey apiKey; - private MultiValueMap headers = new LinkedMultiValueMap<>(); + private HttpHeaders headers = new HttpHeaders(); private String completionsPath = DEFAULT_COMPLETIONS_PATH; @@ -1256,7 +1255,7 @@ public Builder apiKey(String simpleApiKey) { return this; } - public Builder headers(MultiValueMap headers) { + public Builder headers(HttpHeaders headers) { Assert.notNull(headers, "headers cannot be null"); this.headers = headers; return this; diff --git a/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/api/ZhiPuAiApiBuilderTests.java b/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/api/ZhiPuAiApiBuilderTests.java index a6409e70c20..de1684e1c6e 100644 --- a/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/api/ZhiPuAiApiBuilderTests.java +++ b/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/api/ZhiPuAiApiBuilderTests.java @@ -66,7 +66,7 @@ void testMinimalBuilder() { @Test void testFullBuilder() { - MultiValueMap headers = new LinkedMultiValueMap<>(); + var headers = new HttpHeaders(); headers.add("Custom-Header", "test-value"); RestClient.Builder restClientBuilder = RestClient.builder(); WebClient.Builder webClientBuilder = WebClient.builder(); @@ -232,7 +232,7 @@ void dynamicApiKeyRestClientWithAdditionalAuthorizationHeader() throws Interrupt ZhiPuAiApi.ChatCompletionRequest request = new ZhiPuAiApi.ChatCompletionRequest( List.of(chatCompletionMessage), "glm-4-flash", 0.8, false); - MultiValueMap additionalHeaders = new LinkedMultiValueMap<>(); + var additionalHeaders = new HttpHeaders(); additionalHeaders.add(HttpHeaders.AUTHORIZATION, "Bearer additional-key"); ResponseEntity response = api.chatCompletionEntity(request, additionalHeaders); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); @@ -289,7 +289,7 @@ void dynamicApiKeyWebClientWithAdditionalAuthorizationHeader() throws Interrupte ZhiPuAiApi.ChatCompletionMessage.Role.USER); ZhiPuAiApi.ChatCompletionRequest request = new ZhiPuAiApi.ChatCompletionRequest( List.of(chatCompletionMessage), "glm-4-flash", 0.8, true); - MultiValueMap additionalHeaders = new LinkedMultiValueMap<>(); + var additionalHeaders = new HttpHeaders(); additionalHeaders.add(HttpHeaders.AUTHORIZATION, "Bearer additional-key"); List response = api.chatCompletionStream(request, additionalHeaders) .collectList() diff --git a/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/api/ZhiPuAiRetryTests.java b/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/api/ZhiPuAiRetryTests.java index b1b37bd37ba..4fb387a5785 100644 --- a/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/api/ZhiPuAiRetryTests.java +++ b/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/api/ZhiPuAiRetryTests.java @@ -53,10 +53,10 @@ import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi.ZhiPuAiImageRequest; import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi.ZhiPuAiImageResponse; import org.springframework.http.ResponseEntity; -import org.springframework.retry.RetryCallback; -import org.springframework.retry.RetryContext; -import org.springframework.retry.RetryListener; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryListener; +import org.springframework.core.retry.RetryPolicy; +import org.springframework.core.retry.Retryable; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -88,7 +88,7 @@ public class ZhiPuAiRetryTests { public void beforeEach() { this.retryTemplate = RetryUtils.SHORT_RETRY_TEMPLATE; this.retryListener = new TestRetryListener(); - this.retryTemplate.registerListener(this.retryListener); + this.retryTemplate.setRetryListener(this.retryListener); this.chatModel = new ZhiPuAiChatModel(this.zhiPuAiApi, ZhiPuAiChatOptions.builder().build(), this.retryTemplate); @@ -115,7 +115,7 @@ public void zhiPuAiChatTransientError() { assertThat(result).isNotNull(); assertThat(result.getResult().getOutput().getText()).isSameAs("Response"); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); } @@ -144,7 +144,7 @@ public void zhiPuAiChatStreamTransientError() { assertThat(result).isNotNull(); assertThat(result.collectList().block().get(0).getResult().getOutput().getText()).isSameAs("Response"); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); } @@ -174,7 +174,7 @@ public void zhiPuAiEmbeddingTransientError() { assertThat(result).isNotNull(); // choose the first result assertThat(result.getResult().getOutput()).isEqualTo(new float[] { 9.9f, 8.8f }); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); } @@ -201,7 +201,7 @@ public void zhiPuAiImageTransientError() { assertThat(result).isNotNull(); assertThat(result.getResult().getOutput().getUrl()).isEqualTo("url678"); - assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(2); + assertThat(this.retryListener.onSuccessRetryCount).isEqualTo(1); assertThat(this.retryListener.onErrorRetryCount).isEqualTo(2); } @@ -213,21 +213,22 @@ public void zhiPuAiImageNonTransientError() { () -> this.imageModel.call(new ImagePrompt(List.of(new ImageMessage("Image Message"))))); } - private class TestRetryListener implements RetryListener { + private static class TestRetryListener implements RetryListener { int onErrorRetryCount = 0; int onSuccessRetryCount = 0; @Override - public void onSuccess(RetryContext context, RetryCallback callback, T result) { - this.onSuccessRetryCount = context.getRetryCount(); + public void beforeRetry(final RetryPolicy retryPolicy, final Retryable retryable) { + // Count each retry attempt + this.onErrorRetryCount++; } @Override - public void onError(RetryContext context, RetryCallback callback, - Throwable throwable) { - this.onErrorRetryCount = context.getRetryCount(); + public void onRetrySuccess(final RetryPolicy retryPolicy, final Retryable retryable, final Object result) { + // Count successful retries - we increment when we succeed after a failure + this.onSuccessRetryCount++; } } diff --git a/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/chat/ZhiPuAiChatModelObservationIT.java b/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/chat/ZhiPuAiChatModelObservationIT.java index 953c7c3bb4e..a01fc35ec0d 100644 --- a/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/chat/ZhiPuAiChatModelObservationIT.java +++ b/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/chat/ZhiPuAiChatModelObservationIT.java @@ -39,7 +39,7 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.ai.chat.observation.ChatModelObservationDocumentation.HighCardinalityKeyNames; @@ -164,8 +164,8 @@ public ZhiPuAiApi zhiPuAiApi() { @Bean public ZhiPuAiChatModel zhiPuAiChatModel(ZhiPuAiApi zhiPuAiApi, TestObservationRegistry observationRegistry) { - return new ZhiPuAiChatModel(zhiPuAiApi, ZhiPuAiChatOptions.builder().build(), - RetryTemplate.defaultInstance(), observationRegistry); + return new ZhiPuAiChatModel(zhiPuAiApi, ZhiPuAiChatOptions.builder().build(), new RetryTemplate(), + observationRegistry); } } diff --git a/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/embedding/ZhiPuAiEmbeddingModelObservationIT.java b/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/embedding/ZhiPuAiEmbeddingModelObservationIT.java index f6a33037566..11f3bc70f75 100644 --- a/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/embedding/ZhiPuAiEmbeddingModelObservationIT.java +++ b/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/embedding/ZhiPuAiEmbeddingModelObservationIT.java @@ -37,7 +37,7 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; -import org.springframework.retry.support.RetryTemplate; +import org.springframework.core.retry.RetryTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.ai.embedding.observation.EmbeddingModelObservationDocumentation.HighCardinalityKeyNames; @@ -107,7 +107,7 @@ public ZhiPuAiEmbeddingModel zhiPuAiEmbeddingModel(ZhiPuAiApi zhiPuAiApi, TestObservationRegistry observationRegistry) { return new ZhiPuAiEmbeddingModel(zhiPuAiApi, MetadataMode.EMBED, ZhiPuAiEmbeddingOptions.builder().model(ZhiPuAiApi.DEFAULT_EMBEDDING_MODEL).build(), - RetryTemplate.defaultInstance(), observationRegistry); + new RetryTemplate(), observationRegistry); } } diff --git a/pom.xml b/pom.xml index abb2bc543a3..3397cd66948 100644 --- a/pom.xml +++ b/pom.xml @@ -172,7 +172,7 @@ models/spring-ai-bedrock models/spring-ai-bedrock-converse models/spring-ai-elevenlabs - models/spring-ai-huggingface + models/spring-ai-minimax models/spring-ai-mistral-ai models/spring-ai-oci-genai @@ -269,12 +269,12 @@ ${java.version} - 3.5.6 + 4.0.0-M3 4.3.4 1.0.0-beta.16 1.1.0 4.37.0 - 1.9.25 + 2.2.20 2.31.65 @@ -355,12 +355,12 @@ 1.0.0-alpha.5 0.0.4 3.5.0 - true - true + false + false 9.3 3.2.8 - false + trje @@ -380,51 +380,51 @@ - - org.apache.maven.plugins - maven-checkstyle-plugin - ${maven-checkstyle-plugin.version} - - - com.puppycrawl.tools - checkstyle - ${puppycrawl-tools-checkstyle.version} - - - io.spring.javaformat - spring-javaformat-checkstyle - 0.0.43 - - - - - checkstyle-validation - validate - true - - ${disable.checks} - src/checkstyle/checkstyle.xml - src/checkstyle/checkstyle-header.txt - true - - checkstyle.build.directory=${project.build.directory} - checkstyle.suppressions.file=${project.basedir}/src/checkstyle/checkstyle-suppressions.xml - checkstyle.additional.suppressions.file=${project.basedir}/src/checkstyle/checkstyle-suppressions.xml - checkstyle.header.file=${project.basedir}/src/checkstyle/checkstyle-header.txt - - true - ${maven-checkstyle-plugin.failsOnError} - - - ${maven-checkstyle-plugin.failOnViolation} - - - - check - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.apache.maven.plugins maven-site-plugin @@ -1010,39 +1010,39 @@ - - - - org.apache.maven.plugins - maven-project-info-reports-plugin - ${maven-project-info-reports-plugin.version} - - true - - - - org.apache.maven.plugins - maven-checkstyle-plugin - ${maven-checkstyle-plugin.version} - - - - checkstyle - - - - - src/checkstyle/checkstyle.xml - src/checkstyle/checkstyle-header.txt - - checkstyle.build.directory=${project.build.directory} - checkstyle.suppressions.file=${project.basedir}/src/checkstyle/checkstyle-suppressions.xml - checkstyle.additional.suppressions.file=${project.basedir}/src/checkstyle/checkstyle-suppressions.xml - checkstyle.header.file=${project.basedir}/src/checkstyle/checkstyle-header.txt - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-ai-client-chat/src/main/kotlin/org/springframework/ai/chat/client/ChatClientExtensions.kt b/spring-ai-client-chat/src/main/kotlin/org/springframework/ai/chat/client/ChatClientExtensions.kt index 40a4c6ffd84..7128603bbc7 100644 --- a/spring-ai-client-chat/src/main/kotlin/org/springframework/ai/chat/client/ChatClientExtensions.kt +++ b/spring-ai-client-chat/src/main/kotlin/org/springframework/ai/chat/client/ChatClientExtensions.kt @@ -25,8 +25,8 @@ import org.springframework.core.ParameterizedTypeReference * @author Josh Long */ -inline fun ChatClient.CallResponseSpec.entity(): T = +inline fun ChatClient.CallResponseSpec.entity(): T = entity(object : ParameterizedTypeReference() {}) as T -inline fun ChatClient.CallResponseSpec.responseEntity(): ResponseEntity = +inline fun ChatClient.CallResponseSpec.responseEntity(): ResponseEntity = responseEntity(object : ParameterizedTypeReference() {}) diff --git a/spring-ai-model/src/test/kotlin/org/springframework/ai/tool/resolution/TypeResolverHelperKotlinIT.kt b/spring-ai-model/src/test/kotlin/org/springframework/ai/tool/resolution/TypeResolverHelperKotlinIT.kt index b7671a89b98..b2420bcfe4d 100644 --- a/spring-ai-model/src/test/kotlin/org/springframework/ai/tool/resolution/TypeResolverHelperKotlinIT.kt +++ b/spring-ai-model/src/test/kotlin/org/springframework/ai/tool/resolution/TypeResolverHelperKotlinIT.kt @@ -39,7 +39,7 @@ class TypeResolverHelperKotlinIT { val functionType = TypeResolverHelper.resolveBeanType(this.applicationContext, beanName); val functionInputClass = TypeResolverHelper.getFunctionArgumentType(functionType, 0).rawClass; assertThat(functionInputClass).isNotNull(); - assertThat(functionInputClass.typeName).isEqualTo(WeatherRequest::class.java.getName()); + assertThat(functionInputClass!!.typeName).isEqualTo(WeatherRequest::class.java.getName()); } class Outer { diff --git a/spring-ai-retry/pom.xml b/spring-ai-retry/pom.xml index 20393c99ae0..1706fe61276 100644 --- a/spring-ai-retry/pom.xml +++ b/spring-ai-retry/pom.xml @@ -42,11 +42,6 @@ - - org.springframework.retry - spring-retry - - org.springframework spring-web diff --git a/spring-ai-retry/src/main/java/org/springframework/ai/retry/NonTransientAiException.java b/spring-ai-retry/src/main/java/org/springframework/ai/retry/NonTransientAiException.java index 44c405ca6d8..c82762f60e0 100644 --- a/spring-ai-retry/src/main/java/org/springframework/ai/retry/NonTransientAiException.java +++ b/spring-ai-retry/src/main/java/org/springframework/ai/retry/NonTransientAiException.java @@ -26,11 +26,20 @@ */ public class NonTransientAiException extends RuntimeException { - public NonTransientAiException(String message) { + /** + * Constructor with message. + * @param message the exception message + */ + public NonTransientAiException(final String message) { super(message); } - public NonTransientAiException(String message, Throwable cause) { + /** + * Constructor with message and cause. + * @param message the exception message + * @param cause the exception cause + */ + public NonTransientAiException(final String message, final Throwable cause) { super(message, cause); } diff --git a/spring-ai-retry/src/main/java/org/springframework/ai/retry/RetryUtils.java b/spring-ai-retry/src/main/java/org/springframework/ai/retry/RetryUtils.java index 312a7aa9569..7a5d1665697 100644 --- a/spring-ai-retry/src/main/java/org/springframework/ai/retry/RetryUtils.java +++ b/spring-ai-retry/src/main/java/org/springframework/ai/retry/RetryUtils.java @@ -20,17 +20,18 @@ import java.net.URI; import java.nio.charset.StandardCharsets; import java.time.Duration; +import java.util.concurrent.atomic.AtomicInteger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.retry.RetryListener; +import org.springframework.core.retry.RetryPolicy; +import org.springframework.core.retry.RetryTemplate; +import org.springframework.core.retry.Retryable; import org.springframework.http.HttpMethod; import org.springframework.http.client.ClientHttpResponse; import org.springframework.lang.NonNull; -import org.springframework.retry.RetryCallback; -import org.springframework.retry.RetryContext; -import org.springframework.retry.RetryListener; -import org.springframework.retry.support.RetryTemplate; import org.springframework.util.StreamUtils; import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.ResponseErrorHandler; @@ -45,28 +46,44 @@ */ public abstract class RetryUtils { + private static final int DEFAULT_MAX_ATTEMPTS = 10; + + private static final long DEFAULT_INITIAL_INTERVAL = 2000; + + private static final int DEFAULT_MULTIPLIER = 5; + + private static final long DEFAULT_MAX_INTERVAL = 3 * 60000; + + private static final long SHORT_INITIAL_INTERVAL = 100; + + private static final Logger LOGGER = LoggerFactory.getLogger(RetryUtils.class); + + /** + * Default ResponseErrorHandler implementation. + */ public static final ResponseErrorHandler DEFAULT_RESPONSE_ERROR_HANDLER = new ResponseErrorHandler() { @Override - public boolean hasError(@NonNull ClientHttpResponse response) throws IOException { + public boolean hasError(final @NonNull ClientHttpResponse response) throws IOException { return response.getStatusCode().isError(); } @Override - public void handleError(URI url, HttpMethod method, @NonNull ClientHttpResponse response) throws IOException { + public void handleError(final URI url, final HttpMethod method, final @NonNull ClientHttpResponse response) + throws IOException { handleError(response); } @SuppressWarnings("removal") - public void handleError(@NonNull ClientHttpResponse response) throws IOException { + public void handleError(final @NonNull ClientHttpResponse response) throws IOException { if (response.getStatusCode().isError()) { String error = StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8); String message = String.format("%s - %s", response.getStatusCode().value(), error); - /** + /* * Thrown on 4xx client errors, such as 401 - Incorrect API key provided, * 401 - You must be a member of an organization to use the API, 429 - - * Rate limit reached for requests, 429 - You exceeded your current quota - * , please check your plan and billing details. + * Rate limit reached for requests, 429 - You exceeded your current quota, + * please check your plan and billing details. */ if (response.getStatusCode().is4xxClientError()) { throw new NonTransientAiException(message); @@ -74,42 +91,68 @@ public void handleError(@NonNull ClientHttpResponse response) throws IOException throw new TransientAiException(message); } } + }; - private static final Logger logger = LoggerFactory.getLogger(RetryUtils.class); + /** + * Default RetryTemplate with exponential backoff configuration. + */ + public static final RetryTemplate DEFAULT_RETRY_TEMPLATE = createDefaultRetryTemplate(); + + /** + * Short RetryTemplate for testing scenarios. + */ + public static final RetryTemplate SHORT_RETRY_TEMPLATE = createShortRetryTemplate(); - public static final RetryTemplate DEFAULT_RETRY_TEMPLATE = RetryTemplate.builder() - .maxAttempts(10) - .retryOn(TransientAiException.class) - .retryOn(ResourceAccessException.class) - .exponentialBackoff(Duration.ofMillis(2000), 5, Duration.ofMillis(3 * 60000)) - .withListener(new RetryListener() { + private static RetryTemplate createDefaultRetryTemplate() { + RetryPolicy retryPolicy = RetryPolicy.builder() + .maxAttempts(DEFAULT_MAX_ATTEMPTS) + .includes(TransientAiException.class) + .includes(ResourceAccessException.class) + .delay(Duration.ofMillis(DEFAULT_INITIAL_INTERVAL)) + .multiplier(DEFAULT_MULTIPLIER) + .maxDelay(Duration.ofMillis(DEFAULT_MAX_INTERVAL)) + .build(); + + RetryTemplate retryTemplate = new RetryTemplate(retryPolicy); + retryTemplate.setRetryListener(new RetryListener() { + private final AtomicInteger retryCount = new AtomicInteger(0); @Override - public void onError(RetryContext context, - RetryCallback callback, Throwable throwable) { - logger.warn("Retry error. Retry count:{}", context.getRetryCount(), throwable); + public void onRetryFailure(final RetryPolicy policy, final Retryable retryable, + final Throwable throwable) { + int currentRetries = retryCount.incrementAndGet(); + LOGGER.warn("Retry error. Retry count:{}", currentRetries, throwable); } - }) - .build(); + }); + return retryTemplate; + } /** - * Useful in testing scenarios where you don't want to wait long for retry and now - * show stack trace + * Useful in testing scenarios where you don't want to wait long for retry and don't + * need to show stack trace. + * @return a RetryTemplate with short delays */ - public static final RetryTemplate SHORT_RETRY_TEMPLATE = RetryTemplate.builder() - .maxAttempts(10) - .retryOn(TransientAiException.class) - .retryOn(ResourceAccessException.class) - .fixedBackoff(Duration.ofMillis(100)) - .withListener(new RetryListener() { + private static RetryTemplate createShortRetryTemplate() { + RetryPolicy retryPolicy = RetryPolicy.builder() + .maxAttempts(DEFAULT_MAX_ATTEMPTS) + .includes(TransientAiException.class) + .includes(ResourceAccessException.class) + .delay(Duration.ofMillis(SHORT_INITIAL_INTERVAL)) + .build(); + + RetryTemplate retryTemplate = new RetryTemplate(retryPolicy); + retryTemplate.setRetryListener(new RetryListener() { + private final AtomicInteger retryCount = new AtomicInteger(0); @Override - public void onError(RetryContext context, - RetryCallback callback, Throwable throwable) { - logger.warn("Retry error. Retry count:{}", context.getRetryCount()); + public void onRetryFailure(final RetryPolicy policy, final Retryable retryable, + final Throwable throwable) { + int currentRetries = retryCount.incrementAndGet(); + LOGGER.warn("Retry error. Retry count:{}", currentRetries, throwable); } - }) - .build(); + }); + return retryTemplate; + } } diff --git a/spring-ai-retry/src/main/java/org/springframework/ai/retry/TransientAiException.java b/spring-ai-retry/src/main/java/org/springframework/ai/retry/TransientAiException.java index 95b6e37f668..90d43fe0e5c 100644 --- a/spring-ai-retry/src/main/java/org/springframework/ai/retry/TransientAiException.java +++ b/spring-ai-retry/src/main/java/org/springframework/ai/retry/TransientAiException.java @@ -19,18 +19,27 @@ /** * Root of the hierarchy of Model access exceptions that are considered transient - where * a previously failed operation might be able to succeed when the operation is retried - * without any intervention by application-level functionality. + * without any intervention. * * @author Christian Tzolov * @since 0.8.1 */ public class TransientAiException extends RuntimeException { - public TransientAiException(String message) { + /** + * Constructor with message. + * @param message the exception message + */ + public TransientAiException(final String message) { super(message); } - public TransientAiException(String message, Throwable cause) { + /** + * Constructor with message and cause. + * @param message the exception message + * @param cause the exception cause + */ + public TransientAiException(final String message, final Throwable cause) { super(message, cause); } diff --git a/spring-ai-spring-boot-docker-compose/pom.xml b/spring-ai-spring-boot-docker-compose/pom.xml index 642db247343..3e74acd2dd0 100644 --- a/spring-ai-spring-boot-docker-compose/pom.xml +++ b/spring-ai-spring-boot-docker-compose/pom.xml @@ -198,7 +198,14 @@ true - + + org.springframework.boot + spring-boot-starter-mongodb + true + + + + org.springframework.ai @@ -212,6 +219,8 @@ spring-boot-starter-web test + + org.springframework.boot spring-boot-starter-test diff --git a/spring-ai-spring-boot-docker-compose/src/main/java/org/springframework/ai/docker/compose/service/connection/mongo/MongoDbAtlasLocalDockerComposeConnectionDetailsFactory.java b/spring-ai-spring-boot-docker-compose/src/main/java/org/springframework/ai/docker/compose/service/connection/mongo/MongoDbAtlasLocalDockerComposeConnectionDetailsFactory.java index 7c04ff256bf..9fccdf39d99 100644 --- a/spring-ai-spring-boot-docker-compose/src/main/java/org/springframework/ai/docker/compose/service/connection/mongo/MongoDbAtlasLocalDockerComposeConnectionDetailsFactory.java +++ b/spring-ai-spring-boot-docker-compose/src/main/java/org/springframework/ai/docker/compose/service/connection/mongo/MongoDbAtlasLocalDockerComposeConnectionDetailsFactory.java @@ -18,7 +18,7 @@ import com.mongodb.ConnectionString; -import org.springframework.boot.autoconfigure.mongo.MongoConnectionDetails; +import org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails; import org.springframework.boot.docker.compose.core.RunningService; import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory; import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource; diff --git a/spring-ai-spring-boot-docker-compose/src/test/java/org/springframework/ai/docker/compose/service/connection/mongo/MongoDbAtlasLocalDockerComposeConnectionDetailsFactoryIT.java b/spring-ai-spring-boot-docker-compose/src/test/java/org/springframework/ai/docker/compose/service/connection/mongo/MongoDbAtlasLocalDockerComposeConnectionDetailsFactoryIT.java index a85e7438c09..e8682145fc2 100644 --- a/spring-ai-spring-boot-docker-compose/src/test/java/org/springframework/ai/docker/compose/service/connection/mongo/MongoDbAtlasLocalDockerComposeConnectionDetailsFactoryIT.java +++ b/spring-ai-spring-boot-docker-compose/src/test/java/org/springframework/ai/docker/compose/service/connection/mongo/MongoDbAtlasLocalDockerComposeConnectionDetailsFactoryIT.java @@ -19,7 +19,7 @@ import org.junit.jupiter.api.Test; import org.testcontainers.utility.DockerImageName; -import org.springframework.boot.autoconfigure.mongo.MongoConnectionDetails; +import org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails; import org.springframework.boot.docker.compose.service.connection.test.AbstractDockerComposeIT; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-ai-spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/service/connection/test/AbstractDockerComposeIT.java b/spring-ai-spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/service/connection/test/AbstractDockerComposeIT.java index 26d26baccbb..66df65f4d41 100644 --- a/spring-ai-spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/service/connection/test/AbstractDockerComposeIT.java +++ b/spring-ai-spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/service/connection/test/AbstractDockerComposeIT.java @@ -32,7 +32,7 @@ import org.springframework.boot.SpringApplicationShutdownHandlers; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails; -import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration; +import org.springframework.boot.web.server.autoconfigure.servlet.ServletWebServerConfiguration; import org.springframework.boot.testsupport.DisabledIfProcessUnavailable; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; @@ -97,7 +97,7 @@ private File transformedComposeFile(File composeFile, DockerImageName imageName) } @Configuration(proxyBeanMethods = false) - @ImportAutoConfiguration(ServletWebServerFactoryAutoConfiguration.class) + @ImportAutoConfiguration(ServletWebServerConfiguration.class) static class Config { } diff --git a/spring-ai-spring-boot-testcontainers/src/main/java/org/springframework/ai/testcontainers/service/connection/mongo/MongoDbAtlasLocalContainerConnectionDetailsFactory.java b/spring-ai-spring-boot-testcontainers/src/main/java/org/springframework/ai/testcontainers/service/connection/mongo/MongoDbAtlasLocalContainerConnectionDetailsFactory.java index 32bd405326e..91a5c5a6cf1 100644 --- a/spring-ai-spring-boot-testcontainers/src/main/java/org/springframework/ai/testcontainers/service/connection/mongo/MongoDbAtlasLocalContainerConnectionDetailsFactory.java +++ b/spring-ai-spring-boot-testcontainers/src/main/java/org/springframework/ai/testcontainers/service/connection/mongo/MongoDbAtlasLocalContainerConnectionDetailsFactory.java @@ -22,7 +22,7 @@ import com.mongodb.ConnectionString; import org.testcontainers.mongodb.MongoDBAtlasLocalContainer; -import org.springframework.boot.autoconfigure.mongo.MongoConnectionDetails; +import org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails; import org.springframework.boot.ssl.SslBundle; import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory; import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource; diff --git a/spring-ai-spring-boot-testcontainers/src/test/java/org/springframework/ai/testcontainers/service/connection/mongo/MongoDbAtlasLocalContainerConnectionDetailsFactoryIT.java b/spring-ai-spring-boot-testcontainers/src/test/java/org/springframework/ai/testcontainers/service/connection/mongo/MongoDbAtlasLocalContainerConnectionDetailsFactoryIT.java index 6cd28c8982e..3da32032966 100644 --- a/spring-ai-spring-boot-testcontainers/src/test/java/org/springframework/ai/testcontainers/service/connection/mongo/MongoDbAtlasLocalContainerConnectionDetailsFactoryIT.java +++ b/spring-ai-spring-boot-testcontainers/src/test/java/org/springframework/ai/testcontainers/service/connection/mongo/MongoDbAtlasLocalContainerConnectionDetailsFactoryIT.java @@ -35,8 +35,7 @@ import org.springframework.ai.vectorstore.mongodb.autoconfigure.MongoDBAtlasVectorStoreAutoConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; -import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; +import org.springframework.boot.mongodb.autoconfigure.MongoAutoConfiguration; import org.springframework.boot.testcontainers.service.connection.ServiceConnection; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -47,10 +46,10 @@ @SpringJUnitConfig @Testcontainers -@TestPropertySource(properties = { "spring.data.mongodb.database=simpleaidb", - "spring.ai.vectorstore.mongodb.initialize-schema=true", - "spring.ai.vectorstore.mongodb.collection-name=test_collection", - "spring.ai.vectorstore.mongodb.index-name=text_index" }) +@TestPropertySource( + properties = { "spring.mongodb.database=simpleaidb", "spring.ai.vectorstore.mongodb.initialize-schema=true", + "spring.ai.vectorstore.mongodb.collection-name=test_collection", + "spring.ai.vectorstore.mongodb.index-name=text_index" }) @EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") class MongoDbAtlasLocalContainerConnectionDetailsFactoryIT { @@ -94,8 +93,7 @@ public void addAndSearch() throws InterruptedException { } @Configuration(proxyBeanMethods = false) - @ImportAutoConfiguration({ MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, - MongoDBAtlasVectorStoreAutoConfiguration.class }) + @ImportAutoConfiguration({ MongoAutoConfiguration.class, MongoDBAtlasVectorStoreAutoConfiguration.class }) static class Config { @Bean diff --git a/spring-ai-spring-boot-testcontainers/src/test/java/org/springframework/ai/testcontainers/service/connection/ollama/OllamaContainerConnectionDetailsFactoryIT.java b/spring-ai-spring-boot-testcontainers/src/test/java/org/springframework/ai/testcontainers/service/connection/ollama/OllamaContainerConnectionDetailsFactoryIT.java index d3217fc2c8c..6c9dc470f93 100644 --- a/spring-ai-spring-boot-testcontainers/src/test/java/org/springframework/ai/testcontainers/service/connection/ollama/OllamaContainerConnectionDetailsFactoryIT.java +++ b/spring-ai-spring-boot-testcontainers/src/test/java/org/springframework/ai/testcontainers/service/connection/ollama/OllamaContainerConnectionDetailsFactoryIT.java @@ -33,7 +33,7 @@ import org.springframework.ai.ollama.OllamaEmbeddingModel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; +import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.testcontainers.service.connection.ServiceConnection; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.TestPropertySource; diff --git a/vector-stores/spring-ai-cassandra-store/pom.xml b/vector-stores/spring-ai-cassandra-store/pom.xml index 84682622655..7de6c15a6f8 100644 --- a/vector-stores/spring-ai-cassandra-store/pom.xml +++ b/vector-stores/spring-ai-cassandra-store/pom.xml @@ -74,6 +74,12 @@ test + + org.springframework.boot + spring-boot-starter-jdbc + test + + org.testcontainers junit-jupiter diff --git a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraRichSchemaVectorStoreIT.java b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraRichSchemaVectorStoreIT.java index 1db0398c1dd..48b0fa05b3b 100644 --- a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraRichSchemaVectorStoreIT.java +++ b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraRichSchemaVectorStoreIT.java @@ -50,7 +50,7 @@ import org.springframework.ai.vectorstore.cassandra.CassandraVectorStore.SchemaColumn; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; diff --git a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreIT.java b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreIT.java index 040f222e723..cc33f0148c0 100644 --- a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreIT.java +++ b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreIT.java @@ -50,7 +50,7 @@ import org.springframework.ai.vectorstore.filter.Filter; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; diff --git a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/WikiVectorStoreExample.java b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/WikiVectorStoreExample.java index 80d8b945fff..ff3803b16d9 100644 --- a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/WikiVectorStoreExample.java +++ b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/WikiVectorStoreExample.java @@ -32,7 +32,7 @@ import org.springframework.ai.vectorstore.cassandra.CassandraVectorStore.SchemaColumn; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; diff --git a/vector-stores/spring-ai-couchbase-store/pom.xml b/vector-stores/spring-ai-couchbase-store/pom.xml index 50b583b7b68..5a70a6ba3b7 100644 --- a/vector-stores/spring-ai-couchbase-store/pom.xml +++ b/vector-stores/spring-ai-couchbase-store/pom.xml @@ -59,6 +59,11 @@ spring-boot-testcontainers test + + org.springframework.boot + spring-boot-starter-jdbc + test + org.testcontainers couchbase diff --git a/vector-stores/spring-ai-couchbase-store/src/test/java/org/springframework/ai/vectorstore/CouchbaseSearchVectorStoreIT.java b/vector-stores/spring-ai-couchbase-store/src/test/java/org/springframework/ai/vectorstore/CouchbaseSearchVectorStoreIT.java index dba84ff4c9a..b6690292bac 100644 --- a/vector-stores/spring-ai-couchbase-store/src/test/java/org/springframework/ai/vectorstore/CouchbaseSearchVectorStoreIT.java +++ b/vector-stores/spring-ai-couchbase-store/src/test/java/org/springframework/ai/vectorstore/CouchbaseSearchVectorStoreIT.java @@ -45,7 +45,7 @@ import org.springframework.ai.vectorstore.testcontainer.CouchbaseContainerMetadata; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; diff --git a/vector-stores/spring-ai-elasticsearch-store/pom.xml b/vector-stores/spring-ai-elasticsearch-store/pom.xml index 7c64cbb1c5a..fcd3cbb92e0 100644 --- a/vector-stores/spring-ai-elasticsearch-store/pom.xml +++ b/vector-stores/spring-ai-elasticsearch-store/pom.xml @@ -76,6 +76,12 @@ test + + org.springframework.boot + spring-boot-starter-jdbc + test + + org.testcontainers elasticsearch diff --git a/vector-stores/spring-ai-elasticsearch-store/src/main/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStore.java b/vector-stores/spring-ai-elasticsearch-store/src/main/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStore.java index fc77e4f01f5..28446f75377 100644 --- a/vector-stores/spring-ai-elasticsearch-store/src/main/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStore.java +++ b/vector-stores/spring-ai-elasticsearch-store/src/main/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStore.java @@ -32,10 +32,10 @@ import co.elastic.clients.elasticsearch.core.search.Hit; import co.elastic.clients.json.jackson.JacksonJsonpMapper; import co.elastic.clients.transport.Version; -import co.elastic.clients.transport.rest_client.RestClientTransport; +import co.elastic.clients.transport.rest5_client.Rest5ClientTransport; +import co.elastic.clients.transport.rest5_client.low_level.Rest5Client; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; -import org.elasticsearch.client.RestClient; import org.springframework.ai.document.Document; import org.springframework.ai.document.DocumentMetadata; @@ -168,7 +168,7 @@ protected ElasticsearchVectorStore(Builder builder) { this.filterExpressionConverter = builder.filterExpressionConverter; String version = Version.VERSION == null ? "Unknown" : Version.VERSION.toString(); - this.elasticsearchClient = new ElasticsearchClient(new RestClientTransport(builder.restClient, + this.elasticsearchClient = new ElasticsearchClient(new Rest5ClientTransport(builder.restClient, new JacksonJsonpMapper( new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)))) .withTransportOptions(t -> t.addHeader("user-agent", "spring-ai elastic-java/" + version)); @@ -369,13 +369,13 @@ public Optional getNativeClient() { * Creates a new builder instance for ElasticsearchVectorStore. * @return a new ElasticsearchBuilder instance */ - public static Builder builder(RestClient restClient, EmbeddingModel embeddingModel) { + public static Builder builder(Rest5Client restClient, EmbeddingModel embeddingModel) { return new Builder(restClient, embeddingModel); } public static class Builder extends AbstractVectorStoreBuilder { - private final RestClient restClient; + private final Rest5Client restClient; private ElasticsearchVectorStoreOptions options = new ElasticsearchVectorStoreOptions(); @@ -388,7 +388,7 @@ public static class Builder extends AbstractVectorStoreBuilder { * @param restClient the Elasticsearch REST client * @param embeddingModel the Embedding Model to be used */ - public Builder(RestClient restClient, EmbeddingModel embeddingModel) { + public Builder(Rest5Client restClient, EmbeddingModel embeddingModel) { super(embeddingModel); Assert.notNull(restClient, "RestClient must not be null"); this.restClient = restClient; diff --git a/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreIT.java b/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreIT.java index f1f706539df..3703dd4c24d 100644 --- a/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreIT.java +++ b/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreIT.java @@ -17,6 +17,7 @@ package org.springframework.ai.vectorstore.elasticsearch; import java.io.IOException; +import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.ZonedDateTime; @@ -33,12 +34,13 @@ import co.elastic.clients.elasticsearch.cat.indices.IndicesRecord; import co.elastic.clients.elasticsearch.indices.stats.IndicesStats; import co.elastic.clients.json.jackson.JacksonJsonpMapper; +import co.elastic.clients.transport.rest5_client.Rest5ClientTransport; +import co.elastic.clients.transport.rest5_client.low_level.Rest5Client; import co.elastic.clients.transport.rest_client.RestClientTransport; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.http.HttpHost; +import org.apache.hc.core5.http.HttpHost; import org.awaitility.Awaitility; -import org.elasticsearch.client.RestClient; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -59,7 +61,7 @@ import org.springframework.ai.vectorstore.VectorStore; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.core.io.DefaultResourceLoader; @@ -108,7 +110,7 @@ void cleanDatabase() { getContextRunner().run(context -> { // deleting indices and data before following tests ElasticsearchClient elasticsearchClient = context.getBean(ElasticsearchClient.class); - List indices = elasticsearchClient.cat().indices().valueBody().stream().map(IndicesRecord::index).toList(); + var indices = elasticsearchClient.cat().indices().indices().stream().map(IndicesRecord::index).toList(); if (!indices.isEmpty()) { elasticsearchClient.indices().delete(del -> del.index(indices)); } @@ -478,12 +480,12 @@ public void getNativeClientTest() { public static class TestApplication { @Bean("vectorStore_cosine") - public ElasticsearchVectorStore vectorStoreDefault(EmbeddingModel embeddingModel, RestClient restClient) { + public ElasticsearchVectorStore vectorStoreDefault(EmbeddingModel embeddingModel, Rest5Client restClient) { return ElasticsearchVectorStore.builder(restClient, embeddingModel).initializeSchema(true).build(); } @Bean("vectorStore_l2_norm") - public ElasticsearchVectorStore vectorStoreL2(EmbeddingModel embeddingModel, RestClient restClient) { + public ElasticsearchVectorStore vectorStoreL2(EmbeddingModel embeddingModel, Rest5Client restClient) { ElasticsearchVectorStoreOptions options = new ElasticsearchVectorStoreOptions(); options.setIndexName("index_l2"); options.setSimilarity(SimilarityFunction.l2_norm); @@ -494,7 +496,7 @@ public ElasticsearchVectorStore vectorStoreL2(EmbeddingModel embeddingModel, Res } @Bean("vectorStore_dot_product") - public ElasticsearchVectorStore vectorStoreDotProduct(EmbeddingModel embeddingModel, RestClient restClient) { + public ElasticsearchVectorStore vectorStoreDotProduct(EmbeddingModel embeddingModel, Rest5Client restClient) { ElasticsearchVectorStoreOptions options = new ElasticsearchVectorStoreOptions(); options.setIndexName("index_dot_product"); options.setSimilarity(SimilarityFunction.dot_product); @@ -505,7 +507,7 @@ public ElasticsearchVectorStore vectorStoreDotProduct(EmbeddingModel embeddingMo } @Bean("vectorStore_custom_embedding_field") - public ElasticsearchVectorStore vectorStoreCustomField(EmbeddingModel embeddingModel, RestClient restClient) { + public ElasticsearchVectorStore vectorStoreCustomField(EmbeddingModel embeddingModel, Rest5Client restClient) { ElasticsearchVectorStoreOptions options = new ElasticsearchVectorStoreOptions(); options.setEmbeddingFieldName("custom_embedding_field"); return ElasticsearchVectorStore.builder(restClient, embeddingModel) @@ -520,13 +522,13 @@ public EmbeddingModel embeddingModel() { } @Bean - RestClient restClient() { - return RestClient.builder(HttpHost.create(elasticsearchContainer.getHttpHostAddress())).build(); + Rest5Client restClient() throws URISyntaxException { + return Rest5Client.builder(HttpHost.create(elasticsearchContainer.getHttpHostAddress())).build(); } @Bean - ElasticsearchClient elasticsearchClient(RestClient restClient) { - return new ElasticsearchClient(new RestClientTransport(restClient, new JacksonJsonpMapper( + ElasticsearchClient elasticsearchClient(Rest5Client restClient) { + return new ElasticsearchClient(new Rest5ClientTransport(restClient, new JacksonJsonpMapper( new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)))); } diff --git a/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreObservationIT.java b/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreObservationIT.java index 5efeeb1dd28..7ec1bfca2f9 100644 --- a/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreObservationIT.java @@ -17,6 +17,7 @@ package org.springframework.ai.vectorstore.elasticsearch; import java.io.IOException; +import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.List; @@ -26,15 +27,15 @@ import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.elasticsearch.cat.indices.IndicesRecord; import co.elastic.clients.json.jackson.JacksonJsonpMapper; -import co.elastic.clients.transport.rest_client.RestClientTransport; +import co.elastic.clients.transport.rest5_client.Rest5ClientTransport; +import co.elastic.clients.transport.rest5_client.low_level.Rest5Client; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.tck.TestObservationRegistry; import io.micrometer.observation.tck.TestObservationRegistryAssert; -import org.apache.http.HttpHost; +import org.apache.hc.core5.http.HttpHost; import org.awaitility.Awaitility; -import org.elasticsearch.client.RestClient; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -58,7 +59,7 @@ import org.springframework.ai.vectorstore.observation.VectorStoreObservationDocumentation.LowCardinalityKeyNames; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.core.io.DefaultResourceLoader; @@ -111,7 +112,7 @@ void cleanDatabase() { getContextRunner().run(context -> { // deleting indices and data before following tests ElasticsearchClient elasticsearchClient = context.getBean(ElasticsearchClient.class); - List indices = elasticsearchClient.cat().indices().valueBody().stream().map(IndicesRecord::index).toList(); + var indices = elasticsearchClient.cat().indices().indices().stream().map(IndicesRecord::index).toList(); if (!indices.isEmpty()) { elasticsearchClient.indices().delete(del -> del.index(indices)); } @@ -207,7 +208,7 @@ public TestObservationRegistry observationRegistry() { } @Bean - public ElasticsearchVectorStore vectorStoreDefault(EmbeddingModel embeddingModel, RestClient restClient, + public ElasticsearchVectorStore vectorStoreDefault(EmbeddingModel embeddingModel, Rest5Client restClient, ObservationRegistry observationRegistry) { return ElasticsearchVectorStore.builder(restClient, embeddingModel) .initializeSchema(true) @@ -224,13 +225,13 @@ public EmbeddingModel embeddingModel() { } @Bean - RestClient restClient() { - return RestClient.builder(HttpHost.create(elasticsearchContainer.getHttpHostAddress())).build(); + Rest5Client restClient() throws URISyntaxException { + return Rest5Client.builder(HttpHost.create(elasticsearchContainer.getHttpHostAddress())).build(); } @Bean - ElasticsearchClient elasticsearchClient(RestClient restClient) { - return new ElasticsearchClient(new RestClientTransport(restClient, new JacksonJsonpMapper( + ElasticsearchClient elasticsearchClient(Rest5Client restClient) { + return new ElasticsearchClient(new Rest5ClientTransport(restClient, new JacksonJsonpMapper( new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)))); } diff --git a/vector-stores/spring-ai-mariadb-store/pom.xml b/vector-stores/spring-ai-mariadb-store/pom.xml index cb440f3561d..4f72fe546ab 100644 --- a/vector-stores/spring-ai-mariadb-store/pom.xml +++ b/vector-stores/spring-ai-mariadb-store/pom.xml @@ -80,6 +80,12 @@ test + + org.springframework.boot + spring-boot-starter-jdbc + test + + org.testcontainers testcontainers diff --git a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreCustomNamesIT.java b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreCustomNamesIT.java index b69d945524f..3cd53141c6f 100644 --- a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreCustomNamesIT.java +++ b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreCustomNamesIT.java @@ -32,8 +32,8 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.ApplicationContext; diff --git a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreIT.java b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreIT.java index 96955dca876..0f26dae6161 100644 --- a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreIT.java +++ b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreIT.java @@ -53,8 +53,8 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.ApplicationContext; diff --git a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreObservationIT.java b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreObservationIT.java index 616078dae9f..2c42ee159df 100644 --- a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreObservationIT.java +++ b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreObservationIT.java @@ -47,8 +47,8 @@ import org.springframework.ai.vectorstore.observation.VectorStoreObservationDocumentation.LowCardinalityKeyNames; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; diff --git a/vector-stores/spring-ai-milvus-store/pom.xml b/vector-stores/spring-ai-milvus-store/pom.xml index e5031cb6388..0fb49d16130 100644 --- a/vector-stores/spring-ai-milvus-store/pom.xml +++ b/vector-stores/spring-ai-milvus-store/pom.xml @@ -70,6 +70,11 @@ test + + org.springframework.boot + spring-boot-starter-jdbc + test + org.springframework.boot diff --git a/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/milvus/MilvusVectorStoreCustomFieldNamesIT.java b/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/milvus/MilvusVectorStoreCustomFieldNamesIT.java index 14a8422441d..990bc982235 100644 --- a/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/milvus/MilvusVectorStoreCustomFieldNamesIT.java +++ b/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/milvus/MilvusVectorStoreCustomFieldNamesIT.java @@ -28,6 +28,7 @@ import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.milvus.MilvusContainer; @@ -42,7 +43,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.core.io.DefaultResourceLoader; diff --git a/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/milvus/MilvusVectorStoreIT.java b/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/milvus/MilvusVectorStoreIT.java index a367fa4068e..03d569ff268 100644 --- a/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/milvus/MilvusVectorStoreIT.java +++ b/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/milvus/MilvusVectorStoreIT.java @@ -40,6 +40,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.slf4j.LoggerFactory; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.milvus.MilvusContainer; @@ -57,7 +58,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.core.io.DefaultResourceLoader; diff --git a/vector-stores/spring-ai-neo4j-store/pom.xml b/vector-stores/spring-ai-neo4j-store/pom.xml index 478f57f1793..06b65cd2f2f 100644 --- a/vector-stores/spring-ai-neo4j-store/pom.xml +++ b/vector-stores/spring-ai-neo4j-store/pom.xml @@ -84,6 +84,12 @@ test + + org.springframework.boot + spring-boot-starter-jdbc + test + + org.testcontainers neo4j diff --git a/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreIT.java b/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreIT.java index b851269cb59..af751463fb5 100644 --- a/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreIT.java +++ b/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreIT.java @@ -46,7 +46,7 @@ import org.springframework.ai.vectorstore.filter.FilterExpressionTextParser; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; diff --git a/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreObservationIT.java b/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreObservationIT.java index 8ce003d7272..ee3b3117422 100644 --- a/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreObservationIT.java @@ -50,7 +50,7 @@ import org.springframework.ai.vectorstore.observation.VectorStoreObservationDocumentation.LowCardinalityKeyNames; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.core.io.DefaultResourceLoader; diff --git a/vector-stores/spring-ai-opensearch-store/pom.xml b/vector-stores/spring-ai-opensearch-store/pom.xml index 84387f1a7ec..08d973c4a2e 100644 --- a/vector-stores/spring-ai-opensearch-store/pom.xml +++ b/vector-stores/spring-ai-opensearch-store/pom.xml @@ -106,7 +106,13 @@ micrometer-observation-test test - + + + + org.springframework.boot + spring-boot-starter-jdbc + test + diff --git a/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreIT.java b/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreIT.java index 380d434c63b..e56c7de3bb9 100644 --- a/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreIT.java +++ b/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreIT.java @@ -55,7 +55,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.core.io.DefaultResourceLoader; diff --git a/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreObservationIT.java b/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreObservationIT.java index 13bf2eea1a3..5ef705c3a16 100644 --- a/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreObservationIT.java @@ -54,7 +54,7 @@ import org.springframework.ai.vectorstore.observation.VectorStoreObservationDocumentation.LowCardinalityKeyNames; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.core.io.DefaultResourceLoader; diff --git a/vector-stores/spring-ai-oracle-store/pom.xml b/vector-stores/spring-ai-oracle-store/pom.xml index 700e507407a..5f158b55106 100644 --- a/vector-stores/spring-ai-oracle-store/pom.xml +++ b/vector-stores/spring-ai-oracle-store/pom.xml @@ -95,6 +95,12 @@ test + + org.springframework.boot + spring-boot-starter-jdbc + test + + org.testcontainers testcontainers diff --git a/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreIT.java b/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreIT.java index a9bca5631a7..e10bf28817c 100644 --- a/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreIT.java +++ b/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreIT.java @@ -52,8 +52,8 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.ApplicationContext; diff --git a/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreObservationIT.java b/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreObservationIT.java index 066a0295ff6..b729524367a 100644 --- a/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreObservationIT.java @@ -48,8 +48,8 @@ import org.springframework.ai.vectorstore.oracle.OracleVectorStore.OracleVectorStoreDistanceType; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.ApplicationContext; diff --git a/vector-stores/spring-ai-pgvector-store/pom.xml b/vector-stores/spring-ai-pgvector-store/pom.xml index 92251350a7d..c8a2504436d 100644 --- a/vector-stores/spring-ai-pgvector-store/pom.xml +++ b/vector-stores/spring-ai-pgvector-store/pom.xml @@ -98,6 +98,12 @@ test + + org.springframework.boot + spring-boot-starter-jdbc + test + + org.testcontainers testcontainers diff --git a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreAutoTruncationIT.java b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreAutoTruncationIT.java index 819c72f294b..c5688dd9107 100644 --- a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreAutoTruncationIT.java +++ b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreAutoTruncationIT.java @@ -41,8 +41,8 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.ApplicationContext; diff --git a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreCustomNamesIT.java b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreCustomNamesIT.java index 56844743870..d1bf7186806 100644 --- a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreCustomNamesIT.java +++ b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreCustomNamesIT.java @@ -35,8 +35,8 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.ApplicationContext; diff --git a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreIT.java b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreIT.java index e8a75a00d2f..880cceaa675 100644 --- a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreIT.java +++ b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreIT.java @@ -56,8 +56,8 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.ApplicationContext; diff --git a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreObservationIT.java b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreObservationIT.java index 88cbe57520f..38b98e44d21 100644 --- a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreObservationIT.java @@ -49,8 +49,8 @@ import org.springframework.ai.vectorstore.pgvector.PgVectorStore.PgIndexType; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; diff --git a/vector-stores/spring-ai-redis-store/pom.xml b/vector-stores/spring-ai-redis-store/pom.xml index 6a536d76561..570e51e0ecb 100644 --- a/vector-stores/spring-ai-redis-store/pom.xml +++ b/vector-stores/spring-ai-redis-store/pom.xml @@ -75,6 +75,12 @@ test + + org.springframework.boot + spring-boot-starter-data-redis + test + + org.springframework.boot spring-boot-starter-test diff --git a/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreIT.java b/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreIT.java index 80b2b304614..0f2051cb562 100644 --- a/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreIT.java +++ b/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreIT.java @@ -45,8 +45,7 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.data.redis.autoconfigure.RedisAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.core.io.DefaultResourceLoader; @@ -317,7 +316,6 @@ void getNativeClientTest() { } @SpringBootConfiguration - @EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class }) public static class TestApplication { @Bean diff --git a/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreObservationIT.java b/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreObservationIT.java index 53e11eeb750..ffd8ade4fd5 100644 --- a/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreObservationIT.java @@ -47,7 +47,7 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.data.redis.autoconfigure.RedisAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.core.io.DefaultResourceLoader; diff --git a/vector-stores/spring-ai-typesense-store/pom.xml b/vector-stores/spring-ai-typesense-store/pom.xml index 5b7c650efeb..c4f918dd395 100644 --- a/vector-stores/spring-ai-typesense-store/pom.xml +++ b/vector-stores/spring-ai-typesense-store/pom.xml @@ -95,6 +95,11 @@ test + + org.springframework.boot + spring-boot-starter-jdbc + test + diff --git a/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreIT.java b/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreIT.java index 863f72fa00a..34fea59c09a 100644 --- a/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreIT.java +++ b/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreIT.java @@ -46,7 +46,7 @@ import org.springframework.ai.vectorstore.filter.Filter; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.core.io.DefaultResourceLoader;