diff --git a/advisors/spring-ai-advisors-vector-store/src/main/java/org/springframework/ai/chat/client/advisor/vectorstore/QuestionAnswerAdvisor.java b/advisors/spring-ai-advisors-vector-store/src/main/java/org/springframework/ai/chat/client/advisor/vectorstore/QuestionAnswerAdvisor.java index defb0574f24..8c301fbdd04 100644 --- a/advisors/spring-ai-advisors-vector-store/src/main/java/org/springframework/ai/chat/client/advisor/vectorstore/QuestionAnswerAdvisor.java +++ b/advisors/spring-ai-advisors-vector-store/src/main/java/org/springframework/ai/chat/client/advisor/vectorstore/QuestionAnswerAdvisor.java @@ -21,14 +21,14 @@ import java.util.Map; import java.util.stream.Collectors; +import reactor.core.scheduler.Scheduler; +import reactor.core.scheduler.Schedulers; + import org.springframework.ai.chat.client.ChatClientRequest; import org.springframework.ai.chat.client.ChatClientResponse; import org.springframework.ai.chat.client.advisor.api.AdvisorChain; import org.springframework.ai.chat.client.advisor.api.BaseAdvisor; import org.springframework.ai.chat.messages.UserMessage; -import reactor.core.scheduler.Scheduler; -import reactor.core.scheduler.Schedulers; - import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.prompt.PromptTemplate; import org.springframework.ai.document.Document; diff --git a/advisors/spring-ai-advisors-vector-store/src/main/java/org/springframework/ai/chat/client/advisor/vectorstore/VectorStoreChatMemoryAdvisor.java b/advisors/spring-ai-advisors-vector-store/src/main/java/org/springframework/ai/chat/client/advisor/vectorstore/VectorStoreChatMemoryAdvisor.java index 16bbe97f35e..2d44ba5bc05 100644 --- a/advisors/spring-ai-advisors-vector-store/src/main/java/org/springframework/ai/chat/client/advisor/vectorstore/VectorStoreChatMemoryAdvisor.java +++ b/advisors/spring-ai-advisors-vector-store/src/main/java/org/springframework/ai/chat/client/advisor/vectorstore/VectorStoreChatMemoryAdvisor.java @@ -21,7 +21,6 @@ import java.util.List; import java.util.Map; -import org.springframework.util.Assert; import reactor.core.scheduler.Scheduler; import org.springframework.ai.chat.client.ChatClientRequest; @@ -38,6 +37,7 @@ import org.springframework.ai.chat.prompt.PromptTemplate; import org.springframework.ai.document.Document; import org.springframework.ai.vectorstore.VectorStore; +import org.springframework.util.Assert; /** * Memory is retrieved from a VectorStore added into the prompt's system text. @@ -50,7 +50,7 @@ * @author Mark Pollack * @since 1.0.0 */ -public class VectorStoreChatMemoryAdvisor implements BaseChatMemoryAdvisor { +public final class VectorStoreChatMemoryAdvisor implements BaseChatMemoryAdvisor { public static final String TOP_K = "chat_memory_vector_store_top_k"; @@ -104,7 +104,7 @@ public static Builder builder(VectorStore chatMemory) { @Override public int getOrder() { - return order; + return this.order; } @Override diff --git a/advisors/spring-ai-advisors-vector-store/src/test/java/org/springframework/ai/chat/client/advisor/vectorstore/VectorStoreChatMemoryAdvisorTests.java b/advisors/spring-ai-advisors-vector-store/src/test/java/org/springframework/ai/chat/client/advisor/vectorstore/VectorStoreChatMemoryAdvisorTests.java index a8ec91282c0..749a4ffeef9 100644 --- a/advisors/spring-ai-advisors-vector-store/src/test/java/org/springframework/ai/chat/client/advisor/vectorstore/VectorStoreChatMemoryAdvisorTests.java +++ b/advisors/spring-ai-advisors-vector-store/src/test/java/org/springframework/ai/chat/client/advisor/vectorstore/VectorStoreChatMemoryAdvisorTests.java @@ -1,7 +1,24 @@ +/* + * Copyright 2025-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.ai.chat.client.advisor.vectorstore; import org.junit.jupiter.api.Test; import org.mockito.Mockito; + import org.springframework.ai.vectorstore.VectorStore; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-client/src/main/java/org/springframework/ai/mcp/client/autoconfigure/properties/McpClientCommonProperties.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-client/src/main/java/org/springframework/ai/mcp/client/autoconfigure/properties/McpClientCommonProperties.java index d05ca9e9e3b..c53720bbe00 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-client/src/main/java/org/springframework/ai/mcp/client/autoconfigure/properties/McpClientCommonProperties.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-client/src/main/java/org/springframework/ai/mcp/client/autoconfigure/properties/McpClientCommonProperties.java @@ -109,33 +109,6 @@ public enum ClientType { */ private Toolcallback toolcallback = new Toolcallback(); - /** - * Represents a callback configuration for tools. - *

- * This record is used to encapsulate the configuration for enabling or disabling tool - * callbacks in the MCP client. - * - * @param enabled A boolean flag indicating whether the tool callback is enabled. If - * true, the tool callback is active; otherwise, it is disabled. - */ - public static class Toolcallback { - - /** - * A boolean flag indicating whether the tool callback is enabled. If true, the - * tool callback is active; otherwise, it is disabled. - */ - private boolean enabled = true; - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public boolean isEnabled() { - return this.enabled; - } - - } - public boolean isEnabled() { return this.enabled; } @@ -193,11 +166,38 @@ public void setRootChangeNotification(boolean rootChangeNotification) { } public Toolcallback getToolcallback() { - return toolcallback; + return this.toolcallback; } public void setToolcallback(Toolcallback toolcallback) { this.toolcallback = toolcallback; } + /** + * Represents a callback configuration for tools. + *

+ * This record is used to encapsulate the configuration for enabling or disabling tool + * callbacks in the MCP client. + * + * @param enabled A boolean flag indicating whether the tool callback is enabled. If + * true, the tool callback is active; otherwise, it is disabled. + */ + public static class Toolcallback { + + /** + * A boolean flag indicating whether the tool callback is enabled. If true, the + * tool callback is active; otherwise, it is disabled. + */ + private boolean enabled = true; + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isEnabled() { + return this.enabled; + } + + } + } diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-client/src/test/java/org/springframework/ai/mcp/client/autoconfigure/properties/McpClientCommonPropertiesTests.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-client/src/test/java/org/springframework/ai/mcp/client/autoconfigure/properties/McpClientCommonPropertiesTests.java index 49d4c5dba8e..39c25c26327 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-client/src/test/java/org/springframework/ai/mcp/client/autoconfigure/properties/McpClientCommonPropertiesTests.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-client/src/test/java/org/springframework/ai/mcp/client/autoconfigure/properties/McpClientCommonPropertiesTests.java @@ -16,13 +16,14 @@ package org.springframework.ai.mcp.client.autoconfigure.properties; +import java.time.Duration; + import org.junit.jupiter.api.Test; + import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Configuration; -import java.time.Duration; - import static org.assertj.core.api.Assertions.assertThat; /** diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-client/src/test/java/org/springframework/ai/mcp/client/autoconfigure/properties/McpSseClientPropertiesTests.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-client/src/test/java/org/springframework/ai/mcp/client/autoconfigure/properties/McpSseClientPropertiesTests.java index 335ed26b3e1..4eb6dfa64cc 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-client/src/test/java/org/springframework/ai/mcp/client/autoconfigure/properties/McpSseClientPropertiesTests.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-client/src/test/java/org/springframework/ai/mcp/client/autoconfigure/properties/McpSseClientPropertiesTests.java @@ -16,13 +16,14 @@ package org.springframework.ai.mcp.client.autoconfigure.properties; +import java.util.Map; + import org.junit.jupiter.api.Test; + import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Configuration; -import java.util.Map; - import static org.assertj.core.api.Assertions.assertThat; /** diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerAutoConfiguration.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerAutoConfiguration.java index 9a1fb1eca5b..f57cc18dd35 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerAutoConfiguration.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerAutoConfiguration.java @@ -351,4 +351,4 @@ public McpAsyncServer mcpAsyncServer(McpServerTransportProvider transportProvide return serverBuilder.build(); } -} \ No newline at end of file +} diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpWebFluxServerAutoConfigurationTests.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpWebFluxServerAutoConfigurationTests.java index c89f2e337d6..87c4abaf258 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpWebFluxServerAutoConfigurationTests.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpWebFluxServerAutoConfigurationTests.java @@ -13,11 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.ai.mcp.server.autoconfigure; -import static org.assertj.core.api.Assertions.assertThat; +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.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -25,8 +27,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.web.reactive.function.server.RouterFunction; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.modelcontextprotocol.server.transport.WebFluxSseServerTransportProvider; +import static org.assertj.core.api.Assertions.assertThat; class McpWebFluxServerAutoConfigurationTests { @@ -36,7 +37,7 @@ class McpWebFluxServerAutoConfigurationTests { @Test void shouldConfigureWebFluxTransportWithCustomObjectMapper() { - this.contextRunner.run((context) -> { + this.contextRunner.run(context -> { assertThat(context).hasSingleBean(WebFluxSseServerTransportProvider.class); assertThat(context).hasSingleBean(RouterFunction.class); assertThat(context).hasSingleBean(McpServerProperties.class); @@ -48,6 +49,7 @@ void shouldConfigureWebFluxTransportWithCustomObjectMapper() { .isEnabled(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)).isFalse(); // Test with a JSON payload containing unknown fields + // CHECKSTYLE:OFF String jsonWithUnknownField = """ { "tools": ["tool1", "tool2"], @@ -55,6 +57,7 @@ void shouldConfigureWebFluxTransportWithCustomObjectMapper() { "unknownField": "value" } """; + // CHECKSTYLE:ON // This should not throw an exception TestMessage message = objectMapper.readValue(jsonWithUnknownField, TestMessage.class); @@ -75,7 +78,7 @@ static class TestMessage { private String name; public String getName() { - return name; + return this.name; } public void setName(String name) { diff --git a/auto-configurations/models/chat/client/spring-ai-autoconfigure-model-chat-client/src/main/java/org/springframework/ai/model/chat/client/autoconfigure/ChatClientAutoConfiguration.java b/auto-configurations/models/chat/client/spring-ai-autoconfigure-model-chat-client/src/main/java/org/springframework/ai/model/chat/client/autoconfigure/ChatClientAutoConfiguration.java index 9341ea1ae7b..32a09a85425 100644 --- a/auto-configurations/models/chat/client/spring-ai-autoconfigure-model-chat-client/src/main/java/org/springframework/ai/model/chat/client/autoconfigure/ChatClientAutoConfiguration.java +++ b/auto-configurations/models/chat/client/spring-ai-autoconfigure-model-chat-client/src/main/java/org/springframework/ai/model/chat/client/autoconfigure/ChatClientAutoConfiguration.java @@ -20,6 +20,7 @@ import io.micrometer.tracing.Tracer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.ChatClientCustomizer; import org.springframework.ai.chat.client.observation.ChatClientObservationContext; @@ -30,7 +31,11 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.*; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/auto-configurations/models/chat/client/spring-ai-autoconfigure-model-chat-client/src/test/java/org/springframework/ai/model/chat/client/autoconfigure/ChatClientObservationAutoConfigurationTests.java b/auto-configurations/models/chat/client/spring-ai-autoconfigure-model-chat-client/src/test/java/org/springframework/ai/model/chat/client/autoconfigure/ChatClientObservationAutoConfigurationTests.java index 3ef9454d351..94b18d1fa83 100644 --- a/auto-configurations/models/chat/client/spring-ai-autoconfigure-model-chat-client/src/test/java/org/springframework/ai/model/chat/client/autoconfigure/ChatClientObservationAutoConfigurationTests.java +++ b/auto-configurations/models/chat/client/spring-ai-autoconfigure-model-chat-client/src/test/java/org/springframework/ai/model/chat/client/autoconfigure/ChatClientObservationAutoConfigurationTests.java @@ -19,6 +19,7 @@ import io.micrometer.tracing.Tracer; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.ai.chat.client.observation.ChatClientObservationContext; import org.springframework.ai.chat.client.observation.ChatClientPromptContentObservationHandler; import org.springframework.ai.observation.TracingAwareLoggingObservationHandler; 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 c269264d093..e55bc82cea5 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 @@ -18,8 +18,8 @@ import com.datastax.oss.driver.api.core.CqlSession; -import org.springframework.ai.chat.memory.repository.cassandra.CassandraChatMemoryRepositoryConfig; import org.springframework.ai.chat.memory.repository.cassandra.CassandraChatMemoryRepository; +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; 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 6db6e034423..17bed069754 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 @@ -18,8 +18,8 @@ import javax.sql.DataSource; -import org.springframework.ai.chat.memory.repository.jdbc.JdbcChatMemoryRepositoryDialect; import org.springframework.ai.chat.memory.repository.jdbc.JdbcChatMemoryRepository; +import org.springframework.ai.chat.memory.repository.jdbc.JdbcChatMemoryRepositoryDialect; import org.springframework.ai.model.chat.memory.autoconfigure.ChatMemoryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 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/JdbcChatMemoryRepositoryProperties.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/JdbcChatMemoryRepositoryProperties.java index 9ff1697a447..088208ac65b 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/JdbcChatMemoryRepositoryProperties.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/JdbcChatMemoryRepositoryProperties.java @@ -59,7 +59,7 @@ public void setInitializeSchema(DatabaseInitializationMode initializeSchema) { } public String getPlatform() { - return platform; + return this.platform; } public void setPlatform(String platform) { 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 1572ddd6944..90c32235f80 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 @@ -74,11 +74,11 @@ public void setUp() { // Debug: Print current schemas and tables try { - List schemas = jdbcTemplate.queryForList("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA", - String.class); + List schemas = this.jdbcTemplate + .queryForList("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA", String.class); System.out.println("Available schemas: " + schemas); - List tables = jdbcTemplate + List tables = this.jdbcTemplate .queryForList("SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES", String.class); System.out.println("Available tables: " + tables); } @@ -89,22 +89,22 @@ public void setUp() { // Try a more direct approach with explicit SQL statements try { // Drop the table first if it exists to avoid any conflicts - jdbcTemplate.execute("DROP TABLE SPRING_AI_CHAT_MEMORY IF EXISTS"); + this.jdbcTemplate.execute("DROP TABLE SPRING_AI_CHAT_MEMORY IF EXISTS"); System.out.println("Dropped existing table if it existed"); // Create the table with a simplified schema - jdbcTemplate.execute("CREATE TABLE SPRING_AI_CHAT_MEMORY (" + "conversation_id VARCHAR(36) NOT NULL, " - + "content LONGVARCHAR NOT NULL, " + "type VARCHAR(10) NOT NULL, " - + "timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL)"); + this.jdbcTemplate.execute("CREATE TABLE SPRING_AI_CHAT_MEMORY (" + + "conversation_id VARCHAR(36) NOT NULL, " + "content LONGVARCHAR NOT NULL, " + + "type VARCHAR(10) NOT NULL, " + "timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL)"); System.out.println("Created table with simplified schema"); // Create index - jdbcTemplate.execute( + this.jdbcTemplate.execute( "CREATE INDEX SPRING_AI_CHAT_MEMORY_IDX ON SPRING_AI_CHAT_MEMORY(conversation_id, timestamp DESC)"); System.out.println("Created index"); // Verify table was created - boolean tableExists = jdbcTemplate.queryForObject( + boolean tableExists = this.jdbcTemplate.queryForObject( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'SPRING_AI_CHAT_MEMORY'", Integer.class) > 0; System.out.println("Table SPRING_AI_CHAT_MEMORY exists after creation: " + tableExists); @@ -125,7 +125,7 @@ public void setUp() { @Test public void useAutoConfiguredChatMemoryWithJdbc() { // Check that the custom schema initializer is present - assertThat(context.containsBean("jdbcChatMemoryScriptDatabaseInitializer")).isTrue(); + assertThat(this.context.containsBean("jdbcChatMemoryScriptDatabaseInitializer")).isTrue(); // Debug: List all schema-hsqldb.sql resources on the classpath try { @@ -144,7 +144,7 @@ public void useAutoConfiguredChatMemoryWithJdbc() { // Verify the table exists by executing a direct query try { - boolean tableExists = jdbcTemplate.queryForObject( + boolean tableExists = this.jdbcTemplate.queryForObject( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'SPRING_AI_CHAT_MEMORY'", Integer.class) > 0; System.out.println("Table SPRING_AI_CHAT_MEMORY exists: " + tableExists); @@ -157,10 +157,10 @@ public void useAutoConfiguredChatMemoryWithJdbc() { } // Now test the ChatMemory functionality - assertThat(context.getBean(org.springframework.ai.chat.memory.ChatMemory.class)).isNotNull(); - assertThat(context.getBean(JdbcChatMemoryRepository.class)).isNotNull(); + assertThat(this.context.getBean(org.springframework.ai.chat.memory.ChatMemory.class)).isNotNull(); + assertThat(this.context.getBean(JdbcChatMemoryRepository.class)).isNotNull(); - var chatMemory = context.getBean(org.springframework.ai.chat.memory.ChatMemory.class); + var chatMemory = this.context.getBean(org.springframework.ai.chat.memory.ChatMemory.class); var conversationId = java.util.UUID.randomUUID().toString(); var userMessage = new UserMessage("Message from the user"); 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 b7bce37f637..db75aa22d5d 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 @@ -55,12 +55,14 @@ void jdbcChatMemoryScriptDatabaseInitializer_shouldBeLoaded() { @Test void jdbcChatMemoryScriptDatabaseInitializer_shouldNotRunSchemaInit() { + // CHECKSTYLE:OFF this.contextRunner.withPropertyValues("spring.ai.chat.memory.repository.jdbc.initialize-schema=never") .run(context -> { assertThat(context).doesNotHaveBean("jdbcChatMemoryScriptDatabaseInitializer"); // Optionally, check that the schema is not initialized (could check table // absence if needed) }); + // CHECKSTYLE:ON } @Test 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 7638d65917a..a3bf69410ac 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 @@ -1,6 +1,19 @@ /* - * Integration test for SQL Server using Testcontainers, following the same structure as the PostgreSQL test. + * Copyright 2024-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + package org.springframework.ai.model.chat.memory.repository.jdbc.autoconfigure; import java.time.Duration; @@ -8,6 +21,10 @@ import java.util.UUID; import org.junit.jupiter.api.Test; +import org.testcontainers.containers.MSSQLServerContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.ai.chat.memory.repository.jdbc.JdbcChatMemoryRepository; @@ -19,13 +36,12 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.testcontainers.containers.MSSQLServerContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.utility.DockerImageName; import static org.assertj.core.api.Assertions.assertThat; +/* + * Integration test for SQL Server using Testcontainers, following the same structure as the PostgreSQL test. + */ @Testcontainers class JdbcChatMemoryRepositorySqlServerAutoConfigurationIT { @@ -58,9 +74,7 @@ void jdbcChatMemoryScriptDatabaseInitializer_shouldBeLoaded() { @Test void jdbcChatMemoryScriptDatabaseInitializer_shouldNotRunSchemaInit() { this.contextRunner.withPropertyValues("spring.ai.chat.memory.repository.jdbc.initialize-schema=never") - .run(context -> { - assertThat(context).doesNotHaveBean("jdbcChatMemoryScriptDatabaseInitializer"); - }); + .run(context -> assertThat(context).doesNotHaveBean("jdbcChatMemoryScriptDatabaseInitializer")); } @Test 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 85a09532611..970cb6be91c 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 @@ -18,8 +18,8 @@ import org.neo4j.driver.Driver; -import org.springframework.ai.chat.memory.repository.neo4j.Neo4jChatMemoryRepositoryConfig; import org.springframework.ai.chat.memory.repository.neo4j.Neo4jChatMemoryRepository; +import org.springframework.ai.chat.memory.repository.neo4j.Neo4jChatMemoryRepositoryConfig; import org.springframework.ai.model.chat.memory.autoconfigure.ChatMemoryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 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 a7e7ad16b07..236fb2cc011 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 @@ -23,14 +23,13 @@ import java.util.UUID; import org.junit.jupiter.api.Test; - -import org.springframework.ai.chat.memory.ChatMemoryRepository; -import org.springframework.ai.chat.memory.repository.neo4j.Neo4jChatMemoryRepository; import org.testcontainers.containers.Neo4jContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.utility.DockerImageName; +import org.springframework.ai.chat.memory.ChatMemoryRepository; +import org.springframework.ai.chat.memory.repository.neo4j.Neo4jChatMemoryRepository; import org.springframework.ai.chat.memory.repository.neo4j.Neo4jChatMemoryRepositoryConfig; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; diff --git a/auto-configurations/models/chat/memory/spring-ai-autoconfigure-model-chat-memory/src/test/java/org/springframework/ai/model/chat/memory/autoconfigure/ChatMemoryAutoConfigurationTests.java b/auto-configurations/models/chat/memory/spring-ai-autoconfigure-model-chat-memory/src/test/java/org/springframework/ai/model/chat/memory/autoconfigure/ChatMemoryAutoConfigurationTests.java index e40ba588808..60e29089cd7 100644 --- a/auto-configurations/models/chat/memory/spring-ai-autoconfigure-model-chat-memory/src/test/java/org/springframework/ai/model/chat/memory/autoconfigure/ChatMemoryAutoConfigurationTests.java +++ b/auto-configurations/models/chat/memory/spring-ai-autoconfigure-model-chat-memory/src/test/java/org/springframework/ai/model/chat/memory/autoconfigure/ChatMemoryAutoConfigurationTests.java @@ -17,6 +17,7 @@ package org.springframework.ai.model.chat.memory.autoconfigure; import org.junit.jupiter.api.Test; + import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.ai.chat.memory.ChatMemoryRepository; import org.springframework.ai.chat.memory.InMemoryChatMemoryRepository; @@ -40,7 +41,7 @@ class ChatMemoryAutoConfigurationTests { @Test void defaultConfiguration() { - contextRunner.run(context -> { + this.contextRunner.run(context -> { assertThat(context).hasSingleBean(ChatMemoryRepository.class); assertThat(context).hasSingleBean(ChatMemory.class); }); @@ -48,7 +49,7 @@ void defaultConfiguration() { @Test void whenChatMemoryRepositoryExists() { - contextRunner.withUserConfiguration(CustomChatMemoryRepositoryConfiguration.class).run(context -> { + this.contextRunner.withUserConfiguration(CustomChatMemoryRepositoryConfiguration.class).run(context -> { assertThat(context).hasSingleBean(ChatMemoryRepository.class); assertThat(context).hasBean("customChatMemoryRepository"); assertThat(context).doesNotHaveBean("chatMemoryRepository"); @@ -57,7 +58,7 @@ void whenChatMemoryRepositoryExists() { @Test void whenChatMemoryExists() { - contextRunner.withUserConfiguration(CustomChatMemoryRepositoryConfiguration.class).run(context -> { + this.contextRunner.withUserConfiguration(CustomChatMemoryRepositoryConfiguration.class).run(context -> { assertThat(context).hasSingleBean(ChatMemoryRepository.class); assertThat(context).hasBean("customChatMemoryRepository"); assertThat(context).doesNotHaveBean("chatMemoryRepository"); @@ -71,7 +72,7 @@ static class CustomChatMemoryRepositoryConfiguration { @Bean ChatMemoryRepository customChatMemoryRepository() { - return customChatMemoryRepository; + return this.customChatMemoryRepository; } } @@ -83,7 +84,7 @@ static class CustomChatMemoryConfiguration { @Bean ChatMemory customChatMemory() { - return customChatMemory; + return this.customChatMemory; } } diff --git a/auto-configurations/models/chat/observation/spring-ai-autoconfigure-model-chat-observation/src/main/java/org/springframework/ai/model/chat/observation/autoconfigure/ChatObservationAutoConfiguration.java b/auto-configurations/models/chat/observation/spring-ai-autoconfigure-model-chat-observation/src/main/java/org/springframework/ai/model/chat/observation/autoconfigure/ChatObservationAutoConfiguration.java index d2471040c49..02193e15d49 100644 --- a/auto-configurations/models/chat/observation/spring-ai-autoconfigure-model-chat-observation/src/main/java/org/springframework/ai/model/chat/observation/autoconfigure/ChatObservationAutoConfiguration.java +++ b/auto-configurations/models/chat/observation/spring-ai-autoconfigure-model-chat-observation/src/main/java/org/springframework/ai/model/chat/observation/autoconfigure/ChatObservationAutoConfiguration.java @@ -16,10 +16,13 @@ package org.springframework.ai.model.chat.observation.autoconfigure; +import java.util.List; + import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.tracing.Tracer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.ai.chat.client.advisor.observation.AdvisorObservationContext; import org.springframework.ai.chat.client.observation.ChatClientObservationContext; import org.springframework.ai.chat.model.ChatModel; @@ -33,13 +36,15 @@ import org.springframework.ai.observation.TracingAwareLoggingObservationHandler; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.condition.*; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.List; - /** * Auto-configuration for Spring AI chat model observations. * diff --git a/auto-configurations/models/chat/observation/spring-ai-autoconfigure-model-chat-observation/src/test/java/org/springframework/ai/model/chat/observation/autoconfigure/ChatObservationAutoConfigurationTests.java b/auto-configurations/models/chat/observation/spring-ai-autoconfigure-model-chat-observation/src/test/java/org/springframework/ai/model/chat/observation/autoconfigure/ChatObservationAutoConfigurationTests.java index 1db3a52030a..2209029a1d4 100644 --- a/auto-configurations/models/chat/observation/spring-ai-autoconfigure-model-chat-observation/src/test/java/org/springframework/ai/model/chat/observation/autoconfigure/ChatObservationAutoConfigurationTests.java +++ b/auto-configurations/models/chat/observation/spring-ai-autoconfigure-model-chat-observation/src/test/java/org/springframework/ai/model/chat/observation/autoconfigure/ChatObservationAutoConfigurationTests.java @@ -16,10 +16,13 @@ package org.springframework.ai.model.chat.observation.autoconfigure; +import java.util.List; + import io.micrometer.core.instrument.composite.CompositeMeterRegistry; import io.micrometer.tracing.Tracer; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.ai.chat.client.observation.ChatClientObservationContext; import org.springframework.ai.chat.observation.ChatModelCompletionObservationHandler; import org.springframework.ai.chat.observation.ChatModelMeterObservationHandler; @@ -35,8 +38,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; diff --git a/auto-configurations/models/image/observation/spring-ai-autoconfigure-model-image-observation/src/main/java/org/springframework/ai/model/image/observation/autoconfigure/ImageObservationAutoConfiguration.java b/auto-configurations/models/image/observation/spring-ai-autoconfigure-model-image-observation/src/main/java/org/springframework/ai/model/image/observation/autoconfigure/ImageObservationAutoConfiguration.java index e2efd755b8f..24321a38818 100644 --- a/auto-configurations/models/image/observation/spring-ai-autoconfigure-model-image-observation/src/main/java/org/springframework/ai/model/image/observation/autoconfigure/ImageObservationAutoConfiguration.java +++ b/auto-configurations/models/image/observation/spring-ai-autoconfigure-model-image-observation/src/main/java/org/springframework/ai/model/image/observation/autoconfigure/ImageObservationAutoConfiguration.java @@ -19,12 +19,17 @@ import io.micrometer.tracing.Tracer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.ai.image.ImageModel; import org.springframework.ai.image.observation.ImageModelObservationContext; import org.springframework.ai.image.observation.ImageModelPromptContentObservationHandler; import org.springframework.ai.observation.TracingAwareLoggingObservationHandler; import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.condition.*; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/auto-configurations/models/image/observation/spring-ai-autoconfigure-model-image-observation/src/test/java/org/springframework/ai/model/image/observation/autoconfigure/ImageObservationAutoConfigurationTests.java b/auto-configurations/models/image/observation/spring-ai-autoconfigure-model-image-observation/src/test/java/org/springframework/ai/model/image/observation/autoconfigure/ImageObservationAutoConfigurationTests.java index 3fa18e799b5..ce40670a001 100644 --- a/auto-configurations/models/image/observation/spring-ai-autoconfigure-model-image-observation/src/test/java/org/springframework/ai/model/image/observation/autoconfigure/ImageObservationAutoConfigurationTests.java +++ b/auto-configurations/models/image/observation/spring-ai-autoconfigure-model-image-observation/src/test/java/org/springframework/ai/model/image/observation/autoconfigure/ImageObservationAutoConfigurationTests.java @@ -19,6 +19,7 @@ import io.micrometer.tracing.Tracer; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.ai.image.observation.ImageModelObservationContext; import org.springframework.ai.image.observation.ImageModelPromptContentObservationHandler; import org.springframework.ai.observation.TracingAwareLoggingObservationHandler; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-bedrock-ai/src/main/java/org/springframework/ai/model/bedrock/titan/autoconfigure/BedrockTitanEmbeddingAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-bedrock-ai/src/main/java/org/springframework/ai/model/bedrock/titan/autoconfigure/BedrockTitanEmbeddingAutoConfiguration.java index 244f6722a8f..6d0ed14bfb2 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-bedrock-ai/src/main/java/org/springframework/ai/model/bedrock/titan/autoconfigure/BedrockTitanEmbeddingAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-bedrock-ai/src/main/java/org/springframework/ai/model/bedrock/titan/autoconfigure/BedrockTitanEmbeddingAutoConfiguration.java @@ -17,7 +17,6 @@ package org.springframework.ai.model.bedrock.titan.autoconfigure; import com.fasterxml.jackson.databind.ObjectMapper; - import io.micrometer.observation.ObservationRegistry; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.regions.providers.AwsRegionProvider; 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 59507a46c11..23515e416f2 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 @@ -17,10 +17,11 @@ package org.springframework.ai.model.deepseek.autoconfigure; import io.micrometer.observation.ObservationRegistry; + import org.springframework.ai.chat.observation.ChatModelObservationConvention; -import org.springframework.ai.model.SimpleApiKey; import org.springframework.ai.deepseek.DeepSeekChatModel; import org.springframework.ai.deepseek.api.DeepSeekApi; +import org.springframework.ai.model.SimpleApiKey; import org.springframework.ai.model.SpringAIModelProperties; import org.springframework.ai.model.SpringAIModels; import org.springframework.ai.model.tool.DefaultToolExecutionEligibilityPredicate; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/main/java/org/springframework/ai/model/deepseek/autoconfigure/DeepSeekChatProperties.java b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/main/java/org/springframework/ai/model/deepseek/autoconfigure/DeepSeekChatProperties.java index df48de3e7bf..ae1ea7c7779 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/main/java/org/springframework/ai/model/deepseek/autoconfigure/DeepSeekChatProperties.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/main/java/org/springframework/ai/model/deepseek/autoconfigure/DeepSeekChatProperties.java @@ -71,7 +71,7 @@ public void setEnabled(boolean enabled) { } public String getCompletionsPath() { - return completionsPath; + return this.completionsPath; } public void setCompletionsPath(String completionsPath) { @@ -79,7 +79,7 @@ public void setCompletionsPath(String completionsPath) { } public String getBetaPrefixPath() { - return betaPrefixPath; + return this.betaPrefixPath; } public void setBetaPrefixPath(String betaPrefixPath) { diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/DeepSeekAutoConfigurationIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/DeepSeekAutoConfigurationIT.java index a433f558481..22d0678e96b 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/DeepSeekAutoConfigurationIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/DeepSeekAutoConfigurationIT.java @@ -16,10 +16,15 @@ package org.springframework.ai.model.deepseek.autoconfigure; +import java.util.Objects; +import java.util.stream.Collectors; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; +import reactor.core.publisher.Flux; + import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; @@ -28,10 +33,6 @@ import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import reactor.core.publisher.Flux; - -import java.util.Objects; -import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/DeepSeekPropertiesTests.java b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/DeepSeekPropertiesTests.java index 01d3fa30073..8e1d1322242 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/DeepSeekPropertiesTests.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/DeepSeekPropertiesTests.java @@ -17,6 +17,7 @@ package org.springframework.ai.model.deepseek.autoconfigure; import org.junit.jupiter.api.Test; + import org.springframework.ai.deepseek.DeepSeekChatModel; import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/tool/DeepSeekFunctionCallbackIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/tool/DeepSeekFunctionCallbackIT.java index bd4fa91856c..2a5cb68a129 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/tool/DeepSeekFunctionCallbackIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/tool/DeepSeekFunctionCallbackIT.java @@ -16,10 +16,16 @@ package org.springframework.ai.model.deepseek.autoconfigure.tool; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; + import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.model.ChatResponse; @@ -36,11 +42,6 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import reactor.core.publisher.Flux; - -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/tool/FunctionCallbackInPromptIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/tool/FunctionCallbackInPromptIT.java index 47f750e3904..f3accd5ffa0 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/tool/FunctionCallbackInPromptIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/tool/FunctionCallbackInPromptIT.java @@ -16,10 +16,15 @@ package org.springframework.ai.model.deepseek.autoconfigure.tool; +import java.util.List; +import java.util.stream.Collectors; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; + import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.model.ChatResponse; @@ -31,10 +36,6 @@ import org.springframework.ai.tool.function.FunctionToolCallback; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import reactor.core.publisher.Flux; - -import java.util.List; -import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/tool/FunctionCallbackWithPlainFunctionBeanIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/tool/FunctionCallbackWithPlainFunctionBeanIT.java index bcb514bf13e..c6fb1d8527c 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/tool/FunctionCallbackWithPlainFunctionBeanIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/tool/FunctionCallbackWithPlainFunctionBeanIT.java @@ -16,10 +16,16 @@ package org.springframework.ai.model.deepseek.autoconfigure.tool; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; + import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.model.ChatResponse; @@ -34,11 +40,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Description; -import reactor.core.publisher.Flux; - -import java.util.List; -import java.util.function.Function; -import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/tool/MockWeatherService.java b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/tool/MockWeatherService.java index cc8fa2fe5e9..0087311229e 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/tool/MockWeatherService.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-deepseek/src/test/java/org/springframework/ai/model/deepseek/autoconfigure/tool/MockWeatherService.java @@ -16,14 +16,14 @@ package org.springframework.ai.model.deepseek.autoconfigure.tool; +import java.util.function.Function; + import com.fasterxml.jackson.annotation.JsonClassDescription; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyDescription; -import java.util.function.Function; - /** * Mock 3rd party weather service. * diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiImageProperties.java b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiImageProperties.java index 43b80f52f8e..4d81c17327b 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiImageProperties.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/model/openai/autoconfigure/OpenAiImageProperties.java @@ -54,7 +54,7 @@ public void setOptions(OpenAiImageOptions options) { } public String getImagesPath() { - return imagesPath; + return this.imagesPath; } public void setImagesPath(String imagesPath) { diff --git a/auto-configurations/models/tool/spring-ai-autoconfigure-model-tool/src/main/java/org/springframework/ai/model/tool/autoconfigure/ToolCallingAutoConfiguration.java b/auto-configurations/models/tool/spring-ai-autoconfigure-model-tool/src/main/java/org/springframework/ai/model/tool/autoconfigure/ToolCallingAutoConfiguration.java index 4186ce0f806..bdc647db8f7 100644 --- a/auto-configurations/models/tool/spring-ai-autoconfigure-model-tool/src/main/java/org/springframework/ai/model/tool/autoconfigure/ToolCallingAutoConfiguration.java +++ b/auto-configurations/models/tool/spring-ai-autoconfigure-model-tool/src/main/java/org/springframework/ai/model/tool/autoconfigure/ToolCallingAutoConfiguration.java @@ -16,9 +16,13 @@ package org.springframework.ai.model.tool.autoconfigure; +import java.util.ArrayList; +import java.util.List; + import io.micrometer.observation.ObservationRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.model.tool.ToolCallingManager; import org.springframework.ai.tool.ToolCallback; @@ -40,9 +44,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.support.GenericApplicationContext; -import java.util.ArrayList; -import java.util.List; - /** * Auto-configuration for common tool calling features of {@link ChatModel}. * diff --git a/auto-configurations/models/tool/spring-ai-autoconfigure-model-tool/src/main/java/org/springframework/ai/model/tool/autoconfigure/ToolCallingProperties.java b/auto-configurations/models/tool/spring-ai-autoconfigure-model-tool/src/main/java/org/springframework/ai/model/tool/autoconfigure/ToolCallingProperties.java index 0037a45b6a9..8511baad413 100644 --- a/auto-configurations/models/tool/spring-ai-autoconfigure-model-tool/src/main/java/org/springframework/ai/model/tool/autoconfigure/ToolCallingProperties.java +++ b/auto-configurations/models/tool/spring-ai-autoconfigure-model-tool/src/main/java/org/springframework/ai/model/tool/autoconfigure/ToolCallingProperties.java @@ -39,7 +39,7 @@ public static class Observations { private boolean includeContent = false; public boolean isIncludeContent() { - return includeContent; + return this.includeContent; } public void setIncludeContent(boolean includeContent) { diff --git a/auto-configurations/models/tool/spring-ai-autoconfigure-model-tool/src/test/java/org/springframework/ai/model/tool/autoconfigure/ToolCallingAutoConfigurationTests.java b/auto-configurations/models/tool/spring-ai-autoconfigure-model-tool/src/test/java/org/springframework/ai/model/tool/autoconfigure/ToolCallingAutoConfigurationTests.java index 3be8374058f..0b7b638160f 100644 --- a/auto-configurations/models/tool/spring-ai-autoconfigure-model-tool/src/test/java/org/springframework/ai/model/tool/autoconfigure/ToolCallingAutoConfigurationTests.java +++ b/auto-configurations/models/tool/spring-ai-autoconfigure-model-tool/src/test/java/org/springframework/ai/model/tool/autoconfigure/ToolCallingAutoConfigurationTests.java @@ -116,9 +116,7 @@ void resolveMissingToolCallbacks() { void observationFilterDefault() { new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class)) .withUserConfiguration(Config.class) - .run(context -> { - assertThat(context).doesNotHaveBean(ToolCallingContentObservationFilter.class); - }); + .run(context -> assertThat(context).doesNotHaveBean(ToolCallingContentObservationFilter.class)); } @Test @@ -126,9 +124,7 @@ void observationFilterEnabled() { new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class)) .withPropertyValues("spring.ai.tools.observations.include-content=true") .withUserConfiguration(Config.class) - .run(context -> { - assertThat(context).hasSingleBean(ToolCallingContentObservationFilter.class); - }); + .run(context -> assertThat(context).hasSingleBean(ToolCallingContentObservationFilter.class)); } static class WeatherService { diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db/src/main/java/org/springframework/ai/vectorstore/cosmosdb/autoconfigure/CosmosDBVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db/src/main/java/org/springframework/ai/vectorstore/cosmosdb/autoconfigure/CosmosDBVectorStoreAutoConfiguration.java index 2bb9f8dfd93..02b767a10ba 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db/src/main/java/org/springframework/ai/vectorstore/cosmosdb/autoconfigure/CosmosDBVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db/src/main/java/org/springframework/ai/vectorstore/cosmosdb/autoconfigure/CosmosDBVectorStoreAutoConfiguration.java @@ -64,7 +64,7 @@ else if (!mode.equals("direct") && !mode.equals("gateway")) { } CosmosClientBuilder builder = new CosmosClientBuilder().endpoint(properties.getEndpoint()) - .userAgentSuffix(agentSuffix); + .userAgentSuffix(this.agentSuffix); if (properties.getKey() == null || properties.getKey().isEmpty()) { builder.credential(new DefaultAzureCredentialBuilder().build()); diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db/src/main/java/org/springframework/ai/vectorstore/cosmosdb/autoconfigure/CosmosDBVectorStoreProperties.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db/src/main/java/org/springframework/ai/vectorstore/cosmosdb/autoconfigure/CosmosDBVectorStoreProperties.java index ce84aa6eb23..345cff291ea 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db/src/main/java/org/springframework/ai/vectorstore/cosmosdb/autoconfigure/CosmosDBVectorStoreProperties.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db/src/main/java/org/springframework/ai/vectorstore/cosmosdb/autoconfigure/CosmosDBVectorStoreProperties.java @@ -16,12 +16,12 @@ package org.springframework.ai.vectorstore.cosmosdb.autoconfigure; -import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties; -import org.springframework.boot.context.properties.ConfigurationProperties; - import java.util.Arrays; import java.util.List; +import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; + /** * Configuration properties for CosmosDB Vector Store. * diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-chroma/src/main/java/org/springframework/ai/vectorstore/chroma/autoconfigure/ChromaVectorStoreProperties.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-chroma/src/main/java/org/springframework/ai/vectorstore/chroma/autoconfigure/ChromaVectorStoreProperties.java index 92931fe83a0..d901775f565 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-chroma/src/main/java/org/springframework/ai/vectorstore/chroma/autoconfigure/ChromaVectorStoreProperties.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-chroma/src/main/java/org/springframework/ai/vectorstore/chroma/autoconfigure/ChromaVectorStoreProperties.java @@ -39,7 +39,7 @@ public class ChromaVectorStoreProperties extends CommonVectorStoreProperties { private String collectionName = ChromaApiConstants.DEFAULT_COLLECTION_NAME; public String getTenantName() { - return tenantName; + return this.tenantName; } public void setTenantName(String tenantName) { @@ -47,7 +47,7 @@ public void setTenantName(String tenantName) { } public String getDatabaseName() { - return databaseName; + return this.databaseName; } public void setDatabaseName(String databaseName) { diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-observation/src/main/java/org/springframework/ai/vectorstore/observation/autoconfigure/VectorStoreObservationAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-observation/src/main/java/org/springframework/ai/vectorstore/observation/autoconfigure/VectorStoreObservationAutoConfiguration.java index 022539d1570..cf8fe011d57 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-observation/src/main/java/org/springframework/ai/vectorstore/observation/autoconfigure/VectorStoreObservationAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-observation/src/main/java/org/springframework/ai/vectorstore/observation/autoconfigure/VectorStoreObservationAutoConfiguration.java @@ -19,12 +19,17 @@ import io.micrometer.tracing.Tracer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.ai.observation.TracingAwareLoggingObservationHandler; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; import org.springframework.ai.vectorstore.observation.VectorStoreQueryResponseObservationHandler; import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.condition.*; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-observation/src/test/java/org/springframework/ai/vectorstore/observation/autoconfigure/VectorStoreObservationAutoConfigurationTests.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-observation/src/test/java/org/springframework/ai/vectorstore/observation/autoconfigure/VectorStoreObservationAutoConfigurationTests.java index dcdab68371b..2ebcae1c076 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-observation/src/test/java/org/springframework/ai/vectorstore/observation/autoconfigure/VectorStoreObservationAutoConfigurationTests.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-observation/src/test/java/org/springframework/ai/vectorstore/observation/autoconfigure/VectorStoreObservationAutoConfigurationTests.java @@ -19,6 +19,7 @@ import io.micrometer.tracing.Tracer; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.ai.observation.TracingAwareLoggingObservationHandler; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; import org.springframework.ai.vectorstore.observation.VectorStoreQueryResponseObservationHandler; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-opensearch/src/main/java/org/springframework/ai/vectorstore/opensearch/autoconfigure/OpenSearchVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-opensearch/src/main/java/org/springframework/ai/vectorstore/opensearch/autoconfigure/OpenSearchVectorStoreAutoConfiguration.java index 92e117f2f36..554cae00ec9 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-opensearch/src/main/java/org/springframework/ai/vectorstore/opensearch/autoconfigure/OpenSearchVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-opensearch/src/main/java/org/springframework/ai/vectorstore/opensearch/autoconfigure/OpenSearchVectorStoreAutoConfiguration.java @@ -52,7 +52,6 @@ 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.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.ssl.SslBundles; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-opensearch/src/main/java/org/springframework/ai/vectorstore/opensearch/autoconfigure/OpenSearchVectorStoreProperties.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-opensearch/src/main/java/org/springframework/ai/vectorstore/opensearch/autoconfigure/OpenSearchVectorStoreProperties.java index 71a57f06341..6d8bbc6372d 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-opensearch/src/main/java/org/springframework/ai/vectorstore/opensearch/autoconfigure/OpenSearchVectorStoreProperties.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-opensearch/src/main/java/org/springframework/ai/vectorstore/opensearch/autoconfigure/OpenSearchVectorStoreProperties.java @@ -98,7 +98,7 @@ public void setMappingJson(String mappingJson) { } public String getSslBundle() { - return sslBundle; + return this.sslBundle; } public void setSslBundle(String sslBundle) { @@ -106,7 +106,7 @@ public void setSslBundle(String sslBundle) { } public Duration getConnectionTimeout() { - return connectionTimeout; + return this.connectionTimeout; } public void setConnectionTimeout(Duration connectionTimeout) { @@ -114,7 +114,7 @@ public void setConnectionTimeout(Duration connectionTimeout) { } public Duration getReadTimeout() { - return readTimeout; + return this.readTimeout; } public void setReadTimeout(Duration readTimeout) { diff --git a/memory/repository/spring-ai-model-chat-memory-repository-cassandra/src/main/java/org/springframework/ai/chat/memory/repository/cassandra/CassandraChatMemoryRepository.java b/memory/repository/spring-ai-model-chat-memory-repository-cassandra/src/main/java/org/springframework/ai/chat/memory/repository/cassandra/CassandraChatMemoryRepository.java index c31d9e50d30..9f7c71666db 100644 --- a/memory/repository/spring-ai-model-chat-memory-repository-cassandra/src/main/java/org/springframework/ai/chat/memory/repository/cassandra/CassandraChatMemoryRepository.java +++ b/memory/repository/spring-ai-model-chat-memory-repository-cassandra/src/main/java/org/springframework/ai/chat/memory/repository/cassandra/CassandraChatMemoryRepository.java @@ -47,7 +47,7 @@ * @author Mick Semb Wever * @since 1.0.0 */ -public class CassandraChatMemoryRepository implements ChatMemoryRepository { +public final class CassandraChatMemoryRepository implements ChatMemoryRepository { public static final String CONVERSATION_TS = CassandraChatMemoryRepository.class.getSimpleName() + "_message_timestamp"; @@ -125,7 +125,7 @@ public void saveAll(String conversationId, List messages) { Instant instant = Instant.now(); List primaryKeys = this.conf.primaryKeyTranslator.apply(conversationId); - BoundStatementBuilder builder = addStmt.boundStatementBuilder(); + BoundStatementBuilder builder = this.addStmt.boundStatementBuilder(); for (int k = 0; k < primaryKeys.size(); ++k) { CassandraChatMemoryRepositoryConfig.SchemaColumn keyColumn = this.conf.getPrimaryKeyColumn(k); diff --git a/memory/repository/spring-ai-model-chat-memory-repository-cassandra/src/main/java/org/springframework/ai/chat/memory/repository/cassandra/CassandraChatMemoryRepositoryConfig.java b/memory/repository/spring-ai-model-chat-memory-repository-cassandra/src/main/java/org/springframework/ai/chat/memory/repository/cassandra/CassandraChatMemoryRepositoryConfig.java index 4ef377abc45..d5437df3d22 100644 --- a/memory/repository/spring-ai-model-chat-memory-repository-cassandra/src/main/java/org/springframework/ai/chat/memory/repository/cassandra/CassandraChatMemoryRepositoryConfig.java +++ b/memory/repository/spring-ai-model-chat-memory-repository-cassandra/src/main/java/org/springframework/ai/chat/memory/repository/cassandra/CassandraChatMemoryRepositoryConfig.java @@ -34,8 +34,6 @@ import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry; import com.datastax.oss.driver.api.core.type.reflect.GenericType; import com.datastax.oss.driver.api.querybuilder.SchemaBuilder; -import com.datastax.oss.driver.api.querybuilder.schema.AlterTableAddColumn; -import com.datastax.oss.driver.api.querybuilder.schema.AlterTableAddColumnEnd; import com.datastax.oss.driver.api.querybuilder.schema.CreateTable; import com.datastax.oss.driver.api.querybuilder.schema.CreateTableStart; import com.datastax.oss.driver.api.querybuilder.schema.CreateTableWithOptions; @@ -140,13 +138,13 @@ void checkSchemaValid() { Preconditions.checkState(this.session.getMetadata() .getKeyspace(this.schema.keyspace()) .get() - .getUserDefinedType(messageUDT) + .getUserDefinedType(this.messageUDT) .isPresent(), "table %s does not exist"); UserDefinedType udt = this.session.getMetadata() .getKeyspace(this.schema.keyspace()) .get() - .getUserDefinedType(messageUDT) + .getUserDefinedType(this.messageUDT) .get(); Preconditions.checkState(udt.contains(this.messageUdtTimestampColumn), "field %s does not exist", @@ -186,7 +184,7 @@ private void ensureTableExists() { String lastClusteringColumn = this.schema.clusteringKeys.get(this.schema.clusteringKeys.size() - 1).name(); CreateTableWithOptions createTableWithOptions = createTable - .withColumn(this.messagesColumn, DataTypes.frozenListOf(SchemaBuilder.udt(messageUDT, true))) + .withColumn(this.messagesColumn, DataTypes.frozenListOf(SchemaBuilder.udt(this.messageUDT, true))) .withClusteringOrder(lastClusteringColumn, ClusteringOrder.DESC) // TODO replace w/ SchemaBuilder.unifiedCompactionStrategy() when // available @@ -201,11 +199,11 @@ private void ensureTableExists() { private void ensureMessageTypeExist() { - SimpleStatement stmt = SchemaBuilder.createType(messageUDT) + SimpleStatement stmt = SchemaBuilder.createType(this.messageUDT) .ifNotExists() - .withField(messageUdtTimestampColumn, DataTypes.TIMESTAMP) - .withField(messageUdtTypeColumn, DataTypes.TEXT) - .withField(messageUdtContentColumn, DataTypes.TEXT) + .withField(this.messageUdtTimestampColumn, DataTypes.TIMESTAMP) + .withField(this.messageUdtTypeColumn, DataTypes.TEXT) + .withField(this.messageUdtContentColumn, DataTypes.TEXT) .build(); this.session.execute(stmt.setKeyspace(this.schema.keyspace)); @@ -222,7 +220,7 @@ private void ensureTableColumnsExist() { if (tableMetadata.getColumn(this.messagesColumn).isEmpty()) { SimpleStatement stmt = SchemaBuilder.alterTable(this.schema.keyspace(), this.schema.table()) - .addColumn(this.messagesColumn, DataTypes.frozenListOf(SchemaBuilder.udt(messageUDT, true))) + .addColumn(this.messagesColumn, DataTypes.frozenListOf(SchemaBuilder.udt(this.messageUDT, true))) .build(); logger.debug("Executing {}", stmt.getQuery()); 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 97c9735efa9..b16f28d31e0 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 @@ -26,7 +26,6 @@ import com.datastax.oss.driver.api.core.data.UdtValue; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; - import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import org.testcontainers.cassandra.CassandraContainer; diff --git a/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/chat/memory/repository/jdbc/JdbcChatMemoryRepository.java b/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/chat/memory/repository/jdbc/JdbcChatMemoryRepository.java index b24254deb48..d9366aa6519 100644 --- a/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/chat/memory/repository/jdbc/JdbcChatMemoryRepository.java +++ b/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/chat/memory/repository/jdbc/JdbcChatMemoryRepository.java @@ -16,7 +16,10 @@ package org.springframework.ai.chat.memory.repository.jdbc; -import java.sql.*; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -24,6 +27,9 @@ import javax.sql.DataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.springframework.ai.chat.memory.ChatMemoryRepository; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; @@ -37,15 +43,8 @@ import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.lang.Nullable; import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.transaction.TransactionDefinition; -import org.springframework.transaction.TransactionException; -import org.springframework.transaction.TransactionStatus; -import org.springframework.transaction.support.AbstractPlatformTransactionManager; -import org.springframework.transaction.support.DefaultTransactionStatus; import org.springframework.transaction.support.TransactionTemplate; import org.springframework.util.Assert; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * An implementation of {@link ChatMemoryRepository} for JDBC. @@ -56,7 +55,7 @@ * @author Mark Pollack * @since 1.0.0 */ -public class JdbcChatMemoryRepository implements ChatMemoryRepository { +public final class JdbcChatMemoryRepository implements ChatMemoryRepository { private final JdbcTemplate jdbcTemplate; @@ -78,7 +77,7 @@ private JdbcChatMemoryRepository(DataSource dataSource, JdbcChatMemoryRepository @Override public List findConversationIds() { - List conversationIds = this.jdbcTemplate.query(dialect.getSelectConversationIdsSql(), rs -> { + List conversationIds = this.jdbcTemplate.query(this.dialect.getSelectConversationIdsSql(), rs -> { var ids = new ArrayList(); while (rs.next()) { ids.add(rs.getString(1)); @@ -91,7 +90,7 @@ public List findConversationIds() { @Override public List findByConversationId(String conversationId) { Assert.hasText(conversationId, "conversationId cannot be null or empty"); - return this.jdbcTemplate.query(dialect.getSelectMessagesSql(), new MessageRowMapper(), conversationId); + return this.jdbcTemplate.query(this.dialect.getSelectMessagesSql(), new MessageRowMapper(), conversationId); } @Override @@ -100,9 +99,9 @@ public void saveAll(String conversationId, List messages) { Assert.notNull(messages, "messages cannot be null"); Assert.noNullElements(messages, "messages cannot contain null elements"); - transactionTemplate.execute(status -> { + this.transactionTemplate.execute(status -> { deleteByConversationId(conversationId); - jdbcTemplate.batchUpdate(dialect.getInsertMessageSql(), + this.jdbcTemplate.batchUpdate(this.dialect.getInsertMessageSql(), new AddBatchPreparedStatement(conversationId, messages)); return null; }); @@ -111,7 +110,11 @@ public void saveAll(String conversationId, List messages) { @Override public void deleteByConversationId(String conversationId) { Assert.hasText(conversationId, "conversationId cannot be null or empty"); - this.jdbcTemplate.update(dialect.getDeleteMessagesSql(), conversationId); + this.jdbcTemplate.update(this.dialect.getDeleteMessagesSql(), conversationId); + } + + public static Builder builder() { + return new Builder(); } private record AddBatchPreparedStatement(String conversationId, List messages, @@ -128,7 +131,7 @@ public void setValues(PreparedStatement ps, int i) throws SQLException { ps.setString(1, this.conversationId); ps.setString(2, message.getText()); ps.setString(3, message.getMessageType().name()); - ps.setTimestamp(4, new Timestamp(instantSeq.getAndIncrement())); + ps.setTimestamp(4, new Timestamp(this.instantSeq.getAndIncrement())); } @Override @@ -158,11 +161,7 @@ public Message mapRow(ResultSet rs, int i) throws SQLException { } - public static Builder builder() { - return new Builder(); - } - - public static class Builder { + public static final class Builder { private JdbcTemplate jdbcTemplate; diff --git a/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/chat/memory/repository/jdbc/JdbcChatMemoryRepositoryDialect.java b/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/chat/memory/repository/jdbc/JdbcChatMemoryRepositoryDialect.java index 98533498da4..3d7032df4bd 100644 --- a/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/chat/memory/repository/jdbc/JdbcChatMemoryRepositoryDialect.java +++ b/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/chat/memory/repository/jdbc/JdbcChatMemoryRepositoryDialect.java @@ -55,16 +55,21 @@ static JdbcChatMemoryRepositoryDialect from(DataSource dataSource) { // Simple detection (could be improved) try { String url = dataSource.getConnection().getMetaData().getURL().toLowerCase(); - if (url.contains("postgresql")) + if (url.contains("postgresql")) { return new PostgresChatMemoryRepositoryDialect(); - if (url.contains("mysql")) + } + if (url.contains("mysql")) { return new MysqlChatMemoryRepositoryDialect(); - if (url.contains("mariadb")) + } + if (url.contains("mariadb")) { return new MysqlChatMemoryRepositoryDialect(); - if (url.contains("sqlserver")) + } + if (url.contains("sqlserver")) { return new SqlServerChatMemoryRepositoryDialect(); - if (url.contains("hsqldb")) + } + if (url.contains("hsqldb")) { return new HsqldbChatMemoryRepositoryDialect(); + } // Add more as needed } catch (Exception ignored) { 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 0ec671d0e52..407de5fe2da 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 @@ -16,31 +16,30 @@ package org.springframework.ai.chat.memory.repository.jdbc; +import java.sql.Timestamp; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import javax.sql.DataSource; + import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; + import org.springframework.ai.chat.memory.ChatMemoryRepository; +import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.MessageType; -import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.SystemMessage; 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.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.core.JdbcTemplate; -import java.sql.Timestamp; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.stream.Collectors; - -import javax.sql.DataSource; - import static org.assertj.core.api.Assertions.assertThat; /** @@ -58,7 +57,7 @@ public abstract class AbstractJdbcChatMemoryRepositoryIT { @Test void correctChatMemoryRepositoryInstance() { - assertThat(chatMemoryRepository).isInstanceOf(ChatMemoryRepository.class); + assertThat(this.chatMemoryRepository).isInstanceOf(ChatMemoryRepository.class); } @ParameterizedTest @@ -72,13 +71,14 @@ void saveMessagesSingleMessage(String content, MessageType messageType) { case TOOL -> throw new IllegalArgumentException("TOOL message type not supported in this test"); }; - chatMemoryRepository.saveAll(conversationId, List.of(message)); + this.chatMemoryRepository.saveAll(conversationId, List.of(message)); // Use dialect to get the appropriate SQL query - JdbcChatMemoryRepositoryDialect dialect = JdbcChatMemoryRepositoryDialect.from(jdbcTemplate.getDataSource()); + JdbcChatMemoryRepositoryDialect dialect = JdbcChatMemoryRepositoryDialect + .from(this.jdbcTemplate.getDataSource()); String selectSql = dialect.getSelectMessagesSql() .replace("content, type", "conversation_id, content, type, timestamp"); - var result = jdbcTemplate.queryForMap(selectSql, conversationId); + var result = this.jdbcTemplate.queryForMap(selectSql, conversationId); assertThat(result.size()).isEqualTo(4); assertThat(result.get("conversation_id")).isEqualTo(conversationId); @@ -94,13 +94,14 @@ void saveMessagesMultipleMessages() { new UserMessage("Message from user - " + conversationId), new SystemMessage("Message from system - " + conversationId)); - chatMemoryRepository.saveAll(conversationId, messages); + this.chatMemoryRepository.saveAll(conversationId, messages); // Use dialect to get the appropriate SQL query - JdbcChatMemoryRepositoryDialect dialect = JdbcChatMemoryRepositoryDialect.from(jdbcTemplate.getDataSource()); + JdbcChatMemoryRepositoryDialect dialect = JdbcChatMemoryRepositoryDialect + .from(this.jdbcTemplate.getDataSource()); String selectSql = dialect.getSelectMessagesSql() .replace("content, type", "conversation_id, content, type, timestamp"); - var results = jdbcTemplate.queryForList(selectSql, conversationId); + var results = this.jdbcTemplate.queryForList(selectSql, conversationId); assertThat(results).hasSize(messages.size()); @@ -114,12 +115,12 @@ void saveMessagesMultipleMessages() { assertThat(result.get("timestamp")).isInstanceOf(Timestamp.class); } - var count = chatMemoryRepository.findByConversationId(conversationId).size(); + var count = this.chatMemoryRepository.findByConversationId(conversationId).size(); assertThat(count).isEqualTo(messages.size()); - chatMemoryRepository.saveAll(conversationId, List.of(new UserMessage("Hello"))); + this.chatMemoryRepository.saveAll(conversationId, List.of(new UserMessage("Hello"))); - count = chatMemoryRepository.findByConversationId(conversationId).size(); + count = this.chatMemoryRepository.findByConversationId(conversationId).size(); assertThat(count).isEqualTo(1); } @@ -131,9 +132,9 @@ void findMessagesByConversationId() { new UserMessage("Message from user - " + conversationId), new SystemMessage("Message from system - " + conversationId)); - chatMemoryRepository.saveAll(conversationId, messages); + this.chatMemoryRepository.saveAll(conversationId, messages); - var results = chatMemoryRepository.findByConversationId(conversationId); + var results = this.chatMemoryRepository.findByConversationId(conversationId); assertThat(results.size()).isEqualTo(messages.size()); assertThat(results).isEqualTo(messages); @@ -146,12 +147,12 @@ void deleteMessagesByConversationId() { new UserMessage("Message from user - " + conversationId), new SystemMessage("Message from system - " + conversationId)); - chatMemoryRepository.saveAll(conversationId, messages); + this.chatMemoryRepository.saveAll(conversationId, messages); - chatMemoryRepository.deleteByConversationId(conversationId); + this.chatMemoryRepository.deleteByConversationId(conversationId); - var count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ?", - Integer.class, conversationId); + var count = this.jdbcTemplate.queryForObject( + "SELECT COUNT(*) FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ?", Integer.class, conversationId); assertThat(count).isZero(); } @@ -160,8 +161,8 @@ void deleteMessagesByConversationId() { void testMessageOrder() { // Create a repository using the from method to detect the dialect JdbcChatMemoryRepository repository = JdbcChatMemoryRepository.builder() - .jdbcTemplate(jdbcTemplate) - .dialect(JdbcChatMemoryRepositoryDialect.from(jdbcTemplate.getDataSource())) + .jdbcTemplate(this.jdbcTemplate) + .dialect(JdbcChatMemoryRepositoryDialect.from(this.jdbcTemplate.getDataSource())) .build(); var conversationId = UUID.randomUUID().toString(); diff --git a/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/chat/memory/repository/jdbc/JdbcChatMemoryRepositoryBuilderTests.java b/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/chat/memory/repository/jdbc/JdbcChatMemoryRepositoryBuilderTests.java index c6eb00c4abe..a6f8951542e 100644 --- a/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/chat/memory/repository/jdbc/JdbcChatMemoryRepositoryBuilderTests.java +++ b/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/chat/memory/repository/jdbc/JdbcChatMemoryRepositoryBuilderTests.java @@ -19,6 +19,7 @@ import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; + import javax.sql.DataSource; import org.junit.jupiter.api.Test; diff --git a/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/chat/memory/repository/jdbc/JdbcChatMemoryRepositoryPostgresqlIT.java b/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/chat/memory/repository/jdbc/JdbcChatMemoryRepositoryPostgresqlIT.java index 026ca4ed524..49b1356a6a2 100644 --- a/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/chat/memory/repository/jdbc/JdbcChatMemoryRepositoryPostgresqlIT.java +++ b/memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/test/java/org/springframework/ai/chat/memory/repository/jdbc/JdbcChatMemoryRepositoryPostgresqlIT.java @@ -18,6 +18,7 @@ import java.util.List; import java.util.UUID; + import javax.sql.DataSource; import org.junit.jupiter.api.Test; @@ -53,7 +54,7 @@ class JdbcChatMemoryRepositoryPostgresqlIT extends AbstractJdbcChatMemoryReposit void repositoryWithExplicitTransactionManager() { // Get the repository with explicit transaction manager ChatMemoryRepository repositoryWithTxManager = TestConfiguration - .chatMemoryRepositoryWithTransactionManager(jdbcTemplate, jdbcTemplate.getDataSource()); + .chatMemoryRepositoryWithTransactionManager(this.jdbcTemplate, this.jdbcTemplate.getDataSource()); var conversationId = UUID.randomUUID().toString(); var messages = List.of(new AssistantMessage("Message with transaction manager - " + conversationId), diff --git a/memory/repository/spring-ai-model-chat-memory-repository-neo4j/src/main/java/org/springframework/ai/chat/memory/repository/neo4j/Neo4jChatMemoryRepository.java b/memory/repository/spring-ai-model-chat-memory-repository-neo4j/src/main/java/org/springframework/ai/chat/memory/repository/neo4j/Neo4jChatMemoryRepository.java index e922dd121be..21cdd80a54e 100644 --- a/memory/repository/spring-ai-model-chat-memory-repository-neo4j/src/main/java/org/springframework/ai/chat/memory/repository/neo4j/Neo4jChatMemoryRepository.java +++ b/memory/repository/spring-ai-model-chat-memory-repository-neo4j/src/main/java/org/springframework/ai/chat/memory/repository/neo4j/Neo4jChatMemoryRepository.java @@ -1,18 +1,45 @@ +/* + * Copyright 2025-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.ai.chat.memory.repository.neo4j; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + import org.neo4j.driver.Session; import org.neo4j.driver.Transaction; import org.neo4j.driver.TransactionContext; + import org.springframework.ai.chat.memory.ChatMemoryRepository; -import org.springframework.ai.chat.messages.*; +import org.springframework.ai.chat.messages.AssistantMessage; +import org.springframework.ai.chat.messages.Message; +import org.springframework.ai.chat.messages.MessageType; +import org.springframework.ai.chat.messages.SystemMessage; +import org.springframework.ai.chat.messages.ToolResponseMessage; +import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.content.Media; import org.springframework.ai.content.MediaContent; import org.springframework.util.MimeType; -import java.net.URI; -import java.util.*; -import java.util.stream.Collectors; - /** * An implementation of {@link ChatMemoryRepository} for Neo4J * @@ -31,9 +58,9 @@ public Neo4jChatMemoryRepository(Neo4jChatMemoryRepositoryConfig config) { @Override public List findConversationIds() { - return config.getDriver() + return this.config.getDriver() .executableQuery("MATCH (conversation:$($sessionLabel)) RETURN conversation.id") - .withParameters(Map.of("sessionLabel", config.getSessionLabel())) + .withParameters(Map.of("sessionLabel", this.config.getSessionLabel())) .execute(Collectors.mapping(r -> r.get("conversation.id").asString(), Collectors.toList())); } diff --git a/memory/repository/spring-ai-model-chat-memory-repository-neo4j/src/test/java/org/springframework/ai/chat/memory/repository/neo4j/Neo4JChatMemoryRepositoryConfigIT.java b/memory/repository/spring-ai-model-chat-memory-repository-neo4j/src/test/java/org/springframework/ai/chat/memory/repository/neo4j/Neo4JChatMemoryRepositoryConfigIT.java index 6a8f01b9f2a..463e5465fa7 100644 --- a/memory/repository/spring-ai-model-chat-memory-repository-neo4j/src/test/java/org/springframework/ai/chat/memory/repository/neo4j/Neo4JChatMemoryRepositoryConfigIT.java +++ b/memory/repository/spring-ai-model-chat-memory-repository-neo4j/src/test/java/org/springframework/ai/chat/memory/repository/neo4j/Neo4JChatMemoryRepositoryConfigIT.java @@ -1,12 +1,28 @@ +/* + * Copyright 2025-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.ai.chat.memory.repository.neo4j; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.neo4j.driver.Driver; import org.neo4j.driver.GraphDatabase; -import org.neo4j.driver.Session; import org.neo4j.driver.Result; +import org.neo4j.driver.Session; import org.testcontainers.containers.Neo4jContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -28,8 +44,9 @@ static void setupDriver() { @AfterAll static void closeDriver() { - if (driver != null) + if (driver != null) { driver.close(); + } } @Test @@ -44,10 +61,12 @@ void shouldCreateRequiredIndexes() { while (result.hasNext()) { var record = result.next(); String name = record.get("name").asString(); - if ("session_conversation_id_index".equals(name)) + if ("session_conversation_id_index".equals(name)) { sessionIndexFound = true; - if ("message_index_index".equals(name)) + } + if ("message_index_index".equals(name)) { messageIndexFound = true; + } } // Then assertThat(sessionIndexFound).isTrue(); diff --git a/memory/repository/spring-ai-model-chat-memory-repository-neo4j/src/test/java/org/springframework/ai/chat/memory/repository/neo4j/Neo4jChatMemoryRepositoryIT.java b/memory/repository/spring-ai-model-chat-memory-repository-neo4j/src/test/java/org/springframework/ai/chat/memory/repository/neo4j/Neo4jChatMemoryRepositoryIT.java index a9f0e28b2e1..83ff42a71ae 100644 --- a/memory/repository/spring-ai-model-chat-memory-repository-neo4j/src/test/java/org/springframework/ai/chat/memory/repository/neo4j/Neo4jChatMemoryRepositoryIT.java +++ b/memory/repository/spring-ai-model-chat-memory-repository-neo4j/src/test/java/org/springframework/ai/chat/memory/repository/neo4j/Neo4jChatMemoryRepositoryIT.java @@ -16,6 +16,14 @@ package org.springframework.ai.chat.memory.repository.neo4j; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -24,6 +32,11 @@ import org.neo4j.driver.Driver; import org.neo4j.driver.Result; import org.neo4j.driver.Session; +import org.testcontainers.containers.Neo4jContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + import org.springframework.ai.chat.memory.ChatMemoryRepository; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; @@ -34,18 +47,6 @@ import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.content.Media; import org.springframework.util.MimeType; -import org.testcontainers.containers.Neo4jContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.utility.DockerImageName; - -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; @@ -74,24 +75,24 @@ class Neo4jChatMemoryRepositoryIT { @BeforeEach void setUp() { - driver = Neo4jDriverFactory.create(neo4jContainer.getBoltUrl()); - config = Neo4jChatMemoryRepositoryConfig.builder().withDriver(driver).build(); - chatMemoryRepository = new Neo4jChatMemoryRepository(config); + this.driver = Neo4jDriverFactory.create(neo4jContainer.getBoltUrl()); + this.config = Neo4jChatMemoryRepositoryConfig.builder().withDriver(this.driver).build(); + this.chatMemoryRepository = new Neo4jChatMemoryRepository(this.config); } @AfterEach void tearDown() { // Clean up all data after each test - try (Session session = driver.session()) { + try (Session session = this.driver.session()) { session.run("MATCH (n) DETACH DELETE n"); } - driver.close(); + this.driver.close(); } @Test void correctChatMemoryRepositoryInstance() { - assertThat(chatMemoryRepository).isInstanceOf(ChatMemoryRepository.class); - assertThat(chatMemoryRepository).isInstanceOf(Neo4jChatMemoryRepository.class); + assertThat(this.chatMemoryRepository).isInstanceOf(ChatMemoryRepository.class); + assertThat(this.chatMemoryRepository).isInstanceOf(Neo4jChatMemoryRepository.class); } @ParameterizedTest @@ -101,8 +102,8 @@ void saveAndFindSingleMessage(String content, MessageType messageType) { var conversationId = UUID.randomUUID().toString(); Message message = createMessageByType(content + " - " + conversationId, messageType); - chatMemoryRepository.saveAll(conversationId, List.of(message)); - List retrievedMessages = chatMemoryRepository.findByConversationId(conversationId); + this.chatMemoryRepository.saveAll(conversationId, List.of(message)); + List retrievedMessages = this.chatMemoryRepository.findByConversationId(conversationId); assertThat(retrievedMessages).hasSize(1); @@ -114,10 +115,10 @@ void saveAndFindSingleMessage(String content, MessageType messageType) { } // Verify directly in the database - try (Session session = driver.session()) { + try (Session session = this.driver.session()) { var result = session.run( "MATCH (s:%s {id:$conversationId})-[:HAS_MESSAGE]->(m:%s) RETURN count(m) as count" - .formatted(config.getSessionLabel(), config.getMessageLabel()), + .formatted(this.config.getSessionLabel(), this.config.getMessageLabel()), Map.of("conversationId", conversationId)); assertThat(result.single().get("count").asLong()).isEqualTo(1); } @@ -131,8 +132,8 @@ void saveAndFindMultipleMessages() { new SystemMessage("Message from system - " + conversationId), new ToolResponseMessage(List.of(new ToolResponse("id", "name", "responseData")))); - chatMemoryRepository.saveAll(conversationId, messages); - List retrievedMessages = chatMemoryRepository.findByConversationId(conversationId); + this.chatMemoryRepository.saveAll(conversationId, messages); + List retrievedMessages = this.chatMemoryRepository.findByConversationId(conversationId); assertThat(retrievedMessages).hasSize(messages.size()); @@ -155,8 +156,8 @@ void verifyMessageOrdering() { messages.add(new UserMessage("Message " + i)); } - chatMemoryRepository.saveAll(conversationId, messages); - List retrievedMessages = chatMemoryRepository.findByConversationId(conversationId); + this.chatMemoryRepository.saveAll(conversationId, messages); + List retrievedMessages = this.chatMemoryRepository.findByConversationId(conversationId); assertThat(retrievedMessages).hasSize(messages.size()); @@ -173,11 +174,14 @@ void findConversationIds() { var conversationId2 = UUID.randomUUID().toString(); var conversationId3 = UUID.randomUUID().toString(); - chatMemoryRepository.saveAll(conversationId1, List.of(new UserMessage("Message for conversation 1"))); - chatMemoryRepository.saveAll(conversationId2, List.of(new UserMessage("Message for conversation 2"))); - chatMemoryRepository.saveAll(conversationId3, List.of(new UserMessage("Message for conversation 3"))); + this.chatMemoryRepository.saveAll(conversationId1, + List.of(new UserMessage("Message for conversation 1"))); + this.chatMemoryRepository.saveAll(conversationId2, + List.of(new UserMessage("Message for conversation 2"))); + this.chatMemoryRepository.saveAll(conversationId3, + List.of(new UserMessage("Message for conversation 3"))); - List conversationIds = chatMemoryRepository.findConversationIds(); + List conversationIds = this.chatMemoryRepository.findConversationIds(); assertThat(conversationIds).hasSize(3); assertThat(conversationIds).contains(conversationId1, conversationId2, conversationId3); @@ -189,22 +193,21 @@ void deleteByConversationId() { List messages = List.of(new AssistantMessage("Message from assistant"), new UserMessage("Message from user"), new SystemMessage("Message from system")); - chatMemoryRepository.saveAll(conversationId, messages); + this.chatMemoryRepository.saveAll(conversationId, messages); // Verify messages were saved - assertThat(chatMemoryRepository.findByConversationId(conversationId)).hasSize(3); + assertThat(this.chatMemoryRepository.findByConversationId(conversationId)).hasSize(3); // Delete the conversation - chatMemoryRepository.deleteByConversationId(conversationId); + this.chatMemoryRepository.deleteByConversationId(conversationId); // Verify messages were deleted - assertThat(chatMemoryRepository.findByConversationId(conversationId)).isEmpty(); + assertThat(this.chatMemoryRepository.findByConversationId(conversationId)).isEmpty(); // Verify directly in the database - try (Session session = driver.session()) { - var result = session.run( - "MATCH (s:%s {id:$conversationId}) RETURN count(s) as count".formatted(config.getSessionLabel()), - Map.of("conversationId", conversationId)); + try (Session session = this.driver.session()) { + var result = session.run("MATCH (s:%s {id:$conversationId}) RETURN count(s) as count" + .formatted(this.config.getSessionLabel()), Map.of("conversationId", conversationId)); assertThat(result.single().get("count").asLong()).isZero(); } } @@ -216,17 +219,17 @@ void saveAllReplacesExistingMessages() { // Save initial messages List initialMessages = List.of(new UserMessage("Initial message 1"), new UserMessage("Initial message 2"), new UserMessage("Initial message 3")); - chatMemoryRepository.saveAll(conversationId, initialMessages); + this.chatMemoryRepository.saveAll(conversationId, initialMessages); // Verify initial messages were saved - assertThat(chatMemoryRepository.findByConversationId(conversationId)).hasSize(3); + assertThat(this.chatMemoryRepository.findByConversationId(conversationId)).hasSize(3); // Replace with new messages List newMessages = List.of(new UserMessage("New message 1"), new UserMessage("New message 2")); - chatMemoryRepository.saveAll(conversationId, newMessages); + this.chatMemoryRepository.saveAll(conversationId, newMessages); // Verify only new messages exist - List retrievedMessages = chatMemoryRepository.findByConversationId(conversationId); + List retrievedMessages = this.chatMemoryRepository.findByConversationId(conversationId); assertThat(retrievedMessages).hasSize(2); assertThat(retrievedMessages.get(0).getText()).isEqualTo("New message 1"); assertThat(retrievedMessages.get(1).getText()).isEqualTo("New message 2"); @@ -246,9 +249,9 @@ void handleMediaContent() { UserMessage userMessageWithMedia = UserMessage.builder().text("Message with media").media(media).build(); - chatMemoryRepository.saveAll(conversationId, List.of(userMessageWithMedia)); + this.chatMemoryRepository.saveAll(conversationId, List.of(userMessageWithMedia)); - List retrievedMessages = chatMemoryRepository.findByConversationId(conversationId); + List retrievedMessages = this.chatMemoryRepository.findByConversationId(conversationId); assertThat(retrievedMessages).hasSize(1); UserMessage retrievedMessage = (UserMessage) retrievedMessages.get(0); @@ -264,9 +267,9 @@ void handleAssistantMessageWithToolCalls() { List.of(new AssistantMessage.ToolCall("id1", "type1", "name1", "arguments1"), new AssistantMessage.ToolCall("id2", "type2", "name2", "arguments2"))); - chatMemoryRepository.saveAll(conversationId, List.of(assistantMessage)); + this.chatMemoryRepository.saveAll(conversationId, List.of(assistantMessage)); - List retrievedMessages = chatMemoryRepository.findByConversationId(conversationId); + List retrievedMessages = this.chatMemoryRepository.findByConversationId(conversationId); assertThat(retrievedMessages).hasSize(1); AssistantMessage retrievedMessage = (AssistantMessage) retrievedMessages.get(0); @@ -283,9 +286,9 @@ void handleToolResponseMessage() { .of(new ToolResponse("id1", "name1", "responseData1"), new ToolResponse("id2", "name2", "responseData2")), Map.of("metadataKey", "metadataValue")); - chatMemoryRepository.saveAll(conversationId, List.of(toolResponseMessage)); + this.chatMemoryRepository.saveAll(conversationId, List.of(toolResponseMessage)); - List retrievedMessages = chatMemoryRepository.findByConversationId(conversationId); + List retrievedMessages = this.chatMemoryRepository.findByConversationId(conversationId); assertThat(retrievedMessages).hasSize(1); ToolResponseMessage retrievedMessage = (ToolResponseMessage) retrievedMessages.get(0); @@ -305,8 +308,8 @@ void saveAndFindSystemMessageWithMetadata() { .metadata(customMetadata) .build(); - chatMemoryRepository.saveAll(conversationId, List.of(systemMessage)); - List retrievedMessages = chatMemoryRepository.findByConversationId(conversationId); + this.chatMemoryRepository.saveAll(conversationId, List.of(systemMessage)); + List retrievedMessages = this.chatMemoryRepository.findByConversationId(conversationId); assertThat(retrievedMessages).hasSize(1); Message retrievedMessage = retrievedMessages.get(0); @@ -333,29 +336,29 @@ void saveAllWithEmptyListClearsConversation() { // 1. Setup: Create a conversation with some initial messages UserMessage initialMessage1 = new UserMessage("Initial message 1"); AssistantMessage initialMessage2 = new AssistantMessage("Initial response 1"); - chatMemoryRepository.saveAll(conversationId, List.of(initialMessage1, initialMessage2)); + this.chatMemoryRepository.saveAll(conversationId, List.of(initialMessage1, initialMessage2)); // Verify initial messages are there - List messagesAfterInitialSave = chatMemoryRepository.findByConversationId(conversationId); + List messagesAfterInitialSave = this.chatMemoryRepository.findByConversationId(conversationId); assertThat(messagesAfterInitialSave).hasSize(2); // 2. Action: Call saveAll with an empty list - chatMemoryRepository.saveAll(conversationId, Collections.emptyList()); + this.chatMemoryRepository.saveAll(conversationId, Collections.emptyList()); // 3. Assertions: // a) No messages should be found for the conversationId - List messagesAfterEmptySave = chatMemoryRepository.findByConversationId(conversationId); + List messagesAfterEmptySave = this.chatMemoryRepository.findByConversationId(conversationId); assertThat(messagesAfterEmptySave).isEmpty(); // b) The conversationId itself should no longer be listed (because // deleteByConversationId removes the session node) - List conversationIds = chatMemoryRepository.findConversationIds(); + List conversationIds = this.chatMemoryRepository.findConversationIds(); assertThat(conversationIds).doesNotContain(conversationId); // c) Verify directly in Neo4j that the conversation node is gone - try (Session session = driver.session()) { + try (Session session = this.driver.session()) { Result result = session.run( - "MATCH (s:%s {id: $conversationId}) RETURN s".formatted(config.getSessionLabel()), + "MATCH (s:%s {id: $conversationId}) RETURN s".formatted(this.config.getSessionLabel()), Map.of("conversationId", conversationId)); assertThat(result.hasNext()).isFalse(); // No conversation node should exist } @@ -372,9 +375,9 @@ void saveAndFindMessagesWithEmptyContentOrMetadata() { .build(); List messagesToSave = List.of(messageWithEmptyContent, messageWithEmptyMetadata); - chatMemoryRepository.saveAll(conversationId, messagesToSave); + this.chatMemoryRepository.saveAll(conversationId, messagesToSave); - List retrievedMessages = chatMemoryRepository.findByConversationId(conversationId); + List retrievedMessages = this.chatMemoryRepository.findByConversationId(conversationId); assertThat(retrievedMessages).hasSize(2); // Verify first message (empty content) 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 5c9116651fa..270f3bef43d 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 @@ -51,7 +51,6 @@ import org.springframework.ai.chat.metadata.DefaultUsage; import org.springframework.ai.chat.metadata.EmptyUsage; import org.springframework.ai.chat.metadata.Usage; -import org.springframework.ai.support.UsageCalculator; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.model.Generation; @@ -70,6 +69,7 @@ import org.springframework.ai.model.tool.ToolExecutionEligibilityPredicate; import org.springframework.ai.model.tool.ToolExecutionResult; import org.springframework.ai.retry.RetryUtils; +import org.springframework.ai.support.UsageCalculator; import org.springframework.ai.tool.definition.ToolDefinition; import org.springframework.ai.util.json.JsonParser; import org.springframework.http.ResponseEntity; 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 d9acf174677..adcb897ad89 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 @@ -62,7 +62,7 @@ * @author Claudio Silva Junior * @since 1.0.0 */ -public class AnthropicApi { +public final class AnthropicApi { public static Builder builder() { return new Builder(); diff --git a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/api/AnthropicApiIT.java b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/api/AnthropicApiIT.java index e2da41559f4..35cf443866c 100644 --- a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/api/AnthropicApiIT.java +++ b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/api/AnthropicApiIT.java @@ -142,7 +142,7 @@ void chatCompletionStreamWithToolCall() { .maxTokens(1500) .stream(true) .temperature(0.8) - .tools(tools) + .tools(this.tools) .build(); List responses = this.anthropicApi.chatCompletionStream(chatCompletionRequest) diff --git a/models/spring-ai-azure-openai/src/main/java/org/springframework/ai/azure/openai/AzureOpenAiResponseFormat.java b/models/spring-ai-azure-openai/src/main/java/org/springframework/ai/azure/openai/AzureOpenAiResponseFormat.java index b3dc0483cef..6a271ccd8b1 100644 --- a/models/spring-ai-azure-openai/src/main/java/org/springframework/ai/azure/openai/AzureOpenAiResponseFormat.java +++ b/models/spring-ai-azure-openai/src/main/java/org/springframework/ai/azure/openai/AzureOpenAiResponseFormat.java @@ -16,11 +16,13 @@ package org.springframework.ai.azure.openai; +import java.util.Map; +import java.util.Objects; + import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.Map; -import java.util.Objects; + import org.springframework.ai.model.ModelOptionsUtils; import org.springframework.util.StringUtils; diff --git a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/client/BedrockNovaChatClientIT.java b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/client/BedrockNovaChatClientIT.java index bcb3ea62636..d582d676833 100644 --- a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/client/BedrockNovaChatClientIT.java +++ b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/client/BedrockNovaChatClientIT.java @@ -32,7 +32,6 @@ import org.springframework.ai.bedrock.converse.BedrockProxyChatModel; import org.springframework.ai.bedrock.converse.RequiresAwsCredentials; import org.springframework.ai.chat.client.ChatClient; -import org.springframework.ai.chat.client.ChatClient.StreamResponseSpec; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.content.Media; @@ -171,12 +170,6 @@ else if (request.location().contains("San Francisco")) { assertThat(response).contains("30", "10", "15"); } - public record WeatherRequest(String location, String unit) { - } - - public record WeatherResponse(int temp, String unit) { - } - // https://github.com/spring-projects/spring-ai/issues/1878 @Test void toolAnnotationWeatherForecast() { @@ -214,15 +207,6 @@ void toolAnnotationWeatherForecastStreaming() { assertThat(content).contains("20 degrees"); } - public static class DummyWeatherForecastTools { - - @Tool(description = "Get the current weather forecast in Amsterdam") - String getCurrentDateTime() { - return "Weather is hot and sunny with a temperature of 20 degrees"; - } - - } - // https://github.com/spring-projects/spring-ai/issues/1878 @Test void supplierBasedToolCalling() { @@ -266,17 +250,6 @@ void supplierBasedToolCallingStreaming() { assertThat(content).contains("30.0"); } - public static class WeatherService implements Supplier { - - public record Response(double temp) { - } - - public Response get() { - return new Response(30.0); - } - - } - @SpringBootConfiguration public static class Config { @@ -295,4 +268,31 @@ public BedrockProxyChatModel bedrockConverseChatModel() { } + public record WeatherRequest(String location, String unit) { + } + + public record WeatherResponse(int temp, String unit) { + } + + public static class DummyWeatherForecastTools { + + @Tool(description = "Get the current weather forecast in Amsterdam") + String getCurrentDateTime() { + return "Weather is hot and sunny with a temperature of 20 degrees"; + } + + } + + public static class WeatherService implements Supplier { + + public Response get() { + return new Response(30.0); + } + + public record Response(double temp) { + + } + + } + } diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/api/AbstractBedrockApi.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/api/AbstractBedrockApi.java index dc02ed484ea..8c84204f319 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/api/AbstractBedrockApi.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/api/AbstractBedrockApi.java @@ -22,7 +22,8 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties;import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanEmbeddingModel.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanEmbeddingModel.java index 01f6d58e65b..ca71e6fcc4d 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanEmbeddingModel.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanEmbeddingModel.java @@ -20,6 +20,8 @@ import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import io.micrometer.observation.Observation; +import io.micrometer.observation.ObservationRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,9 +36,6 @@ import org.springframework.ai.embedding.EmbeddingResponse; import org.springframework.util.Assert; -import io.micrometer.observation.ObservationRegistry; -import io.micrometer.observation.Observation; - /** * {@link org.springframework.ai.embedding.EmbeddingModel} implementation that uses the * Bedrock Titan Embedding API. Titan Embedding supports text and image (encoded in diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/titan/BedrockTitanEmbeddingModelIT.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/titan/BedrockTitanEmbeddingModelIT.java index b41f8248b1d..54d2bf74f22 100644 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/titan/BedrockTitanEmbeddingModelIT.java +++ b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/titan/BedrockTitanEmbeddingModelIT.java @@ -22,6 +22,7 @@ import java.util.List; import com.fasterxml.jackson.databind.ObjectMapper; +import io.micrometer.observation.tck.TestObservationRegistry; import org.junit.jupiter.api.Test; import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; import software.amazon.awssdk.regions.Region; @@ -40,8 +41,6 @@ import static org.assertj.core.api.Assertions.assertThat; -import io.micrometer.observation.tck.TestObservationRegistry; - @SpringBootTest @RequiresAwsCredentials class BedrockTitanEmbeddingModelIT { diff --git a/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/DeepSeekAssistantMessage.java b/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/DeepSeekAssistantMessage.java index e7ddcb6b875..6159d9beadb 100644 --- a/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/DeepSeekAssistantMessage.java +++ b/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/DeepSeekAssistantMessage.java @@ -1,12 +1,28 @@ -package org.springframework.ai.deepseek; +/* + * Copyright 2023-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -import org.springframework.ai.chat.messages.AssistantMessage; -import org.springframework.ai.content.Media; +package org.springframework.ai.deepseek; import java.util.List; import java.util.Map; import java.util.Objects; +import org.springframework.ai.chat.messages.AssistantMessage; +import org.springframework.ai.content.Media; + public class DeepSeekAssistantMessage extends AssistantMessage { private Boolean prefix; @@ -50,7 +66,7 @@ public static DeepSeekAssistantMessage prefixAssistantMessage(String context, St } public Boolean getPrefix() { - return prefix; + return this.prefix; } public void setPrefix(Boolean prefix) { @@ -58,7 +74,7 @@ public void setPrefix(Boolean prefix) { } public String getReasoningContent() { - return reasoningContent; + return this.reasoningContent; } public void setReasoningContent(String reasoningContent) { 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 ffce033a421..4b7607c6e38 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 @@ -16,16 +16,32 @@ package org.springframework.ai.deepseek; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.MessageType; import org.springframework.ai.chat.messages.ToolResponseMessage; -import org.springframework.ai.chat.metadata.*; -import org.springframework.ai.chat.model.*; +import org.springframework.ai.chat.metadata.ChatGenerationMetadata; +import org.springframework.ai.chat.metadata.ChatResponseMetadata; +import org.springframework.ai.chat.metadata.DefaultUsage; +import org.springframework.ai.chat.metadata.EmptyUsage; +import org.springframework.ai.chat.metadata.Usage; +import org.springframework.ai.chat.model.ChatModel; +import org.springframework.ai.chat.model.ChatResponse; +import org.springframework.ai.chat.model.Generation; +import org.springframework.ai.chat.model.MessageAggregator; +import org.springframework.ai.chat.model.StreamingChatModel; import org.springframework.ai.chat.observation.ChatModelObservationContext; import org.springframework.ai.chat.observation.ChatModelObservationConvention; import org.springframework.ai.chat.observation.ChatModelObservationDocumentation; @@ -41,7 +57,11 @@ import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionRequest; import org.springframework.ai.deepseek.api.common.DeepSeekConstants; import org.springframework.ai.model.ModelOptionsUtils; -import org.springframework.ai.model.tool.*; +import org.springframework.ai.model.tool.DefaultToolExecutionEligibilityPredicate; +import org.springframework.ai.model.tool.ToolCallingChatOptions; +import org.springframework.ai.model.tool.ToolCallingManager; +import org.springframework.ai.model.tool.ToolExecutionEligibilityPredicate; +import org.springframework.ai.model.tool.ToolExecutionResult; import org.springframework.ai.retry.RetryUtils; import org.springframework.ai.support.UsageCalculator; import org.springframework.ai.tool.definition.ToolDefinition; @@ -49,12 +69,6 @@ import org.springframework.retry.support.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; /** * {@link ChatModel} and {@link StreamingChatModel} implementation for {@literal DeepSeek} @@ -248,12 +262,12 @@ public Flux internalStream(Prompt prompt, ChatResponse previousCha } // @formatter:off - Map metadata = Map.of( - "id", chatCompletion2.id(), - "role", roleMap.getOrDefault(id, ""), - "finishReason", choice.finishReason() != null ? choice.finishReason().name() : "" - ); - // @formatter:on + Map metadata = Map.of( + "id", chatCompletion2.id(), + "role", roleMap.getOrDefault(id, ""), + "finishReason", choice.finishReason() != null ? choice.finishReason().name() : "" + ); + // @formatter:on return buildGeneration(choice, metadata); }).toList(); DeepSeekApi.Usage usage = chatCompletion2.usage(); diff --git a/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/DeepSeekChatOptions.java b/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/DeepSeekChatOptions.java index 5664338a455..0731a1eb6cc 100644 --- a/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/DeepSeekChatOptions.java +++ b/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/DeepSeekChatOptions.java @@ -1,11 +1,11 @@ /* - * Copyright 2023 - 2024 the original author or authors. + * Copyright 2024-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,12 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.ai.deepseek; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; + import org.springframework.ai.deepseek.api.DeepSeekApi; import org.springframework.ai.deepseek.api.ResponseFormat; import org.springframework.ai.model.tool.ToolCallingChatOptions; @@ -26,8 +37,6 @@ import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import java.util.*; - /** * Chat completions options for the DeepSeek chat API. * DeepSeek @@ -323,7 +332,7 @@ public int hashCode() { return Objects.hash(this.model, this.frequencyPenalty, this.logprobs, this.topLogprobs, this.maxTokens, this.presencePenalty, this.responseFormat, this.stop, this.temperature, this.topP, this.tools, this.toolChoice, - this.toolCallbacks, this.toolNames, this.internalToolExecutionEnabled, this.toolContext); + this.toolCallbacks, this.toolNames, this.internalToolExecutionEnabled, this.toolContext); } @@ -351,6 +360,28 @@ public boolean equals(Object o) { && Objects.equals(this.internalToolExecutionEnabled, other.internalToolExecutionEnabled); } + public static DeepSeekChatOptions fromOptions(DeepSeekChatOptions fromOptions) { + return DeepSeekChatOptions.builder() + .model(fromOptions.getModel()) + .frequencyPenalty(fromOptions.getFrequencyPenalty()) + .logprobs(fromOptions.getLogprobs()) + .topLogprobs(fromOptions.getTopLogprobs()) + .maxTokens(fromOptions.getMaxTokens()) + .presencePenalty(fromOptions.getPresencePenalty()) + .responseFormat(fromOptions.getResponseFormat()) + .stop(fromOptions.getStop() != null ? new ArrayList<>(fromOptions.getStop()) : null) + .temperature(fromOptions.getTemperature()) + .topP(fromOptions.getTopP()) + .tools(fromOptions.getTools()) + .toolChoice(fromOptions.getToolChoice()) + .toolCallbacks( + fromOptions.getToolCallbacks() != null ? new ArrayList<>(fromOptions.getToolCallbacks()) : null) + .toolNames(fromOptions.getToolNames() != null ? new HashSet<>(fromOptions.getToolNames()) : null) + .internalToolExecutionEnabled(fromOptions.getInternalToolExecutionEnabled()) + .toolContext(fromOptions.getToolContext() != null ? new HashMap<>(fromOptions.getToolContext()) : null) + .build(); + } + public static class Builder { protected DeepSeekChatOptions options; @@ -472,26 +503,4 @@ public DeepSeekChatOptions build() { } - public static DeepSeekChatOptions fromOptions(DeepSeekChatOptions fromOptions) { - return DeepSeekChatOptions.builder() - .model(fromOptions.getModel()) - .frequencyPenalty(fromOptions.getFrequencyPenalty()) - .logprobs(fromOptions.getLogprobs()) - .topLogprobs(fromOptions.getTopLogprobs()) - .maxTokens(fromOptions.getMaxTokens()) - .presencePenalty(fromOptions.getPresencePenalty()) - .responseFormat(fromOptions.getResponseFormat()) - .stop(fromOptions.getStop() != null ? new ArrayList<>(fromOptions.getStop()) : null) - .temperature(fromOptions.getTemperature()) - .topP(fromOptions.getTopP()) - .tools(fromOptions.getTools()) - .toolChoice(fromOptions.getToolChoice()) - .toolCallbacks( - fromOptions.getToolCallbacks() != null ? new ArrayList<>(fromOptions.getToolCallbacks()) : null) - .toolNames(fromOptions.getToolNames() != null ? new HashSet<>(fromOptions.getToolNames()) : null) - .internalToolExecutionEnabled(fromOptions.getInternalToolExecutionEnabled()) - .toolContext(fromOptions.getToolContext() != null ? new HashMap<>(fromOptions.getToolContext()) : null) - .build(); - } - } diff --git a/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/aot/DeepSeekRuntimeHints.java b/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/aot/DeepSeekRuntimeHints.java index 22d9ce8b56e..bf869a4dc55 100644 --- a/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/aot/DeepSeekRuntimeHints.java +++ b/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/aot/DeepSeekRuntimeHints.java @@ -1,11 +1,11 @@ /* - * Copyright 2023 - 2024 the original author or authors. + * Copyright 2023-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.ai.deepseek.aot; import org.springframework.ai.deepseek.api.DeepSeekApi; @@ -35,8 +36,9 @@ public class DeepSeekRuntimeHints implements RuntimeHintsRegistrar { @Override public void registerHints(@NonNull RuntimeHints hints, @Nullable ClassLoader classLoader) { var mcs = MemberCategory.values(); - for (var tr : findJsonAnnotatedClassesInPackage(DeepSeekApi.class)) + for (var tr : findJsonAnnotatedClassesInPackage(DeepSeekApi.class)) { hints.reflection().registerType(tr, mcs); + } } } 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 69b117db237..f565c2ba26e 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 @@ -47,10 +47,6 @@ import org.springframework.web.client.RestClient; import org.springframework.web.reactive.function.client.WebClient; -import static org.springframework.ai.deepseek.api.common.DeepSeekConstants.DEFAULT_BASE_URL; -import static org.springframework.ai.deepseek.api.common.DeepSeekConstants.DEFAULT_BETA_PATH; -import static org.springframework.ai.deepseek.api.common.DeepSeekConstants.DEFAULT_COMPLETIONS_PATH; - /** * Single class implementation of the DeepSeek Chat Completion API: * https://platform.deepseek.com/api-docs/api/create-chat-completion @@ -196,6 +192,19 @@ public Flux chatCompletionStream(ChatCompletionRequest chat .flatMap(mono -> mono); } + private String getEndpoint(ChatCompletionRequest request) { + boolean isPrefix = request.messages.stream() + .map(ChatCompletionMessage::prefix) + .filter(Objects::nonNull) + .anyMatch(prefix -> prefix); + String endpointPrefix = isPrefix ? this.betaPrefixPath : ""; + return endpointPrefix + this.completionsPath; + } + + public static Builder builder() { + return new Builder(); + } + /** * DeepSeek Chat Completion * Models @@ -226,12 +235,12 @@ public enum ChatModel implements ChatModelDescription { } public String getValue() { - return value; + return this.value; } @Override public String getName() { - return value; + return this.value; } } @@ -506,10 +515,9 @@ public record ChatCompletionRequest(// @formatter:off @JsonProperty("temperature") Double temperature, @JsonProperty("top_p") Double topP, @JsonProperty("logprobs") Boolean logprobs, - @JsonProperty("top_logprobs") Integer topLogprobs, + @JsonProperty("top_logprobs") Integer topLogprobs, @JsonProperty("tools") List tools, - @JsonProperty("tool_choice") Object toolChoice) - { + @JsonProperty("tool_choice") Object toolChoice) { /** @@ -520,8 +528,8 @@ public record ChatCompletionRequest(// @formatter:off * as they become available, with the stream terminated by a data: [DONE] message. */ public ChatCompletionRequest(List messages, Boolean stream) { - this(messages, null, null, null, null, null, - null, stream, null, null, null, null, null, null); + this(messages, null, null, null, null, null, + null, stream, null, null, null, null, null, null); } /** @@ -532,9 +540,9 @@ public ChatCompletionRequest(List messages, Boolean strea * @param temperature What sampling temperature to use, between 0 and 1. */ public ChatCompletionRequest(List messages, String model, Double temperature) { - this(messages, model, null, - null, null, null, null, false, temperature, null, - null, null, null,null); + this(messages, model, null, + null, null, null, null, false, temperature, null, + null, null, null, null); } /** @@ -547,9 +555,9 @@ public ChatCompletionRequest(List messages, String model, * as they become available, with the stream terminated by a data: [DONE] message. */ public ChatCompletionRequest(List messages, String model, Double temperature, boolean stream) { - this(messages, model, null, - null, null, null, null, stream, temperature, null, - null, null, null,null); + this(messages, model, null, + null, null, null, null, stream, temperature, null, + null, null, null, null); } /** @@ -600,8 +608,7 @@ public record ChatCompletionMessage(// @formatter:off @JsonProperty("tool_calls") @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) List toolCalls, @JsonProperty("prefix") Boolean prefix, - @JsonProperty("reasoning_content") String reasoningContent - ) { // @formatter:on + @JsonProperty("reasoning_content") String reasoningContent) { // @formatter:on /** * Create a chat completion message with the given content and role. All other @@ -898,30 +905,17 @@ public record ChunkChoice(// @formatter:off } - private String getEndpoint(ChatCompletionRequest request) { - boolean isPrefix = request.messages.stream() - .map(ChatCompletionMessage::prefix) - .filter(Objects::nonNull) - .anyMatch(prefix -> prefix); - String endpointPrefix = isPrefix ? betaPrefixPath : ""; - return endpointPrefix + completionsPath; - } - - public static Builder builder() { - return new Builder(); - } - public static class Builder { - private String baseUrl = DEFAULT_BASE_URL; + private String baseUrl = org.springframework.ai.deepseek.api.common.DeepSeekConstants.DEFAULT_BASE_URL; private ApiKey apiKey; private MultiValueMap headers = new LinkedMultiValueMap<>(); - private String completionsPath = DEFAULT_COMPLETIONS_PATH; + private String completionsPath = org.springframework.ai.deepseek.api.common.DeepSeekConstants.DEFAULT_COMPLETIONS_PATH; - private String betaPrefixPath = DEFAULT_BETA_PATH; + private String betaPrefixPath = org.springframework.ai.deepseek.api.common.DeepSeekConstants.DEFAULT_BETA_PATH; private RestClient.Builder restClientBuilder = RestClient.builder(); diff --git a/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/api/DeepSeekStreamFunctionCallingHelper.java b/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/api/DeepSeekStreamFunctionCallingHelper.java index 7fe854428f4..68cbe2a4b93 100644 --- a/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/api/DeepSeekStreamFunctionCallingHelper.java +++ b/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/api/DeepSeekStreamFunctionCallingHelper.java @@ -16,6 +16,9 @@ package org.springframework.ai.deepseek.api; +import java.util.ArrayList; +import java.util.List; + import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionChunk; import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionChunk.ChunkChoice; import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionFinishReason; @@ -25,9 +28,6 @@ import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionMessage.ToolCall; import org.springframework.util.CollectionUtils; -import java.util.ArrayList; -import java.util.List; - /** * Helper class to support Streaming function calling. It can merge the streamed * ChatCompletionChunk in case of function calling message. diff --git a/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/api/ResponseFormat.java b/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/api/ResponseFormat.java index 826675545fa..32ba099a763 100644 --- a/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/api/ResponseFormat.java +++ b/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/api/ResponseFormat.java @@ -16,12 +16,12 @@ package org.springframework.ai.deepseek.api; +import java.util.Objects; + import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.Objects; - /** * An object specifying the format that the model must output. Setting to { "type": * "json_object" } enables JSON Output, which guarantees the message the model generates @@ -42,7 +42,7 @@ */ @JsonInclude(Include.NON_NULL) -public class ResponseFormat { +public final class ResponseFormat { /** * Type Must be one of 'text', 'json_object'. diff --git a/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/api/common/DeepSeekConstants.java b/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/api/common/DeepSeekConstants.java index 904b8e9a916..3bf26d3d47c 100644 --- a/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/api/common/DeepSeekConstants.java +++ b/models/spring-ai-deepseek/src/main/java/org/springframework/ai/deepseek/api/common/DeepSeekConstants.java @@ -1,11 +1,11 @@ /* - * Copyright 2023 - 2024 the original author or authors. + * Copyright 2023-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.ai.deepseek.api.common; import org.springframework.ai.observation.conventions.AiProvider; @@ -20,7 +21,7 @@ /** * @author Geng Rong */ -public class DeepSeekConstants { +public final class DeepSeekConstants { public static final String DEFAULT_BASE_URL = "https://api.deepseek.com"; diff --git a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/DeepSeekChatCompletionRequestTests.java b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/DeepSeekChatCompletionRequestTests.java index c5fafb72eae..11975ada387 100644 --- a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/DeepSeekChatCompletionRequestTests.java +++ b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/DeepSeekChatCompletionRequestTests.java @@ -1,11 +1,11 @@ /* - * Copyright 2023 - 2024 the original author or authors. + * Copyright 2023-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,9 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.ai.deepseek; import org.junit.jupiter.api.Test; + import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.deepseek.api.DeepSeekApi; 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 772f2fe106b..35f24eaadeb 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 @@ -16,15 +16,22 @@ package org.springframework.ai.deepseek; +import java.util.List; +import java.util.Optional; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; + import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.deepseek.api.DeepSeekApi; -import org.springframework.ai.deepseek.api.DeepSeekApi.*; +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletion; +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionFinishReason; +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionMessage; import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionMessage.Role; +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionRequest; import org.springframework.ai.retry.RetryUtils; import org.springframework.ai.retry.TransientAiException; import org.springframework.http.ResponseEntity; @@ -33,9 +40,6 @@ import org.springframework.retry.RetryListener; import org.springframework.retry.support.RetryTemplate; -import java.util.List; -import java.util.Optional; - import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.isA; @@ -65,7 +69,6 @@ public void beforeEach() { .defaultOptions(DeepSeekChatOptions.builder().build()) .retryTemplate(retryTemplate) .build(); - ; } @Test diff --git a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/DeepSeekTestConfiguration.java b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/DeepSeekTestConfiguration.java index 6e6cbdc3e49..b2b0ea8861b 100644 --- a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/DeepSeekTestConfiguration.java +++ b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/DeepSeekTestConfiguration.java @@ -1,11 +1,11 @@ /* - * Copyright 2023 - 2024 the original author or authors. + * Copyright 2023-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.ai.deepseek; import org.springframework.ai.deepseek.api.DeepSeekApi; diff --git a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/aot/DeepSeekRuntimeHintsTests.java b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/aot/DeepSeekRuntimeHintsTests.java index 089db117125..8157e212daf 100644 --- a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/aot/DeepSeekRuntimeHintsTests.java +++ b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/aot/DeepSeekRuntimeHintsTests.java @@ -1,11 +1,11 @@ /* - * Copyright 2023 - 2024 the original author or authors. + * Copyright 2023-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,15 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.ai.deepseek.aot; +import java.util.Set; + import org.junit.jupiter.api.Test; + import org.springframework.ai.deepseek.api.DeepSeekApi; import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.TypeReference; -import java.util.Set; - import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.springframework.ai.aot.AiRuntimeHints.findJsonAnnotatedClassesInPackage; import static org.springframework.aot.hint.predicate.RuntimeHintsPredicates.reflection; diff --git a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/api/DeepSeekApiIT.java b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/api/DeepSeekApiIT.java index 0e02625604f..8419cb5073c 100644 --- a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/api/DeepSeekApiIT.java +++ b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/api/DeepSeekApiIT.java @@ -1,11 +1,11 @@ /* - * Copyright 2023 - 2024 the original author or authors. + * Copyright 2023-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,16 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.ai.deepseek.api; +import java.util.List; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; -import org.springframework.ai.deepseek.api.DeepSeekApi.*; -import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionMessage.Role; -import org.springframework.http.ResponseEntity; import reactor.core.publisher.Flux; -import java.util.List; +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletion; +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionChunk; +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionMessage; +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionMessage.Role; +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatCompletionRequest; +import org.springframework.ai.deepseek.api.DeepSeekApi.ChatModel; +import org.springframework.http.ResponseEntity; import static org.assertj.core.api.Assertions.assertThat; @@ -37,7 +43,7 @@ public class DeepSeekApiIT { @Test void chatCompletionEntity() { ChatCompletionMessage chatCompletionMessage = new ChatCompletionMessage("Hello world", Role.USER); - ResponseEntity response = deepSeekApi.chatCompletionEntity( + ResponseEntity response = this.deepSeekApi.chatCompletionEntity( new ChatCompletionRequest(List.of(chatCompletionMessage), ChatModel.DEEPSEEK_CHAT.value, 1D, false)); assertThat(response).isNotNull(); @@ -47,7 +53,7 @@ void chatCompletionEntity() { @Test void chatCompletionStream() { ChatCompletionMessage chatCompletionMessage = new ChatCompletionMessage("Hello world", Role.USER); - Flux response = deepSeekApi.chatCompletionStream( + Flux response = this.deepSeekApi.chatCompletionStream( new ChatCompletionRequest(List.of(chatCompletionMessage), ChatModel.DEEPSEEK_CHAT.value, 1D, true)); assertThat(response).isNotNull(); diff --git a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/api/MockWeatherService.java b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/api/MockWeatherService.java index 060c6594706..4c200fe7a28 100644 --- a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/api/MockWeatherService.java +++ b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/api/MockWeatherService.java @@ -16,14 +16,14 @@ package org.springframework.ai.deepseek.api; +import java.util.function.Function; + import com.fasterxml.jackson.annotation.JsonClassDescription; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyDescription; -import java.util.function.Function; - /** * @author Geng Rong */ diff --git a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/chat/ActorsFilms.java b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/chat/ActorsFilms.java index 53f529ef3e4..a27d24ae5c1 100644 --- a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/chat/ActorsFilms.java +++ b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/chat/ActorsFilms.java @@ -1,11 +1,11 @@ /* - * Copyright 2023 - 2024 the original author or authors. + * Copyright 2023-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.ai.deepseek.chat; import java.util.List; @@ -30,7 +31,7 @@ public ActorsFilms() { } public String getActor() { - return actor; + return this.actor; } public void setActor(String actor) { @@ -38,7 +39,7 @@ public void setActor(String actor) { } public List getMovies() { - return movies; + return this.movies; } public void setMovies(List movies) { @@ -47,7 +48,7 @@ public void setMovies(List movies) { @Override public String toString() { - return "ActorsFilms{" + "actor='" + actor + '\'' + ", movies=" + movies + '}'; + return "ActorsFilms{" + "actor='" + this.actor + '\'' + ", movies=" + this.movies + '}'; } } diff --git a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/chat/DeepSeekChatModelFunctionCallingIT.java b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/chat/DeepSeekChatModelFunctionCallingIT.java index 32306d34079..f562719835b 100644 --- a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/chat/DeepSeekChatModelFunctionCallingIT.java +++ b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/chat/DeepSeekChatModelFunctionCallingIT.java @@ -16,10 +16,18 @@ package org.springframework.ai.deepseek.chat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; + import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.UserMessage; @@ -34,13 +42,6 @@ import org.springframework.ai.tool.function.FunctionToolCallback; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import reactor.core.publisher.Flux; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; diff --git a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/chat/DeepSeekChatModelIT.java b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/chat/DeepSeekChatModelIT.java index 1909ce808a0..1bd8067ee6d 100644 --- a/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/chat/DeepSeekChatModelIT.java +++ b/models/spring-ai-deepseek/src/test/java/org/springframework/ai/deepseek/chat/DeepSeekChatModelIT.java @@ -1,11 +1,11 @@ /* - * Copyright 2023 - 2024 the original author or authors. + * Copyright 2023-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,12 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.ai.deepseek.chat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.UserMessage; @@ -32,21 +41,16 @@ import org.springframework.ai.converter.BeanOutputConverter; import org.springframework.ai.converter.ListOutputConverter; import org.springframework.ai.converter.MapOutputConverter; +import org.springframework.ai.deepseek.DeepSeekAssistantMessage; import org.springframework.ai.deepseek.DeepSeekChatOptions; import org.springframework.ai.deepseek.DeepSeekTestConfiguration; -import org.springframework.ai.deepseek.DeepSeekAssistantMessage; import org.springframework.ai.deepseek.api.DeepSeekApi; -import org.springframework.ai.deepseek.api.MockWeatherService; -import org.springframework.ai.tool.function.FunctionToolCallback; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.io.Resource; -import java.util.*; -import java.util.stream.Collectors; - import static org.assertj.core.api.Assertions.assertThat; /** @@ -71,10 +75,10 @@ class DeepSeekChatModelIT { void roleTest() { UserMessage userMessage = new UserMessage( "Tell me about 3 famous pirates from the Golden Age of Piracy and what they did."); - SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemResource); + SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(this.systemResource); Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", "Bob", "voice", "pirate")); Prompt prompt = new Prompt(List.of(systemMessage, userMessage)); - ChatResponse response = chatModel.call(prompt); + ChatResponse response = this.chatModel.call(prompt); assertThat(response.getResults()).hasSize(1); assertThat(response.getResults().get(0).getOutput().getText()).contains("Blackbeard"); // needs fine tuning... evaluateQuestionAndAnswer(request, response, false); @@ -118,7 +122,7 @@ void mapOutputConverter() { format)) .build(); Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = chatModel.call(prompt).getResult(); + Generation generation = this.chatModel.call(prompt).getResult(); Map result = outputConverter.convert(generation.getOutput().getText()); assertThat(result.get("numbers")).isEqualTo(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9)); @@ -141,14 +145,11 @@ void beanOutputConverter() { .variables(Map.of("format", format)) .build(); Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = chatModel.call(prompt).getResult(); + Generation generation = this.chatModel.call(prompt).getResult(); ActorsFilms actorsFilms = outputConverter.convert(generation.getOutput().getText()); } - record ActorsFilmsRecord(String actor, List movies) { - } - @Test void beanOutputConverterRecords() { @@ -165,7 +166,7 @@ void beanOutputConverterRecords() { .variables(Map.of("format", format)) .build(); Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = chatModel.call(prompt).getResult(); + Generation generation = this.chatModel.call(prompt).getResult(); ActorsFilmsRecord actorsFilms = outputConverter.convert(generation.getOutput().getText()); logger.info("" + actorsFilms); @@ -190,7 +191,7 @@ void beanStreamOutputConverterRecords() { .build(); Prompt prompt = new Prompt(promptTemplate.createMessage()); - String generationTextFromStream = streamingChatModel.stream(prompt) + String generationTextFromStream = this.streamingChatModel.stream(prompt) .collectList() .block() .stream() @@ -225,7 +226,7 @@ void prefixCompletionTest() { UserMessage userMessage = new UserMessage(userMessageContent); Message assistantMessage = new DeepSeekAssistantMessage("{\"code\":200,\"result\":{\"total\":1,\"data\":[1"); Prompt prompt = new Prompt(List.of(userMessage, assistantMessage)); - ChatResponse response = chatModel.call(prompt); + ChatResponse response = this.chatModel.call(prompt); assertThat(response.getResult().getOutput().getText().equals(",2,3]}}")); } @@ -239,7 +240,7 @@ void reasonerModelTest() { .model(DeepSeekApi.ChatModel.DEEPSEEK_REASONER.getValue()) .build(); Prompt prompt = new Prompt("9.11 and 9.8, which is greater?", promptOptions); - ChatResponse response = chatModel.call(prompt); + ChatResponse response = this.chatModel.call(prompt); DeepSeekAssistantMessage deepSeekAssistantMessage = (DeepSeekAssistantMessage) response.getResult().getOutput(); assertThat(deepSeekAssistantMessage.getReasoningContent()).isNotEmpty(); @@ -258,7 +259,7 @@ void reasonerModelMultiRoundTest() { .build(); Prompt prompt = new Prompt(messages, promptOptions); - ChatResponse response = chatModel.call(prompt); + ChatResponse response = this.chatModel.call(prompt); DeepSeekAssistantMessage deepSeekAssistantMessage = (DeepSeekAssistantMessage) response.getResult().getOutput(); assertThat(deepSeekAssistantMessage.getReasoningContent()).isNotEmpty(); @@ -267,7 +268,7 @@ void reasonerModelMultiRoundTest() { messages.add(new AssistantMessage(Objects.requireNonNull(deepSeekAssistantMessage.getText()))); messages.add(new UserMessage("How many Rs are there in the word 'strawberry'?")); Prompt prompt2 = new Prompt(messages, promptOptions); - ChatResponse response2 = chatModel.call(prompt2); + ChatResponse response2 = this.chatModel.call(prompt2); DeepSeekAssistantMessage deepSeekAssistantMessage2 = (DeepSeekAssistantMessage) response2.getResult() .getOutput(); @@ -275,4 +276,7 @@ void reasonerModelMultiRoundTest() { assertThat(deepSeekAssistantMessage2.getText()).isNotEmpty(); } + record ActorsFilmsRecord(String actor, List movies) { + } + } 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 e95cc46b885..00e8732dade 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 @@ -16,11 +16,16 @@ package org.springframework.ai.deepseek.chat; +import java.util.List; +import java.util.stream.Collectors; + import io.micrometer.observation.tck.TestObservationRegistry; import io.micrometer.observation.tck.TestObservationRegistryAssert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; +import reactor.core.publisher.Flux; + import org.springframework.ai.chat.metadata.ChatResponseMetadata; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.observation.DefaultChatModelObservationConvention; @@ -36,10 +41,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.retry.support.RetryTemplate; -import reactor.core.publisher.Flux; - -import java.util.List; -import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.ai.chat.observation.ChatModelObservationDocumentation.HighCardinalityKeyNames; 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 9a5983785f7..5dd0077fed3 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 @@ -40,7 +40,6 @@ import org.springframework.ai.minimax.api.MiniMaxApiConstants; import org.springframework.ai.model.ModelOptionsUtils; import org.springframework.ai.retry.RetryUtils; -import org.springframework.lang.Nullable; import org.springframework.retry.support.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; 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 eee07597c7f..b9838dcedf1 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 @@ -39,7 +39,6 @@ import org.springframework.ai.chat.metadata.ChatResponseMetadata; import org.springframework.ai.chat.metadata.DefaultUsage; import org.springframework.ai.chat.metadata.Usage; -import org.springframework.ai.support.UsageCalculator; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.model.Generation; @@ -66,6 +65,7 @@ import org.springframework.ai.model.tool.ToolExecutionEligibilityPredicate; import org.springframework.ai.model.tool.ToolExecutionResult; import org.springframework.ai.retry.RetryUtils; +import org.springframework.ai.support.UsageCalculator; import org.springframework.ai.tool.definition.ToolDefinition; import org.springframework.http.ResponseEntity; import org.springframework.retry.support.RetryTemplate; diff --git a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatModelIT.java b/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatModelIT.java index 95386aed92d..38112b1e992 100644 --- a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatModelIT.java +++ b/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatModelIT.java @@ -364,14 +364,14 @@ void chatMemory() { UserMessage userMessage1 = new UserMessage("My name is James Bond"); memory.add(conversationId, userMessage1); - ChatResponse response1 = chatModel.call(new Prompt(memory.get(conversationId))); + ChatResponse response1 = this.chatModel.call(new Prompt(memory.get(conversationId))); assertThat(response1).isNotNull(); memory.add(conversationId, response1.getResult().getOutput()); UserMessage userMessage2 = new UserMessage("What is my name?"); memory.add(conversationId, userMessage2); - ChatResponse response2 = chatModel.call(new Prompt(memory.get(conversationId))); + ChatResponse response2 = this.chatModel.call(new Prompt(memory.get(conversationId))); assertThat(response2).isNotNull(); memory.add(conversationId, response2.getResult().getOutput()); @@ -396,7 +396,7 @@ void chatMemoryWithTools() { chatMemory.add(conversationId, prompt.getInstructions()); Prompt promptWithMemory = new Prompt(chatMemory.get(conversationId), chatOptions); - ChatResponse chatResponse = chatModel.call(promptWithMemory); + ChatResponse chatResponse = this.chatModel.call(promptWithMemory); chatMemory.add(conversationId, chatResponse.getResult().getOutput()); while (chatResponse.hasToolCalls()) { @@ -405,7 +405,7 @@ void chatMemoryWithTools() { chatMemory.add(conversationId, toolExecutionResult.conversationHistory() .get(toolExecutionResult.conversationHistory().size() - 1)); promptWithMemory = new Prompt(chatMemory.get(conversationId), chatOptions); - chatResponse = chatModel.call(promptWithMemory); + chatResponse = this.chatModel.call(promptWithMemory); chatMemory.add(conversationId, chatResponse.getResult().getOutput()); } @@ -415,7 +415,7 @@ void chatMemoryWithTools() { UserMessage newUserMessage = new UserMessage("What did I ask you earlier?"); chatMemory.add(conversationId, newUserMessage); - ChatResponse newResponse = chatModel.call(new Prompt(chatMemory.get(conversationId))); + ChatResponse newResponse = this.chatModel.call(new Prompt(chatMemory.get(conversationId))); assertThat(newResponse).isNotNull(); assertThat(newResponse.getResult().getOutput().getText()).contains("6").contains("8"); diff --git a/models/spring-ai-oci-genai/src/main/java/org/springframework/ai/oci/cohere/OCICohereChatModel.java b/models/spring-ai-oci-genai/src/main/java/org/springframework/ai/oci/cohere/OCICohereChatModel.java index 462a9773ab4..b9c771b58bb 100644 --- a/models/spring-ai-oci-genai/src/main/java/org/springframework/ai/oci/cohere/OCICohereChatModel.java +++ b/models/spring-ai-oci-genai/src/main/java/org/springframework/ai/oci/cohere/OCICohereChatModel.java @@ -53,7 +53,6 @@ import org.springframework.ai.chat.prompt.ChatOptions; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.model.ModelOptionsUtils; -import org.springframework.ai.model.tool.ToolCallingChatOptions; import org.springframework.ai.observation.conventions.AiProvider; import org.springframework.ai.oci.ServingModeHelper; import org.springframework.util.Assert; diff --git a/models/spring-ai-oci-genai/src/main/java/org/springframework/ai/oci/cohere/OCICohereChatOptions.java b/models/spring-ai-oci-genai/src/main/java/org/springframework/ai/oci/cohere/OCICohereChatOptions.java index 69488cea8ea..62e5867b350 100644 --- a/models/spring-ai-oci-genai/src/main/java/org/springframework/ai/oci/cohere/OCICohereChatOptions.java +++ b/models/spring-ai-oci-genai/src/main/java/org/springframework/ai/oci/cohere/OCICohereChatOptions.java @@ -267,16 +267,19 @@ public ChatOptions copy() { @Override public int hashCode() { - return Objects.hash(model, maxTokens, compartment, servingMode, preambleOverride, temperature, topP, topK, stop, - frequencyPenalty, presencePenalty, documents, tools); + return Objects.hash(this.model, this.maxTokens, this.compartment, this.servingMode, this.preambleOverride, + this.temperature, this.topP, this.topK, this.stop, this.frequencyPenalty, this.presencePenalty, + this.documents, this.tools); } @Override public boolean equals(Object o) { - if (this == o) + if (this == o) { return true; - if (o == null || getClass() != o.getClass()) + } + if (o == null || getClass() != o.getClass()) { return false; + } OCICohereChatOptions that = (OCICohereChatOptions) o; diff --git a/models/spring-ai-oci-genai/src/test/java/org/springframework/ai/oci/cohere/OCICohereChatOptionsTests.java b/models/spring-ai-oci-genai/src/test/java/org/springframework/ai/oci/cohere/OCICohereChatOptionsTests.java index 4359d920bb5..4a87f40289c 100644 --- a/models/spring-ai-oci-genai/src/test/java/org/springframework/ai/oci/cohere/OCICohereChatOptionsTests.java +++ b/models/spring-ai-oci-genai/src/test/java/org/springframework/ai/oci/cohere/OCICohereChatOptionsTests.java @@ -16,12 +16,12 @@ package org.springframework.ai.oci.cohere; -import com.oracle.bmc.generativeaiinference.model.CohereTool; -import org.junit.jupiter.api.Test; - import java.util.List; import java.util.Map; +import com.oracle.bmc.generativeaiinference.model.CohereTool; +import org.junit.jupiter.api.Test; + import static org.assertj.core.api.Assertions.assertThat; /** 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 54bf4461187..a75a274a797 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 @@ -344,7 +344,8 @@ private Flux internalStream(Prompt prompt, ChatResponse previousCh return Flux.just(ChatResponse.builder().from(response) .generations(ToolExecutionResult.buildGenerations(toolExecutionResult)) .build()); - } else { + } + else { // Send the tool execution result back to the model. return this.internalStream(new Prompt(toolExecutionResult.conversationHistory(), prompt.getOptions()), response); diff --git a/models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/api/OllamaApi.java b/models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/api/OllamaApi.java index 15faf10f183..e0ffc06c31d 100644 --- a/models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/api/OllamaApi.java +++ b/models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/api/OllamaApi.java @@ -54,9 +54,11 @@ * @since 0.8.0 */ // @formatter:off -public class OllamaApi { +public final class OllamaApi { - public static Builder builder() { return new Builder(); } + public static Builder builder() { + return new Builder(); + } public static final String REQUEST_BODY_NULL_ERROR = "The request body can not be null."; diff --git a/models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaChatModelIT.java b/models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaChatModelIT.java index ed460135f87..b322a82d764 100644 --- a/models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaChatModelIT.java +++ b/models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaChatModelIT.java @@ -280,14 +280,14 @@ void chatMemory() { UserMessage userMessage1 = new UserMessage("My name is James Bond"); memory.add(conversationId, userMessage1); - ChatResponse response1 = chatModel.call(new Prompt(memory.get(conversationId))); + ChatResponse response1 = this.chatModel.call(new Prompt(memory.get(conversationId))); assertThat(response1).isNotNull(); memory.add(conversationId, response1.getResult().getOutput()); UserMessage userMessage2 = new UserMessage("What is my name?"); memory.add(conversationId, userMessage2); - ChatResponse response2 = chatModel.call(new Prompt(memory.get(conversationId))); + ChatResponse response2 = this.chatModel.call(new Prompt(memory.get(conversationId))); assertThat(response2).isNotNull(); memory.add(conversationId, response2.getResult().getOutput()); @@ -312,7 +312,7 @@ void chatMemoryWithTools() { chatMemory.add(conversationId, prompt.getInstructions()); Prompt promptWithMemory = new Prompt(chatMemory.get(conversationId), chatOptions); - ChatResponse chatResponse = chatModel.call(promptWithMemory); + ChatResponse chatResponse = this.chatModel.call(promptWithMemory); chatMemory.add(conversationId, chatResponse.getResult().getOutput()); while (chatResponse.hasToolCalls()) { @@ -321,7 +321,7 @@ void chatMemoryWithTools() { chatMemory.add(conversationId, toolExecutionResult.conversationHistory() .get(toolExecutionResult.conversationHistory().size() - 1)); promptWithMemory = new Prompt(chatMemory.get(conversationId), chatOptions); - chatResponse = chatModel.call(promptWithMemory); + chatResponse = this.chatModel.call(promptWithMemory); chatMemory.add(conversationId, chatResponse.getResult().getOutput()); } @@ -331,7 +331,7 @@ void chatMemoryWithTools() { UserMessage newUserMessage = new UserMessage("What did I ask you earlier?"); chatMemory.add(conversationId, newUserMessage); - ChatResponse newResponse = chatModel.call(new Prompt(chatMemory.get(conversationId))); + ChatResponse newResponse = this.chatModel.call(new Prompt(chatMemory.get(conversationId))); assertThat(newResponse).isNotNull(); assertThat(newResponse.getResult().getOutput().getText()).contains("6").contains("8"); 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 ae840a073a2..58a0062eccd 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 @@ -43,7 +43,6 @@ import org.springframework.ai.chat.metadata.EmptyUsage; import org.springframework.ai.chat.metadata.RateLimit; import org.springframework.ai.chat.metadata.Usage; -import org.springframework.ai.support.UsageCalculator; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.model.Generation; @@ -74,6 +73,7 @@ import org.springframework.ai.openai.api.common.OpenAiApiConstants; import org.springframework.ai.openai.metadata.support.OpenAiResponseHeaderExtractor; import org.springframework.ai.retry.RetryUtils; +import org.springframework.ai.support.UsageCalculator; import org.springframework.ai.tool.definition.ToolDefinition; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.Resource; 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 ac3c52e691f..2b11927f908 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 @@ -296,6 +296,31 @@ public ResponseEntity> embeddings(EmbeddingRequest< }); } + // Package-private getters for mutate/copy + String getBaseUrl() { + return this.baseUrl; + } + + ApiKey getApiKey() { + return this.apiKey; + } + + MultiValueMap getHeaders() { + return this.headers; + } + + String getCompletionsPath() { + return this.completionsPath; + } + + String getEmbeddingsPath() { + return this.embeddingsPath; + } + + ResponseErrorHandler getResponseErrorHandler() { + return this.responseErrorHandler; + } + /** * OpenAI Chat Completion Models. *

@@ -1193,7 +1218,7 @@ public record StreamOptions( */ @JsonInclude(Include.NON_NULL) public record WebSearchOptions(@JsonProperty("search_context_size") SearchContextSize searchContextSize, - @JsonProperty("user_location") UserLocation userLocation) { + @JsonProperty("user_location") UserLocation userLocation) { /** * High level guidance for the amount of context window space to use for the @@ -1229,11 +1254,11 @@ public enum SearchContextSize { */ @JsonInclude(Include.NON_NULL) public record UserLocation(@JsonProperty("type") String type, - @JsonProperty("approximate") Approximate approximate) { + @JsonProperty("approximate") Approximate approximate) { @JsonInclude(Include.NON_NULL) public record Approximate(@JsonProperty("city") String city, @JsonProperty("country") String country, - @JsonProperty("region") String region, @JsonProperty("timezone") String timezone) { + @JsonProperty("region") String region, @JsonProperty("timezone") String timezone) { } } @@ -1891,29 +1916,4 @@ public OpenAiApi build() { } - // Package-private getters for mutate/copy - String getBaseUrl() { - return this.baseUrl; - } - - ApiKey getApiKey() { - return this.apiKey; - } - - MultiValueMap getHeaders() { - return this.headers; - } - - String getCompletionsPath() { - return this.completionsPath; - } - - String getEmbeddingsPath() { - return this.embeddingsPath; - } - - ResponseErrorHandler getResponseErrorHandler() { - return this.responseErrorHandler; - } - } 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 251b3d6a10f..1dc869b1593 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 @@ -36,26 +36,29 @@ class OpenAiChatModelMutateTests { private final OpenAiApi baseApi = OpenAiApi.builder().baseUrl("https://api.openai.com").apiKey("base-key").build(); private final OpenAiChatModel baseModel = OpenAiChatModel.builder() - .openAiApi(baseApi) + .openAiApi(this.baseApi) .defaultOptions(OpenAiChatOptions.builder().model("gpt-3.5-turbo").build()) .build(); @Test void testMutateCreatesDistinctClientsWithDifferentEndpointsAndModels() { // Mutate for GPT-4 - OpenAiApi gpt4Api = baseApi.mutate().baseUrl("https://api.openai.com").apiKey("your-api-key-for-gpt4").build(); - OpenAiChatModel gpt4Model = baseModel.mutate() + OpenAiApi gpt4Api = this.baseApi.mutate() + .baseUrl("https://api.openai.com") + .apiKey("your-api-key-for-gpt4") + .build(); + OpenAiChatModel gpt4Model = this.baseModel.mutate() .openAiApi(gpt4Api) .defaultOptions(OpenAiChatOptions.builder().model("gpt-4").temperature(0.7).build()) .build(); ChatClient gpt4Client = ChatClient.builder(gpt4Model).build(); // Mutate for Llama - OpenAiApi llamaApi = baseApi.mutate() + OpenAiApi llamaApi = this.baseApi.mutate() .baseUrl("https://your-custom-endpoint.com") .apiKey("your-api-key-for-llama") .build(); - OpenAiChatModel llamaModel = baseModel.mutate() + OpenAiChatModel llamaModel = this.baseModel.mutate() .openAiApi(llamaApi) .defaultOptions(OpenAiChatOptions.builder().model("llama-70b").temperature(0.5).build()) .build(); @@ -72,29 +75,29 @@ void testMutateCreatesDistinctClientsWithDifferentEndpointsAndModels() { @Test void testCloneCreatesDeepCopy() { - OpenAiChatModel clone = baseModel.clone(); - assertThat(clone).isNotSameAs(baseModel); - assertThat(clone.toString()).isEqualTo(baseModel.toString()); + OpenAiChatModel clone = this.baseModel.clone(); + assertThat(clone).isNotSameAs(this.baseModel); + assertThat(clone.toString()).isEqualTo(this.baseModel.toString()); } @Test void mutateDoesNotAffectOriginal() { - OpenAiChatModel mutated = baseModel.mutate() + OpenAiChatModel mutated = this.baseModel.mutate() .defaultOptions(OpenAiChatOptions.builder().model("gpt-4").build()) .build(); - assertThat(mutated).isNotSameAs(baseModel); + assertThat(mutated).isNotSameAs(this.baseModel); assertThat(mutated.getDefaultOptions().getModel()).isEqualTo("gpt-4"); - assertThat(baseModel.getDefaultOptions().getModel()).isEqualTo("gpt-3.5-turbo"); + assertThat(this.baseModel.getDefaultOptions().getModel()).isEqualTo("gpt-3.5-turbo"); } @Test void mutateHeadersCreatesDistinctHeaders() { - OpenAiApi mutatedApi = baseApi.mutate() + OpenAiApi mutatedApi = this.baseApi.mutate() .headers(new LinkedMultiValueMap<>(java.util.Map.of("X-Test", java.util.List.of("value")))) .build(); assertThat(mutatedApi.getHeaders()).containsKey("X-Test"); - assertThat(baseApi.getHeaders()).doesNotContainKey("X-Test"); + assertThat(this.baseApi.getHeaders()).doesNotContainKey("X-Test"); } @Test @@ -108,7 +111,9 @@ void mutateHandlesNullAndDefaults() { @Test void multipleSequentialMutationsProduceDistinctInstances() { - OpenAiChatModel m1 = baseModel.mutate().defaultOptions(OpenAiChatOptions.builder().model("m1").build()).build(); + OpenAiChatModel m1 = this.baseModel.mutate() + .defaultOptions(OpenAiChatOptions.builder().model("m1").build()) + .build(); OpenAiChatModel m2 = m1.mutate().defaultOptions(OpenAiChatOptions.builder().model("m2").build()).build(); OpenAiChatModel m3 = m2.mutate().defaultOptions(OpenAiChatOptions.builder().model("m3").build()).build(); assertThat(m1).isNotSameAs(m2); @@ -120,8 +125,8 @@ void multipleSequentialMutationsProduceDistinctInstances() { @Test void mutateAndCloneAreEquivalent() { - OpenAiChatModel mutated = baseModel.mutate().build(); - OpenAiChatModel cloned = baseModel.clone(); + OpenAiChatModel mutated = this.baseModel.mutate().build(); + OpenAiChatModel cloned = this.baseModel.clone(); assertThat(mutated.toString()).isEqualTo(cloned.toString()); assertThat(mutated).isNotSameAs(cloned); } 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 df4a6fa8bbf..f24b71f62d1 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 @@ -18,7 +18,6 @@ import java.net.MalformedURLException; import java.net.URI; -import java.net.URL; import java.util.List; import java.util.Map; diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiChatModelIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiChatModelIT.java index 747f7d7caec..108e1d31bfa 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiChatModelIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiChatModelIT.java @@ -643,14 +643,14 @@ void chatMemory() { UserMessage userMessage1 = new UserMessage("My name is James Bond"); memory.add(conversationId, userMessage1); - ChatResponse response1 = chatModel.call(new Prompt(memory.get(conversationId))); + ChatResponse response1 = this.chatModel.call(new Prompt(memory.get(conversationId))); assertThat(response1).isNotNull(); memory.add(conversationId, response1.getResult().getOutput()); UserMessage userMessage2 = new UserMessage("What is my name?"); memory.add(conversationId, userMessage2); - ChatResponse response2 = chatModel.call(new Prompt(memory.get(conversationId))); + ChatResponse response2 = this.chatModel.call(new Prompt(memory.get(conversationId))); assertThat(response2).isNotNull(); memory.add(conversationId, response2.getResult().getOutput()); @@ -675,7 +675,7 @@ void chatMemoryWithTools() { chatMemory.add(conversationId, prompt.getInstructions()); Prompt promptWithMemory = new Prompt(chatMemory.get(conversationId), chatOptions); - ChatResponse chatResponse = chatModel.call(promptWithMemory); + ChatResponse chatResponse = this.chatModel.call(promptWithMemory); chatMemory.add(conversationId, chatResponse.getResult().getOutput()); while (chatResponse.hasToolCalls()) { @@ -684,7 +684,7 @@ void chatMemoryWithTools() { chatMemory.add(conversationId, toolExecutionResult.conversationHistory() .get(toolExecutionResult.conversationHistory().size() - 1)); promptWithMemory = new Prompt(chatMemory.get(conversationId), chatOptions); - chatResponse = chatModel.call(promptWithMemory); + chatResponse = this.chatModel.call(promptWithMemory); chatMemory.add(conversationId, chatResponse.getResult().getOutput()); } @@ -694,21 +694,12 @@ void chatMemoryWithTools() { UserMessage newUserMessage = new UserMessage("What did I ask you earlier?"); chatMemory.add(conversationId, newUserMessage); - ChatResponse newResponse = chatModel.call(new Prompt(chatMemory.get(conversationId))); + ChatResponse newResponse = this.chatModel.call(new Prompt(chatMemory.get(conversationId))); assertThat(newResponse).isNotNull(); assertThat(newResponse.getResult().getOutput().getText()).contains("6").contains("8"); } - static class MathTools { - - @Tool(description = "Multiply the two numbers") - double multiply(double a, double b) { - return a * b; - } - - } - @Test void webSearchAnnotationsTest() { UserMessage userMessage = new UserMessage("What is the latest news on the Mars rover?"); @@ -779,4 +770,13 @@ record ActorsFilmsRecord(String actor, List movies) { } + static class MathTools { + + @Tool(description = "Multiply the two numbers") + double multiply(double a, double b) { + return a * b; + } + + } + } diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiPaymentTransactionIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiPaymentTransactionIT.java index b3b3a876192..d2cee2e2eae 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiPaymentTransactionIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiPaymentTransactionIT.java @@ -28,10 +28,10 @@ import org.junit.jupiter.params.provider.ValueSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor; import reactor.core.publisher.Flux; import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor; import org.springframework.ai.converter.BeanOutputConverter; import org.springframework.ai.model.tool.ToolCallingManager; import org.springframework.ai.openai.OpenAiChatModel; diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientMemoryAdvisorReproIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientMemoryAdvisorReproIT.java index 6db48a15baa..30a75f1b6dc 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientMemoryAdvisorReproIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientMemoryAdvisorReproIT.java @@ -1,3 +1,19 @@ +/* + * Copyright 2025-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.ai.openai.chat.client; import java.util.List; @@ -41,7 +57,7 @@ void messageChatMemoryAdvisor_withPromptMessages_throwsException() { .build(); MessageChatMemoryAdvisor advisor = MessageChatMemoryAdvisor.builder(chatMemory).build(); - ChatClient chatClient = ChatClient.builder(chatModel).defaultAdvisors(advisor).build(); + ChatClient chatClient = ChatClient.builder(this.chatModel).defaultAdvisors(advisor).build(); // Act: call should succeed without exception (issue #2339 is fixed) chatClient.prompt(prompt).call().chatResponse(); // Should not throw diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/ReReadingAdvisor.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/ReReadingAdvisor.java index cdd92d07b04..d4d8c94f9b9 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/ReReadingAdvisor.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/ReReadingAdvisor.java @@ -57,7 +57,7 @@ public ReReadingAdvisor(String re2AdviseTemplate) { @Override public ChatClientRequest before(ChatClientRequest chatClientRequest, AdvisorChain advisorChain) { String augmentedUserText = PromptTemplate.builder() - .template(re2AdviseTemplate) + .template(this.re2AdviseTemplate) .variables(Map.of("re2_input_query", chatClientRequest.prompt().getUserMessage().getText())) .build() .render(); diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/advisor/AbstractChatMemoryAdvisorIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/advisor/AbstractChatMemoryAdvisorIT.java index 238ceb171ac..1b7105e7ba5 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/advisor/AbstractChatMemoryAdvisorIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/advisor/AbstractChatMemoryAdvisorIT.java @@ -81,7 +81,7 @@ protected void testMultipleUserMessagesInPrompt() { var advisor = createAdvisor(chatMemory); - ChatClient chatClient = ChatClient.builder(chatModel).defaultAdvisors(advisor).build(); + ChatClient chatClient = ChatClient.builder(this.chatModel).defaultAdvisors(advisor).build(); // Create a prompt with multiple user messages List messages = new ArrayList<>(); @@ -131,7 +131,7 @@ protected void testMultipleUserMessagesInSamePrompt() { // Create advisor with the conversation ID var advisor = createAdvisor(chatMemory); - ChatClient chatClient = ChatClient.builder(chatModel).defaultAdvisors(advisor).build(); + ChatClient chatClient = ChatClient.builder(this.chatModel).defaultAdvisors(advisor).build(); // Act - Create a list of messages for the prompt List messages = new ArrayList<>(); @@ -193,7 +193,7 @@ protected void testUseCustomConversationId() { // Create advisor without a default conversation ID var advisor = createAdvisor(chatMemory); - ChatClient chatClient = ChatClient.builder(chatModel).defaultAdvisors(advisor).build(); + ChatClient chatClient = ChatClient.builder(this.chatModel).defaultAdvisors(advisor).build(); String question = "What is the capital of Germany?"; @@ -231,7 +231,7 @@ protected void testMaintainSeparateConversations() { // Create advisor without a default conversation ID var advisor = createAdvisor(chatMemory); - ChatClient chatClient = ChatClient.builder(chatModel).defaultAdvisors(advisor).build(); + ChatClient chatClient = ChatClient.builder(this.chatModel).defaultAdvisors(advisor).build(); // Act - First conversation String answer1 = chatClient.prompt() @@ -316,7 +316,7 @@ protected void testHandleNonExistentConversation() { // Create advisor without a default conversation ID var advisor = createAdvisor(chatMemory); - ChatClient chatClient = ChatClient.builder(chatModel).defaultAdvisors(advisor).build(); + ChatClient chatClient = ChatClient.builder(this.chatModel).defaultAdvisors(advisor).build(); // Act - Send a question to a non-existent conversation String question = "Do you remember our previous conversation?"; @@ -375,7 +375,7 @@ protected void testHandleMultipleMessagesInReactiveMode() { var advisor = createAdvisor(chatMemory); - ChatClient chatClient = ChatClient.builder(chatModel).defaultAdvisors(advisor).build(); + ChatClient chatClient = ChatClient.builder(this.chatModel).defaultAdvisors(advisor).build(); List responseList = new ArrayList<>(); for (String message : List.of("My name is Charlie.", "I am 30 years old.", "I live in London.")) { diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/advisor/MessageChatMemoryAdvisorIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/advisor/MessageChatMemoryAdvisorIT.java index 45f63ac714b..06e2e994eb1 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/advisor/MessageChatMemoryAdvisorIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/advisor/MessageChatMemoryAdvisorIT.java @@ -91,7 +91,7 @@ void shouldHandleMultipleUserMessagesInPrompt() { .conversationId(conversationId) .build(); - ChatClient chatClient = ChatClient.builder(chatModel).defaultAdvisors(advisor).build(); + ChatClient chatClient = ChatClient.builder(this.chatModel).defaultAdvisors(advisor).build(); // Create a prompt with multiple user messages List messages = new ArrayList<>(); @@ -151,7 +151,7 @@ void shouldStoreCompleteContentInStreamingMode() { .conversationId(conversationId) .build(); - ChatClient chatClient = ChatClient.builder(chatModel).defaultAdvisors(advisor).build(); + ChatClient chatClient = ChatClient.builder(this.chatModel).defaultAdvisors(advisor).build(); // Act - Use streaming API String userInput = "Tell me a short joke about programming"; diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/MultiOpenAiClientIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/MultiOpenAiClientIT.java index 15a49d40afe..af3e0eaa55c 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/MultiOpenAiClientIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/MultiOpenAiClientIT.java @@ -50,25 +50,25 @@ class MultiOpenAiClientIT { @Test void multiClientFlow() { // Derive a new OpenAiApi for Groq (Llama3) - OpenAiApi groqApi = baseOpenAiApi.mutate() + OpenAiApi groqApi = this.baseOpenAiApi.mutate() .baseUrl("https://api.groq.com/openai") .apiKey(System.getenv("GROQ_API_KEY")) .build(); // Derive a new OpenAiApi for OpenAI GPT-4 - OpenAiApi gpt4Api = baseOpenAiApi.mutate() + OpenAiApi gpt4Api = this.baseOpenAiApi.mutate() .baseUrl("https://api.openai.com") .apiKey(System.getenv("OPENAI_API_KEY")) .build(); // Derive a new OpenAiChatModel for Groq - OpenAiChatModel groqModel = baseChatModel.mutate() + OpenAiChatModel groqModel = this.baseChatModel.mutate() .openAiApi(groqApi) .defaultOptions(OpenAiChatOptions.builder().model("llama3-70b-8192").temperature(0.5).build()) .build(); // Derive a new OpenAiChatModel for GPT-4 - OpenAiChatModel gpt4Model = baseChatModel.mutate() + OpenAiChatModel gpt4Model = this.baseChatModel.mutate() .openAiApi(gpt4Api) .defaultOptions(OpenAiChatOptions.builder().model("gpt-4").temperature(0.7).build()) .build(); diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/VertexAIGeminiWithOpenAiChatModelIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/VertexAIGeminiWithOpenAiChatModelIT.java index 7b3ed862f5e..d25c3190f9c 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/VertexAIGeminiWithOpenAiChatModelIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/VertexAIGeminiWithOpenAiChatModelIT.java @@ -16,8 +16,14 @@ package org.springframework.ai.openai.chat.proxy; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; +import reactor.core.publisher.Flux; + import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.UserMessage; @@ -36,11 +42,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.core.io.Resource; -import reactor.core.publisher.Flux; - -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/transformer/MetadataTransformerIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/transformer/MetadataTransformerIT.java index 15f588fa532..cec72f2d3ef 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/transformer/MetadataTransformerIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/transformer/MetadataTransformerIT.java @@ -24,10 +24,10 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; -import org.springframework.ai.model.transformer.KeywordMetadataEnricher; -import org.springframework.ai.model.transformer.SummaryMetadataEnricher; import org.springframework.ai.document.DefaultContentFormatter; import org.springframework.ai.document.Document; +import org.springframework.ai.model.transformer.KeywordMetadataEnricher; +import org.springframework.ai.model.transformer.SummaryMetadataEnricher; import org.springframework.ai.openai.OpenAiChatModel; import org.springframework.ai.openai.api.OpenAiApi; import org.springframework.ai.transformer.ContentFormatTransformer; diff --git a/models/spring-ai-vertex-ai-embedding/src/test/java/org/springframework/ai/vertexai/embedding/text/VertexAiTextEmbeddingModelIT.java b/models/spring-ai-vertex-ai-embedding/src/test/java/org/springframework/ai/vertexai/embedding/text/VertexAiTextEmbeddingModelIT.java index 40b7ffd881b..fc7105807af 100644 --- a/models/spring-ai-vertex-ai-embedding/src/test/java/org/springframework/ai/vertexai/embedding/text/VertexAiTextEmbeddingModelIT.java +++ b/models/spring-ai-vertex-ai-embedding/src/test/java/org/springframework/ai/vertexai/embedding/text/VertexAiTextEmbeddingModelIT.java @@ -37,7 +37,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; -import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest(classes = VertexAiTextEmbeddingModelIT.Config.class) @@ -169,7 +168,7 @@ private float[] getEmbeddingUsingGoogleSdk(String text, String taskType) { .stream() .map(Value::getNumberValue) .map(Double::floatValue) - .collect(toList()); + .toList(); float[] floatArray = new float[floatList.size()]; for (int i = 0; i < floatList.size(); i++) { 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 a228d345a95..01ab8b96c02 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 @@ -63,7 +63,6 @@ import org.springframework.ai.chat.metadata.DefaultUsage; import org.springframework.ai.chat.metadata.EmptyUsage; import org.springframework.ai.chat.metadata.Usage; -import org.springframework.ai.support.UsageCalculator; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.model.Generation; @@ -83,6 +82,7 @@ import org.springframework.ai.model.tool.ToolExecutionEligibilityPredicate; import org.springframework.ai.model.tool.ToolExecutionResult; import org.springframework.ai.retry.RetryUtils; +import org.springframework.ai.support.UsageCalculator; import org.springframework.ai.tool.definition.ToolDefinition; import org.springframework.ai.vertexai.gemini.common.VertexAiGeminiConstants; import org.springframework.ai.vertexai.gemini.common.VertexAiGeminiSafetySetting; diff --git a/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/CreateGeminiRequestTests.java b/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/CreateGeminiRequestTests.java index 37d68bcf613..bcb32a748fa 100644 --- a/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/CreateGeminiRequestTests.java +++ b/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/CreateGeminiRequestTests.java @@ -18,7 +18,6 @@ import java.net.MalformedURLException; import java.net.URI; -import java.net.URL; import java.util.List; import com.google.cloud.vertexai.VertexAI; diff --git a/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/tool/VertexAiGeminiPaymentTransactionIT.java b/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/tool/VertexAiGeminiPaymentTransactionIT.java index b5901439bb0..71d9311e56e 100644 --- a/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/tool/VertexAiGeminiPaymentTransactionIT.java +++ b/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/tool/VertexAiGeminiPaymentTransactionIT.java @@ -29,10 +29,10 @@ import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor; import reactor.core.publisher.Flux; import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor; import org.springframework.ai.model.tool.ToolCallingManager; import org.springframework.ai.tool.ToolCallback; import org.springframework.ai.tool.execution.DefaultToolExecutionExceptionProcessor; diff --git a/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/tool/VertexAiGeminiPaymentTransactionMethodIT.java b/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/tool/VertexAiGeminiPaymentTransactionMethodIT.java index 128800abf39..2b2635d8ba4 100644 --- a/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/tool/VertexAiGeminiPaymentTransactionMethodIT.java +++ b/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/tool/VertexAiGeminiPaymentTransactionMethodIT.java @@ -29,14 +29,14 @@ import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor; import reactor.core.publisher.Flux; import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor; import org.springframework.ai.model.tool.ToolCallingManager; +import org.springframework.ai.support.ToolCallbacks; import org.springframework.ai.tool.ToolCallback; import org.springframework.ai.tool.ToolCallbackProvider; -import org.springframework.ai.support.ToolCallbacks; import org.springframework.ai.tool.annotation.Tool; import org.springframework.ai.tool.execution.DefaultToolExecutionExceptionProcessor; import org.springframework.ai.tool.resolution.DelegatingToolCallbackResolver; diff --git a/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/tool/VertexAiGeminiPaymentTransactionToolsIT.java b/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/tool/VertexAiGeminiPaymentTransactionToolsIT.java index ba905754299..5832839b5de 100644 --- a/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/tool/VertexAiGeminiPaymentTransactionToolsIT.java +++ b/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/tool/VertexAiGeminiPaymentTransactionToolsIT.java @@ -28,10 +28,10 @@ import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor; import reactor.core.publisher.Flux; import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor; import org.springframework.ai.model.tool.ToolCallingManager; import org.springframework.ai.tool.ToolCallback; import org.springframework.ai.tool.annotation.Tool; diff --git a/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/chat/ZhiPuAiChatModelIT.java b/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/chat/ZhiPuAiChatModelIT.java index 1792c015c73..c18e22c0e0a 100644 --- a/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/chat/ZhiPuAiChatModelIT.java +++ b/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/chat/ZhiPuAiChatModelIT.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.net.URI; -import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.List; diff --git a/pom.xml b/pom.xml index 6c45eb4d619..bc24b6641f3 100644 --- a/pom.xml +++ b/pom.xml @@ -337,7 +337,7 @@ true 9.3 - true + false diff --git a/spring-ai-bom/pom.xml b/spring-ai-bom/pom.xml index 38f3c6b86be..ca1a57cf65b 100644 --- a/spring-ai-bom/pom.xml +++ b/spring-ai-bom/pom.xml @@ -82,11 +82,6 @@ 4.0.0-M13 3.3.0 3.1.1 - 3.5.0 - true - true - 9.3 - true @@ -1145,51 +1140,6 @@ - - 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 diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/ChatClientAttributes.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/ChatClientAttributes.java index b7a967c3a3b..c0c6fe22525 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/ChatClientAttributes.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/ChatClientAttributes.java @@ -37,7 +37,7 @@ public enum ChatClientAttributes { } public String getKey() { - return key; + return this.key; } } diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/ChatClientRequest.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/ChatClientRequest.java index 958cde32cb0..5a04db360c7 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/ChatClientRequest.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/ChatClientRequest.java @@ -16,12 +16,12 @@ package org.springframework.ai.chat.client; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.util.Assert; - import java.util.HashMap; import java.util.Map; +import org.springframework.ai.chat.prompt.Prompt; +import org.springframework.util.Assert; + /** * Represents a request processed by a {@link ChatClient} that ultimately is used to build * a {@link Prompt} to be sent to an AI model. @@ -79,7 +79,7 @@ public Builder context(String key, Object value) { } public ChatClientRequest build() { - return new ChatClientRequest(prompt, context); + return new ChatClientRequest(this.prompt, this.context); } } diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/ChatClientResponse.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/ChatClientResponse.java index 9a0db3ae419..a069702356b 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/ChatClientResponse.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/ChatClientResponse.java @@ -16,13 +16,13 @@ package org.springframework.ai.chat.client; +import java.util.HashMap; +import java.util.Map; + import org.springframework.ai.chat.model.ChatResponse; import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import java.util.HashMap; -import java.util.Map; - /** * Represents a response returned by a {@link ChatClient}. * @@ -50,7 +50,7 @@ public static Builder builder() { return new Builder(); } - public static class Builder { + public static final class Builder { private ChatResponse chatResponse; diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/DefaultChatClient.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/DefaultChatClient.java index 82327f43981..f5a1e8cd11a 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/DefaultChatClient.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/DefaultChatClient.java @@ -52,11 +52,11 @@ import org.springframework.ai.content.Media; import org.springframework.ai.converter.BeanOutputConverter; import org.springframework.ai.converter.StructuredOutputConverter; +import org.springframework.ai.support.ToolCallbacks; import org.springframework.ai.template.TemplateRenderer; import org.springframework.ai.template.st.StTemplateRenderer; import org.springframework.ai.tool.ToolCallback; import org.springframework.ai.tool.ToolCallbackProvider; -import org.springframework.ai.support.ToolCallbacks; import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.io.Resource; import org.springframework.lang.Nullable; @@ -455,17 +455,20 @@ private ChatClientResponse doGetObservableChatClientResponse(ChatClientRequest c ChatClientObservationContext observationContext = ChatClientObservationContext.builder() .request(chatClientRequest) - .advisors(advisorChain.getCallAdvisors()) + .advisors(this.advisorChain.getCallAdvisors()) .stream(false) .format(outputFormat) .build(); - var observation = ChatClientObservationDocumentation.AI_CHAT_CLIENT.observation(observationConvention, - DEFAULT_CHAT_CLIENT_OBSERVATION_CONVENTION, () -> observationContext, observationRegistry); + var observation = ChatClientObservationDocumentation.AI_CHAT_CLIENT.observation(this.observationConvention, + DEFAULT_CHAT_CLIENT_OBSERVATION_CONVENTION, () -> observationContext, this.observationRegistry); + + // CHECKSTYLE:OFF var chatClientResponse = observation.observe(() -> { // Apply the advisor chain that terminates with the ChatModelCallAdvisor. - return advisorChain.nextCall(chatClientRequest); + return this.advisorChain.nextCall(chatClientRequest); }); + // CHECKSTYLE:ON return chatClientResponse != null ? chatClientResponse : ChatClientResponse.builder().build(); } @@ -508,20 +511,20 @@ private Flux doGetObservableFluxChatResponse(ChatClientReque ChatClientObservationContext observationContext = ChatClientObservationContext.builder() .request(chatClientRequest) - .advisors(advisorChain.getStreamAdvisors()) + .advisors(this.advisorChain.getStreamAdvisors()) .stream(true) .build(); Observation observation = ChatClientObservationDocumentation.AI_CHAT_CLIENT.observation( - observationConvention, DEFAULT_CHAT_CLIENT_OBSERVATION_CONVENTION, () -> observationContext, - observationRegistry); + this.observationConvention, DEFAULT_CHAT_CLIENT_OBSERVATION_CONVENTION, + () -> observationContext, this.observationRegistry); observation.parentObservation(contextView.getOrDefault(ObservationThreadLocalAccessor.KEY, null)) .start(); // @formatter:off // Apply the advisor chain that terminates with the ChatModelStreamAdvisor. - return advisorChain.nextStream(chatClientRequest) + return this.advisorChain.nextStream(chatClientRequest) .doOnError(observation::error) .doFinally(s -> observation.stop()) .contextWrite(ctx -> ctx.put(ObservationThreadLocalAccessor.KEY, observation)); @@ -900,13 +903,13 @@ public ChatClientRequestSpec templateRenderer(TemplateRenderer templateRenderer) public CallResponseSpec call() { BaseAdvisorChain advisorChain = buildAdvisorChain(); return new DefaultCallResponseSpec(DefaultChatClientUtils.toChatClientRequest(this), advisorChain, - observationRegistry, observationConvention); + this.observationRegistry, this.observationConvention); } public StreamResponseSpec stream() { BaseAdvisorChain advisorChain = buildAdvisorChain(); return new DefaultStreamResponseSpec(DefaultChatClientUtils.toChatClientRequest(this), advisorChain, - observationRegistry, observationConvention); + this.observationRegistry, this.observationConvention); } private BaseAdvisorChain buildAdvisorChain() { diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/DefaultChatClientUtils.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/DefaultChatClientUtils.java index 3b793d6a99a..10f623e2b70 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/DefaultChatClientUtils.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/DefaultChatClientUtils.java @@ -16,6 +16,13 @@ package org.springframework.ai.chat.client; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.chat.messages.UserMessage; @@ -28,20 +35,17 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - /** * Utilities for supporting the {@link DefaultChatClient} implementation. * * @author Thomas Vitale * @since 1.0.0 */ -class DefaultChatClientUtils { +final class DefaultChatClientUtils { + + private DefaultChatClientUtils() { + // prevents instantiation + } static ChatClientRequest toChatClientRequest(DefaultChatClient.DefaultChatClientRequestSpec inputRequest) { Assert.notNull(inputRequest, "inputRequest cannot be null"); diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/AdvisorUtils.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/AdvisorUtils.java index 2059ceda57c..172484dd7ed 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/AdvisorUtils.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/AdvisorUtils.java @@ -16,12 +16,12 @@ package org.springframework.ai.chat.client.advisor; +import java.util.function.Predicate; + import org.springframework.ai.chat.client.ChatClientResponse; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.util.StringUtils; -import java.util.function.Predicate; - /** * Utilities to work with advisors. */ diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/ChatModelCallAdvisor.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/ChatModelCallAdvisor.java index 390208c675f..051cbdd808c 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/ChatModelCallAdvisor.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/ChatModelCallAdvisor.java @@ -16,6 +16,8 @@ package org.springframework.ai.chat.client.advisor; +import java.util.Map; + import org.springframework.ai.chat.client.ChatClientAttributes; import org.springframework.ai.chat.client.ChatClientRequest; import org.springframework.ai.chat.client.ChatClientResponse; @@ -28,8 +30,6 @@ import org.springframework.util.Assert; import org.springframework.util.StringUtils; -import java.util.Map; - /** * A {@link CallAdvisor} that uses a {@link ChatModel} to generate a response. * @@ -51,7 +51,7 @@ public ChatClientResponse adviseCall(ChatClientRequest chatClientRequest, CallAd ChatClientRequest formattedChatClientRequest = augmentWithFormatInstructions(chatClientRequest); - ChatResponse chatResponse = chatModel.call(formattedChatClientRequest.prompt()); + ChatResponse chatResponse = this.chatModel.call(formattedChatClientRequest.prompt()); return ChatClientResponse.builder() .chatResponse(chatResponse) .context(Map.copyOf(formattedChatClientRequest.context())) @@ -90,7 +90,7 @@ public static Builder builder() { return new Builder(); } - public static class Builder { + public static final class Builder { private ChatModel chatModel; diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/ChatModelStreamAdvisor.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/ChatModelStreamAdvisor.java index 9bec78fc4d9..de691318df1 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/ChatModelStreamAdvisor.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/ChatModelStreamAdvisor.java @@ -16,16 +16,18 @@ package org.springframework.ai.chat.client.advisor; +import java.util.Map; + +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; + import org.springframework.ai.chat.client.ChatClientRequest; import org.springframework.ai.chat.client.ChatClientResponse; -import org.springframework.ai.chat.client.advisor.api.*; +import org.springframework.ai.chat.client.advisor.api.StreamAdvisor; +import org.springframework.ai.chat.client.advisor.api.StreamAdvisorChain; import org.springframework.ai.chat.model.ChatModel; import org.springframework.core.Ordered; import org.springframework.util.Assert; -import reactor.core.publisher.Flux; -import reactor.core.scheduler.Schedulers; - -import java.util.Map; /** * A {@link StreamAdvisor} that uses a {@link ChatModel} to generate a streaming response. @@ -47,7 +49,7 @@ public Flux adviseStream(ChatClientRequest chatClientRequest StreamAdvisorChain streamAdvisorChain) { Assert.notNull(chatClientRequest, "the chatClientRequest cannot be null"); - return chatModel.stream(chatClientRequest.prompt()) + return this.chatModel.stream(chatClientRequest.prompt()) .map(chatResponse -> ChatClientResponse.builder() .chatResponse(chatResponse) .context(Map.copyOf(chatClientRequest.context())) @@ -69,7 +71,7 @@ public static Builder builder() { return new Builder(); } - public static class Builder { + public static final class Builder { private ChatModel chatModel; diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/DefaultAroundAdvisorChain.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/DefaultAroundAdvisorChain.java index 838b8cbc5b6..e9d1a1d2066 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/DefaultAroundAdvisorChain.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/DefaultAroundAdvisorChain.java @@ -23,22 +23,22 @@ import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor; +import reactor.core.publisher.Flux; + import org.springframework.ai.chat.client.ChatClientRequest; import org.springframework.ai.chat.client.ChatClientResponse; import org.springframework.ai.chat.client.advisor.api.Advisor; import org.springframework.ai.chat.client.advisor.api.BaseAdvisorChain; import org.springframework.ai.chat.client.advisor.api.CallAdvisor; import org.springframework.ai.chat.client.advisor.api.StreamAdvisor; -import org.springframework.ai.template.TemplateRenderer; -import org.springframework.ai.template.st.StTemplateRenderer; -import org.springframework.lang.Nullable; -import reactor.core.publisher.Flux; - import org.springframework.ai.chat.client.advisor.observation.AdvisorObservationContext; import org.springframework.ai.chat.client.advisor.observation.AdvisorObservationConvention; import org.springframework.ai.chat.client.advisor.observation.AdvisorObservationDocumentation; import org.springframework.ai.chat.client.advisor.observation.DefaultAdvisorObservationConvention; +import org.springframework.ai.template.TemplateRenderer; +import org.springframework.ai.template.st.StTemplateRenderer; import org.springframework.core.OrderComparator; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/MessageChatMemoryAdvisor.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/MessageChatMemoryAdvisor.java index 835beb8aab1..1b8bbea84e9 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/MessageChatMemoryAdvisor.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/MessageChatMemoryAdvisor.java @@ -19,7 +19,6 @@ import java.util.ArrayList; import java.util.List; -import org.springframework.util.Assert; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Scheduler; @@ -35,6 +34,7 @@ import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.UserMessage; +import org.springframework.util.Assert; /** * Memory is retrieved added as a collection of messages to the prompt @@ -44,7 +44,7 @@ * @author Thomas Vitale * @since 1.0.0 */ -public class MessageChatMemoryAdvisor implements BaseChatMemoryAdvisor { +public final class MessageChatMemoryAdvisor implements BaseChatMemoryAdvisor { private final ChatMemory chatMemory; @@ -67,7 +67,7 @@ private MessageChatMemoryAdvisor(ChatMemory chatMemory, String defaultConversati @Override public int getOrder() { - return order; + return this.order; } @Override @@ -132,7 +132,7 @@ public static Builder builder(ChatMemory chatMemory) { return new Builder(chatMemory); } - public static class Builder { + public static final class Builder { private String conversationId = ChatMemory.DEFAULT_CONVERSATION_ID; diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/PromptChatMemoryAdvisor.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/PromptChatMemoryAdvisor.java index bd5f6b0bdc9..5ae3c9459d0 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/PromptChatMemoryAdvisor.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/PromptChatMemoryAdvisor.java @@ -23,7 +23,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.Assert; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Scheduler; @@ -42,6 +41,7 @@ import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.prompt.PromptTemplate; +import org.springframework.util.Assert; /** * Memory is retrieved added into the prompt's system text. @@ -52,7 +52,7 @@ * @author Mark Pollack * @since 1.0.0 */ -public class PromptChatMemoryAdvisor implements BaseChatMemoryAdvisor { +public final class PromptChatMemoryAdvisor implements BaseChatMemoryAdvisor { private static final Logger logger = LoggerFactory.getLogger(PromptChatMemoryAdvisor.class); @@ -97,7 +97,7 @@ public static Builder builder(ChatMemory chatMemory) { @Override public int getOrder() { - return order; + return this.order; } @Override @@ -186,7 +186,7 @@ public Flux adviseStream(ChatClientRequest chatClientRequest /** * Builder for PromptChatMemoryAdvisor. */ - public static class Builder { + public static final class Builder { private PromptTemplate systemPromptTemplate = DEFAULT_SYSTEM_PROMPT_TEMPLATE; diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/SimpleLoggerAdvisor.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/SimpleLoggerAdvisor.java index 0160e3155a0..be2693c52cd 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/SimpleLoggerAdvisor.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/SimpleLoggerAdvisor.java @@ -115,7 +115,7 @@ public static Builder builder() { return new Builder(); } - public static class Builder { + public static final class Builder { private Function requestToString; @@ -142,7 +142,7 @@ public Builder order(int order) { } public SimpleLoggerAdvisor build() { - return new SimpleLoggerAdvisor(requestToString, responseToString, order); + return new SimpleLoggerAdvisor(this.requestToString, this.responseToString, this.order); } } diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/api/BaseChatMemoryAdvisor.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/api/BaseChatMemoryAdvisor.java index b05cc09639b..e5559d42530 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/api/BaseChatMemoryAdvisor.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/api/BaseChatMemoryAdvisor.java @@ -1,11 +1,11 @@ /* - * Copyright 2024 - 2025 the original author or authors. + * Copyright 2024-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.ai.chat.client.advisor.api; import java.util.Map; diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/api/CallAdvisorChain.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/api/CallAdvisorChain.java index 13624abce93..cfb009b2fb8 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/api/CallAdvisorChain.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/api/CallAdvisorChain.java @@ -16,11 +16,11 @@ package org.springframework.ai.chat.client.advisor.api; +import java.util.List; + import org.springframework.ai.chat.client.ChatClientRequest; import org.springframework.ai.chat.client.ChatClientResponse; -import java.util.List; - /** * A chain of {@link CallAdvisor} instances orchestrating the execution of a * {@link ChatClientRequest} on the next {@link CallAdvisor} in the chain. diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/api/StreamAdvisor.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/api/StreamAdvisor.java index a5e3becfff9..aef13fc1187 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/api/StreamAdvisor.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/api/StreamAdvisor.java @@ -16,9 +16,10 @@ package org.springframework.ai.chat.client.advisor.api; +import reactor.core.publisher.Flux; + import org.springframework.ai.chat.client.ChatClientRequest; import org.springframework.ai.chat.client.ChatClientResponse; -import reactor.core.publisher.Flux; /** * Advisor for execution flows ultimately resulting in a streaming call to an AI model. diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/api/StreamAdvisorChain.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/api/StreamAdvisorChain.java index 2b99dc47a24..230192de3aa 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/api/StreamAdvisorChain.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/api/StreamAdvisorChain.java @@ -16,11 +16,12 @@ package org.springframework.ai.chat.client.advisor.api; -import org.springframework.ai.chat.client.ChatClientRequest; -import org.springframework.ai.chat.client.ChatClientResponse; +import java.util.List; + import reactor.core.publisher.Flux; -import java.util.List; +import org.springframework.ai.chat.client.ChatClientRequest; +import org.springframework.ai.chat.client.ChatClientResponse; /** * A chain of {@link StreamAdvisor} instances orchestrating the execution of a diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/observation/ChatClientObservationContext.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/observation/ChatClientObservationContext.java index f12de8feac0..df750398a0f 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/observation/ChatClientObservationContext.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/observation/ChatClientObservationContext.java @@ -16,6 +16,8 @@ package org.springframework.ai.chat.client.observation; +import java.util.List; + import io.micrometer.observation.Observation; import org.springframework.ai.chat.client.ChatClientAttributes; @@ -28,8 +30,6 @@ import org.springframework.util.Assert; import org.springframework.util.StringUtils; -import java.util.List; - /** * Context used to store metadata for chat client workflows. * @@ -121,8 +121,8 @@ public Builder stream(boolean isStream) { } public ChatClientObservationContext build() { - if (StringUtils.hasText(format)) { - this.chatClientRequest.context().put(ChatClientAttributes.OUTPUT_FORMAT.getKey(), format); + if (StringUtils.hasText(this.format)) { + this.chatClientRequest.context().put(ChatClientAttributes.OUTPUT_FORMAT.getKey(), this.format); } return new ChatClientObservationContext(this.chatClientRequest, this.advisors, this.isStream); } diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/observation/ChatClientPromptContentObservationHandler.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/observation/ChatClientPromptContentObservationHandler.java index dcd3711e8b9..ddf276b6886 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/observation/ChatClientPromptContentObservationHandler.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/observation/ChatClientPromptContentObservationHandler.java @@ -16,16 +16,17 @@ package org.springframework.ai.chat.client.observation; +import java.util.HashMap; +import java.util.Map; + import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.ai.observation.ObservabilityHelper; import org.springframework.util.CollectionUtils; -import java.util.HashMap; -import java.util.Map; - /** * Handler for emitting the chat client prompt content to logs. * diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/observation/DefaultChatClientObservationConvention.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/observation/DefaultChatClientObservationConvention.java index b573c4bcf23..cfbe797b4d5 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/observation/DefaultChatClientObservationConvention.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/observation/DefaultChatClientObservationConvention.java @@ -16,6 +16,8 @@ package org.springframework.ai.chat.client.observation; +import java.util.ArrayList; + import io.micrometer.common.KeyValue; import io.micrometer.common.KeyValues; @@ -30,8 +32,6 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; -import java.util.ArrayList; - /** * Default conventions to populate observations for chat client workflows. * diff --git a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/ChatClientRequestTests.java b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/ChatClientRequestTests.java index 708f86a51f9..8678b6b1961 100644 --- a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/ChatClientRequestTests.java +++ b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/ChatClientRequestTests.java @@ -16,12 +16,13 @@ package org.springframework.ai.chat.client; -import org.junit.jupiter.api.Test; -import org.springframework.ai.chat.prompt.Prompt; - import java.util.HashMap; import java.util.Map; +import org.junit.jupiter.api.Test; + +import org.springframework.ai.chat.prompt.Prompt; + import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/ChatClientResponseTests.java b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/ChatClientResponseTests.java index d4a3c96ba90..234309a02c8 100644 --- a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/ChatClientResponseTests.java +++ b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/ChatClientResponseTests.java @@ -16,11 +16,11 @@ package org.springframework.ai.chat.client; -import org.junit.jupiter.api.Test; - import java.util.HashMap; import java.util.Map; +import org.junit.jupiter.api.Test; + import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/DefaultChatClientUtilsTests.java b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/DefaultChatClientUtilsTests.java index a14f5d3fdce..9d4d4962069 100644 --- a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/DefaultChatClientUtilsTests.java +++ b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/DefaultChatClientUtilsTests.java @@ -16,7 +16,12 @@ package org.springframework.ai.chat.client; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.junit.jupiter.api.Test; + import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.chat.messages.UserMessage; @@ -30,10 +35,6 @@ import org.springframework.ai.tool.definition.ToolDefinition; import org.springframework.ai.tool.metadata.ToolMetadata; -import java.util.List; -import java.util.Map; -import java.util.Set; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.mock; diff --git a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/AdvisorUtilsTests.java b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/AdvisorUtilsTests.java index a9878c1b1d0..f5aaa9ea115 100644 --- a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/AdvisorUtilsTests.java +++ b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/AdvisorUtilsTests.java @@ -16,16 +16,17 @@ package org.springframework.ai.chat.client.advisor; +import java.util.List; + import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; + import org.springframework.ai.chat.client.ChatClientResponse; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.metadata.ChatGenerationMetadata; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.model.Generation; -import java.util.List; - import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; diff --git a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/DefaultAroundAdvisorChainTests.java b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/DefaultAroundAdvisorChainTests.java index 4b9e14e67a4..ed00537f716 100644 --- a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/DefaultAroundAdvisorChainTests.java +++ b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/DefaultAroundAdvisorChainTests.java @@ -16,16 +16,22 @@ package org.springframework.ai.chat.client.advisor; +import java.util.ArrayList; +import java.util.List; + import io.micrometer.observation.ObservationRegistry; import org.junit.jupiter.api.Test; +import reactor.core.publisher.Flux; + import org.springframework.ai.chat.client.ChatClientRequest; import org.springframework.ai.chat.client.ChatClientResponse; -import org.springframework.ai.chat.client.advisor.api.*; +import org.springframework.ai.chat.client.advisor.api.Advisor; +import org.springframework.ai.chat.client.advisor.api.AdvisorChain; +import org.springframework.ai.chat.client.advisor.api.CallAdvisor; +import org.springframework.ai.chat.client.advisor.api.CallAdvisorChain; +import org.springframework.ai.chat.client.advisor.api.StreamAdvisor; +import org.springframework.ai.chat.client.advisor.api.StreamAdvisorChain; import org.springframework.ai.chat.prompt.Prompt; -import reactor.core.publisher.Flux; - -import java.util.ArrayList; -import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/MessageChatMemoryAdvisorTests.java b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/MessageChatMemoryAdvisorTests.java index 4e1125aa74e..52ec1c00a98 100644 --- a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/MessageChatMemoryAdvisorTests.java +++ b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/MessageChatMemoryAdvisorTests.java @@ -17,11 +17,12 @@ package org.springframework.ai.chat.client.advisor; import org.junit.jupiter.api.Test; +import reactor.core.scheduler.Schedulers; + import org.springframework.ai.chat.client.advisor.api.Advisor; import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.ai.chat.memory.InMemoryChatMemoryRepository; import org.springframework.ai.chat.memory.MessageWindowChatMemory; -import reactor.core.scheduler.Schedulers; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/PromptChatMemoryAdvisorTests.java b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/PromptChatMemoryAdvisorTests.java index dbfb380a151..f875a7bf803 100644 --- a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/PromptChatMemoryAdvisorTests.java +++ b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/PromptChatMemoryAdvisorTests.java @@ -17,12 +17,13 @@ package org.springframework.ai.chat.client.advisor; import org.junit.jupiter.api.Test; +import reactor.core.scheduler.Schedulers; + import org.springframework.ai.chat.client.advisor.api.Advisor; import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.ai.chat.memory.InMemoryChatMemoryRepository; import org.springframework.ai.chat.memory.MessageWindowChatMemory; import org.springframework.ai.chat.prompt.PromptTemplate; -import reactor.core.scheduler.Schedulers; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/observation/AdvisorObservationContextTests.java b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/observation/AdvisorObservationContextTests.java index 06c4f66368a..b100f33d221 100644 --- a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/observation/AdvisorObservationContextTests.java +++ b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/advisor/observation/AdvisorObservationContextTests.java @@ -17,6 +17,7 @@ package org.springframework.ai.chat.client.advisor.observation; import org.junit.jupiter.api.Test; + import org.springframework.ai.chat.client.ChatClientRequest; import org.springframework.ai.chat.prompt.Prompt; diff --git a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/observation/ChatClientObservationContextTests.java b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/observation/ChatClientObservationContextTests.java index 66efa14c4ac..c03312a7408 100644 --- a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/observation/ChatClientObservationContextTests.java +++ b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/observation/ChatClientObservationContextTests.java @@ -16,6 +16,9 @@ package org.springframework.ai.chat.client.observation; +import java.util.ArrayList; +import java.util.List; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -26,9 +29,6 @@ import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.prompt.Prompt; -import java.util.ArrayList; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.mock; diff --git a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/observation/ChatClientPromptContentObservationHandlerTests.java b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/observation/ChatClientPromptContentObservationHandlerTests.java index 616dba0e1c3..b6e24c6cbfb 100644 --- a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/observation/ChatClientPromptContentObservationHandlerTests.java +++ b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/observation/ChatClientPromptContentObservationHandlerTests.java @@ -16,9 +16,12 @@ package org.springframework.ai.chat.client.observation; +import java.util.List; + import io.micrometer.observation.Observation; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.ai.chat.client.ChatClientRequest; import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.chat.messages.UserMessage; @@ -26,8 +29,6 @@ import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; /** @@ -60,7 +61,7 @@ void whenEmptyPromptThenOutputNothing(CapturedOutput output) { var context = ChatClientObservationContext.builder() .request(ChatClientRequest.builder().prompt(new Prompt(List.of())).build()) .build(); - observationHandler.onStop(context); + this.observationHandler.onStop(context); assertThat(output).contains(""" Chat Client Prompt Content: [] @@ -72,7 +73,7 @@ void whenPromptWithTextThenOutputIt(CapturedOutput output) { var context = ChatClientObservationContext.builder() .request(ChatClientRequest.builder().prompt(new Prompt("supercalifragilisticexpialidocious")).build()) .build(); - observationHandler.onStop(context); + this.observationHandler.onStop(context); assertThat(output).contains(""" Chat Client Prompt Content: ["user":"supercalifragilisticexpialidocious"] @@ -87,7 +88,7 @@ void whenPromptWithMessagesThenOutputIt(CapturedOutput output) { new UserMessage("supercalifragilisticexpialidocious")))) .build()) .build(); - observationHandler.onStop(context); + this.observationHandler.onStop(context); assertThat(output).contains(""" Chat Client Prompt Content: ["system":"you're a chimney sweep", "user":"supercalifragilisticexpialidocious"] diff --git a/spring-ai-commons/src/main/java/org/springframework/ai/observation/TracingAwareLoggingObservationHandler.java b/spring-ai-commons/src/main/java/org/springframework/ai/observation/TracingAwareLoggingObservationHandler.java index 6826b2a96f6..1edec284894 100644 --- a/spring-ai-commons/src/main/java/org/springframework/ai/observation/TracingAwareLoggingObservationHandler.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/observation/TracingAwareLoggingObservationHandler.java @@ -85,7 +85,8 @@ public void onStop(T context) { .getRequired(TracingObservationHandler.TracingContext.class); Span currentSpan = tracingContext.getSpan(); if (currentSpan != null) { - try (CurrentTraceContext.Scope ignored = tracer.currentTraceContext().maybeScope(currentSpan.context())) { + try (CurrentTraceContext.Scope ignored = this.tracer.currentTraceContext() + .maybeScope(currentSpan.context())) { this.delegate.onStop(context); } } diff --git a/spring-ai-commons/src/main/java/org/springframework/ai/template/NoOpTemplateRenderer.java b/spring-ai-commons/src/main/java/org/springframework/ai/template/NoOpTemplateRenderer.java index 7bcf8032d2c..d4685201cf7 100644 --- a/spring-ai-commons/src/main/java/org/springframework/ai/template/NoOpTemplateRenderer.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/template/NoOpTemplateRenderer.java @@ -36,4 +36,4 @@ public String apply(String template, Map variables) { return template; } -} \ No newline at end of file +} diff --git a/spring-ai-commons/src/main/java/org/springframework/ai/template/TemplateRenderer.java b/spring-ai-commons/src/main/java/org/springframework/ai/template/TemplateRenderer.java index 847c35bed28..96b199af43a 100644 --- a/spring-ai-commons/src/main/java/org/springframework/ai/template/TemplateRenderer.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/template/TemplateRenderer.java @@ -30,4 +30,4 @@ public interface TemplateRenderer extends BiFunction @Override String apply(String template, Map variables); -} \ No newline at end of file +} diff --git a/spring-ai-commons/src/main/java/org/springframework/ai/template/ValidationMode.java b/spring-ai-commons/src/main/java/org/springframework/ai/template/ValidationMode.java index 363178b6df8..548e32a7cf7 100644 --- a/spring-ai-commons/src/main/java/org/springframework/ai/template/ValidationMode.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/template/ValidationMode.java @@ -38,6 +38,6 @@ public enum ValidationMode { /** * No validation is performed. */ - NONE; + NONE -} \ No newline at end of file +} diff --git a/spring-ai-commons/src/test/java/org/springframework/ai/document/DocumentTests.java b/spring-ai-commons/src/test/java/org/springframework/ai/document/DocumentTests.java index 44fc2be542c..1845710b617 100644 --- a/spring-ai-commons/src/test/java/org/springframework/ai/document/DocumentTests.java +++ b/spring-ai-commons/src/test/java/org/springframework/ai/document/DocumentTests.java @@ -16,9 +16,7 @@ package org.springframework.ai.document; -import java.net.MalformedURLException; import java.net.URI; -import java.net.URL; import java.util.HashMap; import java.util.Map; diff --git a/spring-ai-commons/src/test/java/org/springframework/ai/document/TextBlockAssertion.java b/spring-ai-commons/src/test/java/org/springframework/ai/document/TextBlockAssertion.java index d85721426ed..0490cd7a6d0 100644 --- a/spring-ai-commons/src/test/java/org/springframework/ai/document/TextBlockAssertion.java +++ b/spring-ai-commons/src/test/java/org/springframework/ai/document/TextBlockAssertion.java @@ -1,11 +1,11 @@ /* - * Copyright 2024-2025 the original author or authors. + * Copyright 2023-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/spring-ai-commons/src/test/java/org/springframework/ai/observation/ObservabilityHelperTests.java b/spring-ai-commons/src/test/java/org/springframework/ai/observation/ObservabilityHelperTests.java index dcbbe53e47b..5fed20b442e 100644 --- a/spring-ai-commons/src/test/java/org/springframework/ai/observation/ObservabilityHelperTests.java +++ b/spring-ai-commons/src/test/java/org/springframework/ai/observation/ObservabilityHelperTests.java @@ -16,12 +16,12 @@ package org.springframework.ai.observation; -import org.junit.jupiter.api.Test; - import java.util.List; import java.util.Map; import java.util.TreeMap; +import org.junit.jupiter.api.Test; + import static org.assertj.core.api.AssertionsForClassTypes.assertThat; /** diff --git a/spring-ai-commons/src/test/java/org/springframework/ai/observation/TracingAwareLoggingObservationHandlerTests.java b/spring-ai-commons/src/test/java/org/springframework/ai/observation/TracingAwareLoggingObservationHandlerTests.java index f3c433384db..e324dfef134 100644 --- a/spring-ai-commons/src/test/java/org/springframework/ai/observation/TracingAwareLoggingObservationHandlerTests.java +++ b/spring-ai-commons/src/test/java/org/springframework/ai/observation/TracingAwareLoggingObservationHandlerTests.java @@ -29,7 +29,9 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; /** * Tests for {@link TracingAwareLoggingObservationHandler}. @@ -53,30 +55,30 @@ void callsShouldBeDelegated() { Observation.Context context = new Observation.Context(); context.put(TracingObservationHandler.TracingContext.class, new TracingObservationHandler.TracingContext()); - handler.onStart(context); - verify(delegate).onStart(context); + this.handler.onStart(context); + verify(this.delegate).onStart(context); - handler.onError(context); - verify(delegate).onError(context); + this.handler.onError(context); + verify(this.delegate).onError(context); Observation.Event event = Observation.Event.of("test"); - handler.onEvent(event, context); - verify(delegate).onEvent(event, context); + this.handler.onEvent(event, context); + verify(this.delegate).onEvent(event, context); - handler.onScopeOpened(context); - verify(delegate).onScopeOpened(context); + this.handler.onScopeOpened(context); + verify(this.delegate).onScopeOpened(context); - handler.onStop(context); - verify(delegate).onStop(context); + this.handler.onStop(context); + verify(this.delegate).onStop(context); - handler.onScopeClosed(context); - verify(delegate).onScopeClosed(context); + this.handler.onScopeClosed(context); + verify(this.delegate).onScopeClosed(context); - handler.onScopeReset(context); - verify(delegate).onScopeReset(context); + this.handler.onScopeReset(context); + verify(this.delegate).onScopeReset(context); - handler.supportsContext(context); - verify(delegate).supportsContext(context); + this.handler.supportsContext(context); + verify(this.delegate).supportsContext(context); } @Test @@ -92,14 +94,14 @@ void spanShouldBeAvailableOnStop() { CurrentTraceContext.Scope scope = mock(CurrentTraceContext.Scope.class); when(span.context()).thenReturn(traceContext); - when(tracer.currentTraceContext()).thenReturn(currentTraceContext); + when(this.tracer.currentTraceContext()).thenReturn(currentTraceContext); when(currentTraceContext.maybeScope(traceContext)).thenReturn(scope); - handler.onStop(observationContext); + this.handler.onStop(observationContext); verify(scope).close(); verify(currentTraceContext).maybeScope(traceContext); - verify(delegate).onStop(observationContext); + verify(this.delegate).onStop(observationContext); } } diff --git a/spring-ai-commons/src/test/java/org/springframework/ai/template/NoOpTemplateRendererTests.java b/spring-ai-commons/src/test/java/org/springframework/ai/template/NoOpTemplateRendererTests.java index ffbc9f2c900..caea33f01a8 100644 --- a/spring-ai-commons/src/test/java/org/springframework/ai/template/NoOpTemplateRendererTests.java +++ b/spring-ai-commons/src/test/java/org/springframework/ai/template/NoOpTemplateRendererTests.java @@ -16,14 +16,14 @@ package org.springframework.ai.template; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + /** * Unit tests for {@link NoOpTemplateRenderer}. * @@ -114,4 +114,4 @@ void shouldReturnUnchangedComplexTemplate() { assertThat(result).isEqualToNormalizingNewlines(template); } -} \ No newline at end of file +} diff --git a/spring-ai-integration-tests/src/test/java/org/springframework/ai/integration/tests/client/advisor/QuestionAnswerAdvisorIT.java b/spring-ai-integration-tests/src/test/java/org/springframework/ai/integration/tests/client/advisor/QuestionAnswerAdvisorIT.java index bfe9a1496bd..e27c262439e 100644 --- a/spring-ai-integration-tests/src/test/java/org/springframework/ai/integration/tests/client/advisor/QuestionAnswerAdvisorIT.java +++ b/spring-ai-integration-tests/src/test/java/org/springframework/ai/integration/tests/client/advisor/QuestionAnswerAdvisorIT.java @@ -16,19 +16,22 @@ package org.springframework.ai.integration.tests.client.advisor; +import java.util.List; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; + import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor; +import org.springframework.ai.chat.evaluation.RelevancyEvaluator; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.prompt.PromptTemplate; import org.springframework.ai.document.Document; import org.springframework.ai.document.DocumentReader; import org.springframework.ai.evaluation.EvaluationRequest; import org.springframework.ai.evaluation.EvaluationResponse; -import org.springframework.ai.chat.evaluation.RelevancyEvaluator; import org.springframework.ai.integration.tests.TestApplication; import org.springframework.ai.openai.OpenAiChatModel; import org.springframework.ai.reader.markdown.MarkdownDocumentReader; @@ -40,8 +43,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.core.io.Resource; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; /** @@ -183,9 +184,6 @@ void qaOutputConverter() { assertThat(answer.content()).containsIgnoringCase("Highlands"); } - private record Answer(String content) { - } - private void evaluateRelevancy(String question, ChatResponse chatResponse) { EvaluationRequest evaluationRequest = new EvaluationRequest(question, chatResponse.getMetadata().get(QuestionAnswerAdvisor.RETRIEVED_DOCUMENTS), @@ -195,4 +193,7 @@ private void evaluateRelevancy(String question, ChatResponse chatResponse) { assertThat(evaluationResponse.isPass()).isTrue(); } + private record Answer(String content) { + } + } diff --git a/spring-ai-integration-tests/src/test/java/org/springframework/ai/integration/tests/client/advisor/QuestionAnswerAdvisorStreamIT.java b/spring-ai-integration-tests/src/test/java/org/springframework/ai/integration/tests/client/advisor/QuestionAnswerAdvisorStreamIT.java index 85757e4ab56..83974f383d9 100644 --- a/spring-ai-integration-tests/src/test/java/org/springframework/ai/integration/tests/client/advisor/QuestionAnswerAdvisorStreamIT.java +++ b/spring-ai-integration-tests/src/test/java/org/springframework/ai/integration/tests/client/advisor/QuestionAnswerAdvisorStreamIT.java @@ -16,14 +16,17 @@ package org.springframework.ai.integration.tests.client.advisor; +import java.util.List; +import java.util.stream.Collectors; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; +import reactor.core.publisher.Flux; + import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.converter.BeanOutputConverter; import org.springframework.ai.document.Document; import org.springframework.ai.document.DocumentReader; import org.springframework.ai.integration.tests.TestApplication; @@ -36,10 +39,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.core.io.Resource; -import reactor.core.publisher.Flux; - -import java.util.List; -import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-ai-model/src/main/java/org/springframework/ai/chat/memory/ChatMemory.java b/spring-ai-model/src/main/java/org/springframework/ai/chat/memory/ChatMemory.java index 3609d59b3a2..f13a971e56f 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/chat/memory/ChatMemory.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/chat/memory/ChatMemory.java @@ -16,11 +16,11 @@ package org.springframework.ai.chat.memory; +import java.util.List; + import org.springframework.ai.chat.messages.Message; import org.springframework.util.Assert; -import java.util.List; - /** * The contract for storing and managing the memory of chat conversations. * diff --git a/spring-ai-model/src/main/java/org/springframework/ai/chat/memory/ChatMemoryRepository.java b/spring-ai-model/src/main/java/org/springframework/ai/chat/memory/ChatMemoryRepository.java index ff4b823a174..350b1ebbcf7 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/chat/memory/ChatMemoryRepository.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/chat/memory/ChatMemoryRepository.java @@ -16,10 +16,10 @@ package org.springframework.ai.chat.memory; -import org.springframework.ai.chat.messages.Message; - import java.util.List; +import org.springframework.ai.chat.messages.Message; + /** * A repository for storing and retrieving chat messages. * diff --git a/spring-ai-model/src/main/java/org/springframework/ai/chat/memory/InMemoryChatMemoryRepository.java b/spring-ai-model/src/main/java/org/springframework/ai/chat/memory/InMemoryChatMemoryRepository.java index 290ccfb4174..0843af8ffa2 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/chat/memory/InMemoryChatMemoryRepository.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/chat/memory/InMemoryChatMemoryRepository.java @@ -16,14 +16,14 @@ package org.springframework.ai.chat.memory; -import org.springframework.ai.chat.messages.Message; -import org.springframework.util.Assert; - import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.springframework.ai.chat.messages.Message; +import org.springframework.util.Assert; + /** * An in-memory implementation of {@link ChatMemoryRepository}. * diff --git a/spring-ai-model/src/main/java/org/springframework/ai/chat/memory/MessageWindowChatMemory.java b/spring-ai-model/src/main/java/org/springframework/ai/chat/memory/MessageWindowChatMemory.java index d9625424416..9c56c9d50bf 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/chat/memory/MessageWindowChatMemory.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/chat/memory/MessageWindowChatMemory.java @@ -115,7 +115,7 @@ public static Builder builder() { return new Builder(); } - public static class Builder { + public static final class Builder { private ChatMemoryRepository chatMemoryRepository; diff --git a/spring-ai-model/src/main/java/org/springframework/ai/chat/messages/MessageUtils.java b/spring-ai-model/src/main/java/org/springframework/ai/chat/messages/MessageUtils.java index cf732eec4c0..06d3b7c0424 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/chat/messages/MessageUtils.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/chat/messages/MessageUtils.java @@ -16,14 +16,14 @@ package org.springframework.ai.chat.messages; -import org.springframework.core.io.Resource; -import org.springframework.util.Assert; -import org.springframework.util.StreamUtils; - import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; +import org.springframework.util.StreamUtils; + /** * Utility class for managing messages. * diff --git a/spring-ai-model/src/main/java/org/springframework/ai/chat/messages/SystemMessage.java b/spring-ai-model/src/main/java/org/springframework/ai/chat/messages/SystemMessage.java index a5d2fe013e4..8a187add90e 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/chat/messages/SystemMessage.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/chat/messages/SystemMessage.java @@ -115,11 +115,11 @@ public Builder metadata(Map metadata) { } public SystemMessage build() { - if (StringUtils.hasText(textContent) && resource != null) { + if (StringUtils.hasText(this.textContent) && this.resource != null) { throw new IllegalArgumentException("textContent and resource cannot be set at the same time"); } - else if (resource != null) { - this.textContent = MessageUtils.readResource(resource); + else if (this.resource != null) { + this.textContent = MessageUtils.readResource(this.resource); } return new SystemMessage(this.textContent, this.metadata); } diff --git a/spring-ai-model/src/main/java/org/springframework/ai/chat/messages/UserMessage.java b/spring-ai-model/src/main/java/org/springframework/ai/chat/messages/UserMessage.java index 499949153f6..2495e09e975 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/chat/messages/UserMessage.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/chat/messages/UserMessage.java @@ -124,11 +124,11 @@ public Builder metadata(Map metadata) { } public UserMessage build() { - if (StringUtils.hasText(textContent) && resource != null) { + if (StringUtils.hasText(this.textContent) && this.resource != null) { throw new IllegalArgumentException("textContent and resource cannot be set at the same time"); } - else if (resource != null) { - this.textContent = MessageUtils.readResource(resource); + else if (this.resource != null) { + this.textContent = MessageUtils.readResource(this.resource); } return new UserMessage(this.textContent, this.media, this.metadata); } diff --git a/spring-ai-model/src/main/java/org/springframework/ai/chat/observation/ChatModelCompletionObservationHandler.java b/spring-ai-model/src/main/java/org/springframework/ai/chat/observation/ChatModelCompletionObservationHandler.java index c3c4ab348ff..597ce0a1f2f 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/chat/observation/ChatModelCompletionObservationHandler.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/chat/observation/ChatModelCompletionObservationHandler.java @@ -16,16 +16,17 @@ package org.springframework.ai.chat.observation; +import java.util.List; + import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.ai.observation.ObservabilityHelper; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; -import java.util.List; - /** * Handler for emitting the chat completion content to logs. * diff --git a/spring-ai-model/src/main/java/org/springframework/ai/chat/observation/ChatModelObservationContext.java b/spring-ai-model/src/main/java/org/springframework/ai/chat/observation/ChatModelObservationContext.java index 819edec419f..2aa46628ff6 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/chat/observation/ChatModelObservationContext.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/chat/observation/ChatModelObservationContext.java @@ -17,12 +17,10 @@ package org.springframework.ai.chat.observation; import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.prompt.ChatOptions; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.model.observation.ModelObservationContext; import org.springframework.ai.observation.AiOperationMetadata; import org.springframework.ai.observation.conventions.AiOperationType; -import org.springframework.util.Assert; /** * Context used to store metadata for chat model exchanges. diff --git a/spring-ai-model/src/main/java/org/springframework/ai/chat/observation/ChatModelObservationDocumentation.java b/spring-ai-model/src/main/java/org/springframework/ai/chat/observation/ChatModelObservationDocumentation.java index e25cddf69a4..29840ef4aaa 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/chat/observation/ChatModelObservationDocumentation.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/chat/observation/ChatModelObservationDocumentation.java @@ -20,6 +20,7 @@ import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationConvention; import io.micrometer.observation.docs.ObservationDocumentation; + import org.springframework.ai.observation.conventions.AiObservationAttributes; /** diff --git a/spring-ai-model/src/main/java/org/springframework/ai/chat/observation/ChatModelPromptContentObservationHandler.java b/spring-ai-model/src/main/java/org/springframework/ai/chat/observation/ChatModelPromptContentObservationHandler.java index 067b7514260..88b353b68d8 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/chat/observation/ChatModelPromptContentObservationHandler.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/chat/observation/ChatModelPromptContentObservationHandler.java @@ -16,16 +16,17 @@ package org.springframework.ai.chat.observation; +import java.util.List; + import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.ai.content.Content; import org.springframework.ai.observation.ObservabilityHelper; import org.springframework.util.CollectionUtils; -import java.util.List; - /** * Handler for emitting the chat prompt content to logs. * diff --git a/spring-ai-model/src/main/java/org/springframework/ai/chat/prompt/PromptTemplate.java b/spring-ai-model/src/main/java/org/springframework/ai/chat/prompt/PromptTemplate.java index 6cc10e50de3..9e33506399d 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/chat/prompt/PromptTemplate.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/chat/prompt/PromptTemplate.java @@ -24,22 +24,20 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; -import org.springframework.ai.template.TemplateRenderer; -import org.springframework.ai.template.st.StTemplateRenderer; -import org.springframework.util.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.content.Media; -import org.springframework.core.io.Resource; +import org.springframework.ai.template.TemplateRenderer; +import org.springframework.ai.template.st.StTemplateRenderer; import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; import org.springframework.util.StreamUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * A template for creating prompts. It allows you to define a template string with * placeholders for variables, and then render the template with specific values for those @@ -89,7 +87,7 @@ public PromptTemplate(String template) { try (InputStream inputStream = resource.getInputStream()) { this.template = StreamUtils.copyToString(inputStream, Charset.defaultCharset()); - Assert.hasText(template, "template cannot be null or empty"); + Assert.hasText(this.template, "template cannot be null or empty"); } catch (IOException ex) { throw new RuntimeException("Failed to read resource", ex); @@ -120,7 +118,7 @@ public String render() { processedVariables.put(entry.getKey(), entry.getValue()); } } - return this.renderer.apply(template, processedVariables); + return this.renderer.apply(this.template, processedVariables); } @Override @@ -136,7 +134,7 @@ public String render(Map additionalVariables) { } } - return this.renderer.apply(template, combinedVariables); + return this.renderer.apply(this.template, combinedVariables); } private String renderResource(Resource resource) { @@ -211,7 +209,7 @@ public static Builder builder() { return new Builder(); } - public static class Builder { + public static final class Builder { private String template; diff --git a/spring-ai-model/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContext.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContext.java index bc35c72533b..f076366df86 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContext.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContext.java @@ -16,7 +16,6 @@ package org.springframework.ai.embedding.observation; -import org.springframework.ai.embedding.EmbeddingOptions; import org.springframework.ai.embedding.EmbeddingRequest; import org.springframework.ai.embedding.EmbeddingResponse; import org.springframework.ai.model.observation.ModelObservationContext; diff --git a/spring-ai-model/src/main/java/org/springframework/ai/image/observation/ImageModelObservationContext.java b/spring-ai-model/src/main/java/org/springframework/ai/image/observation/ImageModelObservationContext.java index d65ea7970ae..f40d68481f2 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/image/observation/ImageModelObservationContext.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/image/observation/ImageModelObservationContext.java @@ -16,7 +16,6 @@ package org.springframework.ai.image.observation; -import org.springframework.ai.image.ImageOptions; import org.springframework.ai.image.ImagePrompt; import org.springframework.ai.image.ImageResponse; import org.springframework.ai.model.observation.ModelObservationContext; diff --git a/spring-ai-model/src/main/java/org/springframework/ai/image/observation/ImageModelObservationDocumentation.java b/spring-ai-model/src/main/java/org/springframework/ai/image/observation/ImageModelObservationDocumentation.java index 3dd7b13ba84..d2719147e9e 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/image/observation/ImageModelObservationDocumentation.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/image/observation/ImageModelObservationDocumentation.java @@ -20,6 +20,7 @@ import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationConvention; import io.micrometer.observation.docs.ObservationDocumentation; + import org.springframework.ai.observation.conventions.AiObservationAttributes; /** diff --git a/spring-ai-model/src/main/java/org/springframework/ai/image/observation/ImageModelPromptContentObservationHandler.java b/spring-ai-model/src/main/java/org/springframework/ai/image/observation/ImageModelPromptContentObservationHandler.java index e27f2fb27ca..b15d535b3f5 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/image/observation/ImageModelPromptContentObservationHandler.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/image/observation/ImageModelPromptContentObservationHandler.java @@ -16,13 +16,14 @@ package org.springframework.ai.image.observation; +import java.util.StringJoiner; + import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.CollectionUtils; -import java.util.StringJoiner; +import org.springframework.util.CollectionUtils; /** * Handler for emitting image prompt content to logs. diff --git a/spring-ai-model/src/main/java/org/springframework/ai/moderation/CategoryScores.java b/spring-ai-model/src/main/java/org/springframework/ai/moderation/CategoryScores.java index dd458712ac5..328e2e8682e 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/moderation/CategoryScores.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/moderation/CategoryScores.java @@ -131,23 +131,23 @@ public double getViolence() { } public double getDangerousAndCriminalContent() { - return dangerousAndCriminalContent; + return this.dangerousAndCriminalContent; } public double getHealth() { - return health; + return this.health; } public double getFinancial() { - return financial; + return this.financial; } public double getLaw() { - return law; + return this.law; } public double getPii() { - return pii; + return this.pii; } @Override @@ -189,8 +189,8 @@ public String toString() { + this.hateThreatening + ", violenceGraphic=" + this.violenceGraphic + ", selfHarmIntent=" + this.selfHarmIntent + ", selfHarmInstructions=" + this.selfHarmInstructions + ", harassmentThreatening=" + this.harassmentThreatening + ", violence=" + this.violence - + ", dangerousAndCriminalContent=" + dangerousAndCriminalContent + ", health=" + health + ", financial=" - + financial + ", law=" + law + ", pii=" + pii + '}'; + + ", dangerousAndCriminalContent=" + this.dangerousAndCriminalContent + ", health=" + this.health + + ", financial=" + this.financial + ", law=" + this.law + ", pii=" + this.pii + '}'; } public static class Builder { diff --git a/spring-ai-model/src/main/java/org/springframework/ai/tool/definition/DefaultToolDefinition.java b/spring-ai-model/src/main/java/org/springframework/ai/tool/definition/DefaultToolDefinition.java index b38c6708d17..cafd1a70364 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/tool/definition/DefaultToolDefinition.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/tool/definition/DefaultToolDefinition.java @@ -16,7 +16,6 @@ package org.springframework.ai.tool.definition; -import org.springframework.ai.tool.support.ToolUtils; import org.springframework.ai.util.ParsingUtils; import org.springframework.util.Assert; import org.springframework.util.StringUtils; diff --git a/spring-ai-model/src/main/java/org/springframework/ai/tool/observation/DefaultToolCallingObservationConvention.java b/spring-ai-model/src/main/java/org/springframework/ai/tool/observation/DefaultToolCallingObservationConvention.java index 0842ec5deec..c12ea52555f 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/tool/observation/DefaultToolCallingObservationConvention.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/tool/observation/DefaultToolCallingObservationConvention.java @@ -18,6 +18,7 @@ import io.micrometer.common.KeyValue; import io.micrometer.common.KeyValues; + import org.springframework.ai.observation.conventions.SpringAiKind; import org.springframework.lang.Nullable; import org.springframework.util.Assert; diff --git a/spring-ai-model/src/main/java/org/springframework/ai/tool/observation/ToolCallingObservationContext.java b/spring-ai-model/src/main/java/org/springframework/ai/tool/observation/ToolCallingObservationContext.java index 3ce781824a3..ea73f6fd75e 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/tool/observation/ToolCallingObservationContext.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/tool/observation/ToolCallingObservationContext.java @@ -17,6 +17,7 @@ package org.springframework.ai.tool.observation; import io.micrometer.observation.Observation; + import org.springframework.ai.observation.AiOperationMetadata; import org.springframework.ai.observation.conventions.AiOperationType; import org.springframework.ai.observation.conventions.AiProvider; @@ -31,7 +32,7 @@ * @author Thomas Vitale * @since 1.0.0 */ -public class ToolCallingObservationContext extends Observation.Context { +public final class ToolCallingObservationContext extends Observation.Context { private final AiOperationMetadata operationMetadata = new AiOperationMetadata(AiOperationType.FRAMEWORK.value(), AiProvider.SPRING_AI.value()); @@ -58,24 +59,24 @@ private ToolCallingObservationContext(ToolDefinition toolDefinition, ToolMetadat } public AiOperationMetadata getOperationMetadata() { - return operationMetadata; + return this.operationMetadata; } public ToolDefinition getToolDefinition() { - return toolDefinition; + return this.toolDefinition; } public ToolMetadata getToolMetadata() { - return toolMetadata; + return this.toolMetadata; } public String getToolCallArguments() { - return toolCallArguments; + return this.toolCallArguments; } @Nullable public String getToolCallResult() { - return toolCallResult; + return this.toolCallResult; } public void setToolCallResult(@Nullable String toolCallResult) { @@ -86,7 +87,7 @@ public static Builder builder() { return new Builder(); } - public static class Builder { + public static final class Builder { private ToolDefinition toolDefinition; @@ -121,7 +122,8 @@ public Builder toolCallResult(@Nullable String toolCallResult) { } public ToolCallingObservationContext build() { - return new ToolCallingObservationContext(toolDefinition, toolMetadata, toolCallArguments, toolCallResult); + return new ToolCallingObservationContext(this.toolDefinition, this.toolMetadata, this.toolCallArguments, + this.toolCallResult); } } diff --git a/spring-ai-model/src/main/java/org/springframework/ai/tool/observation/ToolCallingObservationDocumentation.java b/spring-ai-model/src/main/java/org/springframework/ai/tool/observation/ToolCallingObservationDocumentation.java index dd6447c92af..91d4d681af4 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/tool/observation/ToolCallingObservationDocumentation.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/tool/observation/ToolCallingObservationDocumentation.java @@ -20,6 +20,7 @@ import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationConvention; import io.micrometer.observation.docs.ObservationDocumentation; + import org.springframework.ai.observation.conventions.AiObservationAttributes; /** diff --git a/spring-ai-model/src/main/java/org/springframework/ai/tool/support/ToolDefinitions.java b/spring-ai-model/src/main/java/org/springframework/ai/tool/support/ToolDefinitions.java index 25819ea719d..68d4646333a 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/tool/support/ToolDefinitions.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/tool/support/ToolDefinitions.java @@ -1,11 +1,11 @@ /* - * Copyright 2024 - 2024 the original author or authors. + * Copyright 2024-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.ai.tool.support; import java.lang.reflect.Method; @@ -34,7 +35,11 @@ * @author Mark Pollack * @since 1.0.0 */ -public class ToolDefinitions { +public final class ToolDefinitions { + + private ToolDefinitions() { + // prevents instantiation. + } /** * Create a default {@link ToolDefinition} builder from a {@link Method}. diff --git a/spring-ai-model/src/test/java/org/springframework/ai/aot/SpringAiCoreRuntimeHintsTest.java b/spring-ai-model/src/test/java/org/springframework/ai/aot/SpringAiCoreRuntimeHintsTest.java index 01d180686ce..ea7badcc0af 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/aot/SpringAiCoreRuntimeHintsTest.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/aot/SpringAiCoreRuntimeHintsTest.java @@ -42,4 +42,4 @@ void core() { assertThat(runtimeHints).matches(reflection().onType(ToolDefinition.class)); } -} \ No newline at end of file +} diff --git a/spring-ai-model/src/test/java/org/springframework/ai/chat/memory/InMemoryChatMemoryRepositoryTests.java b/spring-ai-model/src/test/java/org/springframework/ai/chat/memory/InMemoryChatMemoryRepositoryTests.java index 6fc4315c19e..90283e3e9c2 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/chat/memory/InMemoryChatMemoryRepositoryTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/chat/memory/InMemoryChatMemoryRepositoryTests.java @@ -16,15 +16,16 @@ package org.springframework.ai.chat.memory; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + import org.junit.jupiter.api.Test; + import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.UserMessage; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -44,14 +45,14 @@ void findConversationIds() { List messages1 = List.of(new UserMessage("Hello")); List messages2 = List.of(new AssistantMessage("Hi there")); - chatMemoryRepository.saveAll(conversationId1, messages1); - chatMemoryRepository.saveAll(conversationId2, messages2); + this.chatMemoryRepository.saveAll(conversationId1, messages1); + this.chatMemoryRepository.saveAll(conversationId2, messages2); - assertThat(chatMemoryRepository.findConversationIds()).containsExactlyInAnyOrder(conversationId1, + assertThat(this.chatMemoryRepository.findConversationIds()).containsExactlyInAnyOrder(conversationId1, conversationId2); - chatMemoryRepository.deleteByConversationId(conversationId1); - assertThat(chatMemoryRepository.findConversationIds()).containsExactlyInAnyOrder(conversationId2); + this.chatMemoryRepository.deleteByConversationId(conversationId1); + assertThat(this.chatMemoryRepository.findConversationIds()).containsExactlyInAnyOrder(conversationId2); } @Test @@ -59,13 +60,13 @@ void saveMessagesAndFindMultipleMessagesInConversation() { String conversationId = UUID.randomUUID().toString(); List messages = List.of(new AssistantMessage("I, Robot"), new UserMessage("Hello")); - chatMemoryRepository.saveAll(conversationId, messages); + this.chatMemoryRepository.saveAll(conversationId, messages); - assertThat(chatMemoryRepository.findByConversationId(conversationId)).containsAll(messages); + assertThat(this.chatMemoryRepository.findByConversationId(conversationId)).containsAll(messages); - chatMemoryRepository.deleteByConversationId(conversationId); + this.chatMemoryRepository.deleteByConversationId(conversationId); - assertThat(chatMemoryRepository.findByConversationId(conversationId)).isEmpty(); + assertThat(this.chatMemoryRepository.findByConversationId(conversationId)).isEmpty(); } @Test @@ -74,20 +75,20 @@ void saveMessagesAndFindSingleMessageInConversation() { Message message = new UserMessage("Hello"); List messages = List.of(message); - chatMemoryRepository.saveAll(conversationId, messages); + this.chatMemoryRepository.saveAll(conversationId, messages); - assertThat(chatMemoryRepository.findByConversationId(conversationId)).contains(message); + assertThat(this.chatMemoryRepository.findByConversationId(conversationId)).contains(message); - chatMemoryRepository.deleteByConversationId(conversationId); + this.chatMemoryRepository.deleteByConversationId(conversationId); - assertThat(chatMemoryRepository.findByConversationId(conversationId)).isEmpty(); + assertThat(this.chatMemoryRepository.findByConversationId(conversationId)).isEmpty(); } @Test void findNonExistingConversation() { String conversationId = UUID.randomUUID().toString(); - assertThat(chatMemoryRepository.findByConversationId(conversationId)).isEmpty(); + assertThat(this.chatMemoryRepository.findByConversationId(conversationId)).isEmpty(); } @Test @@ -96,38 +97,39 @@ void subsequentSaveOverwritesPreviousVersion() { List firstMessages = List.of(new UserMessage("Hello")); List secondMessages = List.of(new AssistantMessage("Hi there")); - chatMemoryRepository.saveAll(conversationId, firstMessages); - chatMemoryRepository.saveAll(conversationId, secondMessages); + this.chatMemoryRepository.saveAll(conversationId, firstMessages); + this.chatMemoryRepository.saveAll(conversationId, secondMessages); - assertThat(chatMemoryRepository.findByConversationId(conversationId)).containsExactlyElementsOf(secondMessages); + assertThat(this.chatMemoryRepository.findByConversationId(conversationId)) + .containsExactlyElementsOf(secondMessages); } @Test void nullConversationIdNotAllowed() { - assertThatThrownBy(() -> chatMemoryRepository.saveAll(null, List.of(new UserMessage("Hello")))) + assertThatThrownBy(() -> this.chatMemoryRepository.saveAll(null, List.of(new UserMessage("Hello")))) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("conversationId cannot be null or empty"); - assertThatThrownBy(() -> chatMemoryRepository.findByConversationId(null)) + assertThatThrownBy(() -> this.chatMemoryRepository.findByConversationId(null)) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("conversationId cannot be null or empty"); - assertThatThrownBy(() -> chatMemoryRepository.deleteByConversationId(null)) + assertThatThrownBy(() -> this.chatMemoryRepository.deleteByConversationId(null)) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("conversationId cannot be null or empty"); } @Test void emptyConversationIdNotAllowed() { - assertThatThrownBy(() -> chatMemoryRepository.saveAll("", List.of(new UserMessage("Hello")))) + assertThatThrownBy(() -> this.chatMemoryRepository.saveAll("", List.of(new UserMessage("Hello")))) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("conversationId cannot be null or empty"); - assertThatThrownBy(() -> chatMemoryRepository.findByConversationId("")) + assertThatThrownBy(() -> this.chatMemoryRepository.findByConversationId("")) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("conversationId cannot be null or empty"); - assertThatThrownBy(() -> chatMemoryRepository.deleteByConversationId("")) + assertThatThrownBy(() -> this.chatMemoryRepository.deleteByConversationId("")) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("conversationId cannot be null or empty"); } @@ -135,7 +137,7 @@ void emptyConversationIdNotAllowed() { @Test void nullMessagesNotAllowed() { String conversationId = UUID.randomUUID().toString(); - assertThatThrownBy(() -> chatMemoryRepository.saveAll(conversationId, null)) + assertThatThrownBy(() -> this.chatMemoryRepository.saveAll(conversationId, null)) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("messages cannot be null"); } @@ -146,7 +148,7 @@ void messagesWithNullElementsNotAllowed() { List messagesWithNull = new ArrayList<>(); messagesWithNull.add(null); - assertThatThrownBy(() -> chatMemoryRepository.saveAll(conversationId, messagesWithNull)) + assertThatThrownBy(() -> this.chatMemoryRepository.saveAll(conversationId, messagesWithNull)) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("messages cannot contain null elements"); } diff --git a/spring-ai-model/src/test/java/org/springframework/ai/chat/memory/MessageWindowChatMemoryTests.java b/spring-ai-model/src/test/java/org/springframework/ai/chat/memory/MessageWindowChatMemoryTests.java index 6684e48d3d5..caca4fca63b 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/chat/memory/MessageWindowChatMemoryTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/chat/memory/MessageWindowChatMemoryTests.java @@ -16,16 +16,17 @@ package org.springframework.ai.chat.memory; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + import org.junit.jupiter.api.Test; + import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.chat.messages.UserMessage; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -57,13 +58,13 @@ void handleMultipleMessagesInConversation() { String conversationId = UUID.randomUUID().toString(); List messages = List.of(new AssistantMessage("I, Robot"), new UserMessage("Hello")); - chatMemory.add(conversationId, messages); + this.chatMemory.add(conversationId, messages); - assertThat(chatMemory.get(conversationId)).containsAll(messages); + assertThat(this.chatMemory.get(conversationId)).containsAll(messages); - chatMemory.clear(conversationId); + this.chatMemory.clear(conversationId); - assertThat(chatMemory.get(conversationId)).isEmpty(); + assertThat(this.chatMemory.get(conversationId)).isEmpty(); } @Test @@ -71,53 +72,53 @@ void handleSingleMessageInConversation() { String conversationId = UUID.randomUUID().toString(); Message message = new UserMessage("Hello"); - chatMemory.add(conversationId, message); + this.chatMemory.add(conversationId, message); - assertThat(chatMemory.get(conversationId)).contains(message); + assertThat(this.chatMemory.get(conversationId)).contains(message); - chatMemory.clear(conversationId); + this.chatMemory.clear(conversationId); - assertThat(chatMemory.get(conversationId)).isEmpty(); + assertThat(this.chatMemory.get(conversationId)).isEmpty(); } @Test void nullConversationIdNotAllowed() { - assertThatThrownBy(() -> chatMemory.add(null, List.of(new UserMessage("Hello")))) + assertThatThrownBy(() -> this.chatMemory.add(null, List.of(new UserMessage("Hello")))) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("conversationId cannot be null or empty"); - assertThatThrownBy(() -> chatMemory.add(null, new UserMessage("Hello"))) + assertThatThrownBy(() -> this.chatMemory.add(null, new UserMessage("Hello"))) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("conversationId cannot be null or empty"); - assertThatThrownBy(() -> chatMemory.get(null)).isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy(() -> this.chatMemory.get(null)).isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("conversationId cannot be null or empty"); - assertThatThrownBy(() -> chatMemory.clear(null)).isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy(() -> this.chatMemory.clear(null)).isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("conversationId cannot be null or empty"); } @Test void emptyConversationIdNotAllowed() { - assertThatThrownBy(() -> chatMemory.add("", List.of(new UserMessage("Hello")))) + assertThatThrownBy(() -> this.chatMemory.add("", List.of(new UserMessage("Hello")))) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("conversationId cannot be null or empty"); - assertThatThrownBy(() -> chatMemory.add(null, new UserMessage("Hello"))) + assertThatThrownBy(() -> this.chatMemory.add(null, new UserMessage("Hello"))) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("conversationId cannot be null or empty"); - assertThatThrownBy(() -> chatMemory.get("")).isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy(() -> this.chatMemory.get("")).isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("conversationId cannot be null or empty"); - assertThatThrownBy(() -> chatMemory.clear("")).isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy(() -> this.chatMemory.clear("")).isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("conversationId cannot be null or empty"); } @Test void nullMessagesNotAllowed() { String conversationId = UUID.randomUUID().toString(); - assertThatThrownBy(() -> chatMemory.add(conversationId, (List) null)) + assertThatThrownBy(() -> this.chatMemory.add(conversationId, (List) null)) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("messages cannot be null"); } @@ -125,7 +126,7 @@ void nullMessagesNotAllowed() { @Test void nullMessageNotAllowed() { String conversationId = UUID.randomUUID().toString(); - assertThatThrownBy(() -> chatMemory.add(conversationId, (Message) null)) + assertThatThrownBy(() -> this.chatMemory.add(conversationId, (Message) null)) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("message cannot be null"); } @@ -136,7 +137,7 @@ void messagesWithNullElementsNotAllowed() { List messagesWithNull = new ArrayList<>(); messagesWithNull.add(null); - assertThatThrownBy(() -> chatMemory.add(conversationId, messagesWithNull)) + assertThatThrownBy(() -> this.chatMemory.add(conversationId, messagesWithNull)) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("messages cannot contain null elements"); } diff --git a/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/MessageUtilsTests.java b/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/MessageUtilsTests.java index 9fee140b12c..c60befb3443 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/MessageUtilsTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/MessageUtilsTests.java @@ -16,10 +16,11 @@ package org.springframework.ai.chat.messages; +import java.nio.charset.StandardCharsets; + import org.junit.jupiter.api.Test; -import org.springframework.core.io.ClassPathResource; -import java.nio.charset.StandardCharsets; +import org.springframework.core.io.ClassPathResource; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/SystemMessageTests.java b/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/SystemMessageTests.java index 188a9816617..c722e14e55b 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/SystemMessageTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/SystemMessageTests.java @@ -16,14 +16,16 @@ package org.springframework.ai.chat.messages; +import java.util.Map; + import org.junit.jupiter.api.Test; + import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; -import java.util.Map; - import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.springframework.ai.chat.messages.AbstractMessage.MESSAGE_TYPE; /** diff --git a/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/UserMessageTests.java b/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/UserMessageTests.java index 26bb59718bd..0887a7e4d71 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/UserMessageTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/UserMessageTests.java @@ -16,14 +16,15 @@ package org.springframework.ai.chat.messages; +import java.util.Map; + import org.junit.jupiter.api.Test; + import org.springframework.ai.content.Media; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.util.MimeTypeUtils; -import java.util.Map; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.springframework.ai.chat.messages.AbstractMessage.MESSAGE_TYPE; @@ -39,7 +40,6 @@ class UserMessageTests { void userMessageWithNullText() { assertThatThrownBy(() -> new UserMessage((String) null)).isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("Content must not be null for SYSTEM or USER messages"); - ; } @Test @@ -55,7 +55,6 @@ void userMessageWithTextContent() { void userMessageWithNullResource() { assertThatThrownBy(() -> new UserMessage((Resource) null)).isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("resource cannot be null"); - ; } @Test diff --git a/spring-ai-model/src/test/java/org/springframework/ai/chat/observation/ChatModelCompletionObservationHandlerTests.java b/spring-ai-model/src/test/java/org/springframework/ai/chat/observation/ChatModelCompletionObservationHandlerTests.java index 4b204b7e5ad..69f4f902369 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/chat/observation/ChatModelCompletionObservationHandlerTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/chat/observation/ChatModelCompletionObservationHandlerTests.java @@ -16,9 +16,12 @@ package org.springframework.ai.chat.observation; +import java.util.List; + import io.micrometer.observation.Observation; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.model.Generation; @@ -27,8 +30,6 @@ import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; /** @@ -63,7 +64,7 @@ void whenEmptyResponseThenOutputNothing(CapturedOutput output) { .prompt(generatePrompt(ChatOptions.builder().model("mistral").build())) .provider("superprovider") .build(); - observationHandler.onStop(context); + this.observationHandler.onStop(context); assertThat(output).contains(""" Chat Model Completion: [] @@ -77,7 +78,7 @@ void whenEmptyCompletionThenOutputNothing(CapturedOutput output) { .provider("superprovider") .build(); context.setResponse(new ChatResponse(List.of(new Generation(new AssistantMessage(""))))); - observationHandler.onStop(context); + this.observationHandler.onStop(context); assertThat(output).contains(""" Chat Model Completion: [] @@ -92,7 +93,7 @@ void whenCompletionWithTextThenOutputIt(CapturedOutput output) { .build(); context.setResponse(new ChatResponse(List.of(new Generation(new AssistantMessage("say please")), new Generation(new AssistantMessage("seriously, say please"))))); - observationHandler.onStop(context); + this.observationHandler.onStop(context); assertThat(output).contains(""" Chat Model Completion: ["say please", "seriously, say please"] diff --git a/spring-ai-model/src/test/java/org/springframework/ai/chat/observation/ChatModelObservationContextTests.java b/spring-ai-model/src/test/java/org/springframework/ai/chat/observation/ChatModelObservationContextTests.java index 37f3dc85836..e1b64b9dfff 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/chat/observation/ChatModelObservationContextTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/chat/observation/ChatModelObservationContextTests.java @@ -22,7 +22,6 @@ import org.springframework.ai.chat.prompt.Prompt; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; /** * Unit tests for {@link ChatModelObservationContext}. diff --git a/spring-ai-model/src/test/java/org/springframework/ai/chat/observation/ChatModelPromptContentObservationHandlerTests.java b/spring-ai-model/src/test/java/org/springframework/ai/chat/observation/ChatModelPromptContentObservationHandlerTests.java index e48c5f729bd..dd885c397ee 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/chat/observation/ChatModelPromptContentObservationHandlerTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/chat/observation/ChatModelPromptContentObservationHandlerTests.java @@ -16,9 +16,12 @@ package org.springframework.ai.chat.observation; +import java.util.List; + import io.micrometer.observation.Observation; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.prompt.ChatOptions; @@ -26,8 +29,6 @@ import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; /** @@ -44,7 +45,7 @@ class ChatModelPromptContentObservationHandlerTests { @Test void whenNotSupportedObservationContextThenReturnFalse() { var context = new Observation.Context(); - assertThat(observationHandler.supportsContext(context)).isFalse(); + assertThat(this.observationHandler.supportsContext(context)).isFalse(); } @Test @@ -53,7 +54,7 @@ void whenSupportedObservationContextThenReturnTrue() { .prompt(new Prompt(List.of(), ChatOptions.builder().model("mistral").build())) .provider("superprovider") .build(); - assertThat(observationHandler.supportsContext(context)).isTrue(); + assertThat(this.observationHandler.supportsContext(context)).isTrue(); } @Test @@ -62,7 +63,7 @@ void whenEmptyPromptThenOutputNothing(CapturedOutput output) { .prompt(new Prompt(List.of(), ChatOptions.builder().model("mistral").build())) .provider("superprovider") .build(); - observationHandler.onStop(context); + this.observationHandler.onStop(context); assertThat(output).contains(""" Chat Model Prompt Content: [] @@ -75,7 +76,7 @@ void whenPromptWithTextThenOutputIt(CapturedOutput output) { .prompt(new Prompt("supercalifragilisticexpialidocious", ChatOptions.builder().model("mistral").build())) .provider("superprovider") .build(); - observationHandler.onStop(context); + this.observationHandler.onStop(context); assertThat(output).contains(""" Chat Model Prompt Content: ["supercalifragilisticexpialidocious"] @@ -91,7 +92,7 @@ void whenPromptWithMessagesThenOutputIt(CapturedOutput output) { ChatOptions.builder().model("mistral").build())) .provider("superprovider") .build(); - observationHandler.onStop(context); + this.observationHandler.onStop(context); assertThat(output).contains(""" Chat Model Prompt Content: ["you're a chimney sweep", "supercalifragilisticexpialidocious"] diff --git a/spring-ai-model/src/test/java/org/springframework/ai/chat/prompt/PromptTemplateBuilderTests.java b/spring-ai-model/src/test/java/org/springframework/ai/chat/prompt/PromptTemplateBuilderTests.java index 7695647c36d..249d980c615 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/chat/prompt/PromptTemplateBuilderTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/chat/prompt/PromptTemplateBuilderTests.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.ai.chat.prompt; import java.util.HashMap; diff --git a/spring-ai-model/src/test/java/org/springframework/ai/chat/prompt/PromptTemplateTests.java b/spring-ai-model/src/test/java/org/springframework/ai/chat/prompt/PromptTemplateTests.java index a58290ffe16..ecd33e0317d 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/chat/prompt/PromptTemplateTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/chat/prompt/PromptTemplateTests.java @@ -282,18 +282,6 @@ void variablesOverwriting_Builder() { assertThat(promptTemplate.render()).isEqualTo("Hello Overwritten Day!"); } - // Helper Custom Renderer for testing - private static class CustomTestRenderer implements TemplateRenderer { - - @Override - public String apply(String template, Map model) { - // Simple renderer that just appends a marker - // Note: This simple renderer ignores the model map for test purposes. - return template + " (Rendered by Custom)"; - } - - } - @Test void customRenderer_Builder() { String template = "This is a test."; @@ -318,4 +306,16 @@ void resource_Builder() { assertThat(promptTemplate.render()).isEqualTo("Hello Builder from Resource!"); } + // Helper Custom Renderer for testing + private static class CustomTestRenderer implements TemplateRenderer { + + @Override + public String apply(String template, Map model) { + // Simple renderer that just appends a marker + // Note: This simple renderer ignores the model map for test purposes. + return template + " (Rendered by Custom)"; + } + + } + } diff --git a/spring-ai-model/src/test/java/org/springframework/ai/chat/prompt/PromptTests.java b/spring-ai-model/src/test/java/org/springframework/ai/chat/prompt/PromptTests.java index a9e8f84ecef..db88c270103 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/chat/prompt/PromptTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/chat/prompt/PromptTests.java @@ -16,13 +16,14 @@ package org.springframework.ai.chat.prompt; +import java.util.List; + import org.junit.jupiter.api.Test; + import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.chat.messages.UserMessage; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/spring-ai-model/src/test/java/org/springframework/ai/embedding/observation/DefaultEmbeddingModelObservationConventionTests.java b/spring-ai-model/src/test/java/org/springframework/ai/embedding/observation/DefaultEmbeddingModelObservationConventionTests.java index ba5c6467da6..b69863d5e20 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/embedding/observation/DefaultEmbeddingModelObservationConventionTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/embedding/observation/DefaultEmbeddingModelObservationConventionTests.java @@ -22,7 +22,6 @@ import io.micrometer.common.KeyValue; import io.micrometer.observation.Observation; -import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; import org.springframework.ai.chat.metadata.Usage; diff --git a/spring-ai-model/src/test/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContextTests.java b/spring-ai-model/src/test/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContextTests.java index 780e881a43b..ff4d68cbae0 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContextTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContextTests.java @@ -25,7 +25,6 @@ import org.springframework.ai.embedding.EmbeddingRequest; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; /** * Unit tests for {@link EmbeddingModelObservationContext}. diff --git a/spring-ai-model/src/test/java/org/springframework/ai/image/observation/ImageModelObservationContextTests.java b/spring-ai-model/src/test/java/org/springframework/ai/image/observation/ImageModelObservationContextTests.java index 7e45fbb401b..36b06a1f52c 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/image/observation/ImageModelObservationContextTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/image/observation/ImageModelObservationContextTests.java @@ -23,7 +23,6 @@ import org.springframework.ai.image.ImagePrompt; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; /** * Unit tests for {@link ImageModelObservationContext}. diff --git a/spring-ai-model/src/test/java/org/springframework/ai/image/observation/ImageModelPromptContentObservationHandlerTests.java b/spring-ai-model/src/test/java/org/springframework/ai/image/observation/ImageModelPromptContentObservationHandlerTests.java index 529506012d4..f420f64bfe5 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/image/observation/ImageModelPromptContentObservationHandlerTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/image/observation/ImageModelPromptContentObservationHandlerTests.java @@ -16,17 +16,18 @@ package org.springframework.ai.image.observation; +import java.util.List; + import io.micrometer.observation.Observation; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.ai.image.ImageMessage; import org.springframework.ai.image.ImageOptionsBuilder; import org.springframework.ai.image.ImagePrompt; import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; /** @@ -61,7 +62,7 @@ void whenEmptyPromptThenOutputNothing(CapturedOutput output) { .imagePrompt(new ImagePrompt("", ImageOptionsBuilder.builder().model("mistral").build())) .provider("superprovider") .build(); - observationHandler.onStop(context); + this.observationHandler.onStop(context); assertThat(output).contains(""" Image Model Prompt Content: [""] @@ -75,7 +76,7 @@ void whenPromptWithTextThenOutputIt(CapturedOutput output) { ImageOptionsBuilder.builder().model("mistral").build())) .provider("superprovider") .build(); - observationHandler.onStop(context); + this.observationHandler.onStop(context); assertThat(output).contains(""" Image Model Prompt Content: ["supercalifragilisticexpialidocious"] @@ -91,7 +92,7 @@ void whenPromptWithMessagesThenOutputIt(CapturedOutput output) { ImageOptionsBuilder.builder().model("mistral").build())) .provider("superprovider") .build(); - observationHandler.onStop(context); + this.observationHandler.onStop(context); assertThat(output).contains(""" Image Model Prompt Content: ["you're a chimney sweep", "supercalifragilisticexpialidocious"] diff --git a/spring-ai-model/src/test/java/org/springframework/ai/model/ModelOptionsUtilsTests.java b/spring-ai-model/src/test/java/org/springframework/ai/model/ModelOptionsUtilsTests.java index 6235c9d12f8..8cc2b9bd87e 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/model/ModelOptionsUtilsTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/model/ModelOptionsUtilsTests.java @@ -19,16 +19,15 @@ import java.util.Map; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.json.JsonMapper; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.json.JsonMapper; -import com.fasterxml.jackson.databind.SerializationFeature; - /** * @author Christian Tzolov */ @@ -170,14 +169,6 @@ public void pojo_emptyStringAsNullObject() throws Exception { // Person.class)).isInstanceOf(Exception.class); } - public static class Person { - - public String name; - - public Integer age; - - } - @Test public void getJsonPropertyValues() { record TestRecord(@JsonProperty("field1") String fieldA, @JsonProperty("field2") String fieldB) { @@ -187,6 +178,14 @@ record TestRecord(@JsonProperty("field1") String fieldA, @JsonProperty("field2") assertThat(ModelOptionsUtils.getJsonPropertyValues(TestRecord.class)).containsExactly("field1", "field2"); } + public static class Person { + + public String name; + + public Integer age; + + } + public interface TestPortableOptions extends ModelOptions { String getName(); diff --git a/spring-ai-model/src/test/java/org/springframework/ai/model/tool/DefaultToolCallingManagerIT.java b/spring-ai-model/src/test/java/org/springframework/ai/model/tool/DefaultToolCallingManagerIT.java index e35d5a9a8b6..d7d6dd10050 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/model/tool/DefaultToolCallingManagerIT.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/model/tool/DefaultToolCallingManagerIT.java @@ -16,10 +16,14 @@ package org.springframework.ai.model.tool; +import java.util.List; +import java.util.Map; + import io.micrometer.observation.tck.TestObservationRegistry; import io.micrometer.observation.tck.TestObservationRegistryAssert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; + import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.metadata.ChatResponseMetadata; import org.springframework.ai.chat.model.ChatResponse; @@ -39,9 +43,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; -import java.util.List; -import java.util.Map; - import static org.assertj.core.api.Assertions.assertThat; /** @@ -76,7 +77,7 @@ void observationForToolCall() { List.of(new AssistantMessage.ToolCall("toolA", "function", "toolA", "{}")))))) .build(); - ToolExecutionResult toolExecutionResult = toolCallingManager.executeToolCalls(prompt, chatResponse); + ToolExecutionResult toolExecutionResult = this.toolCallingManager.executeToolCalls(prompt, chatResponse); assertThat(toolExecutionResult).isNotNull(); diff --git a/spring-ai-model/src/test/java/org/springframework/ai/tool/method/MethodToolCallbackGenericTypesTest.java b/spring-ai-model/src/test/java/org/springframework/ai/tool/method/MethodToolCallbackGenericTypesTest.java index aaadaf5fc00..9b1baeac431 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/tool/method/MethodToolCallbackGenericTypesTest.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/tool/method/MethodToolCallbackGenericTypesTest.java @@ -55,7 +55,7 @@ void testGenericListType() throws Exception { // Create a JSON input with a list of strings String toolInput = """ { - "strings": ["one", "two", "three"] + "strings": ["one", "two", "three"] } """; @@ -89,7 +89,7 @@ void testGenericMapType() throws Exception { // Create a JSON input with a map of string to integer String toolInput = """ { - "map": {"one": 1, "two": 2, "three": 3} + "map": {"one": 1, "two": 2, "three": 3} } """; @@ -123,10 +123,10 @@ void testNestedGenericType() throws Exception { // Create a JSON input with a list of maps String toolInput = """ { - "listOfMaps": [ - {"a": 1, "b": 2}, - {"c": 3, "d": 4} - ] + "listOfMaps": [ + {"a": 1, "b": 2}, + {"c": 3, "d": 4} + ] } """; diff --git a/spring-ai-model/src/test/java/org/springframework/ai/tool/observation/DefaultToolCallingObservationConventionTests.java b/spring-ai-model/src/test/java/org/springframework/ai/tool/observation/DefaultToolCallingObservationConventionTests.java index ebc71333b2e..788472384a4 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/tool/observation/DefaultToolCallingObservationConventionTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/tool/observation/DefaultToolCallingObservationConventionTests.java @@ -19,6 +19,7 @@ import io.micrometer.common.KeyValue; import io.micrometer.observation.Observation; import org.junit.jupiter.api.Test; + import org.springframework.ai.observation.conventions.AiOperationType; import org.springframework.ai.observation.conventions.AiProvider; import org.springframework.ai.observation.conventions.SpringAiKind; diff --git a/spring-ai-model/src/test/java/org/springframework/ai/tool/observation/ToolCallingContentObservationFilterTests.java b/spring-ai-model/src/test/java/org/springframework/ai/tool/observation/ToolCallingContentObservationFilterTests.java index b053946a781..f64ab4010ed 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/tool/observation/ToolCallingContentObservationFilterTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/tool/observation/ToolCallingContentObservationFilterTests.java @@ -19,6 +19,7 @@ import io.micrometer.common.KeyValue; import io.micrometer.observation.Observation; import org.junit.jupiter.api.Test; + import org.springframework.ai.tool.definition.ToolDefinition; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-ai-model/src/test/java/org/springframework/ai/tool/observation/ToolCallingObservationContextTests.java b/spring-ai-model/src/test/java/org/springframework/ai/tool/observation/ToolCallingObservationContextTests.java index cde5fc1fb9a..da58cb30d62 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/tool/observation/ToolCallingObservationContextTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/tool/observation/ToolCallingObservationContextTests.java @@ -17,6 +17,7 @@ package org.springframework.ai.tool.observation; import org.junit.jupiter.api.Test; + import org.springframework.ai.tool.definition.ToolDefinition; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-ai-model/src/test/java/org/springframework/ai/util/TextBlockAssertion.java b/spring-ai-model/src/test/java/org/springframework/ai/util/TextBlockAssertion.java index 7d6312142ec..103c000a067 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/util/TextBlockAssertion.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/util/TextBlockAssertion.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -33,13 +33,13 @@ public static TextBlockAssertion assertThat(String actual) { @Override public TextBlockAssertion isEqualTo(Object expected) { - Assertions.assertThat(normalizedEOL(actual)).isEqualTo(normalizedEOL((String) expected)); + Assertions.assertThat(normalizedEOL(this.actual)).isEqualTo(normalizedEOL((String) expected)); return this; } @Override public TextBlockAssertion contains(CharSequence... values) { - Assertions.assertThat(normalizedEOL(actual)).contains(normalizedEOL(values)); + Assertions.assertThat(normalizedEOL(this.actual)).contains(normalizedEOL(values)); return this; } diff --git a/spring-ai-rag/src/main/java/org/springframework/ai/rag/advisor/RetrievalAugmentationAdvisor.java b/spring-ai-rag/src/main/java/org/springframework/ai/rag/advisor/RetrievalAugmentationAdvisor.java index c2dbbb6f57a..10cfea33584 100644 --- a/spring-ai-rag/src/main/java/org/springframework/ai/rag/advisor/RetrievalAugmentationAdvisor.java +++ b/spring-ai-rag/src/main/java/org/springframework/ai/rag/advisor/RetrievalAugmentationAdvisor.java @@ -25,10 +25,10 @@ import reactor.core.scheduler.Scheduler; -import org.springframework.ai.chat.client.advisor.api.BaseAdvisor; import org.springframework.ai.chat.client.ChatClientRequest; import org.springframework.ai.chat.client.ChatClientResponse; import org.springframework.ai.chat.client.advisor.api.AdvisorChain; +import org.springframework.ai.chat.client.advisor.api.BaseAdvisor; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.document.Document; import org.springframework.ai.rag.Query; diff --git a/spring-ai-rag/src/main/java/org/springframework/ai/rag/postretrieval/document/DocumentPostProcessor.java b/spring-ai-rag/src/main/java/org/springframework/ai/rag/postretrieval/document/DocumentPostProcessor.java index ce78e272b26..e148d8e5d2a 100644 --- a/spring-ai-rag/src/main/java/org/springframework/ai/rag/postretrieval/document/DocumentPostProcessor.java +++ b/spring-ai-rag/src/main/java/org/springframework/ai/rag/postretrieval/document/DocumentPostProcessor.java @@ -16,12 +16,12 @@ package org.springframework.ai.rag.postretrieval.document; -import org.springframework.ai.document.Document; -import org.springframework.ai.rag.Query; - import java.util.List; import java.util.function.BiFunction; +import org.springframework.ai.document.Document; +import org.springframework.ai.rag.Query; + /** * A component for post-processing retrieved documents based on a query, addressing * challenges such as "lost-in-the-middle", context length restrictions from the model, diff --git a/spring-ai-template-st/src/main/java/org/springframework/ai/template/st/StTemplateRenderer.java b/spring-ai-template-st/src/main/java/org/springframework/ai/template/st/StTemplateRenderer.java index a7f3c9c5475..3780b948a09 100644 --- a/spring-ai-template-st/src/main/java/org/springframework/ai/template/st/StTemplateRenderer.java +++ b/spring-ai-template-st/src/main/java/org/springframework/ai/template/st/StTemplateRenderer.java @@ -16,20 +16,21 @@ package org.springframework.ai.template.st; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + import org.antlr.runtime.Token; import org.antlr.runtime.TokenStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.ai.template.TemplateRenderer; -import org.springframework.ai.template.ValidationMode; -import org.springframework.util.Assert; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.compiler.Compiler; import org.stringtemplate.v4.compiler.STLexer; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import org.springframework.ai.template.TemplateRenderer; +import org.springframework.ai.template.ValidationMode; +import org.springframework.util.Assert; /** * Renders a template using the StringTemplate (ST) v4 library. @@ -103,7 +104,7 @@ public String apply(String template, Map variables) { for (Map.Entry entry : variables.entrySet()) { st.add(entry.getKey(), entry.getValue()); } - if (validationMode != ValidationMode.NONE) { + if (this.validationMode != ValidationMode.NONE) { validate(st, variables); } return st.render(); @@ -111,7 +112,7 @@ public String apply(String template, Map variables) { private ST createST(String template) { try { - return new ST(template, startDelimiterToken, endDelimiterToken); + return new ST(template, this.startDelimiterToken, this.endDelimiterToken); } catch (Exception ex) { throw new IllegalArgumentException("The template string is not valid.", ex); @@ -132,10 +133,10 @@ private Set validate(ST st, Map templateVariables) { missingVariables.removeAll(modelKeys); if (!missingVariables.isEmpty()) { - if (validationMode == ValidationMode.WARN) { + if (this.validationMode == ValidationMode.WARN) { logger.warn(VALIDATION_MESSAGE.formatted(missingVariables)); } - else if (validationMode == ValidationMode.THROW) { + else if (this.validationMode == ValidationMode.THROW) { throw new IllegalStateException(VALIDATION_MESSAGE.formatted(missingVariables)); } } @@ -187,7 +188,7 @@ public static Builder builder() { /** * Builder for configuring and creating {@link StTemplateRenderer} instances. */ - public static class Builder { + public static final class Builder { private char startDelimiterToken = DEFAULT_START_DELIMITER_TOKEN; @@ -258,7 +259,8 @@ public Builder validateStFunctions() { * @return A configured {@link StTemplateRenderer}. */ public StTemplateRenderer build() { - return new StTemplateRenderer(startDelimiterToken, endDelimiterToken, validationMode, validateStFunctions); + return new StTemplateRenderer(this.startDelimiterToken, this.endDelimiterToken, this.validationMode, + this.validateStFunctions); } } diff --git a/spring-ai-template-st/src/test/java/org/springframework/ai/template/st/StTemplateRendererEdgeTests.java b/spring-ai-template-st/src/test/java/org/springframework/ai/template/st/StTemplateRendererEdgeTests.java index 60f310ead1c..d1176385341 100644 --- a/spring-ai-template-st/src/test/java/org/springframework/ai/template/st/StTemplateRendererEdgeTests.java +++ b/spring-ai-template-st/src/test/java/org/springframework/ai/template/st/StTemplateRendererEdgeTests.java @@ -16,15 +16,16 @@ package org.springframework.ai.template.st; -import static org.assertj.core.api.Assertions.assertThat; - import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; + import org.springframework.ai.template.ValidationMode; +import static org.assertj.core.api.Assertions.assertThat; + /** * Additional edge and robustness tests for {@link StTemplateRenderer}. */ diff --git a/spring-ai-template-st/src/test/java/org/springframework/ai/template/st/StTemplateRendererTests.java b/spring-ai-template-st/src/test/java/org/springframework/ai/template/st/StTemplateRendererTests.java index 7d5f86d71c6..4d4e979e869 100644 --- a/spring-ai-template-st/src/test/java/org/springframework/ai/template/st/StTemplateRendererTests.java +++ b/spring-ai-template-st/src/test/java/org/springframework/ai/template/st/StTemplateRendererTests.java @@ -16,15 +16,16 @@ package org.springframework.ai.template.st; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.Test; -import org.springframework.test.util.ReflectionTestUtils; + import org.springframework.ai.template.ValidationMode; +import org.springframework.test.util.ReflectionTestUtils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; /** * Unit tests for {@link StTemplateRenderer}. diff --git a/spring-ai-test/src/main/java/org/springframework/ai/test/CurlyBracketEscaper.java b/spring-ai-test/src/main/java/org/springframework/ai/test/CurlyBracketEscaper.java index 49e7685533a..78594a214dc 100644 --- a/spring-ai-test/src/main/java/org/springframework/ai/test/CurlyBracketEscaper.java +++ b/spring-ai-test/src/main/java/org/springframework/ai/test/CurlyBracketEscaper.java @@ -1,18 +1,19 @@ /* -* Copyright 2025 - 2025 the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* https://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright 2025-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.ai.test; /** @@ -21,7 +22,11 @@ * @author Christian Tzolov * */ -public class CurlyBracketEscaper { +public final class CurlyBracketEscaper { + + private CurlyBracketEscaper() { + // prevents instantiation. + } /** * Escapes all curly brackets in the input string by adding a backslash before them @@ -47,4 +52,4 @@ public static String unescapeCurlyBrackets(String input) { return input.replace("\\{", "{").replace("\\}", "}"); } -} \ No newline at end of file +} diff --git a/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandler.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandler.java index f33f329800b..650c7c545e8 100644 --- a/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandler.java +++ b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandler.java @@ -16,16 +16,17 @@ package org.springframework.ai.vectorstore.observation; +import java.util.List; + import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.ai.document.Document; import org.springframework.ai.observation.ObservabilityHelper; import org.springframework.util.CollectionUtils; -import java.util.List; - /** * Handler for emitting the query response content to logs. * diff --git a/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConventionTests.java b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConventionTests.java index 89d36f6c576..498d8789f81 100644 --- a/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConventionTests.java +++ b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConventionTests.java @@ -16,17 +16,18 @@ package org.springframework.ai.vectorstore.observation; +import java.util.List; + import io.micrometer.common.KeyValue; import io.micrometer.observation.Observation; import org.junit.jupiter.api.Test; + import org.springframework.ai.document.Document; import org.springframework.ai.observation.conventions.SpringAiKind; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.observation.VectorStoreObservationDocumentation.HighCardinalityKeyNames; import org.springframework.ai.vectorstore.observation.VectorStoreObservationDocumentation.LowCardinalityKeyNames; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; /** diff --git a/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandlerTests.java b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandlerTests.java index 6ad8d5d19e7..149f8d75e2f 100644 --- a/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandlerTests.java +++ b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandlerTests.java @@ -16,15 +16,16 @@ package org.springframework.ai.vectorstore.observation; +import java.util.List; + import io.micrometer.observation.Observation; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.ai.document.Document; import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; /** @@ -54,7 +55,7 @@ void whenSupportedObservationContextThenReturnTrue() { @Test void whenEmptyQueryResponseThenOutputNothing(CapturedOutput output) { var context = VectorStoreObservationContext.builder("db", VectorStoreObservationContext.Operation.ADD).build(); - observationHandler.onStop(context); + this.observationHandler.onStop(context); assertThat(output).contains(""" Vector Store Query Response: [] @@ -65,7 +66,7 @@ void whenEmptyQueryResponseThenOutputNothing(CapturedOutput output) { void whenNonEmptyQueryResponseThenOutputIt(CapturedOutput output) { var context = VectorStoreObservationContext.builder("db", VectorStoreObservationContext.Operation.ADD).build(); context.setQueryResponse(List.of(new Document("doc1"), new Document("doc2"))); - observationHandler.onStop(context); + this.observationHandler.onStop(context); assertThat(output).contains(""" Vector Store Query Response: ["doc1", "doc2"] diff --git a/src/checkstyle/checkstyle-suppressions.xml b/src/checkstyle/checkstyle-suppressions.xml index 8569e8d4bda..1083d78182d 100644 --- a/src/checkstyle/checkstyle-suppressions.xml +++ b/src/checkstyle/checkstyle-suppressions.xml @@ -32,6 +32,7 @@ + @@ -39,6 +40,7 @@ + diff --git a/src/checkstyle/checkstyle.xml b/src/checkstyle/checkstyle.xml index 343ae144ac9..b03fd710392 100644 --- a/src/checkstyle/checkstyle.xml +++ b/src/checkstyle/checkstyle.xml @@ -20,6 +20,12 @@ "https://checkstyle.org/dtds/configuration_1_3.dtd"> + + + + + + @@ -100,7 +106,7 @@ + value="org.springframework.ai.chat.messages.AbstractMessage.*, org.springframework.ai.model.openai.autoconfigure.OpenAIAutoConfigurationUtil.*, org.springframework.ai.openai.api.OpenAiApi.ChatCompletionRequest.AudioParameters.Voice.*, org.springframework.ai.mistralai.api.MistralAiModerationApi.*, org.springframework.ai.util.LoggingMarkers.*, org.springframework.ai.embedding.observation.EmbeddingModelObservationDocumentation.*, org.springframework.ai.test.vectorstore.ObservationTestUtil.*, org.springframework.ai.autoconfigure.vectorstore.observation.ObservationTestUtil.*, org.awaitility.Awaitility.*, org.springframework.ai.aot.AiRuntimeHints.*, org.springframework.ai.openai.metadata.support.OpenAiApiResponseHeaders.*, org.springframework.ai.image.observation.ImageModelObservationDocumentation.*, org.springframework.ai.observation.embedding.EmbeddingModelObservationDocumentation.*, org.springframework.aot.hint.predicate.RuntimeHintsPredicates.*, org.springframework.ai.vectorstore.filter.Filter.ExpressionType.*, org.springframework.ai.chat.observation.ChatModelObservationDocumentation.*, org.assertj.core.groups.Tuple.*, org.assertj.core.api.AssertionsForClassTypes.*, org.junit.jupiter.api.Assertions.*, org.assertj.core.api.Assertions.*, org.junit.Assert.*, org.junit.Assume.*, org.junit.internal.matchers.ThrowableMessageMatcher.*, org.hamcrest.CoreMatchers.*, org.hamcrest.Matchers.*, org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.*, org.springframework.boot.configurationprocessor.TestCompiler.*, org.springframework.boot.test.autoconfigure.AutoConfigurationImportedCondition.*, org.mockito.Mockito.*, org.mockito.BDDMockito.*, org.mockito.Matchers.*, org.mockito.ArgumentMatchers.*, org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*, org.springframework.restdocs.hypermedia.HypermediaDocumentation.*, org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*, org.springframework.test.web.servlet.result.MockMvcResultMatchers.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*, org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*, org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo, org.springframework.test.web.client.match.MockRestRequestMatchers.*, org.springframework.test.web.client.response.MockRestResponseCreators.*, org.springframework.web.reactive.function.server.RequestPredicates.*, org.springframework.web.reactive.function.server.RouterFunctions.*, org.springframework.test.web.servlet.setup.MockMvcBuilders.*"/> diff --git a/vector-stores/spring-ai-azure-cosmos-db-store/src/main/java/org/springframework/ai/vectorstore/cosmosdb/CosmosDBVectorStore.java b/vector-stores/spring-ai-azure-cosmos-db-store/src/main/java/org/springframework/ai/vectorstore/cosmosdb/CosmosDBVectorStore.java index 662ff522443..ca2a817001a 100644 --- a/vector-stores/spring-ai-azure-cosmos-db-store/src/main/java/org/springframework/ai/vectorstore/cosmosdb/CosmosDBVectorStore.java +++ b/vector-stores/spring-ai-azure-cosmos-db-store/src/main/java/org/springframework/ai/vectorstore/cosmosdb/CosmosDBVectorStore.java @@ -19,7 +19,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; @@ -33,7 +32,6 @@ import com.azure.cosmos.models.CosmosBulkOperations; import com.azure.cosmos.models.CosmosContainerProperties; import com.azure.cosmos.models.CosmosItemOperation; -import com.azure.cosmos.models.CosmosItemResponse; import com.azure.cosmos.models.CosmosQueryRequestOptions; import com.azure.cosmos.models.CosmosVectorDataType; import com.azure.cosmos.models.CosmosVectorDistanceFunction; @@ -42,7 +40,6 @@ import com.azure.cosmos.models.CosmosVectorIndexSpec; import com.azure.cosmos.models.CosmosVectorIndexType; import com.azure.cosmos.models.ExcludedPath; -import com.azure.cosmos.models.FeedResponse; import com.azure.cosmos.models.IncludedPath; import com.azure.cosmos.models.IndexingMode; import com.azure.cosmos.models.IndexingPolicy; @@ -53,7 +50,6 @@ import com.azure.cosmos.models.SqlQuerySpec; import com.azure.cosmos.models.ThroughputProperties; import com.azure.cosmos.util.CosmosPagedFlux; - import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; diff --git a/vector-stores/spring-ai-azure-cosmos-db-store/src/test/java/org/springframework/ai/vectorstore/cosmosdb/CosmosDBVectorStoreWithMetadataPartitionKeyIT.java b/vector-stores/spring-ai-azure-cosmos-db-store/src/test/java/org/springframework/ai/vectorstore/cosmosdb/CosmosDBVectorStoreWithMetadataPartitionKeyIT.java index 5ec456871c7..2a46c672dd3 100644 --- a/vector-stores/spring-ai-azure-cosmos-db-store/src/test/java/org/springframework/ai/vectorstore/cosmosdb/CosmosDBVectorStoreWithMetadataPartitionKeyIT.java +++ b/vector-stores/spring-ai-azure-cosmos-db-store/src/test/java/org/springframework/ai/vectorstore/cosmosdb/CosmosDBVectorStoreWithMetadataPartitionKeyIT.java @@ -16,6 +16,12 @@ package org.springframework.ai.vectorstore.cosmosdb; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + import com.azure.cosmos.CosmosAsyncClient; import com.azure.cosmos.CosmosAsyncContainer; import com.azure.cosmos.CosmosClientBuilder; @@ -23,6 +29,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; + import org.springframework.ai.document.Document; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.transformers.TransformersEmbeddingModel; @@ -35,12 +42,6 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/vector-stores/spring-ai-chroma-store/src/main/java/org/springframework/ai/chroma/vectorstore/ChromaApi.java b/vector-stores/spring-ai-chroma-store/src/main/java/org/springframework/ai/chroma/vectorstore/ChromaApi.java index 72495566d91..9c55e6011c5 100644 --- a/vector-stores/spring-ai-chroma-store/src/main/java/org/springframework/ai/chroma/vectorstore/ChromaApi.java +++ b/vector-stores/spring-ai-chroma-store/src/main/java/org/springframework/ai/chroma/vectorstore/ChromaApi.java @@ -634,7 +634,7 @@ public Builder objectMapper(ObjectMapper objectMapper) { } public ChromaApi build() { - return new ChromaApi(this.baseUrl, this.restClientBuilder, objectMapper); + return new ChromaApi(this.baseUrl, this.restClientBuilder, this.objectMapper); } } diff --git a/vector-stores/spring-ai-chroma-store/src/main/java/org/springframework/ai/chroma/vectorstore/common/ChromaApiConstants.java b/vector-stores/spring-ai-chroma-store/src/main/java/org/springframework/ai/chroma/vectorstore/common/ChromaApiConstants.java index 80e01975e42..34cc03e7f57 100644 --- a/vector-stores/spring-ai-chroma-store/src/main/java/org/springframework/ai/chroma/vectorstore/common/ChromaApiConstants.java +++ b/vector-stores/spring-ai-chroma-store/src/main/java/org/springframework/ai/chroma/vectorstore/common/ChromaApiConstants.java @@ -21,7 +21,7 @@ * * @author Jonghoon Park */ -public class ChromaApiConstants { +public final class ChromaApiConstants { public static final String DEFAULT_BASE_URL = "http://localhost:8000"; @@ -31,4 +31,8 @@ public class ChromaApiConstants { public static final String DEFAULT_COLLECTION_NAME = "SpringAiCollection"; + private ChromaApiConstants() { + // prevents instantiation. + } + } diff --git a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/BasicAuthChromaWhereIT.java b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/BasicAuthChromaWhereIT.java index f6216e05bd5..a24b9904890 100644 --- a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/BasicAuthChromaWhereIT.java +++ b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/BasicAuthChromaWhereIT.java @@ -22,8 +22,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.testcontainers.chromadb.ChromaDBContainer; -import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; -import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.utility.MountableFile; diff --git a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaApiIT.java b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaApiIT.java index 5d59526342d..25478fab66d 100644 --- a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaApiIT.java +++ b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaApiIT.java @@ -22,10 +22,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.ai.chroma.vectorstore.common.ChromaApiConstants; import org.testcontainers.chromadb.ChromaDBContainer; -import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; -import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -34,6 +31,7 @@ import org.springframework.ai.chroma.vectorstore.ChromaApi.Collection; import org.springframework.ai.chroma.vectorstore.ChromaApi.GetEmbeddingsRequest; import org.springframework.ai.chroma.vectorstore.ChromaApi.QueryRequest; +import org.springframework.ai.chroma.vectorstore.common.ChromaApiConstants; import org.springframework.ai.document.Document; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.transformers.TransformersEmbeddingModel; @@ -72,24 +70,24 @@ public class ChromaApiIT { @BeforeEach public void beforeEach() { - var tenant = this.chromaApi.getTenant(defaultTenantName); + var tenant = this.chromaApi.getTenant(this.defaultTenantName); if (tenant == null) { - this.chromaApi.createTenant(defaultTenantName); + this.chromaApi.createTenant(this.defaultTenantName); } - var database = this.chromaApi.getDatabase(defaultTenantName, defaultDatabaseName); + var database = this.chromaApi.getDatabase(this.defaultTenantName, this.defaultDatabaseName); if (database == null) { - this.chromaApi.createDatabase(defaultTenantName, defaultDatabaseName); + this.chromaApi.createDatabase(this.defaultTenantName, this.defaultDatabaseName); } - this.chromaApi.listCollections(defaultTenantName, defaultDatabaseName) - .forEach(c -> this.chromaApi.deleteCollection(defaultTenantName, defaultDatabaseName, c.name())); + this.chromaApi.listCollections(this.defaultTenantName, this.defaultDatabaseName) + .forEach(c -> this.chromaApi.deleteCollection(this.defaultTenantName, this.defaultDatabaseName, c.name())); } @Test public void testClientWithMetadata() { Map metadata = Map.of("hnsw:space", "cosine", "hnsw:M", 5); - var newCollection = this.chromaApi.createCollection(defaultTenantName, defaultDatabaseName, + var newCollection = this.chromaApi.createCollection(this.defaultTenantName, this.defaultDatabaseName, new ChromaApi.CreateCollectionRequest("TestCollection", metadata)); assertThat(newCollection).isNotNull(); assertThat(newCollection.name()).isEqualTo("TestCollection"); @@ -97,29 +95,30 @@ public void testClientWithMetadata() { @Test public void testClient() { - var newCollection = this.chromaApi.createCollection(defaultTenantName, defaultDatabaseName, + var newCollection = this.chromaApi.createCollection(this.defaultTenantName, this.defaultDatabaseName, new ChromaApi.CreateCollectionRequest("TestCollection")); assertThat(newCollection).isNotNull(); assertThat(newCollection.name()).isEqualTo("TestCollection"); - var getCollection = this.chromaApi.getCollection(defaultTenantName, defaultDatabaseName, "TestCollection"); + var getCollection = this.chromaApi.getCollection(this.defaultTenantName, this.defaultDatabaseName, + "TestCollection"); assertThat(getCollection).isNotNull(); assertThat(getCollection.name()).isEqualTo("TestCollection"); assertThat(getCollection.id()).isEqualTo(newCollection.id()); - List collections = this.chromaApi.listCollections(defaultTenantName, defaultDatabaseName); + List collections = this.chromaApi.listCollections(this.defaultTenantName, this.defaultDatabaseName); assertThat(collections).hasSize(1); assertThat(collections.get(0).id()).isEqualTo(newCollection.id()); - this.chromaApi.deleteCollection(defaultTenantName, defaultDatabaseName, newCollection.name()); - assertThat(this.chromaApi.listCollections(defaultTenantName, defaultDatabaseName)).hasSize(0); + this.chromaApi.deleteCollection(this.defaultTenantName, this.defaultDatabaseName, newCollection.name()); + assertThat(this.chromaApi.listCollections(this.defaultTenantName, this.defaultDatabaseName)).hasSize(0); } @Test public void testCollection() { - var newCollection = this.chromaApi.createCollection(defaultTenantName, defaultDatabaseName, + var newCollection = this.chromaApi.createCollection(this.defaultTenantName, this.defaultDatabaseName, new ChromaApi.CreateCollectionRequest("TestCollection")); - assertThat(this.chromaApi.countEmbeddings(defaultTenantName, defaultDatabaseName, newCollection.id())) + assertThat(this.chromaApi.countEmbeddings(this.defaultTenantName, this.defaultDatabaseName, newCollection.id())) .isEqualTo(0); var addEmbeddingRequest = new AddEmbeddingsRequest(List.of("id1", "id2"), @@ -127,20 +126,20 @@ public void testCollection() { List.of(Map.of(), Map.of("key1", "value1", "key2", true, "key3", 23.4)), List.of("Hello World", "Big World")); - this.chromaApi.upsertEmbeddings(defaultTenantName, defaultDatabaseName, newCollection.id(), + this.chromaApi.upsertEmbeddings(this.defaultTenantName, this.defaultDatabaseName, newCollection.id(), addEmbeddingRequest); var addEmbeddingRequest2 = new AddEmbeddingsRequest("id3", new float[] { 3f, 3f, 3f }, Map.of("key1", "value1", "key2", true, "key3", 23.4), "Big World"); - this.chromaApi.upsertEmbeddings(defaultTenantName, defaultDatabaseName, newCollection.id(), + this.chromaApi.upsertEmbeddings(this.defaultTenantName, this.defaultDatabaseName, newCollection.id(), addEmbeddingRequest2); - assertThat(this.chromaApi.countEmbeddings(defaultTenantName, defaultDatabaseName, newCollection.id())) + assertThat(this.chromaApi.countEmbeddings(this.defaultTenantName, this.defaultDatabaseName, newCollection.id())) .isEqualTo(3); - var queryResult = this.chromaApi.queryCollection(defaultTenantName, defaultDatabaseName, newCollection.id(), - new QueryRequest(new float[] { 1f, 1f, 1f }, 3, this.chromaApi.where(""" + var queryResult = this.chromaApi.queryCollection(this.defaultTenantName, this.defaultDatabaseName, + newCollection.id(), new QueryRequest(new float[] { 1f, 1f, 1f }, 3, this.chromaApi.where(""" { "key2" : { "$eq": true } } @@ -149,16 +148,16 @@ public void testCollection() { assertThat(queryResult.ids().get(0)).containsExactlyInAnyOrder("id2", "id3"); // Update existing embedding. - this.chromaApi.upsertEmbeddings(defaultTenantName, defaultDatabaseName, newCollection.id(), + this.chromaApi.upsertEmbeddings(this.defaultTenantName, this.defaultDatabaseName, newCollection.id(), new AddEmbeddingsRequest("id3", new float[] { 6f, 6f, 6f }, Map.of("key1", "value2", "key2", false, "key4", 23.4), "Small World")); - var result = this.chromaApi.getEmbeddings(defaultTenantName, defaultDatabaseName, newCollection.id(), + var result = this.chromaApi.getEmbeddings(this.defaultTenantName, this.defaultDatabaseName, newCollection.id(), new GetEmbeddingsRequest(List.of("id2"))); assertThat(result.ids().get(0)).isEqualTo("id2"); - queryResult = this.chromaApi.queryCollection(defaultTenantName, defaultDatabaseName, newCollection.id(), - new QueryRequest(new float[] { 1f, 1f, 1f }, 3, this.chromaApi.where(""" + queryResult = this.chromaApi.queryCollection(this.defaultTenantName, this.defaultDatabaseName, + newCollection.id(), new QueryRequest(new float[] { 1f, 1f, 1f }, 3, this.chromaApi.where(""" { "key2" : { "$eq": true } } @@ -170,7 +169,7 @@ public void testCollection() { @Test public void testQueryWhere() { - var collection = this.chromaApi.createCollection(defaultTenantName, defaultDatabaseName, + var collection = this.chromaApi.createCollection(this.defaultTenantName, this.defaultDatabaseName, new ChromaApi.CreateCollectionRequest("TestCollection")); var add1 = new AddEmbeddingsRequest("id1", new float[] { 1f, 1f, 1f }, @@ -184,15 +183,15 @@ public void testQueryWhere() { Map.of("country", "BG", "active", false, "price", 40.1, "year", 2023), "The World is Big and Salvation Lurks Around the Corner"); - this.chromaApi.upsertEmbeddings(defaultTenantName, defaultDatabaseName, collection.id(), add1); - this.chromaApi.upsertEmbeddings(defaultTenantName, defaultDatabaseName, collection.id(), add2); - this.chromaApi.upsertEmbeddings(defaultTenantName, defaultDatabaseName, collection.id(), add3); + this.chromaApi.upsertEmbeddings(this.defaultTenantName, this.defaultDatabaseName, collection.id(), add1); + this.chromaApi.upsertEmbeddings(this.defaultTenantName, this.defaultDatabaseName, collection.id(), add2); + this.chromaApi.upsertEmbeddings(this.defaultTenantName, this.defaultDatabaseName, collection.id(), add3); - assertThat(this.chromaApi.countEmbeddings(defaultTenantName, defaultDatabaseName, collection.id())) + assertThat(this.chromaApi.countEmbeddings(this.defaultTenantName, this.defaultDatabaseName, collection.id())) .isEqualTo(3); - var queryResult = this.chromaApi.queryCollection(defaultTenantName, defaultDatabaseName, collection.id(), - new QueryRequest(new float[] { 1f, 1f, 1f }, 3)); + var queryResult = this.chromaApi.queryCollection(this.defaultTenantName, this.defaultDatabaseName, + collection.id(), new QueryRequest(new float[] { 1f, 1f, 1f }, 3)); assertThat(queryResult.ids().get(0)).hasSize(3); assertThat(queryResult.ids().get(0)).containsExactlyInAnyOrder("id1", "id2", "id3"); @@ -202,7 +201,7 @@ public void testQueryWhere() { assertThat(chromaEmbeddings).hasSize(3); assertThat(chromaEmbeddings).hasSize(3); - queryResult = this.chromaApi.queryCollection(defaultTenantName, defaultDatabaseName, collection.id(), + queryResult = this.chromaApi.queryCollection(this.defaultTenantName, this.defaultDatabaseName, collection.id(), new QueryRequest(new float[] { 1f, 1f, 1f }, 3, this.chromaApi.where(""" { "$and" : [ @@ -214,7 +213,7 @@ public void testQueryWhere() { assertThat(queryResult.ids().get(0)).hasSize(2); assertThat(queryResult.ids().get(0)).containsExactlyInAnyOrder("id1", "id3"); - queryResult = this.chromaApi.queryCollection(defaultTenantName, defaultDatabaseName, collection.id(), + queryResult = this.chromaApi.queryCollection(this.defaultTenantName, this.defaultDatabaseName, collection.id(), new QueryRequest(new float[] { 1f, 1f, 1f }, 3, this.chromaApi.where(""" { "$and" : [ @@ -232,7 +231,7 @@ public void testQueryWhere() { void shouldUseExistingCollectionWhenSchemaInitializationDisabled() { // initializeSchema // is false by // default. - var collection = this.chromaApi.createCollection(defaultTenantName, defaultDatabaseName, + var collection = this.chromaApi.createCollection(this.defaultTenantName, this.defaultDatabaseName, new ChromaApi.CreateCollectionRequest("test-collection")); assertThat(collection).isNotNull(); assertThat(collection.name()).isEqualTo("test-collection"); @@ -254,7 +253,8 @@ void shouldCreateNewCollectionWhenSchemaInitializationEnabled() { .initializeImmediately(true) .build(); - var collection = this.chromaApi.getCollection(defaultTenantName, defaultDatabaseName, "new-collection"); + var collection = this.chromaApi.getCollection(this.defaultTenantName, this.defaultDatabaseName, + "new-collection"); assertThat(collection).isNotNull(); assertThat(collection.name()).isEqualTo("new-collection"); diff --git a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStoreIT.java b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStoreIT.java index b3252c67341..b65333605ad 100644 --- a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStoreIT.java +++ b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStoreIT.java @@ -25,8 +25,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.testcontainers.chromadb.ChromaDBContainer; -import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; -import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; diff --git a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStoreObservationIT.java b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStoreObservationIT.java index 693973617b1..d30d6ff49d7 100644 --- a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStoreObservationIT.java @@ -27,8 +27,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.testcontainers.chromadb.ChromaDBContainer; -import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; -import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; diff --git a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/TokenSecuredChromaWhereIT.java b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/TokenSecuredChromaWhereIT.java index 73b38911b07..463ce84fc0b 100644 --- a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/TokenSecuredChromaWhereIT.java +++ b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/TokenSecuredChromaWhereIT.java @@ -22,8 +22,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.testcontainers.chromadb.ChromaDBContainer; -import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; -import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.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 a35106b1d07..819c72f294b 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 @@ -51,7 +51,7 @@ import org.springframework.jdbc.core.JdbcTemplate; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertThrows; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; /** @@ -147,9 +147,8 @@ public void testExceedingArtificialLimit() { Document massiveDocument = new Document(massiveContent); // This should throw an exception as it exceeds our configured limit - assertThrows(IllegalArgumentException.class, () -> { - batchingStrategy.batch(List.of(massiveDocument)); - }); + assertThatThrownBy(() -> batchingStrategy.batch(List.of(massiveDocument))) + .isInstanceOf(IllegalArgumentException.class); dropTable(context); }); diff --git a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreVectorStoreChatMemoryAdvisorIT.java b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreVectorStoreChatMemoryAdvisorIT.java index ccc91f22df3..9a84f71b28d 100644 --- a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreVectorStoreChatMemoryAdvisorIT.java +++ b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreVectorStoreChatMemoryAdvisorIT.java @@ -79,7 +79,7 @@ void testUseCustomConversationId() throws Exception { .of(new Document("Hello from memory", java.util.Map.of("conversationId", conversationId)))); // Build ChatClient with VectorStoreChatMemoryAdvisor - ChatClient chatClient = ChatClient.builder(chatModel) + ChatClient chatClient = ChatClient.builder(this.chatModel) .defaultAdvisors(VectorStoreChatMemoryAdvisor.builder(store).build()) .build(); @@ -117,7 +117,7 @@ void testSemanticSearchRetrievesRelevantMemory() throws Exception { java.util.Map.of("conversationId", conversationId)), new Document("Dogs are loyal pets.", java.util.Map.of("conversationId", conversationId)))); - ChatClient chatClient = ChatClient.builder(chatModel) + ChatClient chatClient = ChatClient.builder(this.chatModel) .defaultAdvisors(VectorStoreChatMemoryAdvisor.builder(store).defaultTopK(1).build()) .build(); @@ -153,7 +153,7 @@ void testSemanticSynonymRetrieval() throws Exception { store.add(java.util.List .of(new Document("Automobiles are fast.", java.util.Map.of("conversationId", conversationId)))); - ChatClient chatClient = ChatClient.builder(chatModel) + ChatClient chatClient = ChatClient.builder(this.chatModel) .defaultAdvisors(VectorStoreChatMemoryAdvisor.builder(store).defaultTopK(1).build()) .build(); @@ -185,7 +185,7 @@ void testIrrelevantMessageExclusion() throws Exception { new Document("The capital of Italy is Rome.", java.util.Map.of("conversationId", conversationId)), new Document("Bananas are yellow.", java.util.Map.of("conversationId", conversationId)))); - ChatClient chatClient = ChatClient.builder(chatModel) + ChatClient chatClient = ChatClient.builder(this.chatModel) .defaultAdvisors(VectorStoreChatMemoryAdvisor.builder(store).defaultTopK(2).build()) .build(); @@ -219,7 +219,7 @@ void testTopKSemanticRelevance() throws Exception { java.util.Map.of("conversationId", conversationId)), new Document("Dogs are loyal pets.", java.util.Map.of("conversationId", conversationId)))); - ChatClient chatClient = ChatClient.builder(chatModel) + ChatClient chatClient = ChatClient.builder(this.chatModel) .defaultAdvisors(VectorStoreChatMemoryAdvisor.builder(store).defaultTopK(1).build()) .build(); @@ -250,7 +250,7 @@ void testSemanticRetrievalWithParaphrasing() throws Exception { store.add(java.util.List.of(new Document("The quick brown fox jumps over the lazy dog.", java.util.Map.of("conversationId", conversationId)))); - ChatClient chatClient = ChatClient.builder(chatModel) + ChatClient chatClient = ChatClient.builder(this.chatModel) .defaultAdvisors(VectorStoreChatMemoryAdvisor.builder(store).defaultTopK(1).build()) .build(); @@ -282,7 +282,7 @@ void testMultipleRelevantMemoriesTopK() throws Exception { new Document("Strawberries are also red.", java.util.Map.of("conversationId", conversationId)), new Document("Bananas are yellow.", java.util.Map.of("conversationId", conversationId)))); - ChatClient chatClient = ChatClient.builder(chatModel) + ChatClient chatClient = ChatClient.builder(this.chatModel) .defaultAdvisors(VectorStoreChatMemoryAdvisor.builder(store).defaultTopK(2).build()) .build(); @@ -314,7 +314,7 @@ void testNoRelevantMemory() throws Exception { store.add(java.util.List .of(new Document("The sun is a star.", java.util.Map.of("conversationId", conversationId)))); - ChatClient chatClient = ChatClient.builder(chatModel) + ChatClient chatClient = ChatClient.builder(this.chatModel) .defaultAdvisors(VectorStoreChatMemoryAdvisor.builder(store).defaultTopK(1).build()) .build();