Checkstyle fix
This commit is contained in:
@@ -36,7 +36,7 @@ import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
|
||||
|
||||
@SpringBootTest(classes = AnthropicTestConfiguration.class, properties = "spring.ai.retry.on-http-codes=429")
|
||||
@EnabledIfEnvironmentVariable(named = "ANTHROPIC_API_KEY", matches = ".+")
|
||||
@@ -47,6 +47,156 @@ class AnthropicChatClientMethodFunctionCallbackIT {
|
||||
|
||||
public static Map<String, Object> arguments = new ConcurrentHashMap<>();
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
arguments.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherStatic() {
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherStatic", String.class, Unit.class);
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(response).contains("30", "10", "15");
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodTurnLightNoResponse() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLight", String.class, boolean.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("Turn light on in the living room.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Can turn lights on or off by room name")
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(arguments).containsEntry("roomName", "living room");
|
||||
assertThat(arguments).containsEntry("on", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherNonStatic() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class,
|
||||
Unit.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(response).contains("30", "10", "15");
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherToolContext() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherWithContext", String.class,
|
||||
Unit.class, ToolContext.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.toolContext(Map.of("tool", "value"))
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(response).contains("30", "10", "15");
|
||||
assertThat(arguments).containsEntry("tool", "value");
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherToolContextButNonContextMethod() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class,
|
||||
Unit.class);
|
||||
|
||||
// @formatter:off
|
||||
assertThatThrownBy(() -> ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.toolContext(Map.of("tool", "value"))
|
||||
.call()
|
||||
.content())
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("Configured method does not accept ToolContext as input parameter!");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodNoParameters() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLivingRoomLightOn");
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("Turn light on in the living room.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Can turn lights on in the Living Room")
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(arguments).containsEntry("turnLivingRoomLightOn", true);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
ChatModel chatModel;
|
||||
|
||||
@@ -107,154 +257,4 @@ class AnthropicChatClientMethodFunctionCallbackIT {
|
||||
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
arguments.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherStatic() {
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherStatic", String.class, Unit.class);
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(response).contains("30", "10", "15");
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodTurnLightNoResponse() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLight", String.class, boolean.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("Turn light on in the living room.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Can turn lights on or off by room name")
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(arguments).containsEntry("roomName", "living room");
|
||||
assertThat(arguments).containsEntry("on", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherNonStatic() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class,
|
||||
Unit.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(response).contains("30", "10", "15");
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherToolContext() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherWithContext", String.class,
|
||||
Unit.class, ToolContext.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.toolContext(Map.of("tool", "value"))
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(response).contains("30", "10", "15");
|
||||
assertThat(arguments).containsEntry("tool", "value");
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherToolContextButNonContextMethod() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class,
|
||||
Unit.class);
|
||||
|
||||
// @formatter:off
|
||||
assertThrows("Configured method does not accept ToolContext as input parameter!",IllegalArgumentException.class, () -> {
|
||||
ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.toolContext(Map.of("tool", "value"))
|
||||
.call()
|
||||
.content();
|
||||
});
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodNoParameters() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLivingRoomLightOn");
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("Turn light on in the living room.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Can turn lights on in the Living Room")
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(arguments).containsEntry("turnLivingRoomLightOn", true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
|
||||
|
||||
@SpringBootTest(classes = OpenAiTestConfiguration.class)
|
||||
@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+")
|
||||
@@ -50,6 +50,156 @@ class OpenAiChatClientMethodFunctionCallbackIT {
|
||||
@Autowired
|
||||
ChatModel chatModel;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
arguments.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherStatic() {
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherStatic", String.class, Unit.class);
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(response).contains("30", "10", "15");
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodTurnLightNoResponse() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLight", String.class, boolean.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("Turn light on in the living room.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Can turn lights on or off by room name")
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(arguments).containsEntry("roomName", "living room");
|
||||
assertThat(arguments).containsEntry("on", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherNonStatic() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class,
|
||||
Unit.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(response).contains("30", "10", "15");
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherToolContext() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherWithContext", String.class,
|
||||
Unit.class, ToolContext.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.toolContext(Map.of("tool", "value"))
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(response).contains("30", "10", "15");
|
||||
assertThat(arguments).containsEntry("tool", "value");
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherToolContextButNonContextMethod() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class,
|
||||
Unit.class);
|
||||
|
||||
// @formatter:off
|
||||
assertThatThrownBy(() -> ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.toolContext(Map.of("tool", "value"))
|
||||
.call()
|
||||
.content())
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("Configured method does not accept ToolContext as input parameter!");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodNoParameters() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLivingRoomLightOn");
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("Turn light on in the living room.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Can turn lights on in the Living Room")
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(arguments).containsEntry("turnLivingRoomLightOn", true);
|
||||
}
|
||||
|
||||
record MyRecord(String foo, String bar) {
|
||||
}
|
||||
|
||||
@@ -107,154 +257,4 @@ class OpenAiChatClientMethodFunctionCallbackIT {
|
||||
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
arguments.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherStatic() {
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherStatic", String.class, Unit.class);
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(response).contains("30", "10", "15");
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodTurnLightNoResponse() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLight", String.class, boolean.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("Turn light on in the living room.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Can turn lights on or off by room name")
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(arguments).containsEntry("roomName", "living room");
|
||||
assertThat(arguments).containsEntry("on", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherNonStatic() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class,
|
||||
Unit.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(response).contains("30", "10", "15");
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherToolContext() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherWithContext", String.class,
|
||||
Unit.class, ToolContext.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.toolContext(Map.of("tool", "value"))
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(response).contains("30", "10", "15");
|
||||
assertThat(arguments).containsEntry("tool", "value");
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherToolContextButNonContextMethod() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class,
|
||||
Unit.class);
|
||||
|
||||
// @formatter:off
|
||||
assertThrows("Configured method does not accept ToolContext as input parameter!",IllegalArgumentException.class, () -> {
|
||||
ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.toolContext(Map.of("tool", "value"))
|
||||
.call()
|
||||
.content();
|
||||
});
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodNoParameters() {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLivingRoomLightOn");
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("Turn light on in the living room.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Can turn lights on in the Living Room")
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(arguments).containsEntry("turnLivingRoomLightOn", true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
/*
|
||||
* Copyright 2024 - 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ai.model.function;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
@@ -33,9 +34,102 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Christian Tzolov
|
||||
* @since 1.0.0
|
||||
*/
|
||||
|
||||
public class MethodFunctionCallbackTests {
|
||||
|
||||
private static final Map<String, Object> arguments = new ConcurrentHashMap<>();
|
||||
|
||||
String value = """
|
||||
{
|
||||
"unit": "CELSIUS",
|
||||
"city": "Barcelona",
|
||||
"intNumber": 123,
|
||||
"record": {
|
||||
"foo": "foo",
|
||||
"bar": "bar"
|
||||
},
|
||||
"intList": [1, 2, 3]
|
||||
}
|
||||
""";
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEach() {
|
||||
arguments.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void staticMethod() throws NoSuchMethodException, SecurityException {
|
||||
|
||||
Method method = ReflectionUtils.findMethod(TestClassWithFunctionMethods.class, "myStaticMethod", String.class,
|
||||
Unit.class, int.class, MyRecord.class, List.class);
|
||||
|
||||
assertThat(method).isNotNull();
|
||||
assertThat(Modifier.isStatic(method.getModifiers())).isTrue();
|
||||
|
||||
var functionCallback = MethodFunctionCallback.builder()
|
||||
.method(method)
|
||||
.description("weather at location")
|
||||
.mapper(new ObjectMapper())
|
||||
.build();
|
||||
|
||||
String response = functionCallback.call(this.value);
|
||||
|
||||
assertThat(response).isEqualTo("23");
|
||||
|
||||
assertThat(arguments).hasSize(5);
|
||||
assertThat(arguments.get("city")).isEqualTo("Barcelona");
|
||||
assertThat(arguments.get("unit")).isEqualTo(Unit.CELSIUS);
|
||||
assertThat(arguments.get("intNumber")).isEqualTo(123);
|
||||
assertThat(arguments.get("record")).isEqualTo(new MyRecord("foo", "bar"));
|
||||
assertThat(arguments.get("intList")).isEqualTo(List.of(1, 2, 3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonStaticMethod() throws NoSuchMethodException, SecurityException {
|
||||
|
||||
Method method = TestClassWithFunctionMethods.class.getMethod("myNonStaticMethod", String.class, Unit.class,
|
||||
int.class, MyRecord.class, List.class);
|
||||
|
||||
assertThat(Modifier.isStatic(method.getModifiers())).isFalse();
|
||||
|
||||
var functionCallback = MethodFunctionCallback.builder()
|
||||
.functionObject(new TestClassWithFunctionMethods())
|
||||
.method(method)
|
||||
.description("weather at location")
|
||||
.mapper(new ObjectMapper())
|
||||
.build();
|
||||
|
||||
String response = functionCallback.call(this.value);
|
||||
|
||||
assertThat(response).isEqualTo("23");
|
||||
|
||||
assertThat(arguments).hasSize(5);
|
||||
assertThat(arguments.get("city")).isEqualTo("Barcelona");
|
||||
assertThat(arguments.get("unit")).isEqualTo(Unit.CELSIUS);
|
||||
assertThat(arguments.get("intNumber")).isEqualTo(123);
|
||||
assertThat(arguments.get("record")).isEqualTo(new MyRecord("foo", "bar"));
|
||||
assertThat(arguments.get("intList")).isEqualTo(List.of(1, 2, 3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noArgsNoReturnMethod() throws NoSuchMethodException, SecurityException {
|
||||
|
||||
Method method = TestClassWithFunctionMethods.class.getMethod("argumentLessReturnVoid");
|
||||
|
||||
assertThat(Modifier.isStatic(method.getModifiers())).isTrue();
|
||||
|
||||
var functionCallback = MethodFunctionCallback.builder()
|
||||
.method(method)
|
||||
.description("weather at location")
|
||||
.mapper(new ObjectMapper())
|
||||
.build();
|
||||
|
||||
String response = functionCallback.call(this.value);
|
||||
|
||||
assertThat(response).isEqualTo("Done");
|
||||
|
||||
assertThat(arguments.get("method called")).isEqualTo("argumentLessReturnVoid");
|
||||
}
|
||||
|
||||
record MyRecord(String foo, String bar) {
|
||||
}
|
||||
|
||||
@@ -80,98 +174,4 @@ public class MethodFunctionCallbackTests {
|
||||
|
||||
}
|
||||
|
||||
public static Map<String, Object> arguments = new ConcurrentHashMap<>();
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEach() {
|
||||
arguments.clear();
|
||||
}
|
||||
|
||||
String value = """
|
||||
{
|
||||
"unit": "CELSIUS",
|
||||
"city": "Barcelona",
|
||||
"intNumber": 123,
|
||||
"record": {
|
||||
"foo": "foo",
|
||||
"bar": "bar"
|
||||
},
|
||||
"intList": [1, 2, 3]
|
||||
}
|
||||
""";
|
||||
|
||||
@Test
|
||||
public void staticMethod() throws NoSuchMethodException, SecurityException {
|
||||
|
||||
Method method = ReflectionUtils.findMethod(TestClassWithFunctionMethods.class, "myStaticMethod", String.class,
|
||||
Unit.class, int.class, MyRecord.class, List.class);
|
||||
|
||||
assertThat(method).isNotNull();
|
||||
assertThat(Modifier.isStatic(method.getModifiers())).isTrue();
|
||||
|
||||
var functionCallback = MethodFunctionCallback.builder()
|
||||
.method(method)
|
||||
.description("weather at location")
|
||||
.mapper(new ObjectMapper())
|
||||
.build();
|
||||
|
||||
String response = functionCallback.call(value);
|
||||
|
||||
assertThat(response).isEqualTo("23");
|
||||
|
||||
assertThat(arguments).hasSize(5);
|
||||
assertThat(arguments.get("city")).isEqualTo("Barcelona");
|
||||
assertThat(arguments.get("unit")).isEqualTo(Unit.CELSIUS);
|
||||
assertThat(arguments.get("intNumber")).isEqualTo(123);
|
||||
assertThat(arguments.get("record")).isEqualTo(new MyRecord("foo", "bar"));
|
||||
assertThat(arguments.get("intList")).isEqualTo(List.of(1, 2, 3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonStaticMethod() throws NoSuchMethodException, SecurityException {
|
||||
|
||||
Method method = TestClassWithFunctionMethods.class.getMethod("myNonStaticMethod", String.class, Unit.class,
|
||||
int.class, MyRecord.class, List.class);
|
||||
|
||||
assertThat(Modifier.isStatic(method.getModifiers())).isFalse();
|
||||
|
||||
var functionCallback = MethodFunctionCallback.builder()
|
||||
.functionObject(new TestClassWithFunctionMethods())
|
||||
.method(method)
|
||||
.description("weather at location")
|
||||
.mapper(new ObjectMapper())
|
||||
.build();
|
||||
|
||||
String response = functionCallback.call(value);
|
||||
|
||||
assertThat(response).isEqualTo("23");
|
||||
|
||||
assertThat(arguments).hasSize(5);
|
||||
assertThat(arguments.get("city")).isEqualTo("Barcelona");
|
||||
assertThat(arguments.get("unit")).isEqualTo(Unit.CELSIUS);
|
||||
assertThat(arguments.get("intNumber")).isEqualTo(123);
|
||||
assertThat(arguments.get("record")).isEqualTo(new MyRecord("foo", "bar"));
|
||||
assertThat(arguments.get("intList")).isEqualTo(List.of(1, 2, 3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noArgsNoReturnMethod() throws NoSuchMethodException, SecurityException {
|
||||
|
||||
Method method = TestClassWithFunctionMethods.class.getMethod("argumentLessReturnVoid");
|
||||
|
||||
assertThat(Modifier.isStatic(method.getModifiers())).isTrue();
|
||||
|
||||
var functionCallback = MethodFunctionCallback.builder()
|
||||
.method(method)
|
||||
.description("weather at location")
|
||||
.mapper(new ObjectMapper())
|
||||
.build();
|
||||
|
||||
String response = functionCallback.call(value);
|
||||
|
||||
assertThat(response).isEqualTo("Done");
|
||||
|
||||
assertThat(arguments.get("method called")).isEqualTo("argumentLessReturnVoid");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,5 +31,6 @@
|
||||
<suppress files="BaseOllamaIT.java" checks="HideUtilityClassConstructor"/>
|
||||
<suppress files="BaseOCIGenAITest.java" checks="HideUtilityClassConstructor"/>
|
||||
<suppress files="OpenAiChatModelResponseFormatIT.java" checks="RegexpSinglelineJava"/>
|
||||
<suppress files="MethodFunctionCallbackTests.java" checks="RegexpSinglelineJava"/>
|
||||
|
||||
</suppressions>
|
||||
|
||||
Reference in New Issue
Block a user