UNPKG

agentic-qe

Version:

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

298 lines 9.87 kB
"use strict"; /** * Agent - Base class for all autonomous agents in the AQE Fleet * * @remarks * The Agent class provides the foundational capabilities for autonomous agents * including lifecycle management, task execution, capability advertisement, * and performance metrics tracking. * * All concrete agent implementations must extend this class and implement * the abstract methods for agent-specific behavior. * * @example * ```typescript * class CustomAgent extends Agent { * protected async onInitialize(): Promise<void> { * // Custom initialization logic * } * * protected async executeTaskLogic(task: Task): Promise<any> { * // Custom task execution logic * return { success: true }; * } * } * ``` * * @public */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Agent = exports.AgentStatus = void 0; const events_1 = require("events"); const Task_1 = require("./Task"); const Logger_1 = require("../utils/Logger"); /** * Operational status of an agent * * @public */ var AgentStatus; (function (AgentStatus) { /** Agent is being initialized */ AgentStatus["INITIALIZING"] = "initializing"; /** Agent is idle and ready to accept tasks */ AgentStatus["IDLE"] = "idle"; /** Agent is active and monitoring for tasks */ AgentStatus["ACTIVE"] = "active"; /** Agent is currently executing a task */ AgentStatus["BUSY"] = "busy"; /** Agent encountered an error */ AgentStatus["ERROR"] = "error"; /** Agent is in the process of stopping */ AgentStatus["STOPPING"] = "stopping"; /** Agent has been stopped */ AgentStatus["STOPPED"] = "stopped"; })(AgentStatus || (exports.AgentStatus = AgentStatus = {})); class Agent extends events_1.EventEmitter { constructor(id, type, config, eventBus) { super(); this.currentTask = null; this.capabilities = []; this.startTime = null; this.id = id; this.type = type; this.config = config; this.eventBus = eventBus; this.logger = Logger_1.Logger.getInstance(); this.status = AgentStatus.INITIALIZING; this.metrics = { tasksCompleted: 0, tasksFailured: 0, averageExecutionTime: 0, uptime: 0, lastActivity: new Date() }; this.setupEventHandlers(); } /** * Initialize the agent and its capabilities * * @remarks * Performs initialization sequence including capability setup and * agent-specific initialization logic. * * @returns A promise that resolves when initialization is complete * @throws {Error} If initialization fails * @fires agent:initialized * * @public */ async initialize() { this.logger.info(`Initializing agent ${this.type} (${this.id})`); try { // Initialize agent-specific capabilities await this.initializeCapabilities(); // Run agent-specific initialization await this.onInitialize(); this.status = AgentStatus.IDLE; this.startTime = new Date(); this.logger.info(`Agent ${this.type} (${this.id}) initialized successfully`); this.emit('agent:initialized', { agentId: this.id, type: this.type }); } catch (error) { this.status = AgentStatus.ERROR; this.logger.error(`Failed to initialize agent ${this.id}:`, error); this.emit('agent:error', { agentId: this.id, error }); throw error; } } /** * Start the agent */ async start() { if (this.status !== AgentStatus.IDLE) { throw new Error(`Agent ${this.id} must be idle to start`); } this.status = AgentStatus.ACTIVE; await this.onStart(); this.logger.info(`Agent ${this.type} (${this.id}) started`); this.emit('agent:started', { agentId: this.id }); } /** * Stop the agent */ async stop() { this.status = AgentStatus.STOPPING; // Wait for current task to complete if any if (this.currentTask && this.currentTask.getStatus() === Task_1.TaskStatus.RUNNING) { await this.currentTask.waitForCompletion(); } await this.onStop(); this.status = AgentStatus.STOPPED; this.logger.info(`Agent ${this.type} (${this.id}) stopped`); this.emit('agent:stopped', { agentId: this.id }); } /** * Assign a task to this agent for execution * * @param task - The task to assign * @returns A promise that resolves when the task is assigned * @throws {Error} If agent is not available or cannot handle the task type * @fires task:assigned * * @public */ async assignTask(task) { // Check if agent already has a task first (more specific error) if (this.currentTask) { throw new Error(`Agent ${this.id} already has an assigned task`); } // Then check if agent is in correct status if (this.status !== AgentStatus.ACTIVE && this.status !== AgentStatus.IDLE && this.status !== AgentStatus.BUSY) { throw new Error(`Agent ${this.id} is not available for task assignment`); } if (!this.canHandleTaskType(task.getType())) { throw new Error(`Agent ${this.id} cannot handle task type ${task.getType()}`); } this.currentTask = task; this.status = AgentStatus.BUSY; // Set BUSY immediately to prevent race conditions this.metrics.lastActivity = new Date(); this.logger.info(`Task ${task.getId()} assigned to agent ${this.id}`); this.emit('task:assigned', { agentId: this.id, taskId: task.getId() }); // Execute the task asynchronously but don't await it this.executeTask(task).catch(error => { this.logger.error(`Unhandled error in task execution for ${task.getId()}:`, error); }); } /** * Execute a task */ async executeTask(task) { const startTime = Date.now(); try { // Status already set to BUSY in assignTask task.setStatus(Task_1.TaskStatus.RUNNING); this.eventBus.emit('task:started', { agentId: this.id, taskId: task.getId() }); // Execute agent-specific task logic const result = await this.executeTaskLogic(task); task.setResult(result); task.setStatus(Task_1.TaskStatus.COMPLETED); // Update metrics const executionTime = Date.now() - startTime; this.updateMetrics(executionTime, true); this.logger.info(`Task ${task.getId()} completed by agent ${this.id}`); this.eventBus.emit('task:completed', { agentId: this.id, taskId: task.getId(), result, executionTime }); } catch (error) { task.setError(error); task.setStatus(Task_1.TaskStatus.FAILED); // Update metrics const executionTime = Date.now() - startTime; this.updateMetrics(executionTime, false); this.logger.error(`Task ${task.getId()} failed in agent ${this.id}:`, error); this.eventBus.emit('task:failed', { agentId: this.id, taskId: task.getId(), error, executionTime }); } finally { this.currentTask = null; this.status = AgentStatus.ACTIVE; } } /** * Check if agent can handle a specific task type * * @param taskType - The task type to check * @returns True if the agent has a capability for this task type * * @public */ canHandleTaskType(taskType) { return this.capabilities.some(capability => capability.taskTypes.includes(taskType)); } /** * Get agent ID */ getId() { return this.id; } /** * Get agent type */ getType() { return this.type; } /** * Get agent status */ getStatus() { return this.status; } /** * Get agent capabilities */ getCapabilities() { return this.capabilities; } /** * Get agent performance metrics * * @returns Current metrics including task counts and execution times * * @public */ getMetrics() { const uptime = this.startTime ? Date.now() - this.startTime.getTime() : 0; return { ...this.metrics, uptime }; } /** * Get current task */ getCurrentTask() { return this.currentTask; } /** * Update agent metrics */ updateMetrics(executionTime, success) { if (success) { this.metrics.tasksCompleted++; } else { this.metrics.tasksFailured++; } // Update average execution time const totalTasks = this.metrics.tasksCompleted + this.metrics.tasksFailured; if (totalTasks > 0) { this.metrics.averageExecutionTime = (this.metrics.averageExecutionTime * (totalTasks - 1) + executionTime) / totalTasks; } else { this.metrics.averageExecutionTime = executionTime; } this.metrics.lastActivity = new Date(); } /** * Setup event handlers */ setupEventHandlers() { this.on('error', (error) => { this.status = AgentStatus.ERROR; this.logger.error(`Agent ${this.id} encountered an error:`, error); this.eventBus.emit('agent:error', { agentId: this.id, error }); }); } } exports.Agent = Agent; //# sourceMappingURL=Agent.js.map