/** * Standalone Entry - 独立运行入口 * * 三个职责: * 1. runMasterSession() — Master CLI 会话(默认入口,工具编排) * 2. runOrchestration() — 完整多 Agent 编排(向后兼容 + 直接执行) * 3. runSingleAgent() — 单个 Agent 执行(给 Extension mas-run 命令用) * * 共享进程级 RunRegistry 单例,确保同一运行时的进程追踪一致。 */ const path = require('path'); const fs = require('fs'); const { RunRegistry } = require('./engine'); // ─── 进程级单例 ─── let _sharedRegistry = null; function getRegistry() { if (!_sharedRegistry) _sharedRegistry = new RunRegistry(); return _sharedRegistry; } /** * 运行完整编排流程 * * @param {string} task - 任务描述 * @param {object} [options] * @param {string} [options.workDir] - 工作目录 (默认 cwd) * @param {number} [options.maxRepairs] - 最大修复轮次 (默认 5) * @param {string[]} [options.agentFilter] - Agent 过滤列表 * @param {object} [options.config] - 自定义配置 (默认读 agents.json) * @returns {Promise} */ async function runOrchestration(task, options = {}) { const { Orchestrator } = require('./core/orchestrator'); const config = options.config || loadConfig(options.agentFilter); const workDir = options.workDir || process.cwd(); const registry = getRegistry(); const orchestrator = new Orchestrator(config, workDir, { runRegistry: registry, }); try { return await orchestrator.execute(task, { maxIterations: options.maxRepairs || 5, }); } finally { await orchestrator.shutdown(); } } /** * 运行单个 Agent * * @param {string} agentName - Agent 名称 * @param {string} prompt - 任务 prompt * @param {object} [options] * @param {string} [options.workDir] - 工作目录 * @returns {Promise} */ async function runSingleAgent(agentName, prompt, options = {}) { const AgentManager = require('./core/agent-manager'); const config = loadConfig(); const workDir = options.workDir || process.cwd(); const registry = getRegistry(); const manager = new AgentManager(config, workDir, { runRegistry: registry }); try { return await manager.callAgent(agentName, prompt); } finally { await manager.closeAllSessions(); } } /** * 加载配置:从 backends.json 读取 clients/launchers,agents 从可选的 agents.json 补充 * @param {string[]} [agentFilter] - 只保留指定 Agent (master 始终保留) */ function loadConfig(agentFilter) { const configDir = path.resolve(__dirname, '../config'); const backends = JSON.parse(fs.readFileSync(path.join(configDir, 'backends.json'), 'utf-8')); // 可选:从 config/agents.json 加载静态 agent 定义 let agents = {}; const agentsPath = path.join(configDir, 'agents.json'); if (fs.existsSync(agentsPath)) { agents = JSON.parse(fs.readFileSync(agentsPath, 'utf-8')); } const config = { ...backends, agents, agentGroups: {}, settings: { maxIterations: 10, timeout: 600000, logsDir: '.autodev-logs' }, }; // 桥接 launchers → clients if (config.launchers && !config.clients) { config.clients = {}; for (const [name, launcher] of Object.entries(config.launchers)) { config.clients[name] = { name, command: launcher.command, acpArgs: launcher.args || [], acpProtocol: launcher.protocol || 'acp', }; } } if (agentFilter?.length > 0) { const filtered = {}; for (const name of agentFilter) { if (config.agents[name]) filtered[name] = config.agents[name]; } if (config.agents.master) filtered.master = config.agents.master; config.agents = filtered; } return config; } /** * 运行 Master CLI 会话(默认入口) * * 启动一个 MasterSession,Master 可以直接对话或通过工具调用 Sub Agent。 * * @param {string} message - 用户消息 * @param {object} [options] * @param {string} [options.workDir] - 工作目录 (默认 cwd) * @param {object} [options.config] - 自定义配置 * @param {function} [options.onData] - 流式数据回调 * @param {function} [options.onToolCall] - 工具调用通知 * @returns {Promise} */ async function runMasterSession(message, options = {}) { const { MasterSession } = require('./core/master-session'); const config = options.config || loadConfig(); const workDir = options.workDir || process.cwd(); const registry = getRegistry(); const session = new MasterSession(config, workDir, { runRegistry: registry, }); try { return await session.handleMessage(message, { onData: options.onData, onToolCall: options.onToolCall, maxToolRounds: options.maxToolRounds || 10, }); } finally { await session.shutdown(); } } module.exports = { runMasterSession, runOrchestration, runSingleAgent, getRegistry, loadConfig };