Files
metona-ai-desktop/electron/harness/orchestration/orchestrator.ts
T
thzxx 1d185db6b3 feat: MetonaAI Desktop 初始项目
- Electron + React + TypeScript 架构
- 三栏布局: Sidebar | ChatPanel | DetailPanel
- 9 个内置工具 (文件系统/网络/记忆/命令)
- SQLite 持久化 (better-sqlite3)
- MUI 暗色/亮色主题系统
- Agent Loop ReAct 状态机引擎
- DeepSeek / Agnes AI / Ollama Provider 适配器
- MCP 协议集成
- 系统托盘 + 全局快捷键
- Tailwind CSS v4 + Tailwind Merge
- 修复: Sidebar 缺失 TextField 导入导致黑屏
2026-06-27 21:33:27 +08:00

111 lines
3.4 KiB
TypeScript

/**
* 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<string, SubAgentHandle>();
/**
* 委派子任务
*
* 创建一个子任务句柄,通过事件驱动的方式执行。
* 实际执行逻辑由上层 Agent Loop 决定。
*/
async delegate(params: {
taskId?: string;
description: string;
parentSessionId: string;
maxIterations?: number;
tools?: string[];
}): Promise<SubAgentResult> {
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<SubAgentResult>((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<string, unknown>).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<string, unknown>).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();
}
}