UNPKG

agentic-qe

Version:

Agentic Quality Engineering Fleet System - AI-driven quality management platform

354 lines 12.2 kB
"use strict"; /** * FleetManager - Central coordination hub for the AQE Fleet * * @remarks * The FleetManager is the primary interface for managing the Agentic QE Fleet. * It provides comprehensive lifecycle management for autonomous agents, task * coordination, and fleet-wide monitoring through an event-driven architecture. * * @example * ```typescript * // Initialize a fleet with multiple agent types * const config = { * agents: [ * { type: 'test-generator', count: 2, config: { aiModel: 'claude-sonnet-4.5' } }, * { type: 'test-executor', count: 4, config: { maxParallelTests: 8 } }, * { type: 'coverage-analyzer', count: 1 } * ] * }; * * const fleet = new FleetManager(config); * await fleet.initialize(); * await fleet.start(); * * // Submit tasks * const task = new Task('test-generation', 'Generate API tests', { * targetFiles: ['./src/api/*.ts'] * }); * await fleet.submitTask(task); * * // Monitor fleet status * const status = fleet.getStatus(); * console.log(`Active agents: ${status.activeAgents}/${status.totalAgents}`); * ``` * * @public */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.FleetManager = void 0; const events_1 = require("events"); const uuid_1 = require("uuid"); const Agent_1 = require("./Agent"); const Task_1 = require("./Task"); const EventBus_1 = require("./EventBus"); const Database_1 = require("../utils/Database"); const Logger_1 = require("../utils/Logger"); class FleetManager extends events_1.EventEmitter { constructor(config) { super(); this.startTime = null; this.status = 'initializing'; this.id = (0, uuid_1.v4)(); this.agents = new Map(); this.tasks = new Map(); this.eventBus = new EventBus_1.EventBus(); this.database = new Database_1.Database(); this.logger = Logger_1.Logger.getInstance(); this.config = config; this.setupEventHandlers(); } /** * Initialize the fleet manager and its components * * @remarks * This method performs the following operations: * - Initializes the database connection * - Starts the event bus * - Creates the initial pool of agents based on configuration * * @returns A promise that resolves when initialization is complete * @throws {Error} If database initialization fails or agents cannot be created * * @example * ```typescript * const fleet = new FleetManager(config); * await fleet.initialize(); * ``` * * @public */ async initialize() { this.logger.info(`Initializing Fleet Manager ${this.id}`); try { // Initialize database await this.database.initialize(); // Initialize event bus await this.eventBus.initialize(); // Create initial agent pool await this.createInitialAgents(); this.status = 'running'; this.logger.info('Fleet Manager initialized successfully'); } catch (error) { this.logger.error('Failed to initialize Fleet Manager:', error); throw error; } } /** * Start the fleet operations and activate all agents * * @remarks * Starts all agents in the fleet and begins accepting tasks. The fleet must be * initialized before calling this method. * * @returns A promise that resolves when all agents have started * @throws {Error} If fleet is not initialized or agents fail to start * @fires fleet:started * * @public */ async start() { if (this.status !== 'running') { throw new Error('Fleet must be initialized before starting'); } this.startTime = new Date(); this.logger.info('Fleet Manager started'); // Start all agents for (const agent of this.agents.values()) { await agent.start(); } this.emit('fleet:started', this.getStatus()); } /** * Stop the fleet operations gracefully * * @remarks * Performs graceful shutdown: * - Stops accepting new tasks * - Waits for running tasks to complete * - Stops all agents * - Closes database connections * * @returns A promise that resolves when shutdown is complete * @fires fleet:stopped * * @public */ async stop() { this.status = 'stopping'; this.logger.info('Stopping Fleet Manager'); // Stop all agents gracefully const stopPromises = Array.from(this.agents.values()).map(agent => agent.stop()); await Promise.all(stopPromises); // Close database connection await this.database.close(); this.status = 'stopped'; this.emit('fleet:stopped', this.getStatus()); this.logger.info('Fleet Manager stopped'); } /** * Create and register a new agent in the fleet * * @param type - The type of agent to create (e.g., 'test-generator', 'test-executor') * @param config - Optional configuration for the agent * @returns A promise that resolves to the created agent instance * @throws {Error} If agent type is unknown or creation fails * @fires agent:spawned * * @example * ```typescript * const testGen = await fleet.spawnAgent('test-generator', { * aiModel: 'claude-sonnet-4.5', * frameworks: ['jest', 'vitest'] * }); * ``` * * @public */ async spawnAgent(type, config = {}) { const agentId = (0, uuid_1.v4)(); // Import agent factory and create agent const { createAgent } = await Promise.resolve().then(() => __importStar(require('../agents'))); const agent = await createAgent(type, agentId, config, this.eventBus); this.agents.set(agentId, agent); await agent.initialize(); this.logger.info(`Agent spawned: ${type} (${agentId})`); this.emit('agent:spawned', { agentId, type }); return agent; } /** * Remove an agent from the fleet */ async removeAgent(agentId) { const agent = this.agents.get(agentId); if (!agent) { throw new Error(`Agent ${agentId} not found`); } await agent.stop(); this.agents.delete(agentId); this.logger.info(`Agent removed: ${agentId}`); this.emit('agent:removed', { agentId }); } /** * Submit a task for execution by an available agent * * @remarks * The fleet will automatically assign the task to an available agent that can * handle the task type. If no agent is available, the task will be queued. * * @param task - The task to submit * @returns A promise that resolves when the task is submitted * @fires task:submitted * * @example * ```typescript * const task = new Task( * 'coverage-analysis', * 'Analyze test coverage', * { coverageReport: './coverage/coverage-final.json' } * ); * await fleet.submitTask(task); * ``` * * @public */ async submitTask(task) { this.tasks.set(task.getId(), task); // Find available agent for the task const agent = this.findAvailableAgent(task.getType()); if (agent) { await agent.assignTask(task); this.logger.info(`Task ${task.getId()} assigned to agent ${agent.getId()}`); } else { task.setStatus(Task_1.TaskStatus.QUEUED); this.logger.warn(`No available agent for task ${task.getId()}, queuing`); } this.emit('task:submitted', { taskId: task.getId() }); } /** * Get current fleet status and metrics * * @returns Fleet status including agent counts, task metrics, and uptime * * @example * ```typescript * const status = fleet.getStatus(); * console.log(`Fleet ${status.id}: ${status.activeAgents}/${status.totalAgents} agents active`); * console.log(`Tasks: ${status.runningTasks} running, ${status.completedTasks} completed`); * ``` * * @public */ getStatus() { const activeAgents = Array.from(this.agents.values()) .filter(agent => agent.getStatus() === Agent_1.AgentStatus.ACTIVE).length; const runningTasks = Array.from(this.tasks.values()) .filter(task => task.getStatus() === Task_1.TaskStatus.RUNNING).length; const completedTasks = Array.from(this.tasks.values()) .filter(task => task.getStatus() === Task_1.TaskStatus.COMPLETED).length; const failedTasks = Array.from(this.tasks.values()) .filter(task => task.getStatus() === Task_1.TaskStatus.FAILED).length; return { id: this.id, activeAgents, totalAgents: this.agents.size, runningTasks, completedTasks, failedTasks, uptime: this.startTime ? Date.now() - this.startTime.getTime() : 0, status: this.status }; } /** * Get agent by ID */ getAgent(agentId) { return this.agents.get(agentId); } /** * Get all agents */ getAllAgents() { return Array.from(this.agents.values()); } /** * Get task by ID */ getTask(taskId) { return this.tasks.get(taskId); } /** * Get all tasks */ getAllTasks() { return Array.from(this.tasks.values()); } /** * Find an available agent for a specific task type */ findAvailableAgent(taskType) { return Array.from(this.agents.values()).find(agent => agent.getStatus() === Agent_1.AgentStatus.IDLE && agent.canHandleTaskType(taskType)); } /** * Create initial agent pool based on configuration */ async createInitialAgents() { const { agents: agentConfigs } = this.config; for (const agentConfig of agentConfigs) { for (let i = 0; i < agentConfig.count; i++) { await this.spawnAgent(agentConfig.type, agentConfig.config); } } } /** * Setup event handlers for fleet coordination */ setupEventHandlers() { this.eventBus.on('task:completed', (data) => { const task = this.tasks.get(data.taskId); if (task) { this.logger.info(`Task completed: ${data.taskId}`); this.emit('task:completed', data); } }); this.eventBus.on('task:failed', (data) => { const task = this.tasks.get(data.taskId); if (task) { this.logger.error(`Task failed: ${data.taskId}`, data.error); this.emit('task:failed', data); } }); this.eventBus.on('agent:error', (data) => { this.logger.error(`Agent error: ${data.agentId}`, data.error); this.emit('agent:error', data); }); } } exports.FleetManager = FleetManager; //# sourceMappingURL=FleetManager.js.map