cortexweaver
Version:
CortexWeaver is a command-line interface (CLI) tool that orchestrates a swarm of specialized AI agents, powered by Claude Code and Gemini CLI, to assist in software development. It transforms a high-level project plan (plan.md) into a series of coordinate
346 lines • 13.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ErrorHandlerStrategies = void 0;
const error_types_1 = require("../types/error-types");
/**
* Error Handler Strategy Manager
* Contains recovery strategy implementations and error context management
*/
class ErrorHandlerStrategies {
constructor(canvas, sessionManager, agentSpawner, workflowManager) {
this.canvas = canvas;
this.sessionManager = sessionManager;
this.agentSpawner = agentSpawner;
this.workflowManager = workflowManager;
// State tracking for enhanced error handling
this.activeCodeSavantSessions = new Set();
this.taskErrorHistories = new Map();
this.recoveryStatistics = {
totalRecoveries: 0,
successfulRecoveries: 0,
averageAttempts: 0,
circuitBreakerStates: new Map(),
learningDatabase: new Map()
};
}
/**
* Store error context in cognitive canvas
*/
async storeErrorContext(errorContext) {
try {
await this.canvas.createPheromone({
id: errorContext.id,
type: 'error_pheromone',
context: `error_${errorContext.type}_${errorContext.severity}`,
strength: this.getSeverityStrength(errorContext.severity),
metadata: errorContext,
createdAt: new Date().toISOString(),
expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString() // Expires in 7 days
});
}
catch (error) {
console.error('Failed to store error context:', error);
}
}
/**
* Determine recovery strategy based on error context
*/
async determineRecoveryStrategy(errorContext, diagnosticResult) {
// Critical failures need immediate escalation and specialized handling
if (errorContext.severity === 'critical') {
if (errorContext.type === 'system_failure') {
return {
type: 'spawn_helper',
config: { agent: 'Debugger', analysis: diagnosticResult }
};
}
}
// Workflow step errors might benefit from helper agents
if (errorContext.type === 'workflow_step_error') {
if (this.workflowManager.isErrorRecoveryEnabled(errorContext.taskId)) {
return {
type: 'spawn_helper',
config: { agent: 'CodeSavant' }
};
}
}
// Impasse situations always get CodeSavant
if (errorContext.type === 'impasse') {
return {
type: 'spawn_helper',
config: { agent: 'CodeSavant' }
};
}
// Default to escalation
return {
type: 'escalate',
config: { reason: 'No specific recovery strategy available' }
};
}
/**
* Execute recovery strategy
*/
async executeRecoveryStrategy(taskId, strategy, errorContext) {
switch (strategy.type) {
case 'spawn_helper':
return await this.executeSpawnHelper(taskId, strategy.config, errorContext);
case 'retry':
return await this.executeRetry(taskId, strategy.config);
case 'pause_downstream':
return await this.executePauseDownstream(taskId, strategy.config);
case 'escalate':
default:
return {
success: false,
strategy,
message: `Escalated error for task ${taskId}: ${errorContext.errorMessage}`,
escalated: true
};
}
}
/**
* Execute spawn helper strategy
*/
async executeSpawnHelper(taskId, config, errorContext) {
try {
let spawnResult;
if (config.agent === 'Debugger') {
spawnResult = await this.agentSpawner.spawnDebugger(taskId, errorContext);
}
else if (config.agent === 'CodeSavant') {
const sessionOutput = await this.getSessionOutput(taskId);
spawnResult = await this.agentSpawner.spawnCodeSavant(taskId, sessionOutput);
}
else {
throw new Error(`Unknown helper agent type: ${config.agent}`);
}
if (spawnResult.success) {
return {
success: true,
strategy: { type: 'spawn_helper', config },
message: `${config.agent} helper spawned successfully for task ${taskId}`
};
}
else {
return {
success: false,
strategy: { type: 'spawn_helper', config },
message: `Failed to spawn ${config.agent}: ${spawnResult.error}`,
escalated: true
};
}
}
catch (error) {
return {
success: false,
strategy: { type: 'spawn_helper', config },
message: `Helper spawn failed: ${error.message}`,
escalated: true
};
}
}
/**
* Execute retry strategy
*/
async executeRetry(taskId, config) {
// Implementation would depend on retry logic
return {
success: true,
strategy: { type: 'retry', config },
message: `Retry strategy executed for task ${taskId}`
};
}
/**
* Execute pause downstream strategy
*/
async executePauseDownstream(taskId, config) {
try {
// Get task project ID
const tasks = await this.canvas.getTasksByProject(config.projectId || 'unknown');
const task = tasks.find(t => t.id === taskId);
if (task) {
await this.pauseDownstreamTasks(taskId, config.severity || 'medium');
return {
success: true,
strategy: { type: 'pause_downstream', config },
message: `Downstream tasks paused for task ${taskId}`
};
}
else {
return {
success: false,
strategy: { type: 'pause_downstream', config },
message: `Could not find task ${taskId} to pause downstream tasks`
};
}
}
catch (error) {
return {
success: false,
strategy: { type: 'pause_downstream', config },
message: `Failed to pause downstream tasks: ${error.message}`
};
}
}
/**
* Pause downstream tasks based on severity
*/
async pauseDownstreamTasks(taskId, severity) {
try {
console.log(`Pausing downstream tasks due to ${severity} severity issues`);
// Get project ID from task
const tasks = await this.canvas.getTasksByProject('*'); // Would need actual project ID
const task = tasks.find(t => t.id === taskId);
if (!task)
return;
// Get all tasks for the project
const projectTasks = await this.canvas.getTasksByProject(task.projectId);
// Identify tasks that should be paused based on severity
const tasksToControl = projectTasks.filter(t => {
const workflowState = this.workflowManager.getTaskWorkflowState(t.id);
if (!workflowState)
return false;
// Pause downstream tasks based on severity level
if (severity === 'high') {
// High severity: pause all tasks not yet started
return t.status === 'pending';
}
else if (severity === 'medium') {
// Medium severity: pause only architecture and implementation tasks
return ['DESIGN_ARCHITECTURE', 'IMPLEMENT_CODE', 'EXECUTE_TESTS'].includes(workflowState.currentStep) &&
t.status === 'pending';
}
return false;
});
// Mark tasks as paused
for (const t of tasksToControl) {
await this.canvas.updateTaskStatus(t.id, 'paused');
console.log(`Paused task ${t.id} due to ${severity} severity critique issues`);
}
// Store critique pause reason in canvas for tracking
await this.canvas.createPheromone({
id: `pheromone-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
type: 'pause_pheromone',
context: `critique_pause_${severity}`,
strength: severity === 'high' ? 0.9 : 0.7,
metadata: {
reason: 'critique_issues',
severity,
timestamp: new Date().toISOString(),
affectedTasks: tasksToControl.map(t => t.id)
},
createdAt: new Date().toISOString(),
expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString() // Expires in 7 days
});
}
catch (error) {
console.error('Error pausing downstream tasks:', error);
}
}
/**
* Get session output for task
*/
async getSessionOutput(taskId) {
try {
const originalSessionId = `cortex-${taskId}-*`;
return await this.sessionManager.getSessionOutput(originalSessionId);
}
catch (error) {
console.warn('Could not retrieve session output:', error);
return 'No session output available';
}
}
/**
* Determine severity from critique issues
*/
determineSeverity(issues) {
if (issues.some(issue => issue.severity === 'high')) {
return 'high';
}
if (issues.some(issue => issue.severity === 'medium')) {
return 'medium';
}
return 'low';
}
/**
* Get strength value for severity level
*/
getSeverityStrength(severity) {
switch (severity) {
case 'critical': return 1.0;
case 'high': return 0.8;
case 'medium': return 0.6;
case 'low': return 0.4;
default: return 0.5;
}
}
/**
* Get active CodeSavant sessions for compatibility
*/
getActiveCodeSavantSessions() {
return this.activeCodeSavantSessions;
}
/**
* Get error history for a specific task
*/
getTaskErrorHistory(taskId) {
return this.taskErrorHistories.get(taskId) || [];
}
/**
* Get error recovery statistics
*/
getErrorRecoveryStatistics() {
return {
totalRecoveries: this.recoveryStatistics.totalRecoveries,
successRate: this.recoveryStatistics.totalRecoveries > 0
? this.recoveryStatistics.successfulRecoveries / this.recoveryStatistics.totalRecoveries
: 0,
averageAttempts: this.recoveryStatistics.averageAttempts,
circuitBreakerStates: Object.fromEntries(this.recoveryStatistics.circuitBreakerStates),
learningDatabase: Object.fromEntries(this.recoveryStatistics.learningDatabase)
};
}
/**
* Track error for history and statistics
*/
trackError(taskId, errorData) {
// Create CortexError instance for history
const cortexError = new error_types_1.CortexError(errorData.errorMessage || errorData.message || 'Unknown error', {
severity: errorData.severity || error_types_1.ErrorSeverity.MEDIUM,
category: error_types_1.ErrorCategory.AGENT_EXECUTION,
context: {
taskId,
agentId: 'unknown',
agentType: 'unknown',
phase: error_types_1.ErrorPhase.TASK_EXECUTION,
timestamp: errorData.timestamp || new Date().toISOString()
},
retryable: true,
maxRetries: 2,
backoffStrategy: 'exponential',
cause: new Error(errorData.errorMessage || 'Unknown error'),
metadata: errorData.metadata || {}
});
// Add to task error history
if (!this.taskErrorHistories.has(taskId)) {
this.taskErrorHistories.set(taskId, []);
}
this.taskErrorHistories.get(taskId).push(cortexError);
// Update statistics
this.recoveryStatistics.totalRecoveries++;
}
/**
* Track successful recovery
*/
trackSuccessfulRecovery(taskId) {
this.recoveryStatistics.successfulRecoveries++;
}
/**
* Add new CodeSavant session to tracking
*/
addCodeSavantSession(taskId) {
this.activeCodeSavantSessions.add(taskId);
}
}
exports.ErrorHandlerStrategies = ErrorHandlerStrategies;
//# sourceMappingURL=error-handler-strategies.js.map