UNPKG

pdca

Version:

🎯 AI 驅動的 PDCA 多代理開發系統 - 智能循環控制 + 成本管理 + Token 優化 + 多 AI 引擎支援

357 lines (337 loc) 11.2 kB
/** * 多 AI 引擎協調器 * 支援 Claude、Gemini、OpenAI 等多種 AI CLI */ import { EventEmitter } from 'events'; import { spawn } from 'child_process'; import { writeFileSync, mkdirSync, existsSync } from 'fs'; import { join } from 'path'; import { AIEngineManager } from './ai-engine-adapter.js'; import { CommunicationManager } from './communication-manager.js'; import { AgentRole } from './message-protocol.js'; export class MultiAIOrchestrator extends EventEmitter { engineManager; selectedEngine; communicationManager; sessionName; agents = new Map(); communicationDir; constructor(options = {}) { super(); this.engineManager = new AIEngineManager(); this.sessionName = options.sessionName || 'pdca'; this.communicationDir = options.communicationDir || '.raiy-pdca/communication'; this.communicationManager = new CommunicationManager({ baseDir: this.communicationDir }); this.initializeAgents(); this.setupDirectories(); } /** * 初始化代理配置 */ initializeAgents() { const agentConfigs = [ { name: 'plan', role: AgentRole.PLAN, windowIndex: 0, systemPrompt: '你是 PDCA 系統的規劃師,負責分析需求、制定策略和協調任務。' }, { name: 'do', role: AgentRole.DO, windowIndex: 1, systemPrompt: '你是 PDCA 系統的執行者,負責實作功能、編寫高品質程式碼。' }, { name: 'check', role: AgentRole.CHECK, windowIndex: 2, systemPrompt: '你是 PDCA 系統的檢查員,負責品質驗證、測試和代碼審查。' }, { name: 'act', role: AgentRole.ACT, windowIndex: 3, systemPrompt: '你是 PDCA 系統的改善者,負責優化效能、重構程式碼。' }, { name: 'knowledge', role: AgentRole.KNOWLEDGE, windowIndex: 4, systemPrompt: '你是 PDCA 系統的知識管理者,負責記錄決策、整理經驗。' } ]; agentConfigs.forEach(config => { this.agents.set(config.name, config); }); } /** * 設置必要目錄 */ setupDirectories() { const dirs = [ '.raiy-pdca', '.raiy-pdca/communication', '.raiy-pdca/scripts', '.raiy-pdca/logs', '.raiy-pdca/agents' ]; dirs.forEach(dir => { if (!existsSync(dir)) { mkdirSync(dir, { recursive: true }); } }); } /** * 啟動系統 */ async start(engineName) { console.log('🚀 啟動 PDCA 多 AI 代理系統...\n'); // 選擇 AI 引擎 if (engineName) { this.selectedEngine = await this.engineManager.selectEngineByName(engineName); } else { this.selectedEngine = await this.engineManager.selectBestEngine(); } // 根據引擎類型決定啟動方式 if (this.selectedEngine.promptFlag) { // 支援直接執行的引擎(如 Gemini) await this.startWithDirectExecution(); } else { // 只支援互動模式的引擎(如 Claude) await this.startWithInteractiveMode(); } // 開始監聽協調器訊息 this.communicationManager.startListening('coordinator'); console.log('\n✅ 系統啟動完成!'); console.log(`📊 使用 tmux attach -t ${this.sessionName} 查看各代理`); this.emit('system-started', this.selectedEngine); } /** * 使用直接執行模式啟動(Gemini 等) */ async startWithDirectExecution() { console.log('📋 使用直接執行模式(支援 -p 參數)\n'); // 創建 tmux session await this.createTmuxSession(); // 為每個代理創建啟動腳本 for (const [name, config] of this.agents) { const script = this.createDirectExecutionScript(name, config); const scriptPath = join('.raiy-pdca/scripts', `agent-${name}.sh`); writeFileSync(scriptPath, script, { mode: 0o755 }); // 在 tmux 中啟動 await this.startAgentInTmux(name, config.windowIndex, scriptPath); } // 啟動監控 await this.startMonitor(); } /** * 使用互動模式啟動(Claude 等) */ async startWithInteractiveMode() { console.log('📋 使用互動模式(不支援直接執行)'); console.log('⚠️ Claude CLI 需要手動互動,建議使用斜線指令 /pdca\n'); // 提示用戶使用斜線指令 console.log('請執行以下步驟:'); console.log('1. 開啟 Claude CLI: claude'); console.log('2. 使用斜線指令: /pdca:start'); console.log('3. 系統將自動配置多代理環境'); // 仍然創建必要的腳本和目錄 await this.createTmuxSession(); for (const [name, config] of this.agents) { const script = this.createInteractiveScript(name, config); const scriptPath = join('.raiy-pdca/scripts', `agent-${name}.sh`); writeFileSync(scriptPath, script, { mode: 0o755 }); } } /** * 創建直接執行腳本(Gemini 模式) */ createDirectExecutionScript(name, config) { const engine = this.selectedEngine; return `#!/bin/bash # PDCA ${name} 代理 - ${engine.name} 模式 ROLE="${name}" COMM_DIR="${this.communicationDir}" ENGINE_CMD="${engine.command}" PROMPT_FLAG="${engine.promptFlag}" echo "🚀 啟動 PDCA $ROLE 代理 (${engine.name})" # 系統提示詞 SYSTEM_PROMPT="${config.systemPrompt}" # 持續監聽循環 while true; do # 檢查是否有新任務 if [ -f "$COMM_DIR/$ROLE.task" ]; then echo "📋 發現新任務" # 讀取任務 TASK=$(cat "$COMM_DIR/$ROLE.task") # 檢查共享上下文 CONTEXT="" if [ -f "$COMM_DIR/shared-context.md" ]; then CONTEXT=$(cat "$COMM_DIR/shared-context.md") fi # 構建完整 prompt FULL_PROMPT="$SYSTEM_PROMPT 專案上下文: $CONTEXT 當前任務: $TASK 請根據你的角色處理這個任務,提供詳細的執行結果。" # 執行 AI echo "🤖 調用 ${engine.name} 處理任務..." RESPONSE=$($ENGINE_CMD $PROMPT_FLAG "$FULL_PROMPT" 2>&1) # 保存結果 echo "$RESPONSE" > "$COMM_DIR/$ROLE.output" echo "✅ 任務完成,結果已保存" # 通知下一個代理 case $ROLE in "plan") echo "ready" > "$COMM_DIR/do.notify" ;; "do") echo "ready" > "$COMM_DIR/check.notify" ;; "check") echo "ready" > "$COMM_DIR/act.notify" ;; esac # 清理任務檔案 rm "$COMM_DIR/$ROLE.task" fi # 檢查系統命令 if [ -f "$COMM_DIR/system.cmd" ]; then CMD=$(cat "$COMM_DIR/system.cmd") if [ "$CMD" = "STOP" ]; then echo "🛑 收到停止命令" break fi fi sleep 2 done `; } /** * 創建互動模式腳本(Claude 模式) */ createInteractiveScript(name, config) { return `#!/bin/bash # PDCA ${name} 代理 - 互動模式 ROLE="${name}" COMM_DIR="${this.communicationDir}" echo "🚀 ${name} 代理準備就緒(互動模式)" echo "請在 Claude CLI 中手動處理任務" echo "監控目錄: $COMM_DIR" # 顯示系統提示 echo "" echo "代理角色說明:" echo "${config.systemPrompt}" echo "" # 簡單的監控循環 while true; do if [ -f "$COMM_DIR/$ROLE.task" ]; then echo "📋 新任務可用,請手動處理" cat "$COMM_DIR/$ROLE.task" fi sleep 5 done `; } /** * 創建 tmux session */ async createTmuxSession() { // 先停止現有 session try { await this.executeBash(`tmux kill-session -t ${this.sessionName}`); } catch { // 忽略錯誤(session 可能不存在) } // 創建新 session await this.executeBash(`tmux new-session -d -s ${this.sessionName} -n plan`); } /** * 在 tmux 中啟動代理 */ async startAgentInTmux(name, windowIndex, scriptPath) { if (windowIndex === 0) { // 第一個窗口已存在 await this.executeBash(`tmux send-keys -t ${this.sessionName}:0 "bash ${scriptPath}" C-m`); } else { // 創建新窗口 await this.executeBash(`tmux new-window -t ${this.sessionName}:${windowIndex} -n ${name}`); await this.executeBash(`tmux send-keys -t ${this.sessionName}:${windowIndex} "bash ${scriptPath}" C-m`); } } /** * 啟動監控介面 */ async startMonitor() { await this.executeBash(`tmux new-window -t ${this.sessionName}:5 -n monitor`); await this.executeBash(`tmux send-keys -t ${this.sessionName}:5 "node dist/core/monitor.js" C-m`); } /** * 分配任務 */ async assignTask(taskDescription) { console.log(`\n📋 分配任務: ${taskDescription}`); // 將任務寫入 plan 代理 const taskFile = join(this.communicationDir, 'plan.task'); writeFileSync(taskFile, taskDescription); console.log('✅ 任務已分配給 Plan 代理'); this.emit('task-assigned', taskDescription); } /** * 獲取系統狀態 */ getStatus() { return { engine: this.selectedEngine?.name || '未選擇', session: this.sessionName, agents: Array.from(this.agents.keys()) }; } /** * 停止系統 */ async stop() { console.log('\n🛑 停止 PDCA 系統...'); // 發送停止命令 const cmdFile = join(this.communicationDir, 'system.cmd'); writeFileSync(cmdFile, 'STOP'); // 等待代理響應 await new Promise(resolve => setTimeout(resolve, 2000)); // 停止 tmux session try { await this.executeBash(`tmux kill-session -t ${this.sessionName}`); } catch { // 忽略錯誤 } console.log('✅ 系統已停止'); this.emit('system-stopped'); } /** * 執行 bash 命令 */ executeBash(command) { return new Promise((resolve, reject) => { const proc = spawn('bash', ['-c', command]); proc.on('close', (code) => { if (code === 0) { resolve(); } else { reject(new Error(`Command failed: ${command}`)); } }); }); } } export default MultiAIOrchestrator; //# sourceMappingURL=multi-ai-orchestrator.js.map