diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiChatModelFunctionCallingIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiChatModelFunctionCallingIT.java index 6834a74df..1c1087257 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiChatModelFunctionCallingIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiChatModelFunctionCallingIT.java @@ -25,6 +25,7 @@ import org.springframework.ai.chat.messages.UserMessage; 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.ToolContext; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.model.function.FunctionCallbackWrapper; import org.springframework.ai.openai.OpenAiChatModel; @@ -71,12 +72,12 @@ class OpenAiChatModelFunctionCallingIT { @Test void functionCallWithToolContextTest() { - var biFunction = new BiFunction, MockWeatherService.Response>() { + var biFunction = new BiFunction() { @Override - public Response apply(Request request, Map toolContext) { + public Response apply(Request request, ToolContext toolContext) { - assertThat(toolContext).containsEntry("sessionId", "123"); + assertThat(toolContext.getContext()).containsEntry("sessionId", "123"); double temperature = 0; if (request.location().contains("Paris")) { @@ -133,12 +134,12 @@ class OpenAiChatModelFunctionCallingIT { @Test void streamFunctionCallWithToolContextTest() { - var biFunction = new BiFunction, MockWeatherService.Response>() { + var biFunction = new BiFunction() { @Override - public Response apply(Request request, Map toolContext) { + public Response apply(Request request, ToolContext toolContext) { - assertThat(toolContext).containsEntry("sessionId", "123"); + assertThat(toolContext.getContext()).containsEntry("sessionId", "123"); double temperature = 0; if (request.location().contains("Paris")) { diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientMultipleFunctionCallsIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientMultipleFunctionCallsIT.java index a148de5ab..44ab8becf 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientMultipleFunctionCallsIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientMultipleFunctionCallsIT.java @@ -29,7 +29,7 @@ import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ai.chat.client.ChatClient; -import org.springframework.ai.model.function.FunctionCallback; +import org.springframework.ai.chat.model.ToolContext; import org.springframework.ai.openai.OpenAiTestConfiguration; import org.springframework.ai.openai.api.tool.MockWeatherService; import org.springframework.ai.openai.api.tool.MockWeatherService.Request; @@ -115,12 +115,12 @@ class OpenAiChatClientMultipleFunctionCallsIT extends AbstractIT { @Test void defaultFunctionCallTestWithToolContext() { - var biFunction = new BiFunction, MockWeatherService.Response>() { + var biFunction = new BiFunction() { @Override - public Response apply(Request request, Map toolContext) { + public Response apply(Request request, ToolContext toolContext) { - assertThat(toolContext).containsEntry("sessionId", "123"); + assertThat(toolContext.getContext()).containsEntry("sessionId", "123"); double temperature = 0; if (request.location().contains("Paris")) { @@ -155,12 +155,12 @@ class OpenAiChatClientMultipleFunctionCallsIT extends AbstractIT { @Test void functionCallTestWithToolContext() { - var biFunction = new BiFunction, MockWeatherService.Response>() { + var biFunction = new BiFunction() { @Override - public Response apply(Request request, Map toolContext) { + public Response apply(Request request, ToolContext toolContext) { - assertThat(toolContext).containsEntry("sessionId", "123"); + assertThat(toolContext.getContext()).containsEntry("sessionId", "123"); double temperature = 0; if (request.location().contains("Paris")) { diff --git a/spring-ai-core/src/main/java/org/springframework/ai/chat/client/ChatClient.java b/spring-ai-core/src/main/java/org/springframework/ai/chat/client/ChatClient.java index 6de79e792..6f8d2dad6 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/chat/client/ChatClient.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/chat/client/ChatClient.java @@ -26,6 +26,7 @@ import org.springframework.ai.chat.client.observation.ChatClientObservationConve import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.model.ChatResponse; +import org.springframework.ai.chat.model.ToolContext; import org.springframework.ai.chat.prompt.ChatOptions; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.converter.StructuredOutputConverter; @@ -202,7 +203,7 @@ public interface ChatClient { java.util.function.Function function); ChatClientRequestSpec function(String name, String description, - java.util.function.BiFunction, O> function); + java.util.function.BiFunction function); ChatClientRequestSpec functions(FunctionCallback... functionCallbacks); @@ -267,7 +268,7 @@ public interface ChatClient { Builder defaultFunction(String name, String description, java.util.function.Function function); Builder defaultFunction(String name, String description, - java.util.function.BiFunction, O> function); + java.util.function.BiFunction function); Builder defaultFunctions(String... functionNames); diff --git a/spring-ai-core/src/main/java/org/springframework/ai/chat/client/DefaultChatClient.java b/spring-ai-core/src/main/java/org/springframework/ai/chat/client/DefaultChatClient.java index 377055ad6..af8fc31c1 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/chat/client/DefaultChatClient.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/chat/client/DefaultChatClient.java @@ -46,6 +46,7 @@ import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.model.StreamingChatModel; +import org.springframework.ai.chat.model.ToolContext; import org.springframework.ai.chat.prompt.ChatOptions; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.converter.BeanOutputConverter; @@ -693,7 +694,7 @@ public class DefaultChatClient implements ChatClient { } public ChatClientRequestSpec function(String name, String description, - java.util.function.BiFunction, O> biFunction) { + java.util.function.BiFunction biFunction) { Assert.hasText(name, "the name must be non-null and non-empty"); Assert.hasText(description, "the description must be non-null and non-empty"); diff --git a/spring-ai-core/src/main/java/org/springframework/ai/chat/client/DefaultChatClientBuilder.java b/spring-ai-core/src/main/java/org/springframework/ai/chat/client/DefaultChatClientBuilder.java index f876d97e3..1053a5d02 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/chat/client/DefaultChatClientBuilder.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/chat/client/DefaultChatClientBuilder.java @@ -29,6 +29,7 @@ import org.springframework.ai.chat.client.DefaultChatClient.DefaultChatClientReq import org.springframework.ai.chat.client.advisor.api.Advisor; import org.springframework.ai.chat.client.observation.ChatClientObservationConvention; import org.springframework.ai.chat.model.ChatModel; +import org.springframework.ai.chat.model.ToolContext; import org.springframework.ai.chat.prompt.ChatOptions; import org.springframework.ai.model.function.FunctionCallback; import org.springframework.core.io.Resource; @@ -142,7 +143,7 @@ public class DefaultChatClientBuilder implements Builder { } public Builder defaultFunction(String name, String description, - java.util.function.BiFunction, O> biFunction) { + java.util.function.BiFunction biFunction) { this.defaultRequest.function(name, description, biFunction); return this; } diff --git a/spring-ai-core/src/main/java/org/springframework/ai/chat/client/advisor/api/AdvisedRequest.java b/spring-ai-core/src/main/java/org/springframework/ai/chat/client/advisor/api/AdvisedRequest.java index 2a8ea7aa2..032de8b63 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/chat/client/advisor/api/AdvisedRequest.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/chat/client/advisor/api/AdvisedRequest.java @@ -56,6 +56,7 @@ import org.springframework.util.StringUtils; * @param advisors the list of request response advisors * @param advisorParams the map of advisor parameters * @param adviseContext the map of advise context + * @param toolContext the tool context */ public record AdvisedRequest(ChatModel chatModel, String userText, String systemText, ChatOptions chatOptions, List media, List functionNames, List functionCallbacks, List messages, @@ -94,8 +95,6 @@ public record AdvisedRequest(ChatModel chatModel, String userText, String system public static class Builder { - public Map toolContext; - private ChatModel chatModel; private String userText = ""; @@ -122,6 +121,8 @@ public record AdvisedRequest(ChatModel chatModel, String userText, String system private Map adviseContext = Map.of(); + public Map toolContext = Map.of(); + public Builder withChatModel(ChatModel chatModel) { this.chatModel = chatModel; return this; diff --git a/spring-ai-core/src/main/java/org/springframework/ai/chat/model/AbstractToolCallSupport.java b/spring-ai-core/src/main/java/org/springframework/ai/chat/model/AbstractToolCallSupport.java index 4cdac2c11..e32b4da6d 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/chat/model/AbstractToolCallSupport.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/chat/model/AbstractToolCallSupport.java @@ -16,6 +16,7 @@ package org.springframework.ai.chat.model; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -137,11 +138,13 @@ public abstract class AbstractToolCallSupport { } AssistantMessage assistantMessage = toolCallGeneration.get().getOutput(); - Map toolContext = null; - if (prompt.getOptions() instanceof FunctionCallingOptions functionCallOptions) { - toolContext = functionCallOptions.getToolContext(); + Map toolContextMap = Map.of(); + if (prompt.getOptions() instanceof FunctionCallingOptions functionCallOptions + && !CollectionUtils.isEmpty(functionCallOptions.getToolContext())) { + toolContextMap = functionCallOptions.getToolContext(); } - ToolResponseMessage toolMessageResponse = this.executeFunctions(assistantMessage, toolContext); + ToolResponseMessage toolMessageResponse = this.executeFunctions(assistantMessage, + new ToolContext(toolContextMap)); return this.buildToolCallConversation(prompt.getInstructions(), assistantMessage, toolMessageResponse); } @@ -190,7 +193,7 @@ public abstract class AbstractToolCallSupport { return retrievedFunctionCallbacks; } - protected ToolResponseMessage executeFunctions(AssistantMessage assistantMessage, Map toolContext) { + protected ToolResponseMessage executeFunctions(AssistantMessage assistantMessage, ToolContext toolContext) { List toolResponses = new ArrayList<>(); diff --git a/spring-ai-core/src/main/java/org/springframework/ai/chat/model/ToolContext.java b/spring-ai-core/src/main/java/org/springframework/ai/chat/model/ToolContext.java new file mode 100644 index 000000000..2d49e1ebc --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/chat/model/ToolContext.java @@ -0,0 +1,59 @@ +/* +* Copyright 2024 - 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.chat.model; + +import java.util.Collections; +import java.util.Map; + +/** + * Represents the context for tool execution in a function calling scenario. + * + *

+ * This class encapsulates a map of contextual information that can be passed to tools + * (functions) when they are called. It provides an immutable view of the context to + * ensure thread-safety and prevent modification after creation. + *

+ * + *

+ * The context is typically populated from the {@code toolContext} field of + * {@code FunctionCallingOptions} and is used in the function execution process. + *

+ * + * @author Christian Tzolov + * @since 1.0.0 + */ +public class ToolContext { + + private final Map context; + + /** + * Constructs a new ToolContext with the given context map. + * @param context A map containing the tool context information. This map is wrapped + * in an unmodifiable view to prevent changes. + */ + public ToolContext(Map context) { + this.context = Collections.unmodifiableMap(context); + } + + /** + * Returns the immutable context map. + * @return An unmodifiable view of the context map. + */ + public Map getContext() { + return this.context; + } + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/function/AbstractFunctionCallback.java b/spring-ai-core/src/main/java/org/springframework/ai/model/function/AbstractFunctionCallback.java index b118f8565..cd5d43be1 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/model/function/AbstractFunctionCallback.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/model/function/AbstractFunctionCallback.java @@ -15,16 +15,16 @@ */ package org.springframework.ai.model.function; -import java.util.Map; import java.util.Objects; import java.util.function.BiFunction; import java.util.function.Function; +import org.springframework.ai.chat.model.ToolContext; +import org.springframework.util.Assert; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.util.Assert; - /** * Abstract implementation of the {@link FunctionCallback} for interacting with the * Model's function calling protocol and a {@link Function} wrapping the interaction with @@ -40,7 +40,7 @@ import org.springframework.util.Assert; * @param the 3rd party service output type. * @author Christian Tzolov */ -abstract class AbstractFunctionCallback implements BiFunction, O>, FunctionCallback { +abstract class AbstractFunctionCallback implements BiFunction, FunctionCallback { private final String name; @@ -101,7 +101,7 @@ abstract class AbstractFunctionCallback implements BiFunction toolContext) { + public String call(String functionInput, ToolContext toolContext) { I request = fromJson(functionInput, inputType); O response = this.apply(request, toolContext); return this.responseConverter.apply(response); diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/function/FunctionCallback.java b/spring-ai-core/src/main/java/org/springframework/ai/model/function/FunctionCallback.java index a679c3d24..4cde55b38 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/model/function/FunctionCallback.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/model/function/FunctionCallback.java @@ -17,6 +17,8 @@ package org.springframework.ai.model.function; import java.util.Map; +import org.springframework.ai.chat.model.ToolContext; + /** * Represents a model function call handler. Implementations are registered with the * Models and called on prompts that trigger the function call. @@ -60,13 +62,13 @@ public interface FunctionCallback { * @param functionInput JSON string with the function arguments to be passed to the * function. The arguments are defined as JSON schema usually registered with the the * model. Arguments are provided by the AI model. - * @param functionContext Map with the function context. The context is used to pass + * @param tooContext Map with the function context. The context is used to pass * additional user provided state in addition to the arguments provided by the AI * model. * @return String containing the function call response. */ - default String call(String functionInput, Map functionContext) { - if (functionContext != null) { + default String call(String functionInput, ToolContext tooContext) { + if (tooContext != null) { throw new UnsupportedOperationException("Function context is not supported!"); } return call(functionInput); diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/function/FunctionCallbackContext.java b/spring-ai-core/src/main/java/org/springframework/ai/model/function/FunctionCallbackContext.java index 2814de8e0..ef06b80a0 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/model/function/FunctionCallbackContext.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/model/function/FunctionCallbackContext.java @@ -16,12 +16,10 @@ package org.springframework.ai.model.function; import java.lang.reflect.Type; -import java.util.Map; import java.util.function.BiFunction; import java.util.function.Function; -import com.fasterxml.jackson.annotation.JsonClassDescription; - +import org.springframework.ai.chat.model.ToolContext; import org.springframework.beans.BeansException; import org.springframework.cloud.function.context.catalog.FunctionTypeUtils; import org.springframework.cloud.function.context.config.FunctionContextUtils; @@ -33,6 +31,8 @@ import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; +import com.fasterxml.jackson.annotation.JsonClassDescription; + /** * A Spring {@link ApplicationContextAware} implementation that provides a way to retrieve * a {@link Function} from the Spring context and wrap it into a {@link FunctionCallback}. @@ -127,7 +127,7 @@ public class FunctionCallbackContext implements ApplicationContextAware { .build(); } else if (bean instanceof BiFunction biFunction) { - return FunctionCallbackWrapper.builder((BiFunction, ?>) biFunction) + return FunctionCallbackWrapper.builder((BiFunction) biFunction) .withName(functionName) .withSchemaType(this.schemaType) .withDescription(functionDescription) diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/function/FunctionCallbackWrapper.java b/spring-ai-core/src/main/java/org/springframework/ai/model/function/FunctionCallbackWrapper.java index 1a9a0a966..752439940 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/model/function/FunctionCallbackWrapper.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/model/function/FunctionCallbackWrapper.java @@ -15,10 +15,10 @@ */ package org.springframework.ai.model.function; -import java.util.Map; import java.util.function.BiFunction; import java.util.function.Function; +import org.springframework.ai.chat.model.ToolContext; import org.springframework.ai.model.ModelOptionsUtils; import org.springframework.ai.model.function.FunctionCallbackContext.SchemaType; import org.springframework.util.Assert; @@ -37,22 +37,21 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; */ public class FunctionCallbackWrapper extends AbstractFunctionCallback { - private final BiFunction, O> biFunction; + private final BiFunction biFunction; private FunctionCallbackWrapper(String name, String description, String inputTypeSchema, Class inputType, - Function responseConverter, ObjectMapper objectMapper, - BiFunction, O> function) { + Function responseConverter, ObjectMapper objectMapper, BiFunction function) { super(name, description, inputTypeSchema, inputType, responseConverter, objectMapper); Assert.notNull(function, "Function must not be null"); this.biFunction = function; } @Override - public O apply(I input, Map context) { + public O apply(I input, ToolContext context) { return this.biFunction.apply(input, context); } - public static Builder builder(BiFunction, O> biFunction) { + public static Builder builder(BiFunction biFunction) { return new Builder<>(biFunction); } @@ -68,13 +67,13 @@ public class FunctionCallbackWrapper extends AbstractFunctionCallback inputType; - private final BiFunction, O> biFunction; + private final BiFunction biFunction; private final Function function; private SchemaType schemaType = SchemaType.JSON_SCHEMA; - public Builder(BiFunction, O> biFunction) { + public Builder(BiFunction biFunction) { Assert.notNull(biFunction, "Function must not be null"); this.biFunction = biFunction; this.function = null; @@ -159,7 +158,7 @@ public class FunctionCallbackWrapper extends AbstractFunctionCallback, O> finalBiFunction = (this.biFunction != null) ? this.biFunction + BiFunction finalBiFunction = (this.biFunction != null) ? this.biFunction : (request, context) -> this.function.apply(request); return new FunctionCallbackWrapper<>(this.name, this.description, this.inputTypeSchema, this.inputType, @@ -167,9 +166,9 @@ public class FunctionCallbackWrapper extends AbstractFunctionCallback Class resolveInputType(BiFunction, O> biFunction) { + private static Class resolveInputType(BiFunction biFunction) { return (Class) TypeResolverHelper - .getBiFunctionInputClass((Class, O>>) biFunction.getClass()); + .getBiFunctionInputClass((Class>) biFunction.getClass()); } @SuppressWarnings("unchecked") diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/function/FunctionCallingOptions.java b/spring-ai-core/src/main/java/org/springframework/ai/model/function/FunctionCallingOptions.java index f5796cff9..f61897993 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/model/function/FunctionCallingOptions.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/model/function/FunctionCallingOptions.java @@ -77,6 +77,6 @@ public interface FunctionCallingOptions extends ChatOptions { Map getToolContext(); - void setToolContext(Map functionContext); + void setToolContext(Map tooContext); } \ No newline at end of file diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/openai-chat-functions.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/openai-chat-functions.adoc index d21e6fccc..851f019bc 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/openai-chat-functions.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/openai-chat-functions.adoc @@ -224,16 +224,18 @@ The https://github.com/spring-projects/spring-ai/blob/main/spring-ai-spring-boot Spring AI now supports passing additional contextual information to function callbacks through a tool context. This feature allows you to provide extra data that can be used within the function execution, enhancing the flexibility and power of function calling. +The context information that is passed in as the second argument of a `java.util.BiFunction`. The `ToolContext` contains as an immutable `Map` allowing you to access key-value pairs. + ==== How to Use Tool Context You can set the tool context when building your chat options and use a BiFunction for your callback: [source,java] ---- -BiFunction, MockWeatherService.Response> weatherFunction = +BiFunction weatherFunction = (request, toolContext) -> { - String sessionId = (String) toolContext.get("sessionId"); - String userId = (String) toolContext.get("userId"); + String sessionId = (String) toolContext.getContext().get("sessionId"); + String userId = (String) toolContext.getContext().get("userId"); // Use sessionId and userId in your function logic double temperature = 0; diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/azure/tool/FunctionCallWithFunctionBeanIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/azure/tool/FunctionCallWithFunctionBeanIT.java index 669580969..a7e04c351 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/azure/tool/FunctionCallWithFunctionBeanIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/azure/tool/FunctionCallWithFunctionBeanIT.java @@ -15,22 +15,22 @@ */ package org.springframework.ai.autoconfigure.azure.tool; +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.ai.autoconfigure.azure.tool.DeploymentNameUtil.getDeploymentName; + import java.util.List; -import java.util.Map; -import java.util.function.BiFunction; import java.util.function.Function; 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.autoconfigure.azure.openai.AzureOpenAiAutoConfiguration; import org.springframework.ai.azure.openai.AzureOpenAiChatModel; import org.springframework.ai.azure.openai.AzureOpenAiChatOptions; +import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -39,9 +39,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Description; -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.ai.autoconfigure.azure.tool.DeploymentNameUtil.getDeploymentName; - @EnabledIfEnvironmentVariable(named = "AZURE_OPENAI_API_KEY", matches = ".+") @EnabledIfEnvironmentVariable(named = "AZURE_OPENAI_ENDPOINT", matches = ".+") class FunctionCallWithFunctionBeanIT { @@ -112,18 +109,6 @@ class FunctionCallWithFunctionBeanIT { return new MockWeatherService(); } - @Bean - @Description("Get the weather in location") - public Function, MockWeatherService.Response>> weatherFunctionWithContext() { - return request -> context -> new MockWeatherService().apply(request); - } - - @Bean - @Description("Get the weather in location") - public BiFunction, MockWeatherService.Response> weatherFunctionWithContext2() { - return (request, context) -> new MockWeatherService().apply(request); - } - // Relies on the Request's JsonClassDescription annotation to provide the // function description. @Bean diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/FunctionCallbackWithPlainFunctionBeanIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/FunctionCallbackWithPlainFunctionBeanIT.java index dc542dd65..6664797eb 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/FunctionCallbackWithPlainFunctionBeanIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/FunctionCallbackWithPlainFunctionBeanIT.java @@ -32,6 +32,7 @@ import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.model.Generation; +import org.springframework.ai.chat.model.ToolContext; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.model.function.FunctionCallingOptions; import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions; @@ -187,7 +188,7 @@ class FunctionCallbackWithPlainFunctionBeanIT { @Bean @Description("Get the weather in location") - public BiFunction, MockWeatherService.Response> weatherFunctionWithContext() { + public BiFunction weatherFunctionWithContext() { return (request, context) -> { return new MockWeatherService().apply(request); };