From 462f3d504ccd282bf448e94b9ed33f47978a847f Mon Sep 17 00:00:00 2001 From: juanjuandog Date: Sun, 24 May 2026 22:12:11 +0800 Subject: [PATCH] Fix direct ToolCallback overload selection Signed-off-by: juanjuandog --- .../ai/chat/client/ChatClient.java | 16 ++++++++++++++++ .../client/DefaultChatClientBuilderTests.java | 17 +++++++++++++++++ .../ai/chat/client/DefaultChatClientTests.java | 15 +++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/ChatClient.java b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/ChatClient.java index 846b5a9363..fd55045705 100644 --- a/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/ChatClient.java +++ b/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/ChatClient.java @@ -223,6 +223,14 @@ interface ChatClientRequestSpec { ChatClientRequestSpec tools(Consumer consumer); + default ChatClientRequestSpec tools(ToolCallback... toolCallbacks) { + return tools(t -> t.callbacks(toolCallbacks)); + } + + default ChatClientRequestSpec tools(ToolCallbackProvider... toolCallbackProviders) { + return tools(t -> t.callbacks(toolCallbackProviders)); + } + ChatClientRequestSpec tools(Object... toolObjects); /** @@ -337,6 +345,14 @@ interface Builder { Builder defaultTools(Consumer consumer); + default Builder defaultTools(ToolCallback... toolCallbacks) { + return defaultTools(t -> t.callbacks(toolCallbacks)); + } + + default Builder defaultTools(ToolCallbackProvider... toolCallbackProviders) { + return defaultTools(t -> t.callbacks(toolCallbackProviders)); + } + Builder defaultTools(Object... toolObjects); /** diff --git a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/DefaultChatClientBuilderTests.java b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/DefaultChatClientBuilderTests.java index 3afc42bf06..9f3fa82d1d 100644 --- a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/DefaultChatClientBuilderTests.java +++ b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/DefaultChatClientBuilderTests.java @@ -24,6 +24,8 @@ import org.springframework.ai.chat.client.advisor.ToolCallAdvisor; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.model.tool.ToolCallingManager; +import org.springframework.ai.tool.ToolCallback; +import org.springframework.ai.tool.function.FunctionToolCallback; import org.springframework.core.io.ClassPathResource; import org.springframework.test.util.ReflectionTestUtils; @@ -86,6 +88,21 @@ void whenToolCallingManagerThenPropagatedToRequestSpec() { assertThat(ReflectionTestUtils.getField(advisorBuilder, "toolCallingManager")).isSameAs(manager); } + @Test + void whenToolCallbackPassedDirectlyToDefaultToolsThenReturn() { + ToolCallback toolCallback = FunctionToolCallback.builder("directDefaultTool", input -> "hello") + .description("description") + .inputType(String.class) + .build(); + + var builder = new DefaultChatClientBuilder(mock(ChatModel.class)); + builder.defaultTools(toolCallback); + + var defaultRequest = (DefaultChatClient.DefaultChatClientRequestSpec) ReflectionTestUtils.getField(builder, + "defaultRequest"); + assertThat(defaultRequest.getToolCallbacks()).containsExactly(toolCallback); + } + @Test void whenUserResourceIsNullThenThrows() { DefaultChatClientBuilder builder = new DefaultChatClientBuilder(mock(ChatModel.class)); diff --git a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/DefaultChatClientTests.java b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/DefaultChatClientTests.java index e3be63fd45..d567b859b2 100644 --- a/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/DefaultChatClientTests.java +++ b/spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/DefaultChatClientTests.java @@ -1787,6 +1787,21 @@ void whenToolCallbacksThenReturn() { assertThat(defaultSpec.getToolCallbacks()).contains(toolCallback); } + @Test + void whenToolCallbackPassedDirectlyToToolsThenReturn() { + ChatClient chatClient = new DefaultChatClientBuilder(mockChatModel()).build(); + ChatClient.ChatClientRequestSpec spec = chatClient.prompt(); + ToolCallback toolCallback = FunctionToolCallback.builder("directTool", input -> "hello") + .description("description") + .inputType(String.class) + .build(); + + spec = spec.tools(toolCallback); + + DefaultChatClient.DefaultChatClientRequestSpec defaultSpec = (DefaultChatClient.DefaultChatClientRequestSpec) spec; + assertThat(defaultSpec.getToolCallbacks()).containsExactly(toolCallback); + } + @Test void whenFunctionNameIsNullThenThrow() { ChatClient chatClient = new DefaultChatClientBuilder(mockChatModel()).build();