fix(skill): also accept Spring bean names as tool-dep identifiers

This commit is contained in:
matevip 2026-04-24 23:24:52 +08:00
parent 4c861006dc
commit 7b038522aa

View File

@ -168,20 +168,61 @@ public class ToolRegistry {
} }
/** /**
* Returns the set of runtime tool function names i.e. the exact identifiers * Returns every runtime identifier by which a currently-enabled tool can be
* LLMs and skill manifests use to reference tools (the @Tool method name, the * referenced SKILL.md authors use all three conventions interchangeably:
* MCP tool name, or the registered plugin tool name). * <ul>
* * <li>{@code @Tool} function name (e.g. {@code browser_use}, {@code runSkillScript})</li>
* <p>Use this for dependency / availability checks instead of querying the * <li>Spring bean name (e.g. {@code browserUseTool}, {@code skillScriptTool})</li>
* {@code mate_tool} table directly: the DB overlay stores class/bean names, * <li>MCP tool id / plugin tool name (routed via {@code ToolCallbackProvider})</li>
* which do not match the function-name vocabulary skills declare against. * </ul>
* Returning the union lets {@link vip.mate.skill.runtime.SkillDependencyChecker}
* accept whichever convention a skill happens to declare.
*/ */
public Set<String> availableFunctionNames() { public Set<String> availableFunctionNames() {
Set<String> names = new java.util.HashSet<>(); Set<String> names = new java.util.HashSet<>();
AgentToolSet toolSet = getEnabledToolSet();
for (ToolCallback cb : toolSet.callbacks()) { Set<String> disabledBeanNames = toolMapper.selectList(
names.add(cb.getToolDefinition().name()); new LambdaQueryWrapper<ToolEntity>()
.eq(ToolEntity::getEnabled, false)
.isNotNull(ToolEntity::getBeanName)
).stream().map(ToolEntity::getBeanName).collect(Collectors.toSet());
// 1. @Tool beans register both the bean name and every function name exposed.
Map<String, Object> beans = applicationContext.getBeansWithAnnotation(Component.class);
for (Map.Entry<String, Object> entry : beans.entrySet()) {
String beanName = entry.getKey();
Object bean = entry.getValue();
if (disabledBeanNames.contains(beanName)) continue;
boolean hasToolMethod = java.util.Arrays.stream(bean.getClass().getMethods())
.anyMatch(m -> m.isAnnotationPresent(Tool.class));
if (!hasToolMethod) continue;
names.add(beanName);
for (ToolCallback cb : ToolCallbacks.from(bean)) {
names.add(cb.getToolDefinition().name());
}
} }
// 2. MCP providers only function names exist here.
Map<String, ToolCallbackProvider> providers = applicationContext.getBeansOfType(ToolCallbackProvider.class);
for (ToolCallbackProvider provider : providers.values()) {
ToolCallback[] cbs = provider.getToolCallbacks();
if (cbs == null) continue;
for (ToolCallback cb : cbs) {
names.add(cb.getToolDefinition().name());
}
}
// 3. Plugin-registered tools evaluate availability lazily so disabled plugins drop out.
for (PluginToolEntry entry : pluginTools) {
try {
if (Boolean.TRUE.equals(entry.availabilityCheck().get())) {
names.add(entry.callback().getToolDefinition().name());
}
} catch (Exception ignored) {
// Unreachable plugin tools don't contribute to the set.
}
}
return names; return names;
} }