/** * Task Orchestrator — 任务编排器 * * 支持父子委派模式:主 Agent 委派子任务给 SubAgent。 * * @see docs/生产级通用 AI Agent 智能体桌面应用:完整设计与构建指南.html — 第五章 */ import { EventEmitter } from 'events'; import { nanoid } from 'nanoid'; 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(); /** * 委派子任务 * * 创建一个子任务句柄,通过事件驱动的方式执行。 * 实际执行逻辑由上层 Agent Loop 决定。 */ 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 }); // 返回一个可被上层消费的 Promise return new Promise((resolve) => { const handle: SubAgentHandle = { taskId, description: params.description, status: 'pending', abort: () => { handle.status = 'error'; this.activeSubAgents.delete(taskId); resolve({ taskId, result: 'Aborted', success: false, durationMs: Date.now() - startMs }); }, onComplete: (callback) => { if (handle.result) callback(handle.result); }, onError: (_callback) => {}, getStatus: () => ({ taskId, status: handle.status, description: handle.description }), }; this.activeSubAgents.set(taskId, handle); // 立即标记为运行中 handle.status = 'running'; this.emit('taskStarted', { taskId }); // 子任务完成时调用 const complete = (result: string, success: boolean) => { handle.status = success ? 'completed' : 'error'; handle.result = { taskId, result, success, durationMs: Date.now() - startMs }; this.activeSubAgents.delete(taskId); this.emit('taskCompleted', handle.result); resolve(handle.result); }; // 暴露完成方法给调用者 (handle as unknown as Record).complete = complete; }); } /** * 完成子任务 */ completeTask(taskId: string, result: string, success: boolean): void { const handle = this.activeSubAgents.get(taskId); if (handle) { const complete = (handle as unknown as Record).complete as ((result: string, success: boolean) => void) | undefined; complete?.(result, success); } } 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(); } }