codecrucible-synth
Version:
Production-Ready AI Development Platform with Multi-Voice Synthesis, Smithery MCP Integration, Enterprise Security, and Zero-Timeout Reliability
750 lines (653 loc) • 21.8 kB
text/typescript
/**
* Unified Agent System
* Consolidates: enhanced-agentic-client.ts, simple-agent.ts, complex-agent.ts,
* agentic-system.ts, agent-manager.ts, agent-orchestrator.ts
* Created: 2024-12-19 | Purpose: Single agent system with all capabilities
*/
import { EventEmitter } from 'events';
import { UnifiedModelClient } from '../refactor/unified-model-client.js';
import { configManager, AgentConfig } from '../config/config-manager.js';
export type { AgentConfig };
import { PerformanceMonitor } from '../utils/performance.js';
import { logger } from './logger.js';
import {
ExecutionRequest,
ExecutionResponse,
Task,
Workflow,
ProjectContext,
ExecutionResult,
} from './types.js';
export { ExecutionResult };
export interface AgentCapability {
name: string;
description: string;
handler: (task: Task) => Promise<ExecutionResult>;
priority: number;
enabled: boolean;
}
export interface AgentMetrics {
tasksCompleted: number;
averageExecutionTime: number;
successRate: number;
errorCount: number;
lastExecutionTime: number;
}
/**
* Unified Agent System with all capabilities
*/
import { Agent } from '../refactor/agent.js';
export class UnifiedAgent extends EventEmitter {
private agent: Agent;
private modelClient: UnifiedModelClient;
private performanceMonitor: PerformanceMonitor;
private config: AgentConfig = {
enabled: true,
mode: 'balanced',
maxConcurrency: 3,
enableCaching: true,
enableMetrics: true,
enableSecurity: true,
};
private capabilities: Map<string, AgentCapability>;
private activeWorkflows: Map<string, Workflow>;
private metrics: AgentMetrics;
private executionQueue: Task[];
constructor(modelClient: UnifiedModelClient, performanceMonitor: PerformanceMonitor) {
super();
// Increase max listeners to prevent memory leak warnings
this.setMaxListeners(50);
this.modelClient = modelClient;
this.performanceMonitor = performanceMonitor;
this.capabilities = new Map();
this.activeWorkflows = new Map();
this.executionQueue = [];
this.metrics = {
tasksCompleted: 0,
averageExecutionTime: 0,
successRate: 0,
errorCount: 0,
lastExecutionTime: 0,
};
this.agent = new Agent(modelClient);
this.initializeCapabilities();
this.loadConfig();
}
/**
* Initialize agent capabilities
*/
private initializeCapabilities(): void {
// Code Analysis Capability
this.registerCapability({
name: 'code-analysis',
description: 'Analyze code quality, patterns, and improvements',
priority: 10,
enabled: true,
handler: async task => this.agent.handleCodeAnalysis(task),
});
// Code Generation Capability
this.registerCapability({
name: 'code-generation',
description: 'Generate code based on specifications',
priority: 9,
enabled: true,
handler: async task => this.agent.handleCodeGeneration(task),
});
// Documentation Capability
this.registerCapability({
name: 'documentation',
description: 'Generate and improve documentation',
priority: 7,
enabled: true,
handler: async task => this.agent.handleDocumentation(task),
});
// Testing Capability
this.registerCapability({
name: 'testing',
description: 'Generate and optimize tests',
priority: 8,
enabled: true,
handler: async task => this.agent.handleTesting(task),
});
// Refactoring Capability
this.registerCapability({
name: 'refactoring',
description: 'Refactor and optimize code',
priority: 6,
enabled: true,
handler: async task => this.agent.handleRefactoring(task),
});
// Bug Fixing Capability
this.registerCapability({
name: 'bug-fixing',
description: 'Identify and fix bugs',
priority: 10,
enabled: true,
handler: async task => this.agent.handleBugFixing(task),
});
// Performance Optimization Capability
this.registerCapability({
name: 'performance-optimization',
description: 'Optimize code performance',
priority: 5,
enabled: true,
handler: async task => this.agent.handlePerformanceOptimization(task),
});
// Security Analysis Capability
this.registerCapability({
name: 'security-analysis',
description: 'Analyze code for security vulnerabilities',
priority: 9,
enabled: true,
handler: async task => this.agent.handleSecurityAnalysis(task),
});
}
/**
* Load configuration
*/
private async loadConfig(): Promise<void> {
this.config = await configManager.getAgentConfig();
}
/**
* Register a new capability
*/
registerCapability(capability: AgentCapability): void {
this.capabilities.set(capability.name, capability);
this.emit('capability-registered', capability);
}
/**
* Execute agent request with intelligent routing
*/
async execute(request: ExecutionRequest, _context?: ProjectContext): Promise<ExecutionResponse> {
const startTime = Date.now();
const workflowId = this.generateWorkflowId();
try {
// Create workflow
const workflow: Workflow = {
id: workflowId,
request: request as unknown as Record<string, unknown>,
status: 'running',
startTime: new Date(startTime),
tasks: [],
results: {} as Record<string, unknown>,
};
this.activeWorkflows.set(workflowId, workflow);
this.emit('workflow-started', workflow);
// Analyze request and create execution plan
const executionPlan = await this.createExecutionPlan(request);
workflow.tasks = executionPlan;
// Execute plan
const results = await this.executeWorkflow(workflow);
// Complete workflow
workflow.status = 'completed';
workflow.endTime = new Date();
workflow.results = results as unknown as Record<string, unknown>;
const response: ExecutionResponse = {
workflowId,
success: true,
result: results as unknown as Record<string, unknown>,
results: results as unknown as Record<string, unknown>,
executionTime: workflow.endTime.getTime() - workflow.startTime.getTime(),
};
this.updateMetrics(response);
this.emit('workflow-completed', workflow);
return response;
} catch (error) {
const workflow = this.activeWorkflows.get(workflowId);
if (workflow) {
workflow.status = 'failed';
workflow.endTime = new Date();
workflow.error = error instanceof Error ? error.message : String(error);
}
this.metrics.errorCount++;
this.emit('workflow-failed', { workflowId, error });
return {
workflowId,
success: false,
result: {} as Record<string, unknown>,
error: error instanceof Error ? error.message : String(error),
executionTime: Date.now() - startTime,
};
} finally {
this.activeWorkflows.delete(workflowId);
}
}
/**
* Create execution plan based on request
*/
private async createExecutionPlan(request: ExecutionRequest): Promise<Task[]> {
const tasks: Task[] = [];
const mode = request.mode || this.config.mode;
// Determine request complexity and create appropriate tasks
const isSimpleQuery = this.isSimpleQuery(request.input);
const taskType = request.type || this.determineRequestType(request.input);
// For simple queries, create only relevant tasks
if (isSimpleQuery) {
if (taskType === 'code-analysis' || request.input.toLowerCase().includes('analyze')) {
tasks.push({
id: this.generateTaskId(),
type: 'code-analysis',
capability: 'code-analysis',
description: 'Analyze code structure and quality',
input: request.input,
priority: 'high',
estimatedTime: mode === 'fast' ? 5000 : 15000,
});
} else {
// For simple queries, create only one primary task
const capability = this.getValidCapability(taskType);
tasks.push({
id: this.generateTaskId(),
type: taskType,
capability: capability,
description: `Process ${taskType} request`,
input: request.input,
priority: 'high',
estimatedTime: mode === 'fast' ? 5000 : 15000,
});
}
return tasks;
}
// For complex requests, create comprehensive tasks
if (request.type === 'code-analysis' || request.type === 'comprehensive') {
tasks.push({
id: this.generateTaskId(),
type: 'code-analysis',
capability: 'code-analysis',
description: 'Analyze code structure and quality',
input: request.input,
priority: 'high',
estimatedTime: mode === 'fast' ? 5000 : 15000,
});
}
if (request.type === 'code-generation' || request.type === 'comprehensive') {
tasks.push({
id: this.generateTaskId(),
type: 'code-generation',
capability: 'code-generation',
description: 'Generate required code',
input: request.input,
priority: 'high',
estimatedTime: mode === 'fast' ? 10000 : 30000,
});
}
if (request.type === 'testing' || request.type === 'comprehensive') {
tasks.push({
id: this.generateTaskId(),
type: 'testing',
capability: 'testing',
description: 'Generate and validate tests',
input: request.input,
priority: 'medium',
estimatedTime: mode === 'fast' ? 8000 : 20000,
});
}
if (request.type === 'documentation' || request.type === 'comprehensive') {
tasks.push({
id: this.generateTaskId(),
type: 'documentation',
capability: 'documentation',
description: 'Generate documentation',
input: request.input,
priority: 'medium',
estimatedTime: mode === 'fast' ? 5000 : 15000,
});
}
if (request.type === 'security-analysis' || request.type === 'comprehensive') {
tasks.push({
id: this.generateTaskId(),
type: 'security-analysis',
capability: 'security-analysis',
description: 'Analyze security vulnerabilities',
input: request.input,
priority: 'high',
estimatedTime: mode === 'fast' ? 10000 : 25000,
});
}
// Sort tasks by priority
const priorityOrder = { high: 3, medium: 2, low: 1 };
tasks.sort(
(a, b) =>
(priorityOrder[b.priority || 'low'] || 1) - (priorityOrder[a.priority || 'low'] || 1)
);
// Apply mode-specific filtering
if (mode === 'fast') {
return tasks.slice(0, 2); // Only top 2 tasks in fast mode
} else if (mode === 'balanced') {
return tasks.slice(0, 4); // Top 4 tasks in balanced mode
}
return tasks; // All tasks in thorough mode
}
/**
* Execute workflow tasks
*/
private async executeWorkflow(workflow: Workflow): Promise<ExecutionResult[]> {
const results: ExecutionResult[] = [];
const maxConcurrency = this.config.maxConcurrency;
if (maxConcurrency === 1) {
// Sequential execution
for (const task of workflow.tasks) {
const result = await this.executeTask(task);
results.push(result);
this.emit('task-completed', { task, result });
}
} else {
// Parallel execution with concurrency limit
const chunks = this.chunkArray(workflow.tasks, maxConcurrency);
for (const chunk of chunks) {
const chunkResults = await Promise.all(chunk.map(async task => this.executeTask(task)));
results.push(...chunkResults);
for (let i = 0; i < chunk.length; i++) {
this.emit('task-completed', { task: chunk[i], result: chunkResults[i] });
}
}
}
return results;
}
/**
* Execute individual task
*/
private async executeTask(task: Task): Promise<ExecutionResult> {
const capability = this.capabilities.get(task.capability || '');
if (!capability || !capability.enabled) {
throw new Error(`Capability '${task.capability || 'unknown'}' not available`);
}
const startTime = Date.now();
this.emit('task-started', task);
try {
const result = await capability.handler(task);
(result as ExecutionResult & { executionTime?: number; taskId?: string }).executionTime =
Date.now() - startTime;
(result as ExecutionResult & { executionTime?: number; taskId?: string }).taskId = task.id;
return result;
} catch (error) {
return {
success: false,
content: '',
metadata: {
model: 'unknown',
tokens: 0,
latency: Date.now() - startTime,
},
taskId: task.id,
};
}
}
/**
* Utility methods
*/
private generateWorkflowId(): string {
return `workflow-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}
private generateTaskId(): string {
return `task-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}
private isSimpleQuery(input: string): boolean {
const simplePatterns = [
/^what\s+files\s+are\s+in/gi,
/^list\s+files/gi,
/^show\s+me/gi,
/^explain\s+\w+$/gi,
/^how\s+to\s+\w+$/gi,
/^\w+\s+help$/gi,
];
// Simple queries are typically short and don't need comprehensive analysis
return input.length < 100 && simplePatterns.some(pattern => pattern.test(input));
}
private determineRequestType(input: string): string {
const lowerInput = input.toLowerCase();
if (
lowerInput.includes('analyze') ||
lowerInput.includes('review') ||
lowerInput.includes('audit')
) {
return 'code-analysis';
}
if (
lowerInput.includes('generate') ||
lowerInput.includes('create') ||
lowerInput.includes('write')
) {
return 'code-generation';
}
if (lowerInput.includes('test') || lowerInput.includes('spec')) {
return 'testing';
}
if (lowerInput.includes('document') || lowerInput.includes('readme')) {
return 'documentation';
}
if (lowerInput.includes('security') || lowerInput.includes('vulnerabilit')) {
return 'security-analysis';
}
return 'code-analysis'; // Default
}
private getValidCapability(taskType: string): string {
const validCapabilities = [
'code-analysis',
'code-generation',
'documentation',
'testing',
'refactoring',
'bug-fixing',
'performance-optimization',
'security-analysis',
];
return validCapabilities.includes(taskType) ? taskType : 'code-analysis';
}
private async _getProjectStructure(rootPath: string): Promise<string> {
try {
const { readdir, stat } = await import('fs/promises');
const { join, relative } = await import('path');
const structure: string[] = [];
const maxDepth = 3; // Limit depth to avoid huge outputs
const ignorePatterns = [
'node_modules',
'.git',
'dist',
'build',
'.vscode',
'.idea',
'coverage',
'.nyc_output',
'logs',
'*.log',
];
const walkDirectory = async (dirPath: string, depth: number = 0): Promise<void> => {
if (depth > maxDepth) return;
try {
const items = await readdir(dirPath);
for (const item of items) {
// Skip ignored patterns
if (ignorePatterns.some(pattern => item.includes(pattern.replace('*', '')))) {
continue;
}
const itemPath = join(dirPath, item);
const stats = await stat(itemPath);
const relativePath = relative(rootPath, itemPath);
if (stats.isDirectory()) {
structure.push(`${' '.repeat(depth)}📁 ${relativePath}/`);
await walkDirectory(itemPath, depth + 1);
} else if (stats.isFile()) {
const ext = item.split('.').pop()?.toLowerCase();
const icon =
ext === 'js' || ext === 'ts'
? '📄'
: ext === 'json'
? '⚙️'
: ext === 'md'
? '📝'
: ext === 'css'
? '🎨'
: '📄';
structure.push(`${' '.repeat(depth)}${icon} ${relativePath}`);
}
}
} catch (error) {
structure.push(`${' '.repeat(depth)}❌ Error reading ${relative(rootPath, dirPath)}`);
}
};
await walkDirectory(rootPath);
return `Project Structure:\n${structure.slice(0, 100).join('\n')}${structure.length > 100 ? '\n... (truncated)' : ''}`;
} catch (error) {
return `Error reading project structure: ${error instanceof Error ? error.message : String(error)}`;
}
}
private chunkArray<T>(array: T[], chunkSize: number): T[][] {
const chunks: T[][] = [];
for (let i = 0; i < array.length; i += chunkSize) {
chunks.push(array.slice(i, i + chunkSize));
}
return chunks;
}
private updateMetrics(response: ExecutionResponse): void {
this.metrics.tasksCompleted++;
this.metrics.lastExecutionTime = response.executionTime || 0;
if (response.success) {
this.metrics.successRate =
(this.metrics.successRate * (this.metrics.tasksCompleted - 1) + 1) /
this.metrics.tasksCompleted;
} else {
this.metrics.successRate =
(this.metrics.successRate * (this.metrics.tasksCompleted - 1)) /
this.metrics.tasksCompleted;
}
const executionTime = response.executionTime || 0;
this.metrics.averageExecutionTime =
(this.metrics.averageExecutionTime * (this.metrics.tasksCompleted - 1) + executionTime) /
this.metrics.tasksCompleted;
}
/**
* Get agent metrics
*/
getMetrics(): AgentMetrics {
return { ...this.metrics };
}
/**
* Clean up agent resources
*/
async destroy(): Promise<void> {
try {
// Cancel any active workflows
for (const workflow of this.activeWorkflows.values()) {
workflow.status = 'completed';
}
this.activeWorkflows.clear();
// Clear execution queue
this.executionQueue.length = 0;
// Clean up performance monitor
if (this.performanceMonitor && typeof this.performanceMonitor.destroy === 'function') {
this.performanceMonitor.destroy();
}
// Remove all listeners
this.removeAllListeners();
} catch (error) {
logger.error('Error during UnifiedAgent cleanup:', error);
}
}
/**
* Get active workflows
*/
getActiveWorkflows(): Workflow[] {
return Array.from(this.activeWorkflows.values());
}
/**
* Get available capabilities
*/
getCapabilities(): AgentCapability[] {
return Array.from(this.capabilities.values());
}
/**
* Enable/disable capability
*/
setCapabilityEnabled(name: string, enabled: boolean): void {
const capability = this.capabilities.get(name);
if (capability) {
capability.enabled = enabled;
this.emit('capability-toggled', { name, enabled });
}
}
/**
* Update configuration
*/
async updateConfig(newConfig: Partial<AgentConfig>): Promise<void> {
this.config = { ...this.config, ...newConfig };
await configManager.updateAgentConfig(this.config);
this.emit('config-updated', this.config);
}
}
// Legacy compatibility exports
export const timeoutManager = {
async executeWithRetry<T>(fn: () => Promise<T>, retries: number = 3): Promise<T> {
for (let i = 0; i < retries; i++) {
try {
return await fn();
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
throw new Error('Max retries exceeded');
},
};
interface EditSummary {
total: number;
approved: number;
rejected: number;
}
interface EditConfirmationResult {
approved: boolean;
edits: unknown;
}
interface EditApplicationResult {
success: boolean;
edits: unknown;
}
interface ConfirmationResult {
approved: unknown[];
rejected: unknown[];
}
export const globalEditConfirmation = {
getPendingEditsCount: () => 0,
proposeEdits: async (edits: unknown): Promise<EditConfirmationResult> => ({
approved: true,
edits,
}),
confirmAllEdits: async (): Promise<ConfirmationResult> => ({ approved: [], rejected: [] }),
applyEdits: async (edits: unknown): Promise<EditApplicationResult> => ({ success: true, edits }),
clearPendingEdits: () => {},
generateEditSummary: (): EditSummary => ({ total: 0, approved: 0, rejected: 0 }),
displayEditSummary: () => {},
};
interface IndexResult {
indexed: boolean;
path: string;
}
export const globalRAGSystem = {
indexPath: async (path: string): Promise<IndexResult> => ({
indexed: true,
path,
}),
};
let shutdownHandlersRegistered = false;
export const registerShutdownHandler = (handler: () => void) => {
if (!shutdownHandlersRegistered) {
process.on('SIGINT', handler);
process.on('SIGTERM', handler);
shutdownHandlersRegistered = true;
}
};
export const createManagedInterval = (fn: () => void, interval: number) => {
return setInterval(fn, interval);
};
export const clearManagedInterval = (id: NodeJS.Timeout) => {
clearInterval(id);
};
export const initializeEditConfirmation = () => globalEditConfirmation;
export const createUnifiedModelClient = (config: Record<string, unknown>) => {
return new UnifiedModelClient(config as any);
};
export interface AgentContext {
modelClient: UnifiedModelClient;
workingDirectory: string;
config: AgentConfig;
}