"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AgentSpawner = void 0;
/**
 * AgentSpawner
 *
 * Minimal version focused on:
 * - Simple task decomposition
 * - Agent matching via registry
 * - Context budget allocation
 * - Sequential execution planning (parallel comes later)
 */
class AgentSpawner {
    constructor(registry, messageBus, config) {
        this.registry = registry;
        this.messageBus = messageBus;
        this.config = {
            maxConcurrentAgents: config?.maxConcurrentAgents ?? 5,
            maxTotalContextBudgetKB: config?.maxTotalContextBudgetKB ?? 500,
            preferParallel: config?.preferParallel ?? false,
            allowNetworkAgents: config?.allowNetworkAgents ?? true,
            maxTaskDurationMs: config?.maxTaskDurationMs ?? 300000, // 5 minutes
        };
        this.activeInstances = new Map();
    }
    /**
     * Analyze a task and create spawn plan
     */
    async analyzeAndPlan(taskDescription, context) {
        // Step 1: Decompose task into subtasks
        const decomposed = await this.decomposeTask(taskDescription, context);
        // Step 2: Match each subtask to an agent
        const plan = await this.createSpawnPlan(decomposed);
        // Step 3: Validate plan
        this.validatePlan(plan);
        return plan;
    }
    /**
     * Spawn agents based on plan (sequential execution)
     */
    async spawnAgents(plan) {
        const instances = [];
        for (const step of plan.steps) {
            // Check if dependencies are satisfied
            const dependenciesSatisfied = this.checkDependencies(step.dependencies, instances);
            if (!dependenciesSatisfied) {
                throw new Error(`Dependencies not satisfied for step ${step.stepId}`);
            }
            // Create agent instance
            const instance = await this.createAgentInstance(step);
            instances.push(instance);
            this.activeInstances.set(instance.instanceId, instance);
            // Notify via message bus
            await this.messageBus.broadcast("agent:spawned", {
                instanceId: instance.instanceId,
                agentType: instance.agentType,
                taskType: step.taskType,
            });
        }
        return instances;
    }
    /**
     * Decompose task into subtasks (simple version)
     */
    async decomposeTask(taskDescription, context) {
        const warnings = [];
        // Simple heuristic-based decomposition
        // In production, this would call an LLM or use more sophisticated analysis
        const subtasks = this.simpleDecomposition(taskDescription);
        // Calculate estimates
        const estimatedDurationMs = subtasks.reduce((sum, task) => sum + task.estimatedDurationMs, 0);
        const totalContextBudgetKB = subtasks.reduce((sum, task) => {
            // Estimate based on required context
            return sum + task.requiredContext.length * 20; // ~20KB per context item
        }, 0);
        // Assess risk
        const riskLevel = this.assessRisk(subtasks, estimatedDurationMs);
        // Add warnings
        if (estimatedDurationMs > this.config.maxTaskDurationMs) {
            warnings.push(`Estimated duration (${estimatedDurationMs}ms) exceeds maximum (${this.config.maxTaskDurationMs}ms)`);
        }
        if (totalContextBudgetKB > this.config.maxTotalContextBudgetKB) {
            warnings.push(`Total context budget (${totalContextBudgetKB}KB) exceeds maximum (${this.config.maxTotalContextBudgetKB}KB)`);
        }
        return {
            subtasks,
            estimatedDurationMs,
            totalContextBudgetKB,
            riskLevel,
            warnings,
        };
    }
    /**
     * Simple task decomposition (heuristic-based)
     */
    simpleDecomposition(taskDescription) {
        const subtasks = [];
        // Extract intent (always first step)
        subtasks.push({
            id: "subtask-intent",
            type: "intent-extraction",
            description: "Extract user intent from task description",
            requiredContext: ["user-prompt"],
            estimatedDurationMs: 3000,
            priority: "critical",
            dependencies: [],
        });
        // Detect if this is a feature request
        if (taskDescription.toLowerCase().includes("add") ||
            taskDescription.toLowerCase().includes("create") ||
            taskDescription.toLowerCase().includes("build")) {
            subtasks.push({
                id: "subtask-planning",
                type: "feature-planning",
                description: "Plan feature architecture and dependencies",
                requiredContext: ["brain.features", "brain.questions"],
                estimatedDurationMs: 5000,
                priority: "critical",
                dependencies: ["subtask-intent"],
            });
            subtasks.push({
                id: "subtask-codegen",
                type: "code-generation",
                description: "Generate code for feature",
                requiredContext: ["brain.features", "brain.components"],
                estimatedDurationMs: 8000,
                priority: "high",
                dependencies: ["subtask-planning"],
            });
            subtasks.push({
                id: "subtask-validation",
                type: "validation",
                description: "Validate generated code",
                requiredContext: ["operations"],
                estimatedDurationMs: 2000,
                priority: "high",
                dependencies: ["subtask-codegen"],
            });
        }
        // Detect if this includes testing
        if (taskDescription.toLowerCase().includes("test") ||
            taskDescription.toLowerCase().includes("spec")) {
            subtasks.push({
                id: "subtask-tests",
                type: "test-generation",
                description: "Generate test suite",
                requiredContext: ["brain.features", "brain.components"],
                estimatedDurationMs: 6000,
                priority: "medium",
                dependencies: ["subtask-codegen"],
            });
        }
        return subtasks;
    }
    /**
     * Create spawn plan from decomposed task
     */
    async createSpawnPlan(decomposed) {
        const steps = [];
        const warnings = [...decomposed.warnings];
        let totalContextBudget = 0;
        for (const subtask of decomposed.subtasks) {
            // Find best agent for this subtask
            const match = this.registry.getBestAgentFor(subtask.type);
            if (!match) {
                warnings.push(`No agent found for task type: ${subtask.type}`);
                continue;
            }
            // Check if agent requires network
            if (!this.config.allowNetworkAgents &&
                match.capability.requiresNetwork) {
                warnings.push(`Agent ${match.agentType} requires network but network agents are disabled`);
                continue;
            }
            // Create spawn step
            const step = {
                stepId: `step-${subtask.id}`,
                agentType: match.agentType,
                taskType: subtask.type,
                description: subtask.description,
                agentMatch: match,
                contextBudgetKB: match.capability.contextBudgetKB,
                estimatedDurationMs: match.capability.estimatedDurationMs,
                dependencies: subtask.dependencies.map((dep) => `step-${dep}`),
            };
            steps.push(step);
            totalContextBudget += step.contextBudgetKB;
        }
        // Determine if can run in parallel (for now, always false - sequential only)
        const canRunInParallel = false;
        // Calculate total duration (sequential)
        const totalDurationMs = steps.reduce((sum, step) => sum + step.estimatedDurationMs, 0);
        return {
            steps,
            totalDurationMs,
            totalContextBudgetKB: totalContextBudget,
            canRunInParallel,
            warnings,
        };
    }
    /**
     * Validate spawn plan
     */
    validatePlan(plan) {
        if (plan.steps.length === 0) {
            throw new Error("Spawn plan has no steps");
        }
        if (plan.totalContextBudgetKB > this.config.maxTotalContextBudgetKB) {
            throw new Error(`Total context budget (${plan.totalContextBudgetKB}KB) exceeds maximum (${this.config.maxTotalContextBudgetKB}KB)`);
        }
        // Check for circular dependencies
        const visited = new Set();
        const visiting = new Set();
        const hasCycle = (stepId) => {
            if (visiting.has(stepId))
                return true;
            if (visited.has(stepId))
                return false;
            visiting.add(stepId);
            const step = plan.steps.find((s) => s.stepId === stepId);
            if (step) {
                for (const dep of step.dependencies) {
                    if (hasCycle(dep))
                        return true;
                }
            }
            visiting.delete(stepId);
            visited.add(stepId);
            return false;
        };
        for (const step of plan.steps) {
            if (hasCycle(step.stepId)) {
                throw new Error(`Circular dependency detected in spawn plan`);
            }
        }
    }
    /**
     * Create agent instance from spawn step
     */
    async createAgentInstance(step) {
        const instanceId = `agent-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
        const instance = {
            instanceId,
            agentType: step.agentType,
            capability: step.agentMatch.capability,
            status: "spawning",
            task: {
                taskId: step.stepId,
                type: step.taskType,
                description: step.description,
                input: {},
                priority: "medium",
                tags: [],
            },
            allocatedContext: {},
            contextSizeKB: step.contextBudgetKB,
            startedAt: new Date().toISOString(),
            progress: {
                current: 0,
                message: "Spawning",
            },
            metrics: {
                executionTimeMs: 0,
                cpuTimeMs: 0,
                memoryUsedMB: 0,
                contextSizeKB: step.contextBudgetKB,
                operationsExecuted: 0,
                cacheHitRate: 0,
                retryCount: 0,
            },
        };
        return instance;
    }
    /**
     * Check if dependencies are satisfied
     */
    checkDependencies(dependencies, completedInstances) {
        // For now, simple check: all dependencies must be in completed list
        // In full implementation, would check actual completion status
        return dependencies.length === 0; // Simplified for sequential execution
    }
    /**
     * Assess risk level
     */
    assessRisk(subtasks, totalDuration) {
        if (totalDuration > 60000)
            return "high"; // > 1 minute
        if (subtasks.length > 5)
            return "medium";
        return "low";
    }
    /**
     * Get active instances
     */
    getActiveInstances() {
        return Array.from(this.activeInstances.values());
    }
    /**
     * Get instance by ID
     */
    getInstance(instanceId) {
        return this.activeInstances.get(instanceId);
    }
    /**
     * Update instance status
     */
    updateInstanceStatus(instanceId, updates) {
        const instance = this.activeInstances.get(instanceId);
        if (!instance) {
            throw new Error(`Instance ${instanceId} not found`);
        }
        Object.assign(instance, updates);
        this.activeInstances.set(instanceId, instance);
    }
    /**
     * Remove completed instance
     */
    removeInstance(instanceId) {
        return this.activeInstances.delete(instanceId);
    }
    /**
     * Get statistics
     */
    getStats() {
        const instances = this.getActiveInstances();
        return {
            activeInstances: instances.length,
            totalContextUsedKB: instances.reduce((sum, inst) => sum + inst.contextSizeKB, 0),
            averageProgressPercent: instances.length > 0
                ? instances.reduce((sum, inst) => sum + inst.progress.current, 0) /
                    instances.length
                : 0,
        };
    }
}
exports.AgentSpawner = AgentSpawner;
//# sourceMappingURL=AgentSpawner.js.map