agentic-qe
Version:
Agentic Quality Engineering Fleet System - AI-driven quality management platform
354 lines • 12.2 kB
JavaScript
"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