agentic-qe
Version:
Agentic Quality Engineering Fleet System - AI-driven quality management platform
390 lines • 14 kB
JavaScript
"use strict";
/**
* BaseAgent - Abstract base class for all QE agents
* Implements core lifecycle hooks, event handling, and memory access
* Based on SPARC Phase 2 Pseudocode and Phase 3 Architecture
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseAgentFactory = exports.BaseAgent = void 0;
const events_1 = require("events");
const types_1 = require("../types");
class BaseAgent extends events_1.EventEmitter {
constructor(config) {
super();
this.status = types_1.AgentStatus.INITIALIZING;
this.eventHandlers = new Map();
this.performanceMetrics = {
tasksCompleted: 0,
averageExecutionTime: 0,
errorCount: 0,
lastActivity: new Date()
};
this.agentId = {
id: config.id || this.generateAgentId(config.type),
type: config.type,
created: new Date()
};
this.capabilities = new Map(config.capabilities.map(cap => [cap.name, cap]));
this.context = config.context;
this.memoryStore = config.memoryStore;
this.eventBus = config.eventBus;
this.setupEventHandlers();
this.setupLifecycleHooks();
}
// ============================================================================
// Public Interface
// ============================================================================
/**
* Initialize the agent - must be called after construction
*/
async initialize() {
try {
this.status = types_1.AgentStatus.INITIALIZING;
// Execute pre-initialization hooks
await this.executeHook('pre-initialization');
// Load agent knowledge and state
await this.loadKnowledge();
await this.restoreState();
// Initialize agent-specific components
await this.initializeComponents();
// Execute post-initialization hooks
await this.executeHook('post-initialization');
this.status = types_1.AgentStatus.ACTIVE;
this.emitEvent('agent.initialized', { agentId: this.agentId });
// Report initialization to coordination system
await this.reportStatus('initialized');
}
catch (error) {
this.status = types_1.AgentStatus.ERROR;
this.emitEvent('agent.error', { agentId: this.agentId, error });
throw error;
}
}
/**
* Execute a task assignment
*/
async executeTask(assignment) {
const startTime = Date.now();
try {
// Validate task assignment
this.validateTaskAssignment(assignment);
this.currentTask = assignment;
this.status = types_1.AgentStatus.ACTIVE;
// Execute pre-task hooks
await this.executeHook('pre-task', { assignment });
// Broadcast task start
await this.broadcastMessage('task-start', assignment);
// Execute the actual task
const result = await this.performTask(assignment.task);
// Execute post-task hooks
await this.executeHook('post-task', { assignment, result });
// Update performance metrics
this.updatePerformanceMetrics(startTime, true);
// Store task completion in memory
await this.storeTaskResult(assignment.id, result);
this.currentTask = undefined;
this.status = types_1.AgentStatus.IDLE;
return result;
}
catch (error) {
this.updatePerformanceMetrics(startTime, false);
this.currentTask = undefined;
this.status = types_1.AgentStatus.ERROR;
// Execute error hooks
await this.executeHook('task-error', { assignment, error });
throw error;
}
}
/**
* Terminate the agent gracefully
*/
async terminate() {
try {
this.status = types_1.AgentStatus.TERMINATING;
// Execute pre-termination hooks
await this.executeHook('pre-termination');
// Save current state
await this.saveState();
// Clean up resources
await this.cleanup();
// Remove all event handlers from EventBus
for (const [eventType, handlers] of this.eventHandlers.entries()) {
for (const handler of handlers) {
this.eventBus.off(eventType, handler.handler);
}
}
this.eventHandlers.clear();
// Execute post-termination hooks
await this.executeHook('post-termination');
this.status = types_1.AgentStatus.TERMINATED;
this.emitEvent('agent.terminated', { agentId: this.agentId });
// Remove all listeners from this agent (EventEmitter)
this.removeAllListeners();
}
catch (error) {
this.status = types_1.AgentStatus.ERROR;
throw error;
}
}
/**
* Get current agent status and metrics
*/
getStatus() {
return {
agentId: this.agentId,
status: this.status,
currentTask: this.currentTask?.id,
capabilities: Array.from(this.capabilities.keys()),
performanceMetrics: { ...this.performanceMetrics }
};
}
/**
* Check if agent has a specific capability
*/
hasCapability(capabilityName) {
return this.capabilities.has(capabilityName);
}
/**
* Get capability details
*/
getCapability(capabilityName) {
return this.capabilities.get(capabilityName);
}
/**
* Get all capabilities
*/
getCapabilities() {
return Array.from(this.capabilities.values());
}
/**
* Start the agent (alias for initialize)
*/
async start() {
await this.initialize();
}
/**
* Assign a task to the agent
*/
async assignTask(task) {
const assignment = {
id: `task-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
task,
agentId: this.agentId.id,
assignedAt: new Date(),
status: 'assigned'
};
await this.executeTask(assignment);
}
// ============================================================================
// Event System
// ============================================================================
/**
* Register an event handler
*/
registerEventHandler(handler) {
const handlers = this.eventHandlers.get(handler.eventType) || [];
handlers.push(handler);
this.eventHandlers.set(handler.eventType, handlers);
this.eventBus.on(handler.eventType, handler.handler);
}
/**
* Emit an event
*/
emitEvent(type, data, priority = 'medium') {
const event = {
id: this.generateEventId(),
type,
source: this.agentId,
data,
timestamp: new Date(),
priority,
scope: 'global'
};
this.eventBus.emit(type, event);
}
/**
* Broadcast message to other agents
*/
async broadcastMessage(type, payload) {
const message = {
id: this.generateMessageId(),
from: this.agentId,
to: { id: 'broadcast', type: 'all', created: new Date() },
type: type,
payload,
timestamp: new Date(),
priority: 'medium'
};
this.eventBus.emit('agent.message', message);
}
// ============================================================================
// Memory Operations
// ============================================================================
/**
* Store data in memory with automatic namespacing
*/
async storeMemory(key, value, ttl) {
if (!this.memoryStore) {
console.warn(`[WARN] Memory store not available for ${this.agentId.id}`);
return;
}
const namespacedKey = `agent:${this.agentId.id}:${key}`;
await this.memoryStore.store(namespacedKey, value, ttl);
}
/**
* Retrieve data from memory
*/
async retrieveMemory(key) {
if (!this.memoryStore) {
console.warn(`[WARN] Memory store not available for ${this.agentId.id}`);
return null;
}
const namespacedKey = `agent:${this.agentId.id}:${key}`;
return await this.memoryStore.retrieve(namespacedKey);
}
/**
* Store shared data accessible by other agents
*/
async storeSharedMemory(key, value, ttl) {
if (!this.memoryStore) {
console.warn(`[WARN] Memory store not available for ${this.agentId.id}`);
return;
}
const sharedKey = `shared:${this.agentId.type}:${key}`;
await this.memoryStore.store(sharedKey, value, ttl);
}
/**
* Retrieve shared data from other agents
*/
async retrieveSharedMemory(agentType, key) {
if (!this.memoryStore) {
console.warn(`[WARN] Memory store not available for ${this.agentId.id}`);
return null;
}
const sharedKey = `shared:${agentType}:${key}`;
return await this.memoryStore.retrieve(sharedKey);
}
// ============================================================================
// Lifecycle Hooks
// ============================================================================
async executeHook(hookName, data) {
try {
const method = `on${hookName.charAt(0).toUpperCase()}${hookName.slice(1).replace(/-/g, '')}`;
if (typeof this[method] === 'function') {
await this[method](data);
}
}
catch (error) {
console.error(`Hook ${hookName} failed for agent ${this.agentId.id}:`, error);
}
}
// ============================================================================
// Helper Methods
// ============================================================================
setupEventHandlers() {
// Set up base event handlers that all agents should have
this.registerEventHandler({
eventType: 'fleet.shutdown',
handler: async () => {
await this.terminate();
}
});
this.registerEventHandler({
eventType: 'agent.ping',
handler: async (event) => {
if (event.target?.id === this.agentId.id) {
this.emitEvent('agent.pong', { agentId: this.agentId });
}
}
});
}
setupLifecycleHooks() {
// Setup default lifecycle behavior
this.on('error', (error) => {
this.status = types_1.AgentStatus.ERROR;
this.emitEvent('agent.error', { agentId: this.agentId, error });
});
}
validateTaskAssignment(assignment) {
if (!assignment || !assignment.task) {
throw new Error('Invalid task assignment');
}
// Check if agent has required capabilities
const requiredCapabilities = assignment.task.requirements?.capabilities || [];
for (const capability of requiredCapabilities) {
if (!this.hasCapability(capability)) {
throw new Error(`Agent ${this.agentId.id} missing required capability: ${capability}`);
}
}
}
updatePerformanceMetrics(startTime, success) {
const executionTime = Date.now() - startTime;
if (success) {
this.performanceMetrics.tasksCompleted++;
this.performanceMetrics.averageExecutionTime =
(this.performanceMetrics.averageExecutionTime * (this.performanceMetrics.tasksCompleted - 1) + executionTime) /
this.performanceMetrics.tasksCompleted;
}
else {
this.performanceMetrics.errorCount++;
}
this.performanceMetrics.lastActivity = new Date();
}
async storeTaskResult(taskId, result) {
await this.storeMemory(`task:${taskId}:result`, {
result,
timestamp: new Date(),
agentId: this.agentId.id
});
}
async restoreState() {
try {
const state = await this.retrieveMemory('state');
if (state) {
this.performanceMetrics = { ...this.performanceMetrics, ...state.performanceMetrics };
}
}
catch (error) {
// State restoration is optional
console.warn(`Could not restore state for agent ${this.agentId.id}:`, error);
}
}
async saveState() {
try {
await this.storeMemory('state', {
performanceMetrics: this.performanceMetrics,
timestamp: new Date()
});
}
catch (error) {
console.error(`Could not save state for agent ${this.agentId.id}:`, error);
}
}
async reportStatus(status) {
try {
await this.storeSharedMemory('status', {
agentId: this.agentId.id,
status,
timestamp: new Date(),
metrics: this.performanceMetrics
});
}
catch (error) {
console.warn(`Could not report status for agent ${this.agentId.id}:`, error);
}
}
generateAgentId(type) {
return `${type}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}
generateEventId() {
return `event-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}
generateMessageId() {
return `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}
}
exports.BaseAgent = BaseAgent;
class BaseAgentFactory {
}
exports.BaseAgentFactory = BaseAgentFactory;
//# sourceMappingURL=BaseAgent.js.map