package vip.mate.tool.builtin; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.chat.model.ToolContext; import org.springframework.ai.tool.ToolCallback; import org.springframework.ai.tool.annotation.Tool; import org.springframework.ai.tool.annotation.ToolParam; import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; import vip.mate.agent.AgentToolSet; import vip.mate.agent.binding.service.AgentBindingService; import vip.mate.agent.context.ChatOrigin; import vip.mate.tool.ToolRegistry; import vip.mate.tool.disclosure.DisclosureTier; import vip.mate.tool.disclosure.ToolDisclosureService; import java.util.Set; /** * Activates an extension-tier tool for the rest of the conversation. *
* The model calls this after spotting a tool in the {@code ## Extension Tools}
* catalog. The tool only validates and returns a confirmation message — the
* activation is recorded into graph state by the action node (tools cannot
* mutate {@code OverAllState} directly), so the enabled tool's schema becomes
* visible on the next reasoning turn of the same ReAct loop.
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class EnableExtensionTool {
private final ToolRegistry toolRegistry;
private final ToolDisclosureService toolDisclosureService;
private final AgentBindingService agentBindingService;
@Tool(name = "enable_tool", description = """
Activate an extension tool for the rest of this conversation.
Use this when the Extension Tools catalog lists a tool you need to call.
Parameters:
- toolName: The tool's function name exactly as shown in the catalog.
After enabling, issue the real tool call in your NEXT response — it
becomes callable from then on. Only enable a tool the task actually needs.
""")
public String enableTool(
@ToolParam(description = "Extension tool function name from the catalog")
String toolName,
@Nullable ToolContext ctx
) {
if (toolName == null || toolName.isBlank()) {
return "Error: toolName is required. See the Extension Tools catalog for valid names.";
}
// Validate against THIS agent's effective tool set, not the global registry —
// otherwise a tool that exists globally but isn't bound to the agent would be
// reported active yet never appear (the reasoning-node split only activates
// tools in the agent's own set).
AgentToolSet agentSet = toolRegistry.getEnabledToolSet();
Long agentId = ChatOrigin.from(ctx).agentId();
if (agentId != null) {
Set