jay-code
Version:
Streamlined AI CLI orchestration engine with mathematical rigor and enterprise-grade reliability
421 lines (357 loc) • 13.2 kB
text/typescript
/**
* Jay-Code Orchestrator: Single Model Intelligence with Mathematical Agent Coordination
* Integrates Model Manager, Planning Agent, and QA Agent with deterministic operations
*/
import { EventEmitter } from 'events';
import { ModelManager, ModelConfig } from './model-manager.js';
import { PlanningAgent, Task, ExecutionPlan } from './planning-agent.js';
import { QAAgent, QAReport } from './qa-agent.js';
import { JayCodeConfigManager, JayCodeConfig } from '../core/jay-config.js';
export interface ExecutionContext {
sessionId: string;
userId: string;
timestamp: Date;
environment: 'development' | 'testing' | 'production';
memoryNamespace?: string;
}
export interface TaskRequest {
id: string;
description: string;
requirements: string[];
context?: any;
priority: number;
estimatedComplexity?: number;
}
export interface ExecutionResult {
taskId: string;
success: boolean;
generatedCode?: string;
executionPlan?: ExecutionPlan;
qaReport?: QAReport;
metrics: ExecutionMetrics;
errors: string[];
warnings: string[];
artifacts: ResultArtifact[];
}
export interface ExecutionMetrics {
startTime: Date;
endTime: Date;
totalDuration: number;
planningDuration: number;
generationDuration: number;
qaDuration: number;
modelSwitches: number;
memoryOperations: number;
cacheHits: number;
}
export interface ResultArtifact {
type: 'code' | 'documentation' | 'test' | 'schema';
name: string;
content: string;
hash: string;
metadata: any;
}
export class JayCodeOrchestrator extends EventEmitter {
private modelManager: ModelManager;
private planningAgent: PlanningAgent;
private qaAgent: QAAgent;
private configManager: JayCodeConfigManager;
private config: JayCodeConfig;
private activeTasks: Map<string, ExecutionContext> = new Map();
constructor(configPath?: string) {
super();
this.configManager = new JayCodeConfigManager(configPath);
this.config = this.configManager.getConfig();
this.initializeComponents();
}
private initializeComponents(): void {
// Initialize Model Manager with primary and fallback models
const modelConfig = this.configManager.getModelConfig();
this.modelManager = new ModelManager(modelConfig.primary, modelConfig.fallback);
// Initialize Planning Agent with mathematical configuration
const planningConfig = this.configManager.getPlanningAgentConfig();
this.planningAgent = new PlanningAgent({
complexityThreshold: planningConfig.complexityThreshold,
maxSubTasks: planningConfig.maxSubTasks
});
// Initialize QA Agent with statistical configuration
const qaConfig = this.configManager.getQAAgentConfig();
this.qaAgent = new QAAgent({
passThreshold: qaConfig.passThreshold,
strictMode: qaConfig.strictMode,
autoFix: qaConfig.autoFix
});
// Set up event listeners for component coordination
this.setupEventListeners();
}
private setupEventListeners(): void {
this.modelManager.on('fallback-activated', (data) => {
this.emit('model-fallback', data);
});
this.modelManager.on('health-update', (data) => {
this.emit('model-health-update', data);
});
this.planningAgent.on('task-decomposed', (data) => {
this.emit('task-decomposed', data);
});
this.planningAgent.on('execution-coordinated', (data) => {
this.emit('execution-coordinated', data);
});
this.qaAgent.on('review-completed', (data) => {
this.emit('qa-completed', data);
});
}
/**
* Main task execution with mathematical precision and formal verification
*/
async executeTask(taskRequest: TaskRequest, context: ExecutionContext): Promise<ExecutionResult> {
const startTime = new Date();
const errors: string[] = [];
const warnings: string[] = [];
const artifacts: ResultArtifact[] = [];
try {
// Register active task
this.activeTasks.set(taskRequest.id, context);
this.emit('task-started', { taskId: taskRequest.id, context });
// Step 1: Task Analysis and Planning (if enabled)
let executionPlan: ExecutionPlan | undefined;
const planningStartTime = Date.now();
if (this.config.agents.planning.enabled) {
const task: Task = {
id: taskRequest.id,
description: taskRequest.description,
complexity: taskRequest.estimatedComplexity || 0.5,
dependencies: [],
requirements: taskRequest.requirements,
estimatedTokens: this.estimateTokens(taskRequest.description),
priority: taskRequest.priority
};
const subTasks = await this.planningAgent.breakdownTask(task);
executionPlan = {
id: `plan_${taskRequest.id}`,
originalTask: task,
subTasks,
dependencyGraph: new Map(),
criticalPath: [],
estimatedDuration: this.estimateDuration(subTasks),
prompt: this.buildPrompt(task, subTasks),
context: taskRequest.context
};
await this.planningAgent.coordinateExecution(executionPlan);
}
const planningDuration = Date.now() - planningStartTime;
// Step 2: Code Generation using Single Model Intelligence
const generationStartTime = Date.now();
const prompt = executionPlan ? executionPlan.prompt : this.buildSimplePrompt(taskRequest);
const generatedCode = await this.modelManager.generateCode(prompt, {
context: taskRequest.context,
temperature: 0.2, // Lower temperature for more deterministic results
maxTokens: executionPlan ?
executionPlan.subTasks.reduce((sum, st) => sum + st.estimatedTokens, 0) :
this.estimateTokens(taskRequest.description)
});
const generationDuration = Date.now() - generationStartTime;
// Step 3: Quality Assurance Analysis (if enabled)
let qaReport: QAReport | undefined;
const qaStartTime = Date.now();
if (this.config.agents.qa.enabled) {
qaReport = await this.qaAgent.reviewCode(generatedCode, {
requirements: taskRequest.requirements,
context: taskRequest.context,
standards: this.config.validation.enterpriseCompliance.standards
});
// Handle QA failures
if (!qaReport.passed && this.config.agents.qa.autoFix) {
warnings.push('Code quality below threshold, attempting auto-fix');
// Could implement auto-fix logic here
}
}
const qaDuration = Date.now() - qaStartTime;
// Step 4: Create Result Artifacts
artifacts.push({
type: 'code',
name: `${taskRequest.id}.generated.ts`,
content: generatedCode,
hash: this.calculateHash(generatedCode),
metadata: {
model: this.modelManager.getHealthMetrics(),
timestamp: new Date(),
context: taskRequest.context
}
});
if (executionPlan) {
artifacts.push({
type: 'documentation',
name: `${taskRequest.id}.execution-plan.json`,
content: JSON.stringify(executionPlan, null, 2),
hash: this.calculateHash(JSON.stringify(executionPlan)),
metadata: { type: 'execution-plan', subTasks: executionPlan.subTasks.length }
});
}
if (qaReport) {
artifacts.push({
type: 'documentation',
name: `${taskRequest.id}.qa-report.json`,
content: JSON.stringify(qaReport, null, 2),
hash: this.calculateHash(JSON.stringify(qaReport)),
metadata: { score: qaReport.analysis.overallScore, passed: qaReport.passed }
});
}
// Step 5: Finalize Results
const endTime = new Date();
const result: ExecutionResult = {
taskId: taskRequest.id,
success: true,
generatedCode,
executionPlan,
qaReport,
metrics: {
startTime,
endTime,
totalDuration: endTime.getTime() - startTime.getTime(),
planningDuration,
generationDuration,
qaDuration,
modelSwitches: 0, // Track model switches
memoryOperations: 0, // Track memory operations
cacheHits: 0 // Track cache hits
},
errors,
warnings,
artifacts
};
this.emit('task-completed', { taskId: taskRequest.id, success: true, result });
return result;
} catch (error) {
errors.push(`Execution failed: ${error.message}`);
const result: ExecutionResult = {
taskId: taskRequest.id,
success: false,
metrics: {
startTime,
endTime: new Date(),
totalDuration: Date.now() - startTime.getTime(),
planningDuration: 0,
generationDuration: 0,
qaDuration: 0,
modelSwitches: 0,
memoryOperations: 0,
cacheHits: 0
},
errors,
warnings,
artifacts
};
this.emit('task-failed', { taskId: taskRequest.id, error: error.message, result });
return result;
} finally {
// Clean up active task
this.activeTasks.delete(taskRequest.id);
}
}
private estimateTokens(description: string): number {
// Simple token estimation - 4 characters per token average
return Math.ceil(description.length / 4) * 10; // Multiply by 10 for code generation
}
private estimateDuration(subTasks: any[]): number {
// Estimate duration based on token count and complexity
return subTasks.reduce((sum, task) => sum + task.estimatedTokens * 0.1, 0);
}
private buildPrompt(task: Task, subTasks: any[]): string {
const basePrompt = `Generate high-quality TypeScript code for the following task:
Task: ${task.description}
Requirements: ${task.requirements.join(', ')}
Subtasks to implement:
${subTasks.map((st, i) => `${i + 1}. ${st.description}`).join('\n')}
Follow these principles:
- Write clean, maintainable TypeScript code
- Include proper error handling
- Add comprehensive documentation
- Follow mathematical precision and deterministic patterns
- Ensure enterprise-grade reliability
- Use strict typing throughout
Generate complete, production-ready code:`;
return basePrompt;
}
private buildSimplePrompt(taskRequest: TaskRequest): string {
return `Generate high-quality TypeScript code for: ${taskRequest.description}
Requirements: ${taskRequest.requirements.join(', ')}
Follow Jay-Code principles:
- Mathematical precision and deterministic operations
- Enterprise-grade reliability and error handling
- Clean, maintainable code with comprehensive documentation
- Strict TypeScript typing throughout
Generate complete, production-ready code:`;
}
private calculateHash(content: string): string {
// Simple hash function - in production, use crypto.createHash
let hash = 0;
for (let i = 0; i < content.length; i++) {
const char = content.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32-bit integer
}
return Math.abs(hash).toString(16);
}
/**
* Health check with mathematical performance guarantees
*/
async healthCheck(): Promise<{
status: 'healthy' | 'degraded' | 'failed';
components: Record<string, boolean>;
metrics: any;
}> {
const componentHealth = {
modelManager: await this.modelManager.healthCheck(),
planningAgent: this.config.agents.planning.enabled,
qaAgent: this.config.agents.qa.enabled,
configuration: true
};
const overallHealthy = Object.values(componentHealth).every(h => h);
return {
status: overallHealthy ? 'healthy' : 'degraded',
components: componentHealth,
metrics: {
activeTasks: this.activeTasks.size,
modelHealth: this.modelManager.getHealthMetrics(),
uptime: process.uptime()
}
};
}
/**
* Get current system metrics with statistical analysis
*/
getMetrics(): any {
return {
activeTasks: this.activeTasks.size,
modelHealth: this.modelManager.getHealthMetrics(),
configuration: this.config,
uptime: process.uptime(),
memoryUsage: process.memoryUsage()
};
}
}
private rulesEngine: DevelopmentRulesEngine;
constructor(configPath?: string) {
super();
this.configManager = new JayCodeConfigManager(configPath);
this.config = this.configManager.getConfig();
this.rulesEngine = new DevelopmentRulesEngine();
this.initializeComponents();
}
/**
* Validate generated code against Jay-Code development philosophy
*/
private async validateWithRules(code: string, context: any): Promise<any> {
const validation = this.rulesEngine.validateCode(code, context);
if (!validation.passed) {
this.emit('rules-validation-failed', {
score: validation.score,
violations: validation.violations,
recommendations: validation.recommendations
});
}
return validation;
}
// Update executeTask to include rules validation
// [The existing executeTask method would be modified to call validateWithRules]