001/*
002 *  Copyright (c) 2023-2026, Agents-Flex (fuhai999@gmail.com).
003 *  <p>
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *  <p>
008 *  http://www.apache.org/licenses/LICENSE-2.0
009 *  <p>
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package com.agentsflex.core.model.chat.tool;
017
018import com.agentsflex.core.model.chat.tool.annotation.ToolDef;
019import com.agentsflex.core.util.ArrayUtil;
020import com.agentsflex.core.util.ClassUtil;
021
022import java.lang.reflect.Method;
023import java.lang.reflect.Modifier;
024import java.util.ArrayList;
025import java.util.List;
026
027/**
028 * 扫描带有 {@link ToolDef} 注解的方法,并将其转换为 {@link Tool} 实例。
029 */
030public class ToolScanner {
031
032    /**
033     * 从指定对象实例中扫描并提取带 {@link ToolDef} 注解的方法,生成工具列表。
034     *
035     * @param object      对象实例(用于非静态方法)
036     * @param methodNames 可选,指定要扫描的方法名;若为空则扫描所有带注解的方法
037     * @return 工具列表
038     */
039    public static List<Tool> scan(Object object, String... methodNames) {
040        return doScan(object.getClass(), object, methodNames);
041    }
042
043    /**
044     * 从指定类中扫描并提取带 {@link ToolDef} 注解的静态方法,生成工具列表。
045     *
046     * @param clazz       类(仅扫描静态方法)
047     * @param methodNames 可选,指定要扫描的方法名;若为空则扫描所有带注解的方法
048     * @return 工具列表
049     */
050    public static List<Tool> scan(Class<?> clazz, String... methodNames) {
051        return doScan(clazz, null, methodNames);
052    }
053
054    private static List<Tool> doScan(Class<?> clazz, Object object, String... methodNames) {
055        clazz = ClassUtil.getUsefulClass(clazz);
056        List<Method> methodList = ClassUtil.getAllMethods(clazz, method -> {
057            if (object == null && !Modifier.isStatic(method.getModifiers())) {
058                return false;
059            }
060            if (method.getAnnotation(ToolDef.class) == null) {
061                return false;
062            }
063            return methodNames.length == 0 || ArrayUtil.contains(methodNames, method.getName());
064        });
065
066        List<Tool> tools = new ArrayList<>();
067        for (Method method : methodList) {
068            MethodTool tool = new MethodTool();
069            tool.setClazz(clazz);
070            tool.setMethod(method);
071            if (!Modifier.isStatic(method.getModifiers())) {
072                tool.setObject(object);
073            }
074            tools.add(tool);
075        }
076        return tools;
077    }
078}