refactor(core): extract common function callback builder functionality
Extracts shared function callback builder functionality into DefaultCommonCallbackInvokingSpec base class, reducing code duplication across builder implementations. Makes FunctionInvokingSpec and MethodInvokingSpec extend CommonCallbackInvokingSpec for better code organization. Also fixes function/description builder order in Anthropic tests. - Introduced a common base class for function callback builders to centralize shared logic - Standardized the order of method chaining for function and description in multiple AI model test classes - Refactored test cases across various AI model integrations - Corrected builder method order from .description().function() to .function().description() and .description().method() to .method().description() - Updated multiple test files to consistently use .function() before .description() - Updated documentation examples to reflect new builder method order - Modified DefaultFunctionCallbackResolver to maintain new builder method order - Updated DefaultChatClient and ChatClient test classes to reflect new builder pattern - Simplified callback specification by removing parent spec reference - Removed cascading getter logic for description, schema type, and other properties - Minor adjustments to function callback builder and invoking specs
This commit is contained in:
committed by
Ilayaperumal Gopinathan
parent
dcc8d5b620
commit
6a195ee9fe
@@ -276,9 +276,9 @@ class AnthropicChatModelIT {
|
||||
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 @@ class AnthropicChatModelIT {
|
||||
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();
|
||||
|
||||
@@ -250,8 +250,8 @@ class AnthropicChatClientIT {
|
||||
// @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 @@ class AnthropicChatClientIT {
|
||||
Flux<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")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.description("Get the weather in location")
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.stream()
|
||||
|
||||
@@ -80,8 +80,8 @@ class AnthropicChatClientMethodInvokingFunctionCallbackIT {
|
||||
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 @@ class AnthropicChatClientMethodInvokingFunctionCallbackIT {
|
||||
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 @@ class AnthropicChatClientMethodInvokingFunctionCallbackIT {
|
||||
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 @@ class AnthropicChatClientMethodInvokingFunctionCallbackIT {
|
||||
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 @@ class AnthropicChatClientMethodInvokingFunctionCallbackIT {
|
||||
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 @@ class AnthropicChatClientMethodInvokingFunctionCallbackIT {
|
||||
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()
|
||||
|
||||
@@ -70,8 +70,8 @@ class AzureOpenAiChatModelFunctionCallIT {
|
||||
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 @@ class AzureOpenAiChatModelFunctionCallIT {
|
||||
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 @@ class AzureOpenAiChatModelFunctionCallIT {
|
||||
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 @@ class AzureOpenAiChatModelFunctionCallIT {
|
||||
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();
|
||||
|
||||
@@ -214,10 +214,10 @@ class BedrockConverseChatClientIT {
|
||||
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 @@ class BedrockConverseChatClientIT {
|
||||
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 @@ class BedrockConverseChatClientIT {
|
||||
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 @@ class BedrockConverseChatClientIT {
|
||||
// @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 @@ class BedrockConverseChatClientIT {
|
||||
Flux<ChatResponse> 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 @@ class BedrockConverseChatClientIT {
|
||||
Flux<String> 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()
|
||||
|
||||
@@ -139,8 +139,8 @@ public class BedrockConverseUsageAggregationTests {
|
||||
.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();
|
||||
|
||||
|
||||
@@ -255,9 +255,9 @@ class BedrockProxyChatModelIT {
|
||||
|
||||
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 @@ class BedrockProxyChatModelIT {
|
||||
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();
|
||||
|
||||
@@ -53,8 +53,8 @@ public final class BedrockConverseChatModelMain2 {
|
||||
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());
|
||||
|
||||
@@ -51,8 +51,8 @@ public final class BedrockConverseChatModelMain3 {
|
||||
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());
|
||||
|
||||
@@ -68,8 +68,8 @@ public class ChatCompletionRequestTests {
|
||||
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 class ChatCompletionRequestTests {
|
||||
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 class ChatCompletionRequestTests {
|
||||
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()),
|
||||
|
||||
@@ -226,10 +226,10 @@ class MistralAiChatClientIT {
|
||||
.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 @@ class MistralAiChatClientIT {
|
||||
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 @@ class MistralAiChatClientIT {
|
||||
.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()
|
||||
|
||||
@@ -194,8 +194,8 @@ class MistralAiChatModelIT {
|
||||
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 @@ class MistralAiChatModelIT {
|
||||
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();
|
||||
|
||||
@@ -64,8 +64,8 @@ class MoonshotChatModelFunctionCallingIT {
|
||||
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 @@ class MoonshotChatModelFunctionCallingIT {
|
||||
|
||||
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();
|
||||
|
||||
|
||||
@@ -64,9 +64,9 @@ class OllamaChatModelFunctionCallingIT extends BaseOllamaIT {
|
||||
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 @@ class OllamaChatModelFunctionCallingIT extends BaseOllamaIT {
|
||||
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();
|
||||
|
||||
@@ -68,8 +68,8 @@ public class ChatCompletionRequestTests {
|
||||
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 class ChatCompletionRequestTests {
|
||||
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 class ChatCompletionRequestTests {
|
||||
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()),
|
||||
|
||||
@@ -85,8 +85,8 @@ class OpenAiChatModelFunctionCallingIT {
|
||||
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 @@ class OpenAiChatModelFunctionCallingIT {
|
||||
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 @@ class OpenAiChatModelFunctionCallingIT {
|
||||
|
||||
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 @@ class OpenAiChatModelFunctionCallingIT {
|
||||
|
||||
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"))
|
||||
|
||||
@@ -330,8 +330,8 @@ public class OpenAiChatModelIT extends AbstractIT {
|
||||
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();
|
||||
@@ -355,8 +355,8 @@ public class OpenAiChatModelIT extends AbstractIT {
|
||||
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();
|
||||
|
||||
@@ -246,8 +246,8 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
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 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
// @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 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
Flux<String> 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()
|
||||
|
||||
@@ -61,8 +61,8 @@ class OpenAiChatClientMethodInvokingFunctionCallbackIT {
|
||||
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 @@ class OpenAiChatClientMethodInvokingFunctionCallbackIT {
|
||||
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 @@ class OpenAiChatClientMethodInvokingFunctionCallbackIT {
|
||||
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 @@ class OpenAiChatClientMethodInvokingFunctionCallbackIT {
|
||||
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 @@ class OpenAiChatClientMethodInvokingFunctionCallbackIT {
|
||||
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 @@ class OpenAiChatClientMethodInvokingFunctionCallbackIT {
|
||||
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()
|
||||
|
||||
@@ -85,8 +85,8 @@ class OpenAiChatClientMultipleFunctionCallsIT extends AbstractIT {
|
||||
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 @@ class OpenAiChatClientMultipleFunctionCallsIT extends AbstractIT {
|
||||
// @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 @@ class OpenAiChatClientMultipleFunctionCallsIT extends AbstractIT {
|
||||
// @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 @@ class OpenAiChatClientMultipleFunctionCallsIT extends AbstractIT {
|
||||
// @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 @@ class OpenAiChatClientMultipleFunctionCallsIT extends AbstractIT {
|
||||
Flux<String> 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()
|
||||
|
||||
@@ -250,8 +250,8 @@ class GroqWithOpenAiChatModelIT {
|
||||
|
||||
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 @@ class GroqWithOpenAiChatModelIT {
|
||||
|
||||
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();
|
||||
|
||||
@@ -252,8 +252,8 @@ class MistralWithOpenAiChatModelIT {
|
||||
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 @@ class MistralWithOpenAiChatModelIT {
|
||||
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();
|
||||
|
||||
@@ -247,8 +247,8 @@ class NvidiaWithOpenAiChatModelIT {
|
||||
|
||||
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 @@ class NvidiaWithOpenAiChatModelIT {
|
||||
|
||||
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();
|
||||
|
||||
@@ -269,8 +269,8 @@ class OllamaWithOpenAiChatModelIT {
|
||||
|
||||
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 @@ class OllamaWithOpenAiChatModelIT {
|
||||
|
||||
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();
|
||||
|
||||
|
||||
@@ -257,8 +257,8 @@ class PerplexityWithOpenAiChatModelIT {
|
||||
|
||||
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();
|
||||
@@ -279,8 +279,8 @@ class PerplexityWithOpenAiChatModelIT {
|
||||
|
||||
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();
|
||||
|
||||
@@ -118,8 +118,8 @@ public class CreateGeminiRequestTests {
|
||||
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 class CreateGeminiRequestTests {
|
||||
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 class CreateGeminiRequestTests {
|
||||
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()),
|
||||
|
||||
@@ -84,9 +84,9 @@ public class VertexAiGeminiChatModelFunctionCallingIT {
|
||||
|
||||
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 class VertexAiGeminiChatModelFunctionCallingIT {
|
||||
.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 class VertexAiGeminiChatModelFunctionCallingIT {
|
||||
.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 class VertexAiGeminiChatModelFunctionCallingIT {
|
||||
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();
|
||||
|
||||
@@ -68,8 +68,8 @@ public class ChatCompletionRequestTests {
|
||||
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 class ChatCompletionRequestTests {
|
||||
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 class ChatCompletionRequestTests {
|
||||
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()),
|
||||
|
||||
@@ -231,8 +231,8 @@ class ZhiPuAiChatModelIT {
|
||||
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 @@ class ZhiPuAiChatModelIT {
|
||||
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();
|
||||
|
||||
@@ -878,9 +878,9 @@ public class DefaultChatClient implements ChatClient {
|
||||
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);
|
||||
|
||||
@@ -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<B extends CommonCallbackInvokingSpec<B>>
|
||||
implements CommonCallbackInvokingSpec<B> {
|
||||
|
||||
/**
|
||||
* 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<Object, String> 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<Object, String> 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<Object, String> getResponseConverter() {
|
||||
return this.responseConverter;
|
||||
}
|
||||
|
||||
public String getInputTypeSchema() {
|
||||
return this.inputTypeSchema;
|
||||
}
|
||||
|
||||
public ObjectMapper getObjectMapper() {
|
||||
return this.objectMapper;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,21 +23,14 @@ import java.util.function.Consumer;
|
||||
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<Object, String> 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<Object, String> 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 <I, O> FunctionInvokingSpec<I, O> function(String name, Function<I, O> function) {
|
||||
return new DefaultFunctionInvokingSpec<>(name, function);
|
||||
@@ -170,7 +87,8 @@ public class DefaultFunctionCallbackBuilder implements FunctionCallback.Builder
|
||||
return generatedDescription;
|
||||
}
|
||||
|
||||
final class DefaultFunctionInvokingSpec<I, O> implements FunctionInvokingSpec<I, O> {
|
||||
final class DefaultFunctionInvokingSpec<I, O> extends DefaultCommonCallbackInvokingSpec<FunctionInvokingSpec<I, O>>
|
||||
implements FunctionInvokingSpec<I, O> {
|
||||
|
||||
private final String name;
|
||||
|
||||
@@ -213,33 +131,35 @@ public class DefaultFunctionCallbackBuilder implements FunctionCallback.Builder
|
||||
@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<I, ToolContext, O> finalBiFunction = (this.biFunction != null) ? this.biFunction
|
||||
: (request, context) -> this.function.apply(request);
|
||||
|
||||
return new FunctionInvokingFunctionCallback(this.name, this.getDescription(), inputTypeSchema,
|
||||
this.inputType, (Function<I, String>) responseConverter, objectMapper, finalBiFunction);
|
||||
return new FunctionInvokingFunctionCallback(this.name, this.getDescriptionExt(), this.getInputTypeSchema(),
|
||||
this.inputType, (Function<I, String>) 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<MethodInvokingSpec>
|
||||
implements FunctionCallback.MethodInvokingSpec {
|
||||
|
||||
private String name;
|
||||
|
||||
@@ -285,13 +205,13 @@ public class DefaultFunctionCallbackBuilder implements FunctionCallback.Builder
|
||||
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);
|
||||
|
||||
@@ -117,25 +117,25 @@ public class DefaultFunctionCallbackResolver implements ApplicationContextAware,
|
||||
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 @@ public class DefaultFunctionCallbackResolver implements ApplicationContextAware,
|
||||
|
||||
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<?, ToolContext, ?>) bean)
|
||||
.description(functionDescription)
|
||||
.schemaType(this.schemaType)
|
||||
.function(beanName, (BiFunction<?, ToolContext, ?>) 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();
|
||||
}
|
||||
|
||||
@@ -118,37 +118,6 @@ public interface FunctionCallback {
|
||||
*/
|
||||
interface Builder {
|
||||
|
||||
/**
|
||||
* Function description. This description is used by the model do decide if the
|
||||
* function should be called or not.
|
||||
*/
|
||||
Builder description(String description);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
Builder schemaType(SchemaType schemaType);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
Builder responseConverter(Function<Object, String> responseConverter);
|
||||
|
||||
/**
|
||||
* You can provide the Input Type Schema directly. In this case it won't be
|
||||
* generated from the inputType.
|
||||
*/
|
||||
Builder inputTypeSchema(String inputTypeSchema);
|
||||
|
||||
/**
|
||||
* Custom object mapper for JSON operations.
|
||||
*/
|
||||
Builder objectMapper(ObjectMapper objectMapper);
|
||||
|
||||
/**
|
||||
* Builds a {@link Function} invoking {@link FunctionCallback} instance.
|
||||
*/
|
||||
@@ -176,13 +145,48 @@ public interface FunctionCallback {
|
||||
|
||||
}
|
||||
|
||||
interface CommonCallbackInvokingSpec<B extends CommonCallbackInvokingSpec<B>> {
|
||||
|
||||
/**
|
||||
* Function description. This description is used by the model to decide if the
|
||||
* function should be called or not.
|
||||
*/
|
||||
B description(String description);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
B schemaType(SchemaType schemaType);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
B responseConverter(Function<Object, String> responseConverter);
|
||||
|
||||
/**
|
||||
* You can provide the Input Type Schema directly. In this case it won't be
|
||||
* generated from the inputType.
|
||||
*/
|
||||
B inputTypeSchema(String inputTypeSchema);
|
||||
|
||||
/**
|
||||
* Custom object mapper for JSON operations.
|
||||
*/
|
||||
B objectMapper(ObjectMapper objectMapper);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Function} invoking builder interface.
|
||||
*
|
||||
* @param <I> Function input type.
|
||||
* @param <O> Function output type.
|
||||
*/
|
||||
interface FunctionInvokingSpec<I, O> {
|
||||
interface FunctionInvokingSpec<I, O> extends CommonCallbackInvokingSpec<FunctionInvokingSpec<I, O>> {
|
||||
|
||||
/**
|
||||
* Function input type. The input type is used to validate the function input
|
||||
@@ -207,7 +211,7 @@ public interface FunctionCallback {
|
||||
/**
|
||||
* Method invoking builder interface.
|
||||
*/
|
||||
interface MethodInvokingSpec {
|
||||
interface MethodInvokingSpec extends CommonCallbackInvokingSpec<MethodInvokingSpec> {
|
||||
|
||||
/**
|
||||
* Optional function name. If not provided the method name is used as the
|
||||
|
||||
@@ -80,8 +80,8 @@ public class ChatBuilderTests {
|
||||
|
||||
String func = "func";
|
||||
FunctionCallback cb = FunctionCallback.builder()
|
||||
.description("cb")
|
||||
.function("cb", i -> i)
|
||||
.description("cb")
|
||||
.inputType(Integer.class)
|
||||
.build();
|
||||
|
||||
|
||||
@@ -219,8 +219,8 @@ public class ChatClientTest {
|
||||
.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 @@ public class ChatClientTest {
|
||||
.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}")
|
||||
|
||||
@@ -1357,8 +1357,8 @@ class DefaultChatClientTests {
|
||||
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 @@ class DefaultChatClientTests {
|
||||
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 @@ class DefaultChatClientTests {
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -35,51 +35,54 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
*/
|
||||
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 @@ class DefaultFunctionCallbackBuilderTests {
|
||||
@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 @@ class DefaultFunctionCallbackBuilderTests {
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
@@ -56,9 +56,9 @@ public class MethodInvokingFunctionCallbackTests {
|
||||
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 class MethodInvokingFunctionCallbackTests {
|
||||
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 class MethodInvokingFunctionCallbackTests {
|
||||
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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 <I> 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<O>` or `java.util.function.Function<Void, O>` 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<I>` or `java.util.function.Function<I, Void>` 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<TrainSearchSchedule> 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<TrainSearchRequest<TrainSearchSchedule>>() {})
|
||||
.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"))
|
||||
|
||||
@@ -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<MockWeatherService.Request>()
|
||||
.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<MockWeatherService.Request, ToolContext, MockWeatherService.Response>
|
||||
|
||||
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"))
|
||||
|
||||
@@ -59,8 +59,8 @@ public class FunctionCallWithPromptFunctionIT {
|
||||
|
||||
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();
|
||||
|
||||
@@ -80,8 +80,8 @@ public class FunctionCallWithFunctionWrapperIT {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -62,8 +62,8 @@ public class FunctionCallWithPromptFunctionIT {
|
||||
|
||||
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();
|
||||
|
||||
@@ -58,8 +58,8 @@ public class FunctionCallWithPromptFunctionIT {
|
||||
|
||||
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();
|
||||
|
||||
@@ -64,8 +64,8 @@ public class FunctionCallbackInPromptIT {
|
||||
|
||||
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 @@ public class FunctionCallbackInPromptIT {
|
||||
|
||||
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();
|
||||
|
||||
@@ -111,8 +111,8 @@ public class MiniMaxFunctionCallbackIT {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -65,9 +65,9 @@ public class PaymentStatusPromptIT {
|
||||
|
||||
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();
|
||||
|
||||
@@ -74,8 +74,8 @@ public class WeatherServicePromptIT {
|
||||
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 @@ public class WeatherServicePromptIT {
|
||||
|
||||
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()))
|
||||
|
||||
|
||||
@@ -65,8 +65,8 @@ public class FunctionCallbackInPromptIT {
|
||||
|
||||
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 @@ public class FunctionCallbackInPromptIT {
|
||||
|
||||
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();
|
||||
|
||||
@@ -114,8 +114,8 @@ public class MoonshotFunctionCallbackIT {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -72,9 +72,9 @@ public class FunctionCallbackInPromptIT extends BaseOllamaIT {
|
||||
|
||||
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 @@ public class FunctionCallbackInPromptIT extends BaseOllamaIT {
|
||||
|
||||
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();
|
||||
|
||||
@@ -140,9 +140,9 @@ public class OllamaFunctionCallbackIT extends BaseOllamaIT {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -61,8 +61,8 @@ public class FunctionCallbackInPrompt2IT {
|
||||
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 @@ public class FunctionCallbackInPrompt2IT {
|
||||
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 @@ public class FunctionCallbackInPrompt2IT {
|
||||
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();
|
||||
|
||||
@@ -63,8 +63,8 @@ public class FunctionCallbackInPromptIT {
|
||||
|
||||
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 @@ public class FunctionCallbackInPromptIT {
|
||||
|
||||
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();
|
||||
|
||||
@@ -96,8 +96,8 @@ public class OpenAiFunctionCallback2IT {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -107,8 +107,8 @@ public class OpenAiFunctionCallbackIT {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -80,9 +80,9 @@ public class FunctionCallWithFunctionWrapperIT {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -69,9 +69,9 @@ public class FunctionCallWithPromptFunctionIT {
|
||||
|
||||
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();
|
||||
|
||||
@@ -65,8 +65,8 @@ public class FunctionCallbackInPromptIT {
|
||||
|
||||
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 @@ public class FunctionCallbackInPromptIT {
|
||||
|
||||
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();
|
||||
|
||||
@@ -112,8 +112,8 @@ public class ZhipuAiFunctionCallbackIT {
|
||||
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();
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user