From f924ef7f0062e7dd7bdbe2717d5f3f39a1f2a67d Mon Sep 17 00:00:00 2001 From: Dev Bulchandani Date: Fri, 3 Oct 2025 15:12:58 +0530 Subject: [PATCH] Fix google genai auto configurations Signed-off-by: Dev Bulchandani --- .../GoogleGenAiChatAutoConfiguration.java | 2 - ...leGenAiTextEmbeddingAutoConfiguration.java | 6 +- .../autoconfigure/BaseGoogleGenAiIT.java | 55 +++++++++++++++++++ ...dContentServiceAutoConfigurationTests.java | 4 +- .../GoogleGenAiChatAutoConfigurationIT.java | 10 ++-- .../GoogleGenAiModelConfigurationTests.java | 12 ++-- .../tool/FunctionCallWithFunctionBeanIT.java | 9 +-- ...GenAiTextEmbeddingAutoConfigurationIT.java | 4 +- 8 files changed, 75 insertions(+), 27 deletions(-) create mode 100644 auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/BaseGoogleGenAiIT.java diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/main/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiChatAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/main/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiChatAutoConfiguration.java index c9b616cd016..e8c9b8ea2d1 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/main/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiChatAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/main/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiChatAutoConfiguration.java @@ -34,7 +34,6 @@ import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -61,7 +60,6 @@ @ConditionalOnProperty(name = SpringAIModelProperties.CHAT_MODEL, havingValue = SpringAIModels.GOOGLE_GEN_AI, matchIfMissing = true) @EnableConfigurationProperties({ GoogleGenAiChatProperties.class, GoogleGenAiConnectionProperties.class }) -@ImportAutoConfiguration(classes = { SpringAiRetryAutoConfiguration.class, ToolCallingAutoConfiguration.class }) public class GoogleGenAiChatAutoConfiguration { @Bean diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/main/java/org/springframework/ai/model/google/genai/autoconfigure/embedding/GoogleGenAiTextEmbeddingAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/main/java/org/springframework/ai/model/google/genai/autoconfigure/embedding/GoogleGenAiTextEmbeddingAutoConfiguration.java index 40261117755..6fd62c663e4 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/main/java/org/springframework/ai/model/google/genai/autoconfigure/embedding/GoogleGenAiTextEmbeddingAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/main/java/org/springframework/ai/model/google/genai/autoconfigure/embedding/GoogleGenAiTextEmbeddingAutoConfiguration.java @@ -26,7 +26,6 @@ import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -42,13 +41,12 @@ * @author Ilayaperumal Gopinathan * @since 1.1.0 */ -@AutoConfiguration(after = { SpringAiRetryAutoConfiguration.class }) +@AutoConfiguration( + after = { SpringAiRetryAutoConfiguration.class, GoogleGenAiEmbeddingConnectionAutoConfiguration.class }) @ConditionalOnClass(GoogleGenAiTextEmbeddingModel.class) @ConditionalOnProperty(name = SpringAIModelProperties.TEXT_EMBEDDING_MODEL, havingValue = SpringAIModels.GOOGLE_GEN_AI, matchIfMissing = true) @EnableConfigurationProperties(GoogleGenAiTextEmbeddingProperties.class) -@ImportAutoConfiguration( - classes = { SpringAiRetryAutoConfiguration.class, GoogleGenAiEmbeddingConnectionAutoConfiguration.class }) public class GoogleGenAiTextEmbeddingAutoConfiguration { @Bean diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/BaseGoogleGenAiIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/BaseGoogleGenAiIT.java new file mode 100644 index 00000000000..a80a41944a9 --- /dev/null +++ b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/BaseGoogleGenAiIT.java @@ -0,0 +1,55 @@ +/* + * 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.model.google.genai.autoconfigure; + +import java.util.Arrays; +import java.util.stream.Stream; + +import org.springframework.ai.model.google.genai.autoconfigure.chat.GoogleGenAiChatAutoConfiguration; +import org.springframework.ai.model.google.genai.autoconfigure.embedding.GoogleGenAiEmbeddingConnectionAutoConfiguration; +import org.springframework.ai.model.google.genai.autoconfigure.embedding.GoogleGenAiTextEmbeddingAutoConfiguration; +import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; +import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigurations; + +/** + * Base class to provide consistent AutoConfigurations for Google GenAI integration tests. + */ +public abstract class BaseGoogleGenAiIT { + + /** + * AutoConfigurations needed for Google GenAI Chat model. + */ + public static AutoConfigurations googleGenAiChatAutoConfig(Class... additional) { + Class[] dependencies = { SpringAiRetryAutoConfiguration.class, ToolCallingAutoConfiguration.class, + GoogleGenAiChatAutoConfiguration.class }; + Class[] all = Stream.concat(Arrays.stream(dependencies), Arrays.stream(additional)).toArray(Class[]::new); + return AutoConfigurations.of(all); + } + + /** + * AutoConfigurations needed for Google GenAI Text Embedding model. + */ + public static AutoConfigurations googleGenAiEmbeddingAutoConfig(Class... additional) { + Class[] dependencies = { SpringAiRetryAutoConfiguration.class, + GoogleGenAiEmbeddingConnectionAutoConfiguration.class, + GoogleGenAiTextEmbeddingAutoConfiguration.class }; + Class[] all = Stream.concat(Arrays.stream(dependencies), Arrays.stream(additional)).toArray(Class[]::new); + return AutoConfigurations.of(all); + } + +} diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiCachedContentServiceAutoConfigurationTests.java b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiCachedContentServiceAutoConfigurationTests.java index 6802bd0a39d..ee306d0dcc7 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiCachedContentServiceAutoConfigurationTests.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiCachedContentServiceAutoConfigurationTests.java @@ -22,8 +22,8 @@ import org.springframework.ai.google.genai.GoogleGenAiChatModel; import org.springframework.ai.google.genai.cache.GoogleGenAiCachedContentService; +import org.springframework.ai.model.google.genai.autoconfigure.BaseGoogleGenAiIT; import org.springframework.ai.model.tool.ToolCallingManager; -import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -40,7 +40,7 @@ public class GoogleGenAiCachedContentServiceAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(GoogleGenAiChatAutoConfiguration.class)); + .withConfiguration(BaseGoogleGenAiIT.googleGenAiChatAutoConfig()); @Test void cachedContentServiceBeanIsCreatedWhenChatModelExists() { diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiChatAutoConfigurationIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiChatAutoConfigurationIT.java index 09f25495d3f..7532c543571 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiChatAutoConfigurationIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiChatAutoConfigurationIT.java @@ -28,7 +28,7 @@ import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.google.genai.GoogleGenAiChatModel; -import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.ai.model.google.genai.autoconfigure.BaseGoogleGenAiIT; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; @@ -49,7 +49,7 @@ public class GoogleGenAiChatAutoConfigurationIT { void generateWithApiKey() { ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withPropertyValues("spring.ai.google.genai.api-key=" + System.getenv("GOOGLE_API_KEY")) - .withConfiguration(AutoConfigurations.of(GoogleGenAiChatAutoConfiguration.class)); + .withConfiguration(BaseGoogleGenAiIT.googleGenAiChatAutoConfig()); contextRunner.run(context -> { GoogleGenAiChatModel chatModel = context.getBean(GoogleGenAiChatModel.class); @@ -64,7 +64,7 @@ void generateWithApiKey() { void generateStreamingWithApiKey() { ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withPropertyValues("spring.ai.google.genai.api-key=" + System.getenv("GOOGLE_API_KEY")) - .withConfiguration(AutoConfigurations.of(GoogleGenAiChatAutoConfiguration.class)); + .withConfiguration(BaseGoogleGenAiIT.googleGenAiChatAutoConfig()); contextRunner.run(context -> { GoogleGenAiChatModel chatModel = context.getBean(GoogleGenAiChatModel.class); @@ -87,7 +87,7 @@ void generateWithVertexAi() { ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withPropertyValues("spring.ai.google.genai.project-id=" + System.getenv("GOOGLE_CLOUD_PROJECT"), "spring.ai.google.genai.location=" + System.getenv("GOOGLE_CLOUD_LOCATION")) - .withConfiguration(AutoConfigurations.of(GoogleGenAiChatAutoConfiguration.class)); + .withConfiguration(BaseGoogleGenAiIT.googleGenAiChatAutoConfig()); contextRunner.run(context -> { GoogleGenAiChatModel chatModel = context.getBean(GoogleGenAiChatModel.class); @@ -104,7 +104,7 @@ void generateStreamingWithVertexAi() { ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withPropertyValues("spring.ai.google.genai.project-id=" + System.getenv("GOOGLE_CLOUD_PROJECT"), "spring.ai.google.genai.location=" + System.getenv("GOOGLE_CLOUD_LOCATION")) - .withConfiguration(AutoConfigurations.of(GoogleGenAiChatAutoConfiguration.class)); + .withConfiguration(BaseGoogleGenAiIT.googleGenAiChatAutoConfig()); contextRunner.run(context -> { GoogleGenAiChatModel chatModel = context.getBean(GoogleGenAiChatModel.class); diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiModelConfigurationTests.java b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiModelConfigurationTests.java index f73120ad3e6..25e9844257c 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiModelConfigurationTests.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/GoogleGenAiModelConfigurationTests.java @@ -20,7 +20,7 @@ import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.springframework.ai.google.genai.GoogleGenAiChatModel; -import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.ai.model.google.genai.autoconfigure.BaseGoogleGenAiIT; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; @@ -37,14 +37,14 @@ class GoogleGenAiModelConfigurationTests { @Test void chatModelActivationWithApiKey() { - this.contextRunner.withConfiguration(AutoConfigurations.of(GoogleGenAiChatAutoConfiguration.class)) + this.contextRunner.withConfiguration(BaseGoogleGenAiIT.googleGenAiChatAutoConfig()) .withPropertyValues("spring.ai.google.genai.api-key=test-key", "spring.ai.model.chat=none") .run(context -> { assertThat(context.getBeansOfType(GoogleGenAiChatProperties.class)).isEmpty(); assertThat(context.getBeansOfType(GoogleGenAiChatModel.class)).isEmpty(); }); - this.contextRunner.withConfiguration(AutoConfigurations.of(GoogleGenAiChatAutoConfiguration.class)) + this.contextRunner.withConfiguration(BaseGoogleGenAiIT.googleGenAiChatAutoConfig()) .withPropertyValues("spring.ai.google.genai.api-key=test-key", "spring.ai.model.chat=google-genai") .run(context -> { assertThat(context.getBeansOfType(GoogleGenAiChatProperties.class)).isNotEmpty(); @@ -57,7 +57,7 @@ void chatModelActivationWithApiKey() { @EnabledIfEnvironmentVariable(named = "GOOGLE_CLOUD_LOCATION", matches = ".*") void chatModelActivationWithVertexAi() { - this.contextRunner.withConfiguration(AutoConfigurations.of(GoogleGenAiChatAutoConfiguration.class)) + this.contextRunner.withConfiguration(BaseGoogleGenAiIT.googleGenAiChatAutoConfig()) .withPropertyValues("spring.ai.google.genai.project-id=test-project", "spring.ai.google.genai.location=us-central1", "spring.ai.model.chat=none") .run(context -> { @@ -65,7 +65,7 @@ void chatModelActivationWithVertexAi() { assertThat(context.getBeansOfType(GoogleGenAiChatModel.class)).isEmpty(); }); - this.contextRunner.withConfiguration(AutoConfigurations.of(GoogleGenAiChatAutoConfiguration.class)) + this.contextRunner.withConfiguration(BaseGoogleGenAiIT.googleGenAiChatAutoConfig()) .withPropertyValues("spring.ai.google.genai.project-id=test-project", "spring.ai.google.genai.location=us-central1", "spring.ai.model.chat=google-genai") .run(context -> { @@ -78,7 +78,7 @@ void chatModelActivationWithVertexAi() { void chatModelDefaultActivation() { // Tests that the model is activated by default when spring.ai.model.chat is not // set - this.contextRunner.withConfiguration(AutoConfigurations.of(GoogleGenAiChatAutoConfiguration.class)) + this.contextRunner.withConfiguration(BaseGoogleGenAiIT.googleGenAiChatAutoConfig()) .withPropertyValues("spring.ai.google.genai.api-key=test-key") .run(context -> { assertThat(context.getBeansOfType(GoogleGenAiChatProperties.class)).isNotEmpty(); diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/tool/FunctionCallWithFunctionBeanIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/tool/FunctionCallWithFunctionBeanIT.java index 8de4ac3295d..328e742fcfa 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/tool/FunctionCallWithFunctionBeanIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/chat/tool/FunctionCallWithFunctionBeanIT.java @@ -27,10 +27,9 @@ import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.google.genai.GoogleGenAiChatModel; import org.springframework.ai.google.genai.GoogleGenAiChatOptions; -import org.springframework.ai.model.google.genai.autoconfigure.chat.GoogleGenAiChatAutoConfiguration; +import org.springframework.ai.model.google.genai.autoconfigure.BaseGoogleGenAiIT; import org.springframework.ai.tool.ToolCallback; import org.springframework.ai.tool.function.FunctionToolCallback; -import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; @@ -52,8 +51,7 @@ public class FunctionCallWithFunctionBeanIT { void functionCallWithApiKey() { ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withPropertyValues("spring.ai.google.genai.api-key=" + System.getenv("GOOGLE_API_KEY")) - .withConfiguration( - AutoConfigurations.of(RestClientAutoConfiguration.class, GoogleGenAiChatAutoConfiguration.class)) + .withConfiguration(BaseGoogleGenAiIT.googleGenAiChatAutoConfig(RestClientAutoConfiguration.class)) .withUserConfiguration(FunctionConfiguration.class); contextRunner.run(context -> { @@ -83,8 +81,7 @@ void functionCallWithVertexAi() { ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withPropertyValues("spring.ai.google.genai.project-id=" + System.getenv("GOOGLE_CLOUD_PROJECT"), "spring.ai.google.genai.location=" + System.getenv("GOOGLE_CLOUD_LOCATION")) - .withConfiguration( - AutoConfigurations.of(RestClientAutoConfiguration.class, GoogleGenAiChatAutoConfiguration.class)) + .withConfiguration(BaseGoogleGenAiIT.googleGenAiChatAutoConfig(RestClientAutoConfiguration.class)) .withUserConfiguration(FunctionConfiguration.class); contextRunner.run(context -> { diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/embedding/GoogleGenAiTextEmbeddingAutoConfigurationIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/embedding/GoogleGenAiTextEmbeddingAutoConfigurationIT.java index b74bae3f407..29ab0696630 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/embedding/GoogleGenAiTextEmbeddingAutoConfigurationIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/java/org/springframework/ai/model/google/genai/autoconfigure/embedding/GoogleGenAiTextEmbeddingAutoConfigurationIT.java @@ -23,6 +23,7 @@ import org.springframework.ai.embedding.EmbeddingResponse; import org.springframework.ai.google.genai.text.GoogleGenAiTextEmbeddingModel; +import org.springframework.ai.model.google.genai.autoconfigure.BaseGoogleGenAiIT; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -42,8 +43,7 @@ public class GoogleGenAiTextEmbeddingAutoConfigurationIT { void embeddingWithApiKey() { ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withPropertyValues("spring.ai.google.genai.embedding.api-key=" + System.getenv("GOOGLE_API_KEY")) - .withConfiguration(AutoConfigurations.of(GoogleGenAiTextEmbeddingAutoConfiguration.class, - GoogleGenAiEmbeddingConnectionAutoConfiguration.class)); + .withConfiguration(BaseGoogleGenAiIT.googleGenAiEmbeddingAutoConfig()); contextRunner.run(context -> { GoogleGenAiTextEmbeddingModel embeddingModel = context.getBean(GoogleGenAiTextEmbeddingModel.class);