call-agent-tool.js 3.68 KB
/**
 * call-agent-tool.js — Sub Agent 直接调用工具
 *
 * 让 Master Agent 直接调用指定的 Sub Agent。
 * Master 获取 orchestrate plan 后,按步骤逐个调用此工具执行。
 */

/**
 * 创建 call_sub_agent 工具定义
 * @returns {ToolDefinition}
 */
function createCallAgentTool() {
    return {
        name: 'call_sub_agent',
        description: `直接调用一个 Sub Agent 执行任务。你可以指定 agent 名称和任务描述。
适用场景:
- 简单任务,直接调用对应 Agent
- 按照 orchestrate 工具返回的 plan,逐步调用 Agent
- 修复循环中,指定 executor 修复特定问题`,

        parameters: {
            type: 'object',
            required: ['agent', 'task'],
            properties: {
                agent: {
                    type: 'string',
                    description: '要调用的 Agent 名称(如 coder, verifier, writer 等)',
                },
                task: {
                    type: 'string',
                    description: '给该 Agent 的任务描述',
                },
            },
        },

        async execute(params, context) {
            const { agent, task } = params;
            const { agentManager, onSubAgentData } = context;

            if (!agentManager) {
                throw new Error('call_sub_agent 需要 agentManager');
            }

            // 验证 agent 存在(所有 skill 已通过 skill-config-loader 加载到 config.agents)
            try {
                agentManager.getAgentConfig(agent);
            } catch {
                const available = agentManager.listAgents().map(a => a.name).join(', ');
                throw new Error(`Agent "${agent}" 不存在。可用 Agent: ${available}`);
            }

            // 调用 agent,传递流式回调
            const result = await agentManager.callAgent(agent, task, {
                onData: (chunk) => {
                    if (onSubAgentData && chunk && chunk.trim()) {
                        onSubAgentData(agent, chunk);
                    }
                },
            });

            return {
                agent,
                status: 'success',
                output: result.output || '',
            };
        },
    };
}

/**
 * 创建 list_agents 工具定义
 * @returns {ToolDefinition}
 */
function createListAgentsTool() {
    return {
        name: 'list_agents',
        description: '列出所有可用的 Sub Agent 及其描述。在不确定该调用哪个 Agent 时使用。',

        parameters: {
            type: 'object',
            properties: {},
        },

        async execute(_params, context) {
            const { agentManager, config } = context;

            const agents = [];
            const agentConfigs = config?.agents || {};

            for (const [name, cfg] of Object.entries(agentConfigs)) {
                // 跳过 master 自身和 gateway
                if (name === 'master' || name === 'gateway') continue;

                agents.push({
                    name,
                    type: cfg.type,
                    description: cfg.description || '',
                });
            }

            // 也列出 agent groups
            const groups = [];
            const groupConfigs = config?.agentGroups || {};
            for (const [name, grp] of Object.entries(groupConfigs)) {
                groups.push({
                    name,
                    description: grp.description || grp.name || '',
                    agents: grp.agents || [],
                    isDefault: grp.default || false,
                });
            }

            return { agents, groups };
        },
    };
}

module.exports = { createCallAgentTool, createListAgentsTool };