diff --git a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/AnthropicChatModelIT.java b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/AnthropicChatModelIT.java index dd63502ee0a..0777acf5b8f 100644 --- a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/AnthropicChatModelIT.java +++ b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/AnthropicChatModelIT.java @@ -276,9 +276,9 @@ void functionCallTest() { var promptOptions = AnthropicChatOptions.builder() .withModel(AnthropicApi.ChatModel.CLAUDE_3_OPUS.getName()) .withFunctionCallbacks(List.of(FunctionCallback.builder() + .function("getCurrentWeather", new MockWeatherService()) .description( "Get the weather in location. Return temperature in 36°F or 36°C format. Use multi-turn if needed.") - .function("getCurrentWeather", new MockWeatherService()) .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -304,9 +304,9 @@ void streamFunctionCallTest() { var promptOptions = AnthropicChatOptions.builder() .withModel(AnthropicApi.ChatModel.CLAUDE_3_5_SONNET.getName()) .withFunctionCallbacks(List.of(FunctionCallback.builder() + .function("getCurrentWeather", new MockWeatherService()) .description( "Get the weather in location. Return temperature in 36°F or 36°C format. Use multi-turn if needed.") - .function("getCurrentWeather", new MockWeatherService()) .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/client/AnthropicChatClientIT.java b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/client/AnthropicChatClientIT.java index 7a5ff447535..f6d1a889100 100644 --- a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/client/AnthropicChatClientIT.java +++ b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/client/AnthropicChatClientIT.java @@ -250,8 +250,8 @@ void defaultFunctionCallTest() { // @formatter:off String response = ChatClient.builder(this.chatModel) .defaultFunctions(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()) .defaultUser(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")) @@ -273,8 +273,8 @@ void streamFunctionCallTest() { Flux response = ChatClient.create(this.chatModel).prompt() .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") .functions(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()) .stream() diff --git a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/client/AnthropicChatClientMethodInvokingFunctionCallbackIT.java b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/client/AnthropicChatClientMethodInvokingFunctionCallbackIT.java index fbea3c91a9d..2fcee182dd2 100644 --- a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/client/AnthropicChatClientMethodInvokingFunctionCallbackIT.java +++ b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/client/AnthropicChatClientMethodInvokingFunctionCallbackIT.java @@ -80,8 +80,8 @@ void methodGetWeatherStatic() { String response = ChatClient.create(this.chatModel).prompt() .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") .functions(FunctionCallback.builder() - .description("Get the weather in location") .method("getWeatherStatic", String.class, Unit.class) + .description("Get the weather in location") .targetClass(TestFunctionClass.class) .build()) .call() @@ -102,8 +102,8 @@ void methodTurnLightNoResponse() { String response = ChatClient.create(this.chatModel).prompt() .user("Turn light on in the living room.") .functions(FunctionCallback.builder() - .description("Turn light on in the living room.") .method("turnLight", String.class, boolean.class) + .description("Turn light on in the living room.") .targetObject(targetObject) .build()) .call() @@ -125,8 +125,8 @@ void methodGetWeatherNonStatic() { String response = ChatClient.create(this.chatModel).prompt() .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") .functions(FunctionCallback.builder() - .description("Get the weather in location") .method("getWeatherNonStatic", String.class, Unit.class) + .description("Get the weather in location") .targetObject(targetObject) .build()) .call() @@ -147,8 +147,8 @@ void methodGetWeatherToolContext() { String response = ChatClient.create(this.chatModel).prompt() .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") .functions(FunctionCallback.builder() - .description("Get the weather in location") .method("getWeatherWithContext", String.class, Unit.class, ToolContext.class) + .description("Get the weather in location") .targetObject(targetObject) .build()) .toolContext(Map.of("tool", "value")) @@ -174,8 +174,8 @@ void methodGetWeatherToolContextButNonContextMethod() { assertThatThrownBy(() -> ChatClient.create(this.chatModel).prompt() .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") .functions(FunctionCallback.builder() - .description("Get the weather in location") .method("getWeatherNonStatic", String.class, Unit.class) + .description("Get the weather in location") .targetObject(targetObject) .build()) .toolContext(Map.of("tool", "value")) @@ -195,8 +195,8 @@ void methodNoParameters() { String response = ChatClient.create(this.chatModel).prompt() .user("Turn light on in the living room.") .functions(FunctionCallback.builder() - .description("Can turn lights on in the Living Room") .method("turnLivingRoomLightOn") + .description("Can turn lights on in the Living Room") .targetObject(targetObject) .build()) .call() diff --git a/models/spring-ai-azure-openai/src/test/java/org/springframework/ai/azure/openai/function/AzureOpenAiChatModelFunctionCallIT.java b/models/spring-ai-azure-openai/src/test/java/org/springframework/ai/azure/openai/function/AzureOpenAiChatModelFunctionCallIT.java index 33e9ef27a08..8adb93fede8 100644 --- a/models/spring-ai-azure-openai/src/test/java/org/springframework/ai/azure/openai/function/AzureOpenAiChatModelFunctionCallIT.java +++ b/models/spring-ai-azure-openai/src/test/java/org/springframework/ai/azure/openai/function/AzureOpenAiChatModelFunctionCallIT.java @@ -70,8 +70,8 @@ void functionCallTest() { var promptOptions = AzureOpenAiChatOptions.builder() .withDeploymentName(this.selectedModel) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the current weather in a given location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the current weather in a given location") .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -94,8 +94,8 @@ void functionCallSequentialTest() { var promptOptions = AzureOpenAiChatOptions.builder() .withDeploymentName(this.selectedModel) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the current weather in a given location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the current weather in a given location") .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -116,8 +116,8 @@ void streamFunctionCallTest() { var promptOptions = AzureOpenAiChatOptions.builder() .withDeploymentName(this.selectedModel) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the current weather in a given location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the current weather in a given location") .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -153,8 +153,8 @@ void functionCallSequentialAndStreamTest() { var promptOptions = AzureOpenAiChatOptions.builder() .withDeploymentName(this.selectedModel) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the current weather in a given location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the current weather in a given location") .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockConverseChatClientIT.java b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockConverseChatClientIT.java index f49cc87ebf0..5317e31a712 100644 --- a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockConverseChatClientIT.java +++ b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockConverseChatClientIT.java @@ -214,10 +214,10 @@ void functionCallTest() { String response = ChatClient.create(this.chatModel) .prompt("What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.") .functions(FunctionCallback.builder() - .description("Get the weather in location") - .function("getCurrentWeather", new MockWeatherService()) - .inputType(MockWeatherService.Request.class) - .build()) + .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") + .inputType(MockWeatherService.Request.class) + .build()) .call() .content(); // @formatter:on @@ -234,10 +234,10 @@ void functionCallWithUsageMetadataTest() { ChatResponse response = ChatClient.create(this.chatModel) .prompt("What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.") .functions(FunctionCallback.builder() - .description("Get the weather in location") - .function("getCurrentWeather", new MockWeatherService()) - .inputType(MockWeatherService.Request.class) - .build()) + .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") + .inputType(MockWeatherService.Request.class) + .build()) .call() .chatResponse(); // @formatter:on @@ -269,10 +269,10 @@ void functionCallWithAdvisorTest() { String response = ChatClient.create(this.chatModel) .prompt("What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.") .functions(FunctionCallback.builder() - .description("Get the weather in location") - .function("getCurrentWeather", new MockWeatherService()) - .inputType(MockWeatherService.Request.class) - .build()) + .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") + .inputType(MockWeatherService.Request.class) + .build()) .advisors(new SimpleLoggerAdvisor()) .call() .content(); @@ -289,8 +289,8 @@ void defaultFunctionCallTest() { // @formatter:off String response = ChatClient.builder(this.chatModel) .defaultFunctions(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()) .defaultUser(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.")) @@ -312,8 +312,8 @@ void streamFunctionCallTest() { Flux response = ChatClient.create(this.chatModel).prompt() .user("What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.") .functions(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()) .stream() @@ -354,8 +354,8 @@ void singularStreamFunctionCallTest() { Flux response = ChatClient.create(this.chatModel).prompt() .user("What's the weather like in Paris? Return the temperature in Celsius.") .functions(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()) .stream() diff --git a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockConverseUsageAggregationTests.java b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockConverseUsageAggregationTests.java index 3925b7f6220..097982d3e74 100644 --- a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockConverseUsageAggregationTests.java +++ b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockConverseUsageAggregationTests.java @@ -139,8 +139,8 @@ public void callWithToolUse() { .willReturn(converseResponseFinal); FunctionCallback functionCallback = FunctionCallback.builder() - .description("Gets the weather in location") .function("getCurrentWeather", (Request request) -> "15.0°C") + .description("Gets the weather in location") .inputType(Request.class) .build(); diff --git a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModelIT.java b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModelIT.java index a46c06d79a6..27bb6d936ed 100644 --- a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModelIT.java +++ b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModelIT.java @@ -255,9 +255,9 @@ void functionCallTest() { var promptOptions = FunctionCallingOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() + .function("getCurrentWeather", new MockWeatherService()) .description( "Get the weather in location. Return temperature in 36°F or 36°C format. Use multi-turn if needed.") - .function("getCurrentWeather", new MockWeatherService()) .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -283,9 +283,9 @@ void streamFunctionCallTest() { var promptOptions = FunctionCallingOptions.builder() .withModel("anthropic.claude-3-5-sonnet-20240620-v1:0") .withFunctionCallbacks(List.of(FunctionCallback.builder() + .function("getCurrentWeather", new MockWeatherService()) .description( "Get the weather in location. Return temperature in 36°F or 36°C format. Use multi-turn if needed.") - .function("getCurrentWeather", new MockWeatherService()) .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/experiments/BedrockConverseChatModelMain2.java b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/experiments/BedrockConverseChatModelMain2.java index 47e69dbd3f1..bcd6dfffab5 100644 --- a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/experiments/BedrockConverseChatModelMain2.java +++ b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/experiments/BedrockConverseChatModelMain2.java @@ -53,8 +53,8 @@ public static void main(String[] args) { PortableFunctionCallingOptions.builder() .withModel(modelId) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build()); diff --git a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/experiments/BedrockConverseChatModelMain3.java b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/experiments/BedrockConverseChatModelMain3.java index 078c3b2a645..00e9b61c2ad 100644 --- a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/experiments/BedrockConverseChatModelMain3.java +++ b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/experiments/BedrockConverseChatModelMain3.java @@ -51,8 +51,8 @@ public static void main(String[] args) { PortableFunctionCallingOptions.builder() .withModel(modelId) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build()); diff --git a/models/spring-ai-minimax/src/test/java/org/springframework/ai/minimax/ChatCompletionRequestTests.java b/models/spring-ai-minimax/src/test/java/org/springframework/ai/minimax/ChatCompletionRequestTests.java index c89174872df..07d460fd52c 100644 --- a/models/spring-ai-minimax/src/test/java/org/springframework/ai/minimax/ChatCompletionRequestTests.java +++ b/models/spring-ai-minimax/src/test/java/org/springframework/ai/minimax/ChatCompletionRequestTests.java @@ -68,8 +68,8 @@ public void promptOptionsTools() { MiniMaxChatOptions.builder() .withModel("PROMPT_MODEL") .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function(TOOL_FUNCTION_NAME, new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build()), @@ -95,8 +95,8 @@ public void defaultOptionsTools() { MiniMaxChatOptions.builder() .withModel("DEFAULT_MODEL") .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function(TOOL_FUNCTION_NAME, new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build()); @@ -127,8 +127,8 @@ public void defaultOptionsTools() { request = client.createRequest(new Prompt("Test message content", MiniMaxChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Overridden function description") .function(TOOL_FUNCTION_NAME, new MockWeatherService()) + .description("Overridden function description") .inputType(MockWeatherService.Request.class) .build())) .build()), diff --git a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatClientIT.java b/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatClientIT.java index c32f555ca94..45e0b3dce63 100644 --- a/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatClientIT.java +++ b/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatClientIT.java @@ -226,10 +226,10 @@ void functionCallTest() { .options(MistralAiChatOptions.builder().withModel(MistralAiApi.ChatModel.SMALL).withToolChoice(ToolChoice.AUTO).build()) .user(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris? Use parallel function calling if required. Response should be in Celsius.")) .functions(FunctionCallback.builder() - .description("Get the weather in location") - .function("getCurrentWeather", new MockWeatherService()) - .inputType(MockWeatherService.Request.class) - .build()) + .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") + .inputType(MockWeatherService.Request.class) + .build()) .call() .content(); // @formatter:on @@ -248,8 +248,8 @@ void defaultFunctionCallTest() { String response = ChatClient.builder(this.chatModel) .defaultOptions(MistralAiChatOptions.builder().withModel(MistralAiApi.ChatModel.SMALL).build()) .defaultFunctions(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()) .defaultUser(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris? Use parallel function calling if required. Response should be in Celsius.")) @@ -272,8 +272,8 @@ void streamFunctionCallTest() { .options(MistralAiChatOptions.builder().withModel(MistralAiApi.ChatModel.SMALL).build()) .user("What's the weather like in San Francisco, Tokyo, and Paris? Use parallel function calling if required. Response should be in Celsius.") .functions(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()) .stream() 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 a87592e1178..10bbea59fec 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 @@ -194,8 +194,8 @@ void functionCallTest() { var promptOptions = MistralAiChatOptions.builder() .withModel(MistralAiApi.ChatModel.SMALL.getValue()) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -217,8 +217,8 @@ void streamFunctionCallTest() { var promptOptions = MistralAiChatOptions.builder() .withModel(MistralAiApi.ChatModel.SMALL.getValue()) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/models/spring-ai-moonshot/src/test/java/org/springframework/ai/moonshot/chat/MoonshotChatModelFunctionCallingIT.java b/models/spring-ai-moonshot/src/test/java/org/springframework/ai/moonshot/chat/MoonshotChatModelFunctionCallingIT.java index a1964e87ba8..400420671c4 100644 --- a/models/spring-ai-moonshot/src/test/java/org/springframework/ai/moonshot/chat/MoonshotChatModelFunctionCallingIT.java +++ b/models/spring-ai-moonshot/src/test/java/org/springframework/ai/moonshot/chat/MoonshotChatModelFunctionCallingIT.java @@ -64,8 +64,8 @@ void functionCallTest() { var promptOptions = MoonshotChatOptions.builder() .withModel(MoonshotApi.ChatModel.MOONSHOT_V1_8K.getValue()) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -87,8 +87,8 @@ void streamFunctionCallTest() { var promptOptions = MoonshotChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .build())) .build(); diff --git a/models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaChatModelFunctionCallingIT.java b/models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaChatModelFunctionCallingIT.java index 3bad44cb100..5b819c64768 100644 --- a/models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaChatModelFunctionCallingIT.java +++ b/models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaChatModelFunctionCallingIT.java @@ -64,9 +64,9 @@ void functionCallTest() { var promptOptions = OllamaOptions.builder() .withModel(MODEL) .withFunctionCallbacks(List.of(FunctionCallback.builder() + .function("getCurrentWeather", new MockWeatherService()) .description( "Find the weather conditions, forecasts, and temperatures for a location, like a city or state.") - .function("getCurrentWeather", new MockWeatherService()) .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -89,9 +89,9 @@ void streamFunctionCallTest() { var promptOptions = OllamaOptions.builder() .withModel(MODEL) .withFunctionCallbacks(List.of(FunctionCallback.builder() + .function("getCurrentWeather", new MockWeatherService()) .description( "Find the weather conditions, forecasts, and temperatures for a location, like a city or state.") - .function("getCurrentWeather", new MockWeatherService()) .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/ChatCompletionRequestTests.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/ChatCompletionRequestTests.java index 2956d4fb804..45538fc48cf 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/ChatCompletionRequestTests.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/ChatCompletionRequestTests.java @@ -68,8 +68,8 @@ public void promptOptionsTools() { OpenAiChatOptions.builder() .withModel("PROMPT_MODEL") .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function(TOOL_FUNCTION_NAME, new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build()), @@ -95,8 +95,8 @@ public void defaultOptionsTools() { OpenAiChatOptions.builder() .withModel("DEFAULT_MODEL") .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function(TOOL_FUNCTION_NAME, new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build()); @@ -127,8 +127,8 @@ public void defaultOptionsTools() { request = client.createRequest(new Prompt("Test message content", OpenAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Overridden function description") .function(TOOL_FUNCTION_NAME, new MockWeatherService()) + .description("Overridden function description") .inputType(MockWeatherService.Request.class) .build())) .build()), 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 97d98b22b91..7d6f09d9f1b 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 @@ -85,8 +85,8 @@ void functionCallTest() { functionCallTest(OpenAiChatOptions.builder() .withModel(OpenAiApi.ChatModel.GPT_4_O.getValue()) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build()); @@ -121,8 +121,8 @@ else if (request.location().contains("San Francisco")) { functionCallTest(OpenAiChatOptions.builder() .withModel(OpenAiApi.ChatModel.GPT_4_O.getValue()) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", biFunction) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .withToolContext(Map.of("sessionId", "123")) @@ -147,8 +147,8 @@ void streamFunctionCallTest() { streamFunctionCallTest(OpenAiChatOptions.builder() .withFunctionCallbacks(List.of((FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) // .responseConverter(response -> "" + response.temp() + response.unit()) .build()))) @@ -183,8 +183,8 @@ else if (request.location().contains("San Francisco")) { OpenAiChatOptions promptOptions = OpenAiChatOptions.builder() .withFunctionCallbacks(List.of((FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", biFunction) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()))) .withToolContext(Map.of("sessionId", "123")) 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 a8e5c54696d..34eba93cc16 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 @@ -329,8 +329,8 @@ void functionCallTest() { var promptOptions = OpenAiChatOptions.builder() .withModel(OpenAiApi.ChatModel.GPT_4_O.getValue()) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -354,8 +354,8 @@ void streamFunctionCallTest() { var promptOptions = OpenAiChatOptions.builder() // .withModel(OpenAiApi.ChatModel.GPT_4_TURBO_PREVIEW.getValue()) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientIT.java index 7278bfe844e..57b2ce7d4f5 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientIT.java @@ -246,8 +246,8 @@ void beanStreamOutputConverterRecords() { void functionCallTest() { FunctionCallback functionCallback = FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build(); @@ -270,8 +270,8 @@ void defaultFunctionCallTest() { // @formatter:off String response = ChatClient.builder(this.chatModel) .defaultFunctions(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()) .defaultUser(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris?")) @@ -291,8 +291,8 @@ void streamFunctionCallTest() { Flux response = ChatClient.create(this.chatModel).prompt() .user("What's the weather like in San Francisco, Tokyo, and Paris?") .functions(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()) .stream() diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientMethodInvokingFunctionCallbackIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientMethodInvokingFunctionCallbackIT.java index 6606b50bfaf..5d5e6918890 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientMethodInvokingFunctionCallbackIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientMethodInvokingFunctionCallbackIT.java @@ -61,8 +61,8 @@ void methodGetWeatherStatic() { String response = ChatClient.create(this.chatModel).prompt() .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") .functions(FunctionCallback.builder() - .description("Get the weather in location") .method("getWeatherStatic", String.class, Unit.class) + .description("Get the weather in location") .targetClass(TestFunctionClass.class) .build()) .call() @@ -83,8 +83,8 @@ void methodTurnLightNoResponse() { String response = ChatClient.create(this.chatModel).prompt() .user("Turn light on in the living room.") .functions(FunctionCallback.builder() - .description("Can turn lights on or off by room name") .method("turnLight", String.class, boolean.class) + .description("Can turn lights on or off by room name") .targetObject(targetObject) .build()) .call() @@ -106,8 +106,8 @@ void methodGetWeatherNonStatic() { String response = ChatClient.create(this.chatModel).prompt() .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") .functions(FunctionCallback.builder() - .description("Get the weather in location") .method("getWeatherNonStatic", String.class, Unit.class) + .description("Get the weather in location") .targetObject(targetObject) .build()) .call() @@ -128,8 +128,8 @@ void methodGetWeatherToolContext() { String response = ChatClient.create(this.chatModel).prompt() .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") .functions(FunctionCallback.builder() - .description("Get the weather in location") .method("getWeatherWithContext", String.class, Unit.class, ToolContext.class) + .description("Get the weather in location") .targetObject(targetObject) .build()) .toolContext(Map.of("tool", "value")) @@ -152,8 +152,8 @@ void methodGetWeatherToolContextButNonContextMethod() { assertThatThrownBy(() -> ChatClient.create(this.chatModel).prompt() .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") .functions(FunctionCallback.builder() - .description("Get the weather in location") .method("getWeatherNonStatic", String.class, Unit.class) + .description("Get the weather in location") .targetObject(targetObject) .build()) .toolContext(Map.of("tool", "value")) @@ -173,8 +173,8 @@ void methodNoParameters() { String response = ChatClient.create(this.chatModel).prompt() .user("Turn light on in the living room.") .functions(FunctionCallback.builder() - .description("Can turn lights on in the Living Room") .method("turnLivingRoomLightOn") + .description("Can turn lights on in the Living Room") .targetObject(targetObject) .build()) .call() 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 9ffa7777ddf..11a7699b79a 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 @@ -85,8 +85,8 @@ void turnFunctionsOnAndOffTest() { response = chatClientBuilder.build().prompt() .user(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris?")) .functions(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()) .call() @@ -116,8 +116,8 @@ void defaultFunctionCallTest() { // @formatter:off String response = ChatClient.builder(this.chatModel) .defaultFunctions(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()) .defaultUser(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris?")) @@ -159,8 +159,8 @@ else if (request.location().contains("San Francisco")) { // @formatter:off String response = ChatClient.builder(this.chatModel) .defaultFunctions(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", biFunction) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()) .defaultUser(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris?")) @@ -203,8 +203,8 @@ else if (request.location().contains("San Francisco")) { // @formatter:off String response = ChatClient.builder(this.chatModel) .defaultFunctions(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", biFunction) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()) .defaultUser(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris?")) @@ -226,8 +226,8 @@ void streamFunctionCallTest() { Flux response = ChatClient.create(this.chatModel).prompt() .user("What's the weather like in San Francisco, Tokyo, and Paris?") .functions(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()) .stream() diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/GroqWithOpenAiChatModelIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/GroqWithOpenAiChatModelIT.java index c3ee4f550bf..856aa847bdf 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/GroqWithOpenAiChatModelIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/GroqWithOpenAiChatModelIT.java @@ -250,8 +250,8 @@ void functionCallTest() { var promptOptions = OpenAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -273,8 +273,8 @@ void streamFunctionCallTest() { var promptOptions = OpenAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/MistralWithOpenAiChatModelIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/MistralWithOpenAiChatModelIT.java index 0c0ee7ad665..75fb99d6e69 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/MistralWithOpenAiChatModelIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/MistralWithOpenAiChatModelIT.java @@ -252,8 +252,8 @@ void functionCallTest(String modelName) { var promptOptions = OpenAiChatOptions.builder() .withModel(modelName) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -277,8 +277,8 @@ void streamFunctionCallTest(String modelName) { var promptOptions = OpenAiChatOptions.builder() .withModel(modelName) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/NvidiaWithOpenAiChatModelIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/NvidiaWithOpenAiChatModelIT.java index 010896df4ee..a8e8d7b41c3 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/NvidiaWithOpenAiChatModelIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/NvidiaWithOpenAiChatModelIT.java @@ -247,8 +247,8 @@ void functionCallTest() { var promptOptions = OpenAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -270,8 +270,8 @@ void streamFunctionCallTest() { var promptOptions = OpenAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/OllamaWithOpenAiChatModelIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/OllamaWithOpenAiChatModelIT.java index e766074f697..77983755451 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/OllamaWithOpenAiChatModelIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/proxy/OllamaWithOpenAiChatModelIT.java @@ -269,8 +269,8 @@ void functionCallTest(String modelName) { var promptOptions = OpenAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -293,8 +293,8 @@ void streamFunctionCallTest() { var promptOptions = OpenAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .build())) .build(); 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 eb821caa32e..faf3bb79d78 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 @@ -118,8 +118,8 @@ public void promptOptionsTools() { VertexAiGeminiChatOptions.builder() .withModel("PROMPT_MODEL") .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function(TOOL_FUNCTION_NAME, new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build()), @@ -146,8 +146,8 @@ public void defaultOptionsTools() { VertexAiGeminiChatOptions.builder() .withModel("DEFAULT_MODEL") .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function(TOOL_FUNCTION_NAME, new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build()); @@ -179,8 +179,8 @@ public void defaultOptionsTools() { request = client.createGeminiRequest(new Prompt("Test message content", VertexAiGeminiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Overridden function description") .function(TOOL_FUNCTION_NAME, new MockWeatherService()) + .description("Overridden function description") .inputType(MockWeatherService.Request.class) .build())) .build()), diff --git a/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/function/VertexAiGeminiChatModelFunctionCallingIT.java b/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/function/VertexAiGeminiChatModelFunctionCallingIT.java index 638e7e7d877..a9eea815d61 100644 --- a/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/function/VertexAiGeminiChatModelFunctionCallingIT.java +++ b/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/function/VertexAiGeminiChatModelFunctionCallingIT.java @@ -84,9 +84,9 @@ public void functionCallExplicitOpenApiSchema() { var promptOptions = VertexAiGeminiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() + .function("get_current_weather", new MockWeatherService()) .description("Get the current weather in a given location") .inputTypeSchema(openApiSchema) - .function("get_current_weather", new MockWeatherService()) .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -109,16 +109,16 @@ public void functionCallTestInferredOpenApiSchema() { .withModel(VertexAiGeminiChatModel.ChatModel.GEMINI_1_5_FLASH) .withFunctionCallbacks(List.of( FunctionCallback.builder() + .function("get_current_weather", new MockWeatherService()) .schemaType(SchemaType.OPEN_API_SCHEMA) .description("Get the current weather in a given location.") - .function("get_current_weather", new MockWeatherService()) .inputType(MockWeatherService.Request.class) .build(), FunctionCallback.builder() + .function("get_payment_status", new PaymentStatus()) .schemaType(SchemaType.OPEN_API_SCHEMA) .description( "Retrieves the payment status for transaction. For example what is the payment status for transaction 700?") - .function("get_payment_status", new PaymentStatus()) .inputType(PaymentInfoRequest.class) .build())) .build(); @@ -150,16 +150,16 @@ public void functionCallTestInferredOpenApiSchema2() { .withModel(VertexAiGeminiChatModel.ChatModel.GEMINI_1_5_FLASH) .withFunctionCallbacks(List.of( FunctionCallback.builder() + .function("get_current_weather", new MockWeatherService()) .schemaType(SchemaType.OPEN_API_SCHEMA) .description("Get the current weather in a given location.") - .function("get_current_weather", new MockWeatherService()) .inputType(MockWeatherService.Request.class) .build(), FunctionCallback.builder() + .function("get_payment_status", new PaymentStatus()) .schemaType(SchemaType.OPEN_API_SCHEMA) .description( "Retrieves the payment status for transaction. For example what is the payment status for transaction 700?") - .function("get_payment_status", new PaymentStatus()) .inputType(PaymentInfoRequest.class) .build())) .build(); @@ -190,9 +190,9 @@ public void functionCallTestInferredOpenApiSchemaStream() { var promptOptions = VertexAiGeminiChatOptions.builder() .withModel(VertexAiGeminiChatModel.ChatModel.GEMINI_1_5_FLASH) .withFunctionCallbacks(List.of(FunctionCallback.builder() + .function("getCurrentWeather", new MockWeatherService()) .schemaType(SchemaType.OPEN_API_SCHEMA) .description("Get the current weather in a given location") - .function("getCurrentWeather", new MockWeatherService()) .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/ChatCompletionRequestTests.java b/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/ChatCompletionRequestTests.java index c8a21d8603c..56b090edc89 100644 --- a/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/ChatCompletionRequestTests.java +++ b/models/spring-ai-zhipuai/src/test/java/org/springframework/ai/zhipuai/ChatCompletionRequestTests.java @@ -68,8 +68,8 @@ public void promptOptionsTools() { ZhiPuAiChatOptions.builder() .withModel("PROMPT_MODEL") .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function(TOOL_FUNCTION_NAME, new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build()), @@ -95,8 +95,8 @@ public void defaultOptionsTools() { ZhiPuAiChatOptions.builder() .withModel("DEFAULT_MODEL") .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function(TOOL_FUNCTION_NAME, new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build()); @@ -127,8 +127,8 @@ public void defaultOptionsTools() { request = client.createRequest(new Prompt("Test message content", ZhiPuAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Overridden function description") .function(TOOL_FUNCTION_NAME, new MockWeatherService()) + .description("Overridden function description") .inputType(MockWeatherService.Request.class) .build())) .build()), 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 17e273a1e51..b5f035e3182 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 @@ -231,8 +231,8 @@ void functionCallTest() { var promptOptions = ZhiPuAiChatOptions.builder() .withModel(ZhiPuAiApi.ChatModel.GLM_4.getValue()) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -257,8 +257,8 @@ void streamFunctionCallTest() { var promptOptions = ZhiPuAiChatOptions.builder() .withModel(ZhiPuAiApi.ChatModel.GLM_4.getValue()) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); 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 4ab2f37d387..10b7d07c8d0 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 @@ -878,9 +878,9 @@ public ChatClientRequestSpec function(String name, String description, @N Assert.notNull(function, "function cannot be null"); var fcw = FunctionCallback.builder() + .function(name, function) .description(description) .responseConverter(Object::toString) - .function(name, function) .inputType(inputType) .build(); this.functionCallbacks.add(fcw); diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/function/DefaultCommonCallbackInvokingSpec.java b/spring-ai-core/src/main/java/org/springframework/ai/model/function/DefaultCommonCallbackInvokingSpec.java new file mode 100644 index 00000000000..697d8567540 --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/model/function/DefaultCommonCallbackInvokingSpec.java @@ -0,0 +1,115 @@ +package org.springframework.ai.model.function; + +import java.util.function.Function; + +import com.fasterxml.jackson.core.JsonProcessingException; +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.springframework.ai.model.function.FunctionCallback.CommonCallbackInvokingSpec; +import org.springframework.ai.model.function.FunctionCallback.SchemaType; +import org.springframework.ai.util.JacksonUtils; +import org.springframework.util.Assert; + +public class DefaultCommonCallbackInvokingSpec> + implements CommonCallbackInvokingSpec { + + /** + * The description of the function callback. Used to hint the LLM model about the + * tool's purpose and when to use it. + */ + protected String description; + + /** + * The schema type to use for the input type schema generation. The default is JSON + * Schema. Note: Vertex AI requires the input type schema to be in Open API schema + */ + protected SchemaType schemaType = SchemaType.JSON_SCHEMA; + + /** + * The function to convert the response object to a string. The default is to convert + * the response to a JSON string. + */ + protected Function responseConverter = response -> (response instanceof String) ? "" + response + : this.toJsonString(response); + + /** + * (Optional) Instead of generating the input type schema from the input type or + * method argument types, you can provide the schema directly. This will override the + * generated schema. + */ + protected String inputTypeSchema; + + protected ObjectMapper objectMapper = JsonMapper.builder() + .addModules(JacksonUtils.instantiateAvailableModules()) + .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .build(); + + private String toJsonString(Object object) { + try { + return this.objectMapper.writeValueAsString(object); + } + catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @Override + public B description(String description) { + Assert.hasText(description, "Description must not be empty"); + this.description = description; + return (B) this; + } + + @Override + public B schemaType(SchemaType schemaType) { + Assert.notNull(schemaType, "SchemaType must not be null"); + this.schemaType = schemaType; + return (B) this; + } + + @Override + public B responseConverter(Function responseConverter) { + Assert.notNull(responseConverter, "ResponseConverter must not be null"); + this.responseConverter = responseConverter; + return (B) this; + } + + @Override + public B inputTypeSchema(String inputTypeSchema) { + Assert.hasText(inputTypeSchema, "InputTypeSchema must not be empty"); + this.inputTypeSchema = inputTypeSchema; + return (B) this; + } + + @Override + public B objectMapper(ObjectMapper objectMapper) { + Assert.notNull(objectMapper, "ObjectMapper must not be null"); + this.objectMapper = objectMapper; + return (B) this; + } + + public String getDescription() { + return this.description; + } + + public SchemaType getSchemaType() { + return this.schemaType; + } + + public Function getResponseConverter() { + return this.responseConverter; + } + + public String getInputTypeSchema() { + return this.inputTypeSchema; + } + + public ObjectMapper getObjectMapper() { + return this.objectMapper; + } + +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/function/DefaultFunctionCallbackBuilder.java b/spring-ai-core/src/main/java/org/springframework/ai/model/function/DefaultFunctionCallbackBuilder.java index 1399758da6f..fe66bacd0e2 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/model/function/DefaultFunctionCallbackBuilder.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/model/function/DefaultFunctionCallbackBuilder.java @@ -23,21 +23,14 @@ import java.util.function.Function; import java.util.function.Supplier; -import com.fasterxml.jackson.core.JsonProcessingException; -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.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ai.chat.model.ToolContext; import org.springframework.ai.model.ModelOptionsUtils; -import org.springframework.ai.model.function.FunctionCallback.Builder; import org.springframework.ai.model.function.FunctionCallback.FunctionInvokingSpec; import org.springframework.ai.model.function.FunctionCallback.MethodInvokingSpec; import org.springframework.ai.model.function.FunctionCallback.SchemaType; -import org.springframework.ai.util.JacksonUtils; import org.springframework.ai.util.ParsingUtils; import org.springframework.core.ParameterizedTypeReference; import org.springframework.util.Assert; @@ -54,82 +47,6 @@ public class DefaultFunctionCallbackBuilder implements FunctionCallback.Builder private final static Logger logger = LoggerFactory.getLogger(DefaultFunctionCallbackBuilder.class); - /** - * The description of the function callback. Used to hint the LLM model about the - * tool's purpose and when to use it. - */ - private String description; - - /** - * The schema type to use for the input type schema generation. The default is JSON - * Schema. Note: Vertex AI requires the input type schema to be in Open API schema - */ - private SchemaType schemaType = SchemaType.JSON_SCHEMA; - - /** - * The function to convert the response object to a string. The default is to convert - * the response to a JSON string. - */ - private Function responseConverter = response -> (response instanceof String) ? "" + response - : this.toJsonString(response); - - /** - * (Optional) Instead of generating the input type schema from the input type or - * method argument types, you can provide the schema directly. This will override the - * generated schema. - */ - private String inputTypeSchema; - - private ObjectMapper objectMapper = JsonMapper.builder() - .addModules(JacksonUtils.instantiateAvailableModules()) - .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) - .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) - .build(); - - private String toJsonString(Object object) { - try { - return this.objectMapper.writeValueAsString(object); - } - catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - } - - @Override - public Builder description(String description) { - Assert.hasText(description, "Description must not be empty"); - this.description = description; - return this; - } - - @Override - public Builder schemaType(SchemaType schemaType) { - Assert.notNull(schemaType, "SchemaType must not be null"); - this.schemaType = schemaType; - return this; - } - - @Override - public Builder responseConverter(Function responseConverter) { - Assert.notNull(responseConverter, "ResponseConverter must not be null"); - this.responseConverter = responseConverter; - return this; - } - - @Override - public Builder inputTypeSchema(String inputTypeSchema) { - Assert.hasText(inputTypeSchema, "InputTypeSchema must not be empty"); - this.inputTypeSchema = inputTypeSchema; - return this; - } - - @Override - public Builder objectMapper(ObjectMapper objectMapper) { - Assert.notNull(objectMapper, "ObjectMapper must not be null"); - this.objectMapper = objectMapper; - return this; - } - @Override public FunctionInvokingSpec function(String name, Function function) { return new DefaultFunctionInvokingSpec<>(name, function); @@ -170,7 +87,8 @@ private String generateDescription(String fromName) { return generatedDescription; } - final class DefaultFunctionInvokingSpec implements FunctionInvokingSpec { + final class DefaultFunctionInvokingSpec extends DefaultCommonCallbackInvokingSpec> + implements FunctionInvokingSpec { private final String name; @@ -213,33 +131,35 @@ public FunctionInvokingSpec inputType(ParameterizedTypeReference inputT @Override public FunctionCallback build() { - Assert.notNull(objectMapper, "ObjectMapper must not be null"); + Assert.notNull(this.getObjectMapper(), "ObjectMapper must not be null"); Assert.hasText(this.name, "Name must not be empty"); - Assert.notNull(responseConverter, "ResponseConverter must not be null"); + Assert.notNull(this.getResponseConverter(), "ResponseConverter must not be null"); Assert.notNull(this.inputType, "InputType must not be null"); - if (inputTypeSchema == null) { + if (this.getInputTypeSchema() == null) { boolean upperCaseTypeValues = schemaType == SchemaType.OPEN_API_SCHEMA; - inputTypeSchema = ModelOptionsUtils.getJsonSchema(this.inputType, upperCaseTypeValues); + this.inputTypeSchema = ModelOptionsUtils.getJsonSchema(this.inputType, upperCaseTypeValues); } BiFunction finalBiFunction = (this.biFunction != null) ? this.biFunction : (request, context) -> this.function.apply(request); - return new FunctionInvokingFunctionCallback(this.name, this.getDescription(), inputTypeSchema, - this.inputType, (Function) responseConverter, objectMapper, finalBiFunction); + return new FunctionInvokingFunctionCallback(this.name, this.getDescriptionExt(), this.getInputTypeSchema(), + this.inputType, (Function) this.getResponseConverter(), this.getObjectMapper(), + finalBiFunction); } - private String getDescription() { - if (StringUtils.hasText(description)) { - return description; + private String getDescriptionExt() { + if (StringUtils.hasText(this.getDescription())) { + return this.getDescription(); } return generateDescription(this.name); } } - final class DefaultMethodInvokingSpec implements FunctionCallback.MethodInvokingSpec { + final class DefaultMethodInvokingSpec extends DefaultCommonCallbackInvokingSpec + implements FunctionCallback.MethodInvokingSpec { private String name; @@ -285,13 +205,13 @@ public FunctionCallback build() { var method = ReflectionUtils.findMethod(this.targetClass, this.methodName, this.argumentTypes); Assert.notNull(method, "Method: '" + this.methodName + "' with arguments:" + Arrays.toString(this.argumentTypes) + " not found!"); - return new MethodInvokingFunctionCallback(this.targetObject, method, this.getDescription(), objectMapper, - this.name, responseConverter); + return new MethodInvokingFunctionCallback(this.targetObject, method, this.getDescriptionExt(), + this.getObjectMapper(), this.name, this.getResponseConverter()); } - private String getDescription() { - if (StringUtils.hasText(description)) { - return description; + private String getDescriptionExt() { + if (StringUtils.hasText(this.getDescription())) { + return this.getDescription(); } return generateDescription(StringUtils.hasText(this.name) ? this.name : this.methodName); diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/function/DefaultFunctionCallbackResolver.java b/spring-ai-core/src/main/java/org/springframework/ai/model/function/DefaultFunctionCallbackResolver.java index 6f3af304ca5..9e9e0fd1a60 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/model/function/DefaultFunctionCallbackResolver.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/model/function/DefaultFunctionCallbackResolver.java @@ -117,25 +117,25 @@ private FunctionCallback buildFunctionCallback(String beanName, ResolvableType f if (KotlinDetector.isKotlinPresent()) { if (KotlinDelegate.isKotlinFunction(functionType.toClass())) { return FunctionCallback.builder() + .function(beanName, KotlinDelegate.wrapKotlinFunction(bean)) .schemaType(this.schemaType) .description(functionDescription) - .function(beanName, KotlinDelegate.wrapKotlinFunction(bean)) .inputType(ParameterizedTypeReference.forType(functionInputType.getType())) .build(); } if (KotlinDelegate.isKotlinBiFunction(functionType.toClass())) { return FunctionCallback.builder() + .function(beanName, KotlinDelegate.wrapKotlinBiFunction(bean)) .description(functionDescription) .schemaType(this.schemaType) - .function(beanName, KotlinDelegate.wrapKotlinBiFunction(bean)) .inputType(ParameterizedTypeReference.forType(functionInputType.getType())) .build(); } if (KotlinDelegate.isKotlinSupplier(functionType.toClass())) { return FunctionCallback.builder() + .function(beanName, KotlinDelegate.wrapKotlinSupplier(bean)) .description(functionDescription) .schemaType(this.schemaType) - .function(beanName, KotlinDelegate.wrapKotlinSupplier(bean)) .inputType(ParameterizedTypeReference.forType(functionInputType.getType())) .build(); } @@ -143,33 +143,33 @@ private FunctionCallback buildFunctionCallback(String beanName, ResolvableType f if (bean instanceof Function function) { return FunctionCallback.builder() + .function(beanName, function) .schemaType(this.schemaType) .description(functionDescription) - .function(beanName, function) .inputType(ParameterizedTypeReference.forType(functionInputType.getType())) .build(); } if (bean instanceof BiFunction) { return FunctionCallback.builder() + .function(beanName, (BiFunction) bean) .description(functionDescription) .schemaType(this.schemaType) - .function(beanName, (BiFunction) bean) .inputType(ParameterizedTypeReference.forType(functionInputType.getType())) .build(); } if (bean instanceof Supplier supplier) { return FunctionCallback.builder() + .function(beanName, supplier) .description(functionDescription) .schemaType(this.schemaType) - .function(beanName, supplier) .inputType(ParameterizedTypeReference.forType(functionInputType.getType())) .build(); } if (bean instanceof Consumer consumer) { return FunctionCallback.builder() + .function(beanName, consumer) .description(functionDescription) .schemaType(this.schemaType) - .function(beanName, consumer) .inputType(ParameterizedTypeReference.forType(functionInputType.getType())) .build(); } 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 8a30ad37dfe..70c0a8cae5c 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 @@ -119,60 +119,64 @@ enum SchemaType { interface Builder { /** - * Function description. This description is used by the model do decide if the - * function should be called or not. + * Builds a {@link Function} invoking {@link FunctionCallback} instance. */ - Builder description(String description); + FunctionInvokingSpec function(String name, Function function); /** - * Specifies what {@link SchemaType} is used by the AI model to validate the - * function input arguments. Most models use JSON Schema, except Vertex AI that - * uses OpenAPI types. + * Builds a {@link BiFunction} invoking {@link FunctionCallback} instance. */ - Builder schemaType(SchemaType schemaType); + FunctionInvokingSpec function(String name, BiFunction biFunction); /** - * Function response converter. The default implementation converts the output - * into String before sending it to the Model. Provide a custom function - * responseConverter implementation to override this. + * Builds a {@link Supplier} invoking {@link FunctionCallback} instance. */ - Builder responseConverter(Function responseConverter); + FunctionInvokingSpec function(String name, Supplier supplier); /** - * You can provide the Input Type Schema directly. In this case it won't be - * generated from the inputType. + * Builds a {@link Consumer} invoking {@link FunctionCallback} instance. */ - Builder inputTypeSchema(String inputTypeSchema); + FunctionInvokingSpec function(String name, Consumer consumer); /** - * Custom object mapper for JSON operations. + * Builds a Method invoking {@link FunctionCallback} instance. */ - Builder objectMapper(ObjectMapper objectMapper); + MethodInvokingSpec method(String methodName, Class... argumentTypes); + + } + + interface CommonCallbackInvokingSpec> { /** - * Builds a {@link Function} invoking {@link FunctionCallback} instance. + * Function description. This description is used by the model do decide if the + * function should be called or not. */ - FunctionInvokingSpec function(String name, Function function); + B description(String description); /** - * Builds a {@link BiFunction} invoking {@link FunctionCallback} instance. + * Specifies what {@link SchemaType} is used by the AI model to validate the + * function input arguments. Most models use JSON Schema, except Vertex AI that + * uses OpenAPI types. */ - FunctionInvokingSpec function(String name, BiFunction biFunction); + B schemaType(SchemaType schemaType); /** - * Builds a {@link Supplier} invoking {@link FunctionCallback} instance. + * Function response converter. The default implementation converts the output + * into String before sending it to the Model. Provide a custom function + * responseConverter implementation to override this. */ - FunctionInvokingSpec function(String name, Supplier supplier); + B responseConverter(Function responseConverter); /** - * Builds a {@link Consumer} invoking {@link FunctionCallback} instance. + * You can provide the Input Type Schema directly. In this case it won't be + * generated from the inputType. */ - FunctionInvokingSpec function(String name, Consumer consumer); + B inputTypeSchema(String inputTypeSchema); /** - * Builds a Method invoking {@link FunctionCallback} instance. + * Custom object mapper for JSON operations. */ - MethodInvokingSpec method(String methodName, Class... argumentTypes); + B objectMapper(ObjectMapper objectMapper); } @@ -182,7 +186,7 @@ interface Builder { * @param Function input type. * @param Function output type. */ - interface FunctionInvokingSpec { + interface FunctionInvokingSpec extends CommonCallbackInvokingSpec> { /** * Function input type. The input type is used to validate the function input @@ -207,7 +211,7 @@ interface FunctionInvokingSpec { /** * Method invoking builder interface. */ - interface MethodInvokingSpec { + interface MethodInvokingSpec extends CommonCallbackInvokingSpec { /** * Optional function name. If not provided the method name is used as the diff --git a/spring-ai-core/src/test/java/org/springframework/ai/chat/ChatBuilderTests.java b/spring-ai-core/src/test/java/org/springframework/ai/chat/ChatBuilderTests.java index 4789c553762..de1a69af65e 100644 --- a/spring-ai-core/src/test/java/org/springframework/ai/chat/ChatBuilderTests.java +++ b/spring-ai-core/src/test/java/org/springframework/ai/chat/ChatBuilderTests.java @@ -80,8 +80,8 @@ void createFunctionCallingOptionTest() { String func = "func"; FunctionCallback cb = FunctionCallback.builder() - .description("cb") .function("cb", i -> i) + .description("cb") .inputType(Integer.class) .build(); diff --git a/spring-ai-core/src/test/java/org/springframework/ai/chat/client/ChatClientTest.java b/spring-ai-core/src/test/java/org/springframework/ai/chat/client/ChatClientTest.java index 2fa31cacff1..b596efd3bd1 100644 --- a/spring-ai-core/src/test/java/org/springframework/ai/chat/client/ChatClientTest.java +++ b/spring-ai-core/src/test/java/org/springframework/ai/chat/client/ChatClientTest.java @@ -219,8 +219,8 @@ void mutateDefaults() { .param("param2", "value2")) .defaultFunctions("fun1", "fun2") .defaultFunctions(FunctionCallback.builder() - .description("fun3description") .function("fun3", mockFunction) + .description("fun3description") .inputType(String.class) .build()) .defaultUser(u -> u.text("Default user text {uparam1}, {uparam2}") @@ -350,8 +350,8 @@ void mutatePrompt() { .param("param2", "value2")) .defaultFunctions("fun1", "fun2") .defaultFunctions(FunctionCallback.builder() - .description("fun3description") .function("fun3", mockFunction) + .description("fun3description") .inputType(String.class) .build()) .defaultUser(u -> u.text("Default user text {uparam1}, {uparam2}") diff --git a/spring-ai-core/src/test/java/org/springframework/ai/chat/client/DefaultChatClientTests.java b/spring-ai-core/src/test/java/org/springframework/ai/chat/client/DefaultChatClientTests.java index 58f49a11567..7cc9ff91bd0 100644 --- a/spring-ai-core/src/test/java/org/springframework/ai/chat/client/DefaultChatClientTests.java +++ b/spring-ai-core/src/test/java/org/springframework/ai/chat/client/DefaultChatClientTests.java @@ -1357,8 +1357,8 @@ void whenFunctionNameIsNullThenThrow() { ChatClient chatClient = new DefaultChatClientBuilder(mock(ChatModel.class)).build(); ChatClient.ChatClientRequestSpec spec = chatClient.prompt(); assertThatThrownBy(() -> spec.functions(FunctionCallback.builder() - .description("description") .function(null, input -> "hello") + .description("description") .inputType(String.class) .build())).isInstanceOf(IllegalArgumentException.class).hasMessage("Name must not be empty"); } @@ -1368,8 +1368,8 @@ void whenFunctionNameIsEmptyThenThrow() { ChatClient chatClient = new DefaultChatClientBuilder(mock(ChatModel.class)).build(); ChatClient.ChatClientRequestSpec spec = chatClient.prompt(); assertThatThrownBy(() -> spec.functions(FunctionCallback.builder() - .description("description") .function("", input -> "hello") + .description("description") .inputType(String.class) .build())).isInstanceOf(IllegalArgumentException.class).hasMessage("Name must not be empty"); } @@ -1379,8 +1379,8 @@ void whenFunctionDescriptionIsNullThenThrow() { ChatClient chatClient = new DefaultChatClientBuilder(mock(ChatModel.class)).build(); ChatClient.ChatClientRequestSpec spec = chatClient.prompt(); assertThatThrownBy(() -> spec.functions(FunctionCallback.builder() + .function("name", input -> "hello") .description(null) - .function("", input -> "hello") .inputType(String.class) .build())).isInstanceOf(IllegalArgumentException.class).hasMessage("Description must not be empty"); } diff --git a/spring-ai-core/src/test/java/org/springframework/ai/model/function/DefaultFunctionCallbackBuilderTests.java b/spring-ai-core/src/test/java/org/springframework/ai/model/function/DefaultFunctionCallbackBuilderTests.java index e5774a86d75..e7de187676a 100644 --- a/spring-ai-core/src/test/java/org/springframework/ai/model/function/DefaultFunctionCallbackBuilderTests.java +++ b/spring-ai-core/src/test/java/org/springframework/ai/model/function/DefaultFunctionCallbackBuilderTests.java @@ -35,51 +35,54 @@ */ class DefaultFunctionCallbackBuilderTests { - // Common - + // Function @Test - void whenDescriptionIsNullThenThrow() { - assertThatThrownBy(() -> FunctionCallback.builder().description(null)) + void whenFunctionDescriptionIsNullThenThrow() { + assertThatThrownBy( + () -> FunctionCallback.builder().function("functionName", input -> "output").description(null)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Description must not be empty"); } @Test - void whenDescriptionIsEmptyThenThrow() { - assertThatThrownBy(() -> FunctionCallback.builder().description("")) + void whenFunctionDescriptionIsEmptyThenThrow() { + assertThatThrownBy(() -> FunctionCallback.builder().function("functionName", input -> "output").description("")) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Description must not be empty"); } @Test - void whenInputTypeSchemaIsNullThenThrow() { - assertThatThrownBy(() -> FunctionCallback.builder().inputTypeSchema(null)) + void whenFunctionInputTypeSchemaIsNullThenThrow() { + assertThatThrownBy( + () -> FunctionCallback.builder().function("functionName", input -> "output").inputTypeSchema(null)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("InputTypeSchema must not be empty"); } @Test - void whenInputTypeSchemaIsEmptyThenThrow() { - assertThatThrownBy(() -> FunctionCallback.builder().inputTypeSchema("")) + void whenFunctionInputTypeSchemaIsEmptyThenThrow() { + assertThatThrownBy( + () -> FunctionCallback.builder().function("functionName", input -> "output").inputTypeSchema("")) .isInstanceOf(IllegalArgumentException.class) .hasMessage("InputTypeSchema must not be empty"); } @Test - void whenSchemaTypeIsNullThenThrow() { - assertThatThrownBy(() -> FunctionCallback.builder().schemaType(null)) + void whenFunctionSchemaTypeIsNullThenThrow() { + assertThatThrownBy( + () -> FunctionCallback.builder().function("functionName", input -> "output").schemaType(null)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("SchemaType must not be null"); } @Test - void whenResponseConverterIsNullThenThrow() { - assertThatThrownBy(() -> FunctionCallback.builder().responseConverter(null)) + void whenFunctionResponseConverterIsNullThenThrow() { + assertThatThrownBy( + () -> FunctionCallback.builder().function("functionName", input -> "output").responseConverter(null)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("ResponseConverter must not be null"); } - // Function @Test void whenFunctionNameIsNullThenThrow2() { assertThatThrownBy(() -> FunctionCallback.builder().function(null, (Function) null)) @@ -111,8 +114,8 @@ void whenFunctionWithNullInputTypeThenThrow() { @Test void whenFunctionWithInputTypeThenReturn() { FunctionCallback functionCallback = FunctionCallback.builder() - .description("description") .function("functionName", input -> "output") + .description("description") .inputType(String.class) .build(); assertThat(functionCallback).isNotNull(); @@ -179,6 +182,49 @@ void whenBiFunctionThenReturn() { } // Method + + @Test + void whenMethodDescriptionIsNullThenThrow() { + assertThatThrownBy(() -> FunctionCallback.builder().method("methodName").description(null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Description must not be empty"); + } + + @Test + void whenMethodDescriptionIsEmptyThenThrow() { + assertThatThrownBy(() -> FunctionCallback.builder().method("methodName").description("")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Description must not be empty"); + } + + @Test + void whenMethodInputTypeSchemaIsNullThenThrow() { + assertThatThrownBy(() -> FunctionCallback.builder().method("methodName").inputTypeSchema(null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("InputTypeSchema must not be empty"); + } + + @Test + void whenMethodInputTypeSchemaIsEmptyThenThrow() { + assertThatThrownBy(() -> FunctionCallback.builder().method("methodName").inputTypeSchema("")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("InputTypeSchema must not be empty"); + } + + @Test + void whenMethodSchemaTypeIsNullThenThrow() { + assertThatThrownBy(() -> FunctionCallback.builder().method("methodName").schemaType(null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("SchemaType must not be null"); + } + + @Test + void whenMethodResponseConverterIsNullThenThrow() { + assertThatThrownBy(() -> FunctionCallback.builder().method("methodName").responseConverter(null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("ResponseConverter must not be null"); + } + @Test void whenMethodNameIsNullThenThrow() { assertThatThrownBy(() -> FunctionCallback.builder().method(null)).isInstanceOf(IllegalArgumentException.class) diff --git a/spring-ai-core/src/test/java/org/springframework/ai/model/function/MethodInvokingFunctionCallbackTests.java b/spring-ai-core/src/test/java/org/springframework/ai/model/function/MethodInvokingFunctionCallbackTests.java index badc6b9b192..ec3e0c300c2 100644 --- a/spring-ai-core/src/test/java/org/springframework/ai/model/function/MethodInvokingFunctionCallbackTests.java +++ b/spring-ai-core/src/test/java/org/springframework/ai/model/function/MethodInvokingFunctionCallbackTests.java @@ -56,9 +56,9 @@ public void beforeEach() { public void staticMethod() throws NoSuchMethodException, SecurityException { var functionCallback = FunctionCallback.builder() + .method("myStaticMethod", String.class, Unit.class, int.class, MyRecord.class, List.class) .description("weather at location") .objectMapper(new ObjectMapper()) - .method("myStaticMethod", String.class, Unit.class, int.class, MyRecord.class, List.class) .targetClass(TestClassWithFunctionMethods.class) .build(); @@ -80,8 +80,8 @@ public void nonStaticMethod() throws NoSuchMethodException, SecurityException { var object = new TestClassWithFunctionMethods(); var functionCallback = FunctionCallback.builder() - .description("weather at location") .method("myNonStaticMethod", String.class, Unit.class, int.class, MyRecord.class, List.class) + .description("weather at location") .targetObject(object) .build(); @@ -101,9 +101,9 @@ public void nonStaticMethod() throws NoSuchMethodException, SecurityException { public void noArgsNoReturnMethod() throws NoSuchMethodException, SecurityException { var functionCallback = FunctionCallback.builder() + .method("argumentLessReturnVoid") .description("weather at location") .objectMapper(new ObjectMapper()) - .method("argumentLessReturnVoid") .targetClass(TestClassWithFunctionMethods.class) .build(); diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock-converse.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock-converse.adoc index 2c63aa9b2a9..121c1acba02 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock-converse.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock-converse.adoc @@ -109,8 +109,8 @@ var options = FunctionCallingOptions.builder() .withTemperature(0.6) .withMaxTokens(300) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location. Return temperature in 36°F or 36°C format. Use multi-turn if needed.") .function("getCurrentWeather", new WeatherService()) + .description("Get the weather in location. Return temperature in 36°F or 36°C format. Use multi-turn if needed.") .inputType(WeatherService.Request.class) .build())) .build(); diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/anthropic-chat-functions.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/anthropic-chat-functions.adoc index adfae3a9e15..34241def12d 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/anthropic-chat-functions.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/anthropic-chat-functions.adoc @@ -176,8 +176,8 @@ UserMessage userMessage = new UserMessage("What's the weather like in Paris?"); var promptOptions = AnthropicChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") // (2) function description .function("CurrentWeather", new MockWeatherService()) // (1) function name and instance + .description("Get the weather in location") // (2) function description .inputType(MockWeatherService.Request.class) // (3) function signature .build())) // function code .build(); diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/azure-open-ai-chat-functions.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/azure-open-ai-chat-functions.adoc index 9116fbc9020..cc2deaa6f9f 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/azure-open-ai-chat-functions.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/azure-open-ai-chat-functions.adoc @@ -124,8 +124,8 @@ static class Config { public FunctionCallback weatherFunctionInfo() { return FunctionCallback.builder() - .description("Get the current weather in a given location") // (2) function description .function("CurrentWeather", new MockWeatherService()) // (1) function name + .description("Get the current weather in a given location") // (2) function description .inputType(MockWeatherService.Request.class) // (3) function input type .build(); } @@ -181,8 +181,8 @@ UserMessage userMessage = new UserMessage("What's the weather like in San Franci var promptOptions = AzureOpenAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the current weather in a given location") // (2) function description .function("CurrentWeather", new MockWeatherService()) // (1) function name and instance + .description("Get the current weather in a given location") // (2) function description .inputType(MockWeatherService.Request.class) // (3) function input type .build())) .build(); diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/minimax-chat-functions.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/minimax-chat-functions.adoc index 1f528f5ff79..e7e25fcf919 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/minimax-chat-functions.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/minimax-chat-functions.adoc @@ -128,8 +128,8 @@ static class Config { public FunctionCallback weatherFunctionInfo() { return FunctionCallback.builder() - .description("Get the weather in location") // (2) function description .function("CurrentWeather", new MockWeatherService()) // (1) function name and instance + .description("Get the weather in location") // (2) function description .inputType(MockWeatherService.Request.class) // (3) function signature .build(); } @@ -186,8 +186,8 @@ UserMessage userMessage = new UserMessage("What's the weather like in San Franci var promptOptions = MiniMaxChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") // (2) function description .function("CurrentWeather", new MockWeatherService()) // (1) function name and instance + .description("Get the weather in location") // (2) function description .inputType(MockWeatherService.Request.class) // (3) function signature .build())) // function code .build(); diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/mistralai-chat-functions.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/mistralai-chat-functions.adoc index 8b1b1ffbb58..90084e9c869 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/mistralai-chat-functions.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/mistralai-chat-functions.adoc @@ -126,8 +126,8 @@ static class Config { public FunctionCallback weatherFunctionInfo() { return FunctionCallback.builder() - .description("Get the weather in location") // (2) function description .function("CurrentWeather", new MockWeatherService()) // (1) function name and instance + .description("Get the weather in location") // (2) function description .inputType(MockWeatherService.Request.class) // (3) function signature .build(); } @@ -174,8 +174,8 @@ UserMessage userMessage = new UserMessage("What's the weather like in Paris?"); var promptOptions = MistralAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") // (2) function description .function("CurrentWeather", new MockWeatherService()) // (1) function name and instance + .description("Get the weather in location") // (2) function description .inputType(MockWeatherService.Request.class) // (3) function signature .build())) // function code .build(); diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/moonshot-chat-functions.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/moonshot-chat-functions.adoc index f67cff3717a..c5575f500e4 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/moonshot-chat-functions.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/moonshot-chat-functions.adoc @@ -128,8 +128,8 @@ static class Config { public FunctionCallback weatherFunctionInfo() { return FunctionCallback.builder() - .description("Get the weather in location") // (2) function description .function("CurrentWeather", new MockWeatherService()) // (1) function name and instance + .description("Get the weather in location") // (2) function description .inputType(MockWeatherService.Request.class) // (3) function signature .build(); } @@ -186,8 +186,8 @@ UserMessage userMessage = new UserMessage("What's the weather like in San Franci var promptOptions = MoonshotChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") // (2) function description .function("CurrentWeather", new MockWeatherService()) // (1) function name + .description("Get the weather in location") // (2) function description .inputType(MockWeatherService.Request.class) // (3) function signature .build())) // function code .build(); diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/ollama-chat-functions.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/ollama-chat-functions.adoc index f2e0aad9ce2..a10b21bdf65 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/ollama-chat-functions.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/ollama-chat-functions.adoc @@ -130,8 +130,8 @@ static class Config { public FunctionCallback weatherFunctionInfo() { return FunctionCallback.builder() - .description("Get the weather in location") // (2) function description .function("CurrentWeather", new MockWeatherService()) // (1) function name + .description("Get the weather in location") // (2) function description .inputType(MockWeatherService.Request.class) // (3) function signature .build(); } @@ -187,8 +187,8 @@ UserMessage userMessage = new UserMessage("What's the weather like in San Franci var promptOptions = OllamaOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") // (2) function description .function("CurrentWeather", new MockWeatherService()) // (1) function name and instance + .description("Get the weather in location") // (2) function description .inputType(MockWeatherService.Request.class) // (3) function signature .build())) // function code .build(); 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 ed520bb71d9..5adf6a41699 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 @@ -123,8 +123,8 @@ static class Config { public FunctionCallback weatherFunctionInfo() { return FunctionCallback.builder() - .description("Get the weather in location") // (2) function description .function("CurrentWeather", new MockWeatherService()) // (1) function name and instance + .description("Get the weather in location") // (2) function description .inputType(MockWeatherService.Request.class) // (3) function input type .build(); } @@ -180,8 +180,8 @@ UserMessage userMessage = new UserMessage("What's the weather like in San Franci var promptOptions = OpenAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") // (2) function description .function("CurrentWeather", new MockWeatherService()) // (1) function name and instance + .description("Get the weather in location") // (2) function description .inputType(MockWeatherService.Request.class) // (3) function input type .build())) // function code .build(); diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/vertexai-gemini-chat-functions.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/vertexai-gemini-chat-functions.adoc index 6259cd2f745..de5d31de3ed 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/vertexai-gemini-chat-functions.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/vertexai-gemini-chat-functions.adoc @@ -130,9 +130,9 @@ static class Config { public FunctionCallback weatherFunctionInfo() { return FunctionCallback.builder() + .function("CurrentWeather", new MockWeatherService()) // (1) function name and instance .description("Get the current weather in a given location") // (2) function description .schemaType(SchemaType.OPEN_API_SCHEMA) // (3) schema type. Compulsory for Gemini function calling. - .function("CurrentWeather", new MockWeatherService()) // (1) function name and instance .inputType(MockWeatherService.Request.class) // (4) input type .build(); } @@ -189,9 +189,9 @@ UserMessage userMessage = new UserMessage("What's the weather like in San Franci var promptOptions = VertexAiGeminiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() + .function("CurrentWeather", new MockWeatherService()) .schemaType(SchemaType.OPEN_API_SCHEMA) // IMPORTANT!! .description("Get the weather in location") - .function("CurrentWeather", new MockWeatherService()) .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/zhipuai-chat-functions.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/zhipuai-chat-functions.adoc index aa0d6b24e2f..3de67f38b0b 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/zhipuai-chat-functions.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/zhipuai-chat-functions.adoc @@ -128,8 +128,8 @@ static class Config { public FunctionCallback weatherFunctionInfo() { return FunctionCallback.builder() - .description("Get the weather in location") // (2) function description .function("CurrentWeather", new MockWeatherService()) // (1) function name and instance + .description("Get the weather in location") // (2) function description .inputType(MockWeatherService.Request.class) // (3) function signature .build(); } @@ -186,8 +186,8 @@ UserMessage userMessage = new UserMessage("What's the weather like in San Franci var promptOptions = ZhiPuAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") // (2) function description .function("CurrentWeather", new MockWeatherService()) // (1) function name and instance + .description("Get the weather in location") // (2) function description .inputType(MockWeatherService.Request.class) // (3) function signature .build())) // function code .build(); diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/function-callback.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/function-callback.adoc index 4b88740a488..cbef5d9444a 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/function-callback.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/function-callback.adoc @@ -34,8 +34,8 @@ NOTE: You can use lambda expressions or method references to define the function [source,java] ---- FunctionCallback callback = FunctionCallback.builder() - .description("Process a new order") .function("processOrder", (Order order) -> processOrderLogic(order)) + .description("Process a new order") .inputType(Order.class) .build(); ---- @@ -47,9 +47,9 @@ Using Function with input type and additional xref:api/functions.adoc#Tool-C [source,java] ---- FunctionCallback callback = FunctionCallback.builder() - .description("Process a new order with context") .function("processOrder", (Order order, ToolContext context) -> processOrderWithContext(order, context)) + .description("Process a new order with context") .inputType(Order.class) .build(); ---- @@ -61,8 +61,8 @@ Use `java.util.Supplier` or `java.util.function.Function` to define [source,java] ---- FunctionCallback.builder() - .description("Turns light on in the living room") .function("turnsLight", () -> state.put("Light", "ON")) + .description("Turns light on in the living room") .inputType(Void.class) .build(); ---- @@ -76,10 +76,10 @@ Use `java.util.Consumer` or `java.util.function.Function` to define record LightInfo(String roomName, boolean isOn) {} FunctionCallback.builder() - .description("Turns light on/off in a selected room") .function("turnsLight", (LightInfo lightInfo) -> { logger.info("Turning light to [" + lightInfo.isOn + "] in " + lightInfo.roomName()); }) + .description("Turns light on/off in a selected room") .inputType(LightInfo.class) .build(); ---- @@ -97,11 +97,11 @@ record TrainSearchSchedule(String from, String to, String date) {} record TrainSearchScheduleResponse(String from, String to, String date, String trainNumber) {} FunctionCallback.builder() - .description("Schedule a train reservation") .function("trainSchedule", (TrainSearchRequest request) -> { logger.info("Schedule: " + request.data().from() + " to " + request.data().to()); return new TrainSearchScheduleResponse(request.data().from(), request. data().to(), "", "123"); }) + .description("Schedule a train reservation") .inputType(new ParameterizedTypeReference>() {}) .build(); ---- @@ -132,8 +132,8 @@ public class WeatherService { } FunctionCallback callback = FunctionCallback.builder() - .description("Get weather information for a city") .method("getWeather", String.class, TemperatureUnit.class) + .description("Get weather information for a city") .targetClass(WeatherService.class) .build(); ---- @@ -156,8 +156,8 @@ DeviceController controller = new DeviceController(); String response = ChatClient.create(chatModel).prompt() .user("Turn on the living room lights") .functions(FunctionCallback.builder() - .description("Control device state") .method("setDeviceState", String.class,boolean.class,ToolContext.class) + .description("Control device state") .targetObject(controller) .build()) .toolContext(Map.of("location", "home")) diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/functions.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/functions.adoc index 60ed9c56903..6e9b6cad720 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/functions.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/functions.adoc @@ -206,8 +206,8 @@ static class Config { public FunctionCallback weatherFunctionInfo() { return FunctionCallback.builder() - .description("Get the weather in location") // (2) function description .function("CurrentWeather", new MockWeatherService()) // (1) function name and instance + .description("Get the weather in location") // (2) function description .inputType(MockWeatherService.Request.class) // (3) input type to build the JSON schema .build(); } @@ -226,8 +226,8 @@ class Config { fun weatherFunctionInfo(): FunctionCallback { return FunctionCallback.builder() - .description("Get the weather in location") // (2) function description .function("CurrentWeather", MockWeatherService()) // (1) function name and instance + .description("Get the weather in location") // (2) function description // (3) Required due to Kotlin SAM conversion being an opaque lambda .inputType() .build(); @@ -287,8 +287,8 @@ ChatClient chatClient = ... ChatResponse response = this.chatClient.prompt("What's the weather like in San Francisco, Tokyo, and Paris?") .functions(FunctionCallback.builder() - .description("Get the weather in location") // (2) function description .function("currentWeather", (Request request) -> new Response(30.0, Unit.C)) // (1) function name and instance + .description("Get the weather in location") // (2) function description .inputType(MockWeatherService.Request.class) // (3) input type to build the JSON schema .build()) .call() @@ -320,8 +320,8 @@ You need the `FunctionCallback.Builder` to create `MethodInvokingFunctionCallbac ---- // Create using builder pattern FunctionCallback methodInvokingCallback = FunctionCallback.builder() - .description("Function calling description") // Hints the AI to know when to call this method .method("MethodName", Class...argumentTypes) // The method to invoke and its argument types + .description("Function calling description") // Hints the AI to know when to call this method .targetObject(targetObject) // Required instance methods for static methods use targetClass .build(); ---- @@ -342,8 +342,8 @@ public class WeatherService { // Usage FunctionCallback callback = FunctionCallback.builder() - .description("Get weather information for a city") .method("getWeather", String.class, TemperatureUnit.class) + .description("Get weather information for a city") .targetClass(WeatherService.class) .build(); ---- @@ -364,8 +364,8 @@ DeviceController controller = new DeviceController(); String response = ChatClient.create(chatModel).prompt() .user("Turn on the living room lights") .functions(FunctionCallback.builder() - .description("Control device state") .method("setDeviceState", String.class,boolean.class,ToolContext.class) + .description("Control device state") .targetObject(controller) .build()) .toolContext(Map.of("location", "home")) @@ -423,8 +423,8 @@ BiFunction ChatResponse response = chatClient.prompt("What's the weather like in San Francisco, Tokyo, and Paris?") .functions(FunctionCallback.builder() - .description("Get the weather in location") .function("getCurrentWeather", this.weatherFunction) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()) .toolContext(Map.of("sessionId", "1234", "userId", "5678")) @@ -453,8 +453,8 @@ DeviceController controller = new DeviceController(); String response = ChatClient.create(chatModel).prompt() .user("Turn on the living room lights") .functions(FunctionCallback.builder() - .description("Control device state") .method("setDeviceState", String.class,boolean.class,ToolContext.class) + .description("Control device state") .targetObject(controller) .build()) .toolContext(Map.of("location", "home")) diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/anthropic/tool/FunctionCallWithPromptFunctionIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/anthropic/tool/FunctionCallWithPromptFunctionIT.java index aa2d111014d..f856113e6cc 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/anthropic/tool/FunctionCallWithPromptFunctionIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/anthropic/tool/FunctionCallWithPromptFunctionIT.java @@ -59,8 +59,8 @@ void functionCallTest() { var promptOptions = AnthropicChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location. Return temperature in 36°F or 36°C format.") .function("CurrentWeatherService", new MockWeatherService()) + .description("Get the weather in location. Return temperature in 36°F or 36°C format.") .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/azure/tool/FunctionCallWithFunctionWrapperIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/azure/tool/FunctionCallWithFunctionWrapperIT.java index 721359ef286..f1400ab221f 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/azure/tool/FunctionCallWithFunctionWrapperIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/azure/tool/FunctionCallWithFunctionWrapperIT.java @@ -80,8 +80,8 @@ static class Config { public FunctionCallback weatherFunctionInfo() { return FunctionCallback.builder() - .description("Get the current weather in a given location") .function("WeatherInfo", new MockWeatherService()) + .description("Get the current weather in a given location") .inputType(MockWeatherService.Request.class) .build(); } diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/azure/tool/FunctionCallWithPromptFunctionIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/azure/tool/FunctionCallWithPromptFunctionIT.java index 908fbc59ec7..c682aaa8e58 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/azure/tool/FunctionCallWithPromptFunctionIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/azure/tool/FunctionCallWithPromptFunctionIT.java @@ -62,8 +62,8 @@ void functionCallTest() { var promptOptions = AzureOpenAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("CurrentWeatherService", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/converse/tool/FunctionCallWithPromptFunctionIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/converse/tool/FunctionCallWithPromptFunctionIT.java index d5bc704530e..aa05b8dccb8 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/converse/tool/FunctionCallWithPromptFunctionIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/converse/tool/FunctionCallWithPromptFunctionIT.java @@ -58,8 +58,8 @@ void functionCallTest() { var promptOptions = FunctionCallingOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location. Return temperature in 36°F or 36°C format.") .function("CurrentWeatherService", new MockWeatherService()) + .description("Get the weather in location. Return temperature in 36°F or 36°C format.") .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/minimax/FunctionCallbackInPromptIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/minimax/FunctionCallbackInPromptIT.java index e1ca67dbad7..ad91d509411 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/minimax/FunctionCallbackInPromptIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/minimax/FunctionCallbackInPromptIT.java @@ -64,8 +64,8 @@ void functionCallTest() { var promptOptions = MiniMaxChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("CurrentWeatherService", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -90,8 +90,8 @@ void streamingFunctionCallTest() { var promptOptions = MiniMaxChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("CurrentWeatherService", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/minimax/MiniMaxFunctionCallbackIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/minimax/MiniMaxFunctionCallbackIT.java index d2fb03a69a6..3966cbf2c0d 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/minimax/MiniMaxFunctionCallbackIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/minimax/MiniMaxFunctionCallbackIT.java @@ -111,8 +111,8 @@ static class Config { public FunctionCallback weatherFunctionInfo() { return FunctionCallback.builder() - .description("Get the weather in location") .function("WeatherInfo", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build(); } diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/mistralai/tool/PaymentStatusPromptIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/mistralai/tool/PaymentStatusPromptIT.java index 8c001dc7eba..b9d199e5586 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/mistralai/tool/PaymentStatusPromptIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/mistralai/tool/PaymentStatusPromptIT.java @@ -65,9 +65,9 @@ void functionCallTest() { var promptOptions = MistralAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get payment status of a transaction") .function("retrievePaymentStatus", (Transaction transaction) -> new Status(DATA.get(transaction).status())) + .description("Get payment status of a transaction") .inputType(Transaction.class) .build())) .build(); diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/mistralai/tool/WeatherServicePromptIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/mistralai/tool/WeatherServicePromptIT.java index 394a5f155be..48edeb116cc 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/mistralai/tool/WeatherServicePromptIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/mistralai/tool/WeatherServicePromptIT.java @@ -74,8 +74,8 @@ void promptFunctionCall() { var promptOptions = MistralAiChatOptions.builder() .withToolChoice(ToolChoice.AUTO) .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the current weather in requested location") .function("CurrentWeatherService", new MyWeatherService()) + .description("Get the current weather in requested location") .inputType(MyWeatherService.Request.class) .build())) .build(); @@ -100,8 +100,8 @@ void functionCallWithPortableFunctionCallingOptions() { PortableFunctionCallingOptions functionOptions = FunctionCallingOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the current weather in requested location") .function("CurrentWeatherService", new MyWeatherService()) + .description("Get the current weather in requested location") .inputType(MyWeatherService.Request.class) .build())) diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/moonshot/tool/FunctionCallbackInPromptIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/moonshot/tool/FunctionCallbackInPromptIT.java index 3b95bc22241..550939b63b2 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/moonshot/tool/FunctionCallbackInPromptIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/moonshot/tool/FunctionCallbackInPromptIT.java @@ -65,8 +65,8 @@ void functionCallTest() { var promptOptions = MoonshotChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("CurrentWeatherService", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -91,8 +91,8 @@ void streamingFunctionCallTest() { var promptOptions = MoonshotChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("CurrentWeatherService", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/moonshot/tool/MoonshotFunctionCallbackIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/moonshot/tool/MoonshotFunctionCallbackIT.java index c5141515e66..f68bed8b099 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/moonshot/tool/MoonshotFunctionCallbackIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/moonshot/tool/MoonshotFunctionCallbackIT.java @@ -114,8 +114,8 @@ static class Config { public FunctionCallback weatherFunctionInfo() { return FunctionCallback.builder() - .description("Get the weather in location") .function("WeatherInfo", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build(); } diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/ollama/tool/FunctionCallbackInPromptIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/ollama/tool/FunctionCallbackInPromptIT.java index 66d9ef09dde..df37a4edbe3 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/ollama/tool/FunctionCallbackInPromptIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/ollama/tool/FunctionCallbackInPromptIT.java @@ -72,9 +72,9 @@ void functionCallTest() { var promptOptions = OllamaOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() + .function("CurrentWeatherService", new MockWeatherService()) .description( "Find the weather conditions, forecasts, and temperatures for a location, like a city or state.") - .function("CurrentWeatherService", new MockWeatherService()) .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -99,9 +99,9 @@ void streamingFunctionCallTest() { var promptOptions = OllamaOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() + .function("CurrentWeatherService", new MockWeatherService()) .description( "Find the weather conditions, forecasts, and temperatures for a location, like a city or state.") - .function("CurrentWeatherService", new MockWeatherService()) .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/ollama/tool/OllamaFunctionCallbackIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/ollama/tool/OllamaFunctionCallbackIT.java index d8c4c0ae609..1ee3667db99 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/ollama/tool/OllamaFunctionCallbackIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/ollama/tool/OllamaFunctionCallbackIT.java @@ -140,9 +140,9 @@ static class Config { public FunctionCallback weatherFunctionInfo() { return FunctionCallback.builder() + .function("WeatherInfo", new MockWeatherService()) .description( "Find the weather conditions, forecasts, and temperatures for a location, like a city or state.") - .function("WeatherInfo", new MockWeatherService()) .inputType(MockWeatherService.Request.class) .build(); } diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/FunctionCallbackInPrompt2IT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/FunctionCallbackInPrompt2IT.java index 1ae2a5d84fe..aa0018ee803 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/FunctionCallbackInPrompt2IT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/FunctionCallbackInPrompt2IT.java @@ -61,8 +61,8 @@ void functionCallTest() { String content = ChatClient.builder(chatModel).build().prompt() .user("What's the weather like in San Francisco, Tokyo, and Paris?") .functions(FunctionCallback.builder() - .description("Get the weather in location") .function("CurrentWeatherService", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()) .call().content(); @@ -89,11 +89,11 @@ record LightInfo(String roomName, boolean isOn) { String content = ChatClient.builder(chatModel).build().prompt() .user("Turn the light on in the kitchen and in the living room!") .functions(FunctionCallback.builder() - .description("Turn light on or off in a room") .function("turnLight", (LightInfo lightInfo) -> { logger.info("Turning light to [" + lightInfo.isOn + "] in " + lightInfo.roomName()); state.put(lightInfo.roomName(), lightInfo.isOn()); }) + .description("Turn light on or off in a room") .inputType(LightInfo.class) .build()) .call().content(); @@ -115,8 +115,8 @@ void functionCallTest2() { String content = ChatClient.builder(chatModel).build().prompt() .user("What's the weather like in Amsterdam?") .functions(FunctionCallback.builder() - .description("Get the weather in location") .function("CurrentWeatherService", input -> "18 degrees Celsius") + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build()) .call().content(); diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/FunctionCallbackInPromptIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/FunctionCallbackInPromptIT.java index fc4d4a4476d..9526c00f98b 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/FunctionCallbackInPromptIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/FunctionCallbackInPromptIT.java @@ -63,8 +63,8 @@ void functionCallTest() { var promptOptions = OpenAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("CurrentWeatherService", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); @@ -92,8 +92,8 @@ void streamingFunctionCallTest() { var promptOptions = OpenAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("CurrentWeatherService", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/OpenAiFunctionCallback2IT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/OpenAiFunctionCallback2IT.java index c471b154b08..3499278e938 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/OpenAiFunctionCallback2IT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/OpenAiFunctionCallback2IT.java @@ -96,8 +96,8 @@ static class Config { public FunctionCallback weatherFunctionInfo() { return FunctionCallback.builder() - .description("Get the weather in location") .function("WeatherInfo", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build(); } diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/OpenAiFunctionCallbackIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/OpenAiFunctionCallbackIT.java index 468f8ff5e81..1337eadb1b1 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/OpenAiFunctionCallbackIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/tool/OpenAiFunctionCallbackIT.java @@ -107,8 +107,8 @@ static class Config { public FunctionCallback weatherFunctionInfo() { return FunctionCallback.builder() - .description("Get the weather in location") .function("WeatherInfo", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build(); } diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/vertexai/gemini/tool/FunctionCallWithFunctionWrapperIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/vertexai/gemini/tool/FunctionCallWithFunctionWrapperIT.java index f617efdcb84..79272be73a6 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/vertexai/gemini/tool/FunctionCallWithFunctionWrapperIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/vertexai/gemini/tool/FunctionCallWithFunctionWrapperIT.java @@ -80,9 +80,9 @@ static class Config { public FunctionCallback weatherFunctionInfo() { return FunctionCallback.builder() + .function("WeatherInfo", new MockWeatherService()) .description("Get the current weather in a given location") .schemaType(SchemaType.OPEN_API_SCHEMA) - .function("WeatherInfo", new MockWeatherService()) .inputType(MockWeatherService.Request.class) .build(); } diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/vertexai/gemini/tool/FunctionCallWithPromptFunctionIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/vertexai/gemini/tool/FunctionCallWithPromptFunctionIT.java index 3de7c0faf23..d051490ed9c 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/vertexai/gemini/tool/FunctionCallWithPromptFunctionIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/vertexai/gemini/tool/FunctionCallWithPromptFunctionIT.java @@ -69,9 +69,9 @@ void functionCallTest() { var promptOptions = VertexAiGeminiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() + .function("CurrentWeatherService", new MockWeatherService()) .schemaType(SchemaType.OPEN_API_SCHEMA) // IMPORTANT!! .description("Get the weather in location") - .function("CurrentWeatherService", new MockWeatherService()) .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/zhipuai/tool/FunctionCallbackInPromptIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/zhipuai/tool/FunctionCallbackInPromptIT.java index 7dbf4905123..f3d39a0a745 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/zhipuai/tool/FunctionCallbackInPromptIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/zhipuai/tool/FunctionCallbackInPromptIT.java @@ -65,8 +65,8 @@ void functionCallTest() { var promptOptions = ZhiPuAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("CurrentWeatherService", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) // .responseConverter(response -> "" + response.temp() + // response.unit()) @@ -93,8 +93,8 @@ void streamingFunctionCallTest() { var promptOptions = ZhiPuAiChatOptions.builder() .withFunctionCallbacks(List.of(FunctionCallback.builder() - .description("Get the weather in location") .function("CurrentWeatherService", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) .build())) .build(); diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/zhipuai/tool/ZhipuAiFunctionCallbackIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/zhipuai/tool/ZhipuAiFunctionCallbackIT.java index 73f9ea121cf..d22c745ea2d 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/zhipuai/tool/ZhipuAiFunctionCallbackIT.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/zhipuai/tool/ZhipuAiFunctionCallbackIT.java @@ -112,8 +112,8 @@ static class Config { public FunctionCallback weatherFunctionInfo() { return FunctionCallback.builder() - .description("Get the weather in location") .function("WeatherInfo", new MockWeatherService()) + .description("Get the weather in location") .inputType(MockWeatherService.Request.class) // .responseConverter(response -> "" + response.temp() + response.unit()) .build(); diff --git a/spring-ai-spring-boot-autoconfigure/src/test/kotlin/org/springframework/ai/autoconfigure/ollama/tool/FunctionCallbackKotlinIT.kt b/spring-ai-spring-boot-autoconfigure/src/test/kotlin/org/springframework/ai/autoconfigure/ollama/tool/FunctionCallbackKotlinIT.kt index 0b33990270b..c5d7d300aea 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/kotlin/org/springframework/ai/autoconfigure/ollama/tool/FunctionCallbackKotlinIT.kt +++ b/spring-ai-spring-boot-autoconfigure/src/test/kotlin/org/springframework/ai/autoconfigure/ollama/tool/FunctionCallbackKotlinIT.kt @@ -106,10 +106,10 @@ class FunctionCallbackKotlinIT : BaseOllamaIT() { @Bean open fun weatherFunctionInfo(): FunctionCallback { return FunctionCallback.builder() + .function("WeatherInfo", MockKotlinWeatherService()) .description( "Find the weather conditions, forecasts, and temperatures for a location, like a city or state." ) - .function("WeatherInfo", MockKotlinWeatherService()) .inputType(KotlinRequest::class.java) .build() }