diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/main/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiChatAutoConfiguration.java b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/main/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiChatAutoConfiguration.java index d71008196df..2aad74708d6 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/main/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiChatAutoConfiguration.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/main/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiChatAutoConfiguration.java @@ -1,19 +1,3 @@ -/* - * 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 - * - * 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.azure.openai.autoconfigure; import com.azure.ai.openai.OpenAIClientBuilder; @@ -29,7 +13,6 @@ import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; 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; @@ -50,7 +33,6 @@ @EnableConfigurationProperties({ AzureOpenAiChatProperties.class }) @ConditionalOnProperty(name = SpringAIModelProperties.CHAT_MODEL, havingValue = SpringAIModels.AZURE_OPENAI, matchIfMissing = true) -@ImportAutoConfiguration(classes = { ToolCallingAutoConfiguration.class }) @Import(AzureOpenAiClientBuilderConfiguration.class) public class AzureOpenAiChatAutoConfiguration { diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiAutoConfigurationEntraIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiAutoConfigurationEntraIT.java index d8688903026..d142a055dc4 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiAutoConfigurationEntraIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiAutoConfigurationEntraIT.java @@ -41,6 +41,7 @@ import org.springframework.ai.azure.openai.AzureOpenAiAudioTranscriptionModel; import org.springframework.ai.azure.openai.AzureOpenAiChatModel; import org.springframework.ai.azure.openai.AzureOpenAiEmbeddingModel; +import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.UserMessage; @@ -98,7 +99,9 @@ class AzureOpenAiAutoConfigurationEntraIT { @Test void chatCompletion() { - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .run(context -> { AzureOpenAiChatModel chatModel = context.getBean(AzureOpenAiChatModel.class); ChatResponse response = chatModel.call(new Prompt(List.of(this.userMessage, this.systemMessage))); @@ -108,7 +111,9 @@ void chatCompletion() { @Test void httpRequestContainsUserAgentAndCustomHeaders() { - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .withPropertyValues("spring.ai.azure.openai.custom-headers.foo=bar", "spring.ai.azure.openai.custom-headers.fizz=buzz") .run(context -> { @@ -135,7 +140,9 @@ void httpRequestContainsUserAgentAndCustomHeaders() { @Test void chatCompletionStreaming() { - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .run(context -> { AzureOpenAiChatModel chatModel = context.getBean(AzureOpenAiChatModel.class); @@ -159,7 +166,9 @@ void chatCompletionStreaming() { @Test void embedding() { - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiEmbeddingAutoConfiguration.class)) + this.contextRunner + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiEmbeddingAutoConfiguration.class)) .run(context -> { AzureOpenAiEmbeddingModel embeddingModel = context.getBean(AzureOpenAiEmbeddingModel.class); @@ -180,7 +189,8 @@ void embedding() { @EnabledIfEnvironmentVariable(named = "AZURE_OPENAI_TRANSCRIPTION_DEPLOYMENT_NAME", matches = ".+") void transcribe() { this.contextRunner - .withConfiguration(AutoConfigurations.of(AzureOpenAiAudioTranscriptionAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiAudioTranscriptionAutoConfiguration.class)) .run(context -> { AzureOpenAiAudioTranscriptionModel transcriptionModel = context .getBean(AzureOpenAiAudioTranscriptionModel.class); @@ -195,7 +205,9 @@ void transcribe() { void chatActivation() { // Disable the chat auto-configuration. - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .withPropertyValues("spring.ai.model.chat=none") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiChatProperties.class)).isEmpty(); @@ -203,14 +215,18 @@ void chatActivation() { }); // The chat auto-configuration is enabled by default. - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiChatModel.class)).isNotEmpty(); assertThat(context.getBeansOfType(AzureOpenAiChatProperties.class)).isNotEmpty(); }); // Explicitly enable the chat auto-configuration. - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .withPropertyValues("spring.ai.model.chat=azure-openai") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiChatModel.class)).isNotEmpty(); @@ -222,7 +238,9 @@ void chatActivation() { void embeddingActivation() { // Disable the embedding auto-configuration. - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiEmbeddingAutoConfiguration.class)) + this.contextRunner + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiEmbeddingAutoConfiguration.class)) .withPropertyValues("spring.ai.model.embedding=none") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiEmbeddingModel.class)).isEmpty(); @@ -230,14 +248,18 @@ void embeddingActivation() { }); // The embedding auto-configuration is enabled by default. - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiEmbeddingAutoConfiguration.class)) + this.contextRunner + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiEmbeddingAutoConfiguration.class)) .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiEmbeddingModel.class)).isNotEmpty(); assertThat(context.getBeansOfType(AzureOpenAiEmbeddingProperties.class)).isNotEmpty(); }); // Explicitly enable the embedding auto-configuration. - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiEmbeddingAutoConfiguration.class)) + this.contextRunner + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiEmbeddingAutoConfiguration.class)) .withPropertyValues("spring.ai.model.embedding=azure-openai") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiEmbeddingModel.class)).isNotEmpty(); @@ -250,7 +272,8 @@ void audioTranscriptionActivation() { // Disable the transcription auto-configuration. this.contextRunner - .withConfiguration(AutoConfigurations.of(AzureOpenAiAudioTranscriptionAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiAudioTranscriptionAutoConfiguration.class)) .withPropertyValues("spring.ai.model.audio.transcription=none") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiAudioTranscriptionModel.class)).isEmpty(); @@ -259,12 +282,14 @@ void audioTranscriptionActivation() { // The transcription auto-configuration is enabled by default. this.contextRunner - .withConfiguration(AutoConfigurations.of(AzureOpenAiAudioTranscriptionAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiAudioTranscriptionAutoConfiguration.class)) .run(context -> assertThat(context.getBeansOfType(AzureOpenAiAudioTranscriptionModel.class)).isNotEmpty()); // Explicitly enable the transcription auto-configuration. this.contextRunner - .withConfiguration(AutoConfigurations.of(AzureOpenAiAudioTranscriptionAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiAudioTranscriptionAutoConfiguration.class)) .withPropertyValues("spring.ai.model.audio.transcription=azure-openai") .run(context -> assertThat(context.getBeansOfType(AzureOpenAiAudioTranscriptionModel.class)).isNotEmpty()); } @@ -273,7 +298,9 @@ void audioTranscriptionActivation() { void openAIClientBuilderCustomizer() { AtomicBoolean firstCustomizationApplied = new AtomicBoolean(false); AtomicBoolean secondCustomizationApplied = new AtomicBoolean(false); - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .withBean("first", AzureOpenAIClientBuilderCustomizer.class, () -> clientBuilder -> firstCustomizationApplied.set(true)) .withBean("second", AzureOpenAIClientBuilderCustomizer.class, diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiAutoConfigurationIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiAutoConfigurationIT.java index 19f2d78c9a7..3761b748b7e 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiAutoConfigurationIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiAutoConfigurationIT.java @@ -39,6 +39,7 @@ import org.springframework.ai.azure.openai.AzureOpenAiAudioTranscriptionModel; import org.springframework.ai.azure.openai.AzureOpenAiChatModel; import org.springframework.ai.azure.openai.AzureOpenAiEmbeddingModel; +import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.UserMessage; @@ -96,7 +97,9 @@ class AzureOpenAiAutoConfigurationIT { @Test void chatCompletion() { - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .run(context -> { AzureOpenAiChatModel chatModel = context.getBean(AzureOpenAiChatModel.class); ChatResponse response = chatModel.call(new Prompt(List.of(this.userMessage, this.systemMessage))); @@ -106,7 +109,9 @@ void chatCompletion() { @Test void httpRequestContainsUserAgentAndCustomHeaders() { - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .withPropertyValues("spring.ai.azure.openai.custom-headers.foo=bar", "spring.ai.azure.openai.custom-headers.fizz=buzz") .run(context -> { @@ -133,7 +138,9 @@ void httpRequestContainsUserAgentAndCustomHeaders() { @Test void chatCompletionStreaming() { - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .run(context -> { AzureOpenAiChatModel chatModel = context.getBean(AzureOpenAiChatModel.class); @@ -157,7 +164,9 @@ void chatCompletionStreaming() { @Test void embedding() { - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiEmbeddingAutoConfiguration.class)) + this.contextRunner + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiEmbeddingAutoConfiguration.class)) .run(context -> { AzureOpenAiEmbeddingModel embeddingModel = context.getBean(AzureOpenAiEmbeddingModel.class); @@ -178,7 +187,8 @@ void embedding() { @EnabledIfEnvironmentVariable(named = "AZURE_OPENAI_TRANSCRIPTION_DEPLOYMENT_NAME", matches = ".+") void transcribe() { this.contextRunner - .withConfiguration(AutoConfigurations.of(AzureOpenAiAudioTranscriptionAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiAudioTranscriptionAutoConfiguration.class)) .run(context -> { AzureOpenAiAudioTranscriptionModel transcriptionModel = context .getBean(AzureOpenAiAudioTranscriptionModel.class); @@ -193,7 +203,9 @@ void transcribe() { void chatActivation() { // Disable the chat auto-configuration. - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .withPropertyValues("spring.ai.model.chat=none") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiChatProperties.class)).isEmpty(); @@ -201,14 +213,18 @@ void chatActivation() { }); // The chat auto-configuration is enabled by default. - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiChatModel.class)).isNotEmpty(); assertThat(context.getBeansOfType(AzureOpenAiChatProperties.class)).isNotEmpty(); }); // Explicitly enable the chat auto-configuration. - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .withPropertyValues("spring.ai.model.chat=azure-openai") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiChatModel.class)).isNotEmpty(); @@ -220,7 +236,9 @@ void chatActivation() { void embeddingActivation() { // Disable the embedding auto-configuration. - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiEmbeddingAutoConfiguration.class)) + this.contextRunner + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiEmbeddingAutoConfiguration.class)) .withPropertyValues("spring.ai.model.embedding=none") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiEmbeddingModel.class)).isEmpty(); @@ -228,14 +246,18 @@ void embeddingActivation() { }); // The embedding auto-configuration is enabled by default. - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiEmbeddingAutoConfiguration.class)) + this.contextRunner + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiEmbeddingAutoConfiguration.class)) .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiEmbeddingModel.class)).isNotEmpty(); assertThat(context.getBeansOfType(AzureOpenAiEmbeddingProperties.class)).isNotEmpty(); }); // Explicitly enable the embedding auto-configuration. - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiEmbeddingAutoConfiguration.class)) + this.contextRunner + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiEmbeddingAutoConfiguration.class)) .withPropertyValues("spring.ai.model.embedding=azure-openai") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiEmbeddingModel.class)).isNotEmpty(); @@ -248,7 +270,8 @@ void audioTranscriptionActivation() { // Disable the transcription auto-configuration. this.contextRunner - .withConfiguration(AutoConfigurations.of(AzureOpenAiAudioTranscriptionAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiAudioTranscriptionAutoConfiguration.class)) .withPropertyValues("spring.ai.model.audio.transcription=none") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiAudioTranscriptionModel.class)).isEmpty(); @@ -257,12 +280,14 @@ void audioTranscriptionActivation() { // The transcription auto-configuration is enabled by default. this.contextRunner - .withConfiguration(AutoConfigurations.of(AzureOpenAiAudioTranscriptionAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiAudioTranscriptionAutoConfiguration.class)) .run(context -> assertThat(context.getBeansOfType(AzureOpenAiAudioTranscriptionModel.class)).isNotEmpty()); // Explicitly enable the transcription auto-configuration. this.contextRunner - .withConfiguration(AutoConfigurations.of(AzureOpenAiAudioTranscriptionAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiAudioTranscriptionAutoConfiguration.class)) .withPropertyValues("spring.ai.model.audio.transcription=azure-openai") .run(context -> assertThat(context.getBeansOfType(AzureOpenAiAudioTranscriptionModel.class)).isNotEmpty()); } @@ -271,7 +296,9 @@ void audioTranscriptionActivation() { void openAIClientBuilderCustomizer() { AtomicBoolean firstCustomizationApplied = new AtomicBoolean(false); AtomicBoolean secondCustomizationApplied = new AtomicBoolean(false); - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .withBean("first", AzureOpenAIClientBuilderCustomizer.class, () -> clientBuilder -> firstCustomizationApplied.set(true)) .withBean("second", AzureOpenAIClientBuilderCustomizer.class, diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiAutoConfigurationPropertyTests.java b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiAutoConfigurationPropertyTests.java index f166bf28481..f327b4df3cd 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiAutoConfigurationPropertyTests.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiAutoConfigurationPropertyTests.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test; +import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -36,7 +37,8 @@ public void embeddingPropertiesTest() { .withPropertyValues("spring.ai.azure.openai.api-key=TEST_API_KEY", "spring.ai.azure.openai.endpoint=TEST_ENDPOINT", "spring.ai.azure.openai.embedding.options.deployment-name=MODEL_XYZ") - .withConfiguration(AutoConfigurations.of(AzureOpenAiEmbeddingAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiEmbeddingAutoConfiguration.class)) .run(context -> { var chatProperties = context.getBean(AzureOpenAiEmbeddingProperties.class); var connectionProperties = context.getBean(AzureOpenAiConnectionProperties.class); @@ -68,8 +70,8 @@ public void chatPropertiesTest() { "spring.ai.azure.openai.chat.options.user=userXYZ" ) // @formatter:on - .withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class, - AzureOpenAiEmbeddingAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiChatAutoConfiguration.class, AzureOpenAiEmbeddingAutoConfiguration.class)) .run(context -> { var chatProperties = context.getBean(AzureOpenAiChatProperties.class); var connectionProperties = context.getBean(AzureOpenAiConnectionProperties.class); diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiDirectOpenAiAutoConfigurationIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiDirectOpenAiAutoConfigurationIT.java index a3dff4617c0..5449cb6605e 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiDirectOpenAiAutoConfigurationIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiDirectOpenAiAutoConfigurationIT.java @@ -26,6 +26,7 @@ import org.springframework.ai.azure.openai.AzureOpenAiChatModel; import org.springframework.ai.azure.openai.AzureOpenAiEmbeddingModel; +import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.UserMessage; @@ -60,8 +61,8 @@ public class AzureOpenAiDirectOpenAiAutoConfigurationIT { "spring.ai.azure.openai.embedding.options.deployment-name=" + EMBEDDING_MODEL_NAME // @formatter:on ) - .withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class, - AzureOpenAiEmbeddingAutoConfiguration.class)); + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiChatAutoConfiguration.class, AzureOpenAiEmbeddingAutoConfiguration.class)); private final Message systemMessage = new SystemPromptTemplate(""" You are a helpful AI assistant. Your name is {name}. diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiModelConfigurationTests.java b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiModelConfigurationTests.java index b19483ae8f3..7f22a0162cd 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiModelConfigurationTests.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/AzureOpenAiModelConfigurationTests.java @@ -24,6 +24,7 @@ import org.springframework.ai.azure.openai.AzureOpenAiChatModel; import org.springframework.ai.azure.openai.AzureOpenAiEmbeddingModel; import org.springframework.ai.azure.openai.AzureOpenAiImageModel; +import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -43,7 +44,9 @@ public class AzureOpenAiModelConfigurationTests { @Test void chatModelActivation() { - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiChatModel.class)).isNotEmpty(); assertThat(context.getBeansOfType(OpenAIClientBuilder.class)).isNotEmpty(); @@ -52,7 +55,9 @@ void chatModelActivation() { assertThat(context.getBeansOfType(AzureOpenAiAudioTranscriptionModel.class)).isEmpty(); }); - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .withPropertyValues("spring.ai.model.chat=none") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiChatProperties.class)).isEmpty(); @@ -60,14 +65,18 @@ void chatModelActivation() { assertThat(context.getBeansOfType(OpenAIClientBuilder.class)).isEmpty(); }); - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .withPropertyValues("spring.ai.model.chat=azure-openai") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiChatProperties.class)).isNotEmpty(); assertThat(context.getBeansOfType(AzureOpenAiChatModel.class)).isNotEmpty(); }); - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .withPropertyValues("spring.ai.model.chat=azure-openai", "spring.ai.model.embedding=none", "spring.ai.model.image=none", "spring.ai.model.audio.speech=none", "spring.ai.model.audio.transcription=none", "spring.ai.model.moderation=none") @@ -82,7 +91,9 @@ void chatModelActivation() { @Test void embeddingModelActivation() { - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiEmbeddingAutoConfiguration.class)) + this.contextRunner + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiEmbeddingAutoConfiguration.class)) .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiChatModel.class)).isEmpty(); assertThat(context.getBeansOfType(AzureOpenAiEmbeddingModel.class)).isNotEmpty(); @@ -91,7 +102,9 @@ void embeddingModelActivation() { assertThat(context.getBeansOfType(OpenAIClientBuilder.class)).isNotEmpty(); }); - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiEmbeddingAutoConfiguration.class)) + this.contextRunner + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiEmbeddingAutoConfiguration.class)) .withPropertyValues("spring.ai.model.embedding=none") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiEmbeddingProperties.class)).isEmpty(); @@ -99,7 +112,9 @@ void embeddingModelActivation() { assertThat(context.getBeansOfType(OpenAIClientBuilder.class)).isEmpty(); }); - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiEmbeddingAutoConfiguration.class)) + this.contextRunner + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiEmbeddingAutoConfiguration.class)) .withPropertyValues("spring.ai.model.embedding=azure-openai") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiEmbeddingProperties.class)).isNotEmpty(); @@ -107,7 +122,9 @@ void embeddingModelActivation() { assertThat(context.getBeansOfType(OpenAIClientBuilder.class)).isNotEmpty(); }); - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiEmbeddingAutoConfiguration.class)) + this.contextRunner + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiEmbeddingAutoConfiguration.class)) .withPropertyValues("spring.ai.model.chat=none", "spring.ai.model.embedding=azure-openai", "spring.ai.model.image=none", "spring.ai.model.audio.speech=none", "spring.ai.model.audio.transcription=none", "spring.ai.model.moderation=none") @@ -122,7 +139,9 @@ void embeddingModelActivation() { @Test void imageModelActivation() { - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiImageAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiImageAutoConfiguration.class)) .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiChatModel.class)).isEmpty(); assertThat(context.getBeansOfType(AzureOpenAiEmbeddingModel.class)).isEmpty(); @@ -131,7 +150,9 @@ void imageModelActivation() { assertThat(context.getBeansOfType(AzureOpenAiAudioTranscriptionModel.class)).isEmpty(); }); - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiImageAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiImageAutoConfiguration.class)) .withPropertyValues("spring.ai.model.image=none") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiImageOptionsProperties.class)).isEmpty(); @@ -139,7 +160,9 @@ void imageModelActivation() { assertThat(context.getBeansOfType(OpenAIClientBuilder.class)).isEmpty(); }); - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiImageAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiImageAutoConfiguration.class)) .withPropertyValues("spring.ai.model.image=azure-openai") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiImageOptionsProperties.class)).isNotEmpty(); @@ -147,7 +170,9 @@ void imageModelActivation() { assertThat(context.getBeansOfType(OpenAIClientBuilder.class)).isNotEmpty(); }); - this.contextRunner.withConfiguration(AutoConfigurations.of(AzureOpenAiImageAutoConfiguration.class)) + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiImageAutoConfiguration.class)) .withPropertyValues("spring.ai.model.chat=none", "spring.ai.model.embedding=none", "spring.ai.model.image=azure-openai", "spring.ai.model.audio.speech=none", "spring.ai.model.audio.transcription=none", "spring.ai.model.moderation=none") @@ -163,7 +188,8 @@ void imageModelActivation() { @Test void audioTranscriptionModelActivation() { this.contextRunner - .withConfiguration(AutoConfigurations.of(AzureOpenAiAudioTranscriptionAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiAudioTranscriptionAutoConfiguration.class)) .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiChatModel.class)).isEmpty(); assertThat(context.getBeansOfType(AzureOpenAiEmbeddingModel.class)).isEmpty(); @@ -173,7 +199,8 @@ void audioTranscriptionModelActivation() { }); this.contextRunner - .withConfiguration(AutoConfigurations.of(AzureOpenAiAudioTranscriptionAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiAudioTranscriptionAutoConfiguration.class)) .withPropertyValues("spring.ai.model.audio.transcription=none") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiAudioTranscriptionProperties.class)).isEmpty(); @@ -182,7 +209,8 @@ void audioTranscriptionModelActivation() { }); this.contextRunner - .withConfiguration(AutoConfigurations.of(AzureOpenAiAudioTranscriptionAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiAudioTranscriptionAutoConfiguration.class)) .withPropertyValues("spring.ai.model.audio.transcription=azure-openai") .run(context -> { assertThat(context.getBeansOfType(AzureOpenAiAudioTranscriptionProperties.class)).isNotEmpty(); @@ -191,7 +219,8 @@ void audioTranscriptionModelActivation() { }); this.contextRunner - .withConfiguration(AutoConfigurations.of(AzureOpenAiAudioTranscriptionAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(ToolCallingAutoConfiguration.class, + AzureOpenAiAudioTranscriptionAutoConfiguration.class)) .withPropertyValues("spring.ai.model.chat=none", "spring.ai.model.embedding=none", "spring.ai.model.image=none", "spring.ai.model.audio.speech=none", "spring.ai.model.audio.transcription=azure-openai", "spring.ai.model.moderation=none") diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/tool/FunctionCallWithFunctionBeanIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/tool/FunctionCallWithFunctionBeanIT.java index bf125cf42a0..f153c2ede6c 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/tool/FunctionCallWithFunctionBeanIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/tool/FunctionCallWithFunctionBeanIT.java @@ -31,6 +31,7 @@ import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiChatAutoConfiguration; +import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; import org.springframework.ai.model.tool.ToolCallingChatOptions; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -51,7 +52,8 @@ class FunctionCallWithFunctionBeanIT { "spring.ai.azure.openai.api-key=" + System.getenv("AZURE_OPENAI_API_KEY"), "spring.ai.azure.openai.endpoint=" + System.getenv("AZURE_OPENAI_ENDPOINT")) // @formatter:on - .withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .withUserConfiguration(Config.class); @Test diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/tool/FunctionCallWithFunctionWrapperIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/tool/FunctionCallWithFunctionWrapperIT.java index 587360f4ae7..e7d63d042fd 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/tool/FunctionCallWithFunctionWrapperIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/tool/FunctionCallWithFunctionWrapperIT.java @@ -29,6 +29,7 @@ import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiChatAutoConfiguration; +import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; import org.springframework.ai.tool.ToolCallback; import org.springframework.ai.tool.function.FunctionToolCallback; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -49,7 +50,8 @@ public class FunctionCallWithFunctionWrapperIT { "spring.ai.azure.openai.api-key=" + System.getenv("AZURE_OPENAI_API_KEY"), "spring.ai.azure.openai.endpoint=" + System.getenv("AZURE_OPENAI_ENDPOINT")) // @formatter:on - .withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)) + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)) .withUserConfiguration(Config.class); @Test diff --git a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/tool/FunctionCallWithPromptFunctionIT.java b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/tool/FunctionCallWithPromptFunctionIT.java index c290662e9c7..25c4ad24038 100644 --- a/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/tool/FunctionCallWithPromptFunctionIT.java +++ b/auto-configurations/models/spring-ai-autoconfigure-model-azure-openai/src/test/java/org/springframework/ai/model/azure/openai/autoconfigure/tool/FunctionCallWithPromptFunctionIT.java @@ -29,6 +29,7 @@ import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiChatAutoConfiguration; +import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration; import org.springframework.ai.tool.function.FunctionToolCallback; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -46,7 +47,8 @@ public class FunctionCallWithPromptFunctionIT { "spring.ai.azure.openai.api-key=" + System.getenv("AZURE_OPENAI_API_KEY"), "spring.ai.azure.openai.endpoint=" + System.getenv("AZURE_OPENAI_ENDPOINT")) // @formatter:on - .withConfiguration(AutoConfigurations.of(AzureOpenAiChatAutoConfiguration.class)); + .withConfiguration( + AutoConfigurations.of(ToolCallingAutoConfiguration.class, AzureOpenAiChatAutoConfiguration.class)); @Test void functionCallTest() {