Skip to content

feat(tool): support auto tool scan and registration from Spring Context#1192

Open
jujn wants to merge 5 commits intoagentscope-ai:mainfrom
jujn:feat_821
Open

feat(tool): support auto tool scan and registration from Spring Context#1192
jujn wants to merge 5 commits intoagentscope-ai:mainfrom
jujn:feat_821

Conversation

@jujn
Copy link
Copy Markdown
Contributor

@jujn jujn commented Apr 11, 2026

Description

Close #821
This PR enables automatic discovery of Spring Beans annotated with @Tool, significantly reducing manual configuration. It also refactors the core tool invocation logic to ensure compatibility with Spring AOP proxies (e.g., @Transactional, @Async).

Key Changes

1. Core Package Enhancements

  • Toolkit.java: Enhanced the registration API to accept a targetClass alongside the tool instance. This allows the toolkit to scan for annotations on the unproxied class while executing calls on the proxy instance.

  • ToolMethodInvoker.java: Refactored invokeAsync to separate metadata extraction (originalMethod) from actual reflection execution (executableMethod). This prevents annotation loss typically caused by CGLIB or JDK dynamic proxies.

2. Spring Boot Starter Integration

  • AgentscopeToolRegistrar: Implemented a SmartInitializingSingleton to scan the ApplicationContext safely after all beans are initialized.

    • Fail-Fast Validation: Added global uniqueness checks for tool names to prevent LLM routing conflicts.
    • AOP & Inheritance Support: Utilizes Spring's MethodIntrospector and hierarchy traversal to support tools defined in interfaces or superclasses.
    • Graceful Handling: Includes warning logs for @Lazy beans that require early initialization and filters out non-singleton beans to prevent memory leaks.
  • AgentscopeAutoConfiguration:

    • Template & Prototype Scoping: Configured a singleton globalAgentscopeToolkit as a centralized registry to collect all auto-scanned tools at startup. Exposed a prototype-scoped agentscopeToolkit bean that deep-copies this global template, ensuring thread-safe, isolated state for each agent at runtime.
  • AgentscopeProperties: Centralized tool configuration under agentscope.tool.auto-scan, allowing users to easily toggle the feature.

3. Testing & Documentation

@jujn jujn requested review from a team and Copilot April 11, 2026 11:51
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds Spring Boot integration to automatically discover and register @Tool-annotated Spring Bean methods into an AgentScope Toolkit, and refactors the core tool invocation/registration path to work correctly with Spring AOP proxies by separating “metadata methods” from “executable methods”.

Changes:

  • Add a Spring Boot SmartInitializingSingleton registrar that scans the ApplicationContext for @Tool methods and registers them into a global Toolkit template.
  • Refactor Toolkit registration and ToolMethodInvoker invocation to support proxy-safe annotation/metadata extraction while still invoking through proxy methods for AOP.
  • Add Spring Boot starter properties, tests, and update EN/ZH documentation for auto-scan behavior and configuration.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
docs/zh/task/tool.md Documents Spring Boot auto-scan usage/config and behavior notes (ZH).
docs/en/task/tool.md Documents Spring Boot auto-scan usage/config and behavior notes (EN).
agentscope-extensions/.../AgentscopeToolAutoScanTest.java Adds coverage for auto-scan enablement, proxies, lazy beans, prototype filtering, duplicates, inheritance.
agentscope-extensions/.../AgentscopeAutoConfigurationTest.java Updates expectations for new Toolkit bean arrangement.
agentscope-extensions/.../AgentscopeToolRegistrar.java Implements Spring context scanning + registration into a Toolkit.
agentscope-extensions/.../ToolProperties.java Adds agentscope.tool.auto-scan.enabled property model (default enabled).
agentscope-extensions/.../AgentscopeProperties.java Wires ToolProperties under agentscope.tool.
agentscope-extensions/.../AgentscopeAutoConfiguration.java Introduces global template Toolkit + prototype cloned Toolkit; wires registrar.
agentscope-core/.../ToolMethodInvoker*.java Updates invoker API to accept both original/executable methods; adjusts tests.
agentscope-core/.../Toolkit.java Adds targetClass-aware registration and passes original/executable methods to invoker.

Comment on lines +139 to +176
// Build the complete class hierarchy tree (including all superclasses and
// interfaces)
Set<Class<?>> hierarchy = new LinkedHashSet<>();
Class<?> current = originalClass;
while (current != null && current != Object.class) {
hierarchy.add(current);
current = current.getSuperclass();
}
hierarchy.addAll(ClassUtils.getAllInterfacesForClassAsSet(originalClass));

// Filter the hierarchy to find ONLY the classes/interfaces declaring @Tool.
Set<Class<?>> classesToScan = new LinkedHashSet<>();
for (Class<?> clazz : hierarchy) {
// Skip Java and Spring internal interfaces
if (clazz.getName().startsWith("java.")
|| clazz.getName().startsWith("org.springframework.")) {
continue;
}

// Inspect the declared methods to verify if this class/interface contains
// tools
for (Method m : clazz.getDeclaredMethods()) {
if (m.isAnnotationPresent(Tool.class)) {
classesToScan.add(clazz);
break;
}
}
}

for (Class<?> clazzToScan : classesToScan) {
// Pass both the proxy instance (bean) and the specific declaring
// class/interface (clazzToScan).
// This ensures AgentScope extracts metadata (like @Tool) from the exact
// interface/superclass,
// while still routing actual method executions through the proxy to
// preserve Spring AOP aspects.
toolkit.registration().tool(bean, clazzToScan).apply();
}
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The registrar registers tools once per clazzToScan in the hierarchy. If the same tool method is annotated in multiple hierarchy elements (e.g., both an interface and the implementing class, or a superclass and subclass), this will attempt to register the same tool name multiple times; ToolRegistry overwrites silently, and the earlier duplicate-name fail-fast check may not catch this case. Consider deduplicating by tool name per bean (and defining a clear precedence order, e.g., most-specific class wins over interfaces/superclasses) before calling toolkit.registration().tool(...).apply().

Copilot uses AI. Check for mistakes.
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 11, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Support auto tool scan and registration from Spring Context.

2 participants