UNPKG

agentic-qe

Version:

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

227 lines 9.06 kB
"use strict"; /** * Agent Restart Command * * Gracefully restarts an agent while preserving configuration and state. * Handles cleanup, state persistence, and re-initialization. * * @module cli/commands/agent/restart */ 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.AgentRestartCommand = void 0; const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); const AgentRegistry_1 = require("../../../mcp/services/AgentRegistry"); const Logger_1 = require("../../../utils/Logger"); const logger = Logger_1.Logger.getInstance(); /** * Agent Restart Command Implementation */ class AgentRestartCommand { /** * Execute agent restart * * @param options - Restart options * @returns Restart result */ static async execute(options) { const startTime = Date.now(); const { agentId, preserveState = true, timeout = this.DEFAULT_TIMEOUT, force = false } = options; logger.info(`Restarting agent: ${agentId}`, { preserveState, timeout, force }); try { // Get agent registry const registry = (0, AgentRegistry_1.getAgentRegistry)(); // Verify agent exists const registeredAgent = registry.getRegisteredAgent(agentId); if (!registeredAgent) { throw new Error(`Agent not found: ${agentId}`); } // Read current configuration const agentConfigPath = path.join(this.AGENT_DIR, `${agentId}.json`); const agentConfig = await this.readAgentConfig(agentConfigPath); // Preserve state if requested let savedState = null; if (preserveState) { savedState = await this.saveAgentState(agentId, registeredAgent); } // Mark agent as restarting await this.updateAgentStatus(agentConfigPath, 'restarting'); // Terminate old instance await this.terminateAgent(agentId, force, timeout); // Wait for cleanup await this.waitForCleanup(500); // Spawn new instance with preserved config const newAgent = await this.spawnNewInstance(registeredAgent.mcpType, agentConfig, savedState); // Update configuration with new instance ID await this.updateAgentConfig(agentConfigPath, { ...agentConfig, status: 'active', lastRestart: new Date().toISOString(), restartCount: (agentConfig.restartCount || 0) + 1, instanceId: newAgent.id }); const restartTime = Date.now() - startTime; logger.info(`Agent restarted successfully: ${agentId} -> ${newAgent.id}`, { restartTime, stateRestored: preserveState }); return { agentId, oldInstanceId: registeredAgent.id, newInstanceId: newAgent.id, status: 'active', preservedConfig: agentConfig, restartTime, stateRestored: preserveState && savedState !== null }; } catch (error) { logger.error(`Failed to restart agent ${agentId}:`, error); // Attempt to restore from backup try { await this.restoreFromBackup(agentId); } catch (restoreError) { logger.error('Failed to restore from backup:', restoreError); } throw new Error(`Agent restart failed: ${error instanceof Error ? error.message : String(error)}`); } } /** * Read agent configuration */ static async readAgentConfig(configPath) { if (!await fs.pathExists(configPath)) { throw new Error(`Agent configuration not found: ${configPath}`); } return await fs.readJson(configPath); } /** * Save agent state before restart */ static async saveAgentState(agentId, agent) { const statePath = path.join(this.STATE_DIR, `${agentId}.state.json`); await fs.ensureDir(this.STATE_DIR); const state = { savedAt: new Date().toISOString(), agentId, type: agent.type, status: agent.status, tasksCompleted: agent.tasksCompleted, totalExecutionTime: agent.totalExecutionTime, lastActivity: agent.lastActivity, metadata: { spawnedAt: agent.spawnedAt, capabilities: agent.agent?.config?.capabilities || [] } }; await fs.writeJson(statePath, state, { spaces: 2 }); logger.debug(`Agent state saved: ${statePath}`); return state; } /** * Update agent status in config */ static async updateAgentStatus(configPath, status) { const config = await fs.readJson(configPath); config.status = status; config.statusUpdatedAt = new Date().toISOString(); await fs.writeJson(configPath, config, { spaces: 2 }); } /** * Update agent configuration */ static async updateAgentConfig(configPath, config) { await fs.writeJson(configPath, config, { spaces: 2 }); } /** * Terminate agent with timeout */ static async terminateAgent(agentId, force, timeout) { const registry = (0, AgentRegistry_1.getAgentRegistry)(); if (force) { // Force termination await registry.terminateAgent(agentId); logger.debug(`Agent force terminated: ${agentId}`); } else { // Graceful termination with timeout const terminatePromise = registry.terminateAgent(agentId); const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('Termination timeout')), timeout)); try { await Promise.race([terminatePromise, timeoutPromise]); logger.debug(`Agent gracefully terminated: ${agentId}`); } catch (error) { // Timeout occurred, force terminate logger.warn(`Graceful termination timeout, forcing: ${agentId}`); await registry.terminateAgent(agentId); } } } /** * Wait for cleanup to complete */ static async waitForCleanup(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } /** * Spawn new agent instance */ static async spawnNewInstance(mcpType, config, savedState) { const registry = (0, AgentRegistry_1.getAgentRegistry)(); const spawnConfig = { name: config.name || `${mcpType}-${Date.now()}`, description: config.description, capabilities: config.capabilities || [], resources: config.resources }; const newAgent = await registry.spawnAgent(mcpType, spawnConfig); // Restore state if available if (savedState) { logger.debug('Restoring agent state after restart'); // State restoration would happen here via agent methods // This is a placeholder for state restoration logic } return newAgent; } /** * Restore from backup */ static async restoreFromBackup(agentId) { const backupPath = path.join(this.AGENT_DIR, `${agentId}.backup.json`); const configPath = path.join(this.AGENT_DIR, `${agentId}.json`); if (await fs.pathExists(backupPath)) { await fs.copy(backupPath, configPath); logger.info(`Restored agent config from backup: ${agentId}`); } } } exports.AgentRestartCommand = AgentRestartCommand; AgentRestartCommand.AGENT_DIR = path.join(process.cwd(), '.aqe', 'agents'); AgentRestartCommand.STATE_DIR = path.join(process.cwd(), '.aqe', 'state'); AgentRestartCommand.DEFAULT_TIMEOUT = 30000; //# sourceMappingURL=restart.js.map