/** * Task Orchestrator — 任务编排器 * * 支持父子委派模式:主 Agent 委派子任务给 SubAgent。 * 每个子任务运行一个独立的 AgentLoopEngine 实例。 * * @see docs/生产级通用 AI Agent 智能体桌面应用:完整设计与构建指南.html — 第五章 */ import { EventEmitter } from 'events'; import { nanoid } from 'nanoid'; import type { AgentLoopEngine } from '../agent-loop/engine'; import type { MetonaMessage, MetonaSystemPrompt } from '../types'; import type { ToolRegistry } from '../tools/registry'; import type { MetonaToolDef } from '../types'; import log from 'electron-log'; export interface SubAgentResult { taskId: string; result: string; success: boolean; durationMs: number; } interface SubAgentHandle { taskId: string; description: string; status: 'pending' | 'running' | 'completed' | 'error'; result?: SubAgentResult; abort: () => void; onComplete: (callback: (result: SubAgentResult) => void) => void; onError: (callback: (error: Error) => void) => void; getStatus: () => { taskId: string; status: string; description: string }; } export class TaskOrchestrator extends EventEmitter { private activeSubAgents = new Map(); constructor( private agentLoopEngine: AgentLoopEngine, private toolRegistry?: ToolRegistry, ) { super(); } /** * 委派子任务 * * 创建一个独立的 SubAgent 执行上下文,调用 AgentLoopEngine 完成任务。 * 支持限制可用工具列表(白名单)。 */ async delegate(params: { taskId?: string; description: string; parentSessionId: string; maxIterations?: number; tools?: string[]; }): Promise { const taskId = params.taskId ?? `sub_${nanoid(8)}`; const startMs = Date.now(); this.emit('taskDelegated', { taskId, description: params.description, parentSessionId: params.parentSessionId }); const handle: SubAgentHandle = { taskId, description: params.description, status: 'running', abort: () => { handle.status = 'error'; this.activeSubAgents.delete(taskId); }, onComplete: (callback) => { if (handle.result) callback(handle.result); }, onError: (callback) => { /* errors captured by try/catch below */ }, getStatus: () => ({ taskId, status: handle.status, description: handle.description }), }; this.activeSubAgents.set(taskId, handle); this.emit('taskStarted', { taskId }); try { // 构建用户消息 const userMessage: MetonaMessage = { role: 'user', content: params.description, timestamp: Date.now(), }; // 构建 System Prompt(子 Agent 简化版) const systemPrompt: MetonaSystemPrompt = { roleDefinition: '你是一个子任务执行 Agent,负责完成被委派的单一任务。', outputConstraints: '用中文回答,简洁准确地完成任务。', safetyGuidelines: '不访问工作空间外的文件,不执行危险命令。', }; // 保存原始工具列表(子任务完成后恢复) const savedTools = this.agentLoopEngine.getTools?.() ?? []; // 如果指定了工具白名单,设置受限工具集 if (params.tools && params.tools.length > 0 && this.toolRegistry) { const allowedTools: MetonaToolDef[] = []; for (const toolName of params.tools) { const tool = this.toolRegistry.get(toolName); if (tool) { allowedTools.push({ name: tool.definition.name, description: tool.definition.description, parameters: tool.definition.parameters, category: tool.definition.category, riskLevel: tool.definition.riskLevel, requiresPermission: tool.definition.requiresPermission, timeoutMs: tool.definition.timeoutMs, }); } } this.agentLoopEngine.setTools(allowedTools); } // 运行 Agent Loop(同步等待完成) let output; try { output = await this.agentLoopEngine.runStream( userMessage, taskId, [], // 子 Agent 无历史 systemPrompt, ); } finally { // 恢复主 Agent 的原始工具列表 this.agentLoopEngine.setTools(savedTools); } const durationMs = Date.now() - startMs; const success = output.terminationReason === 'completed'; const result: SubAgentResult = { taskId, result: output.finalAnswer, success, durationMs, }; handle.status = success ? 'completed' : 'error'; handle.result = result; this.activeSubAgents.delete(taskId); this.emit('taskCompleted', result); log.info(`[Orchestrator] SubAgent "${taskId}" ${success ? 'completed' : 'failed'} in ${durationMs}ms`); return result; } catch (error) { const durationMs = Date.now() - startMs; const errMsg = (error as Error).message; const result: SubAgentResult = { taskId, result: errMsg, success: false, durationMs, }; handle.status = 'error'; handle.result = result; this.activeSubAgents.delete(taskId); this.emit('taskError', { taskId, error: errMsg }); log.error(`[Orchestrator] SubAgent "${taskId}" error: ${errMsg}`); return result; } } /** * 完成子任务(外部触发) */ completeTask(taskId: string, result: string, success: boolean): void { const handle = this.activeSubAgents.get(taskId); if (handle && handle.status === 'running') { handle.status = success ? 'completed' : 'error'; handle.result = { taskId, result, success, durationMs: 0 }; this.activeSubAgents.delete(taskId); this.emit('taskCompleted', handle.result); } } getActiveAgentsStatus(): Array<{ taskId: string; status: string; description: string }> { return Array.from(this.activeSubAgents.values()).map((a) => a.getStatus()); } abortAll(): void { for (const agent of this.activeSubAgents.values()) { agent.abort(); } this.activeSubAgents.clear(); } }