import * as vscode from 'vscode'; import { lockManager } from '../core/lock'; import { actionQueue } from '../core/queue'; import { logInfo, logError } from '../utils'; /** * 에이전트 인터페이스 정의 (의존성 주입을 위함) */ export interface IAgent { execute(input: string, context?: string, signal?: AbortSignal): Promise; } /** * 파이프라인 단계 상태 정의 */ export type PipelineStage = 'idle' | 'planner' | 'researcher' | 'writer' | 'completed' | 'error'; /** * AgentEngine: * Producer-Consumer 패턴을 기반으로 멀티 에이전트 워크플로우를 오케스트레이션하는 핵심 엔진. * 명시적 락(Mutex)과 의존성 주입(DI)을 통해 안정성과 유연성을 확보합니다. */ export class AgentEngine { private stage: PipelineStage = 'idle'; constructor( private readonly planner: IAgent, private readonly researcher: IAgent, private readonly writer: IAgent ) {} /** * 멀티 에이전트 워크플로우 실행 * @param missionId 작업을 식별하기 위한 고유 ID (Mutex 락에 사용) */ public async runMission( missionId: string, prompt: string, brainContext: string, signal: AbortSignal, onProgress: (stage: PipelineStage, message: string) => void ): Promise { // 1. 명시적 락 획득 (Mutex) - 동일 미션의 중복 실행 방지 const release = await lockManager.acquire(`mission_${missionId}`); try { // 2. 작업을 비동기 큐에 등록 (Producer-Consumer) return await actionQueue.enqueue(async () => { logInfo(`[AgentEngine] 미션 시작: ${missionId}`); // --- Phase 1: Planner --- this.updateStage('planner', '전략 수립 중...', onProgress); if (signal.aborted) throw new Error('AbortError'); const plan = await this.planner.execute(prompt, brainContext, signal); this.validateResult(plan, 'Planner'); // --- Phase 2: Researcher --- this.updateStage('researcher', '핵심 정보 수집 및 분석 중...', onProgress); if (signal.aborted) throw new Error('AbortError'); await this.delay(500); // 시스템 부하 분산을 위한 미세 지연 const research = await this.researcher.execute(plan, brainContext, signal); this.validateResult(research, 'Researcher'); // --- Phase 3: Writer --- this.updateStage('writer', '최종 리포트 작성 및 편집 중...', onProgress); if (signal.aborted) throw new Error('AbortError'); await this.delay(500); const finalReport = await this.writer.execute(research, prompt, signal); this.validateResult(finalReport, 'Writer'); this.updateStage('completed', '미션 완료', onProgress); return finalReport; }); } catch (error: any) { this.updateStage('error', `오류 발생: ${error.message}`, onProgress); logError(`[AgentEngine] 미션 실패 (${missionId}):`, error); throw error; } finally { // 3. 락 해제 release(); this.stage = 'idle'; } } private updateStage(stage: PipelineStage, message: string, onProgress: (stage: PipelineStage, message: string) => void) { this.stage = stage; onProgress(stage, message); } private validateResult(data: string, step: string) { if (!data || data.trim().length < 10) { throw new Error(`${step} 에이전트로부터 유효한 응답을 받지 못했습니다.`); } } private delay(ms: number) { return new Promise(r => setTimeout(r, ms)); } }