UNPKG

claude-flow-multilang

Version:

Revolutionary multilingual AI orchestration framework with cultural awareness and DDD architecture

1,005 lines (836 loc) 30.1 kB
import { getErrorMessage, hasAgentLoad, hasAgentTask, hasWorkStealingData, } from '../utils/type-guards.js'; /** * Advanced load balancing and work stealing implementation */ import { EventEmitter } from 'node:events'; import type { ILogger } from '../core/logger.js'; import type { IEventBus } from '../core/event-bus.js'; import type { AgentId, AgentState, TaskDefinition, TaskId, LoadBalancingStrategy, } from '../swarm/types.js'; import { WorkStealingCoordinator } from './work-stealing.js'; export interface LoadBalancerConfig { strategy: LoadBalancingStrategy; enableWorkStealing: boolean; stealThreshold: number; maxStealBatch: number; rebalanceInterval: number; loadSamplingInterval: number; affinityWeight: number; performanceWeight: number; loadWeight: number; latencyWeight: number; queueDepthThreshold: number; adaptiveThresholds: boolean; predictiveEnabled: boolean; debugMode: boolean; } export interface AgentLoad { agentId: string; queueDepth: number; cpuUsage: number; memoryUsage: number; taskCount: number; averageResponseTime: number; throughput: number; lastUpdated: Date; capacity: number; utilization: number; efficiency: number; affinityScore: number; } export interface LoadBalancingDecision { selectedAgent: AgentId; reason: string; confidence: number; alternatives: Array<{ agent: AgentId; score: number; reason: string; }>; loadBefore: Record<string, number>; predictedLoadAfter: Record<string, number>; timestamp: Date; } export interface WorkStealingOperation { id: string; sourceAgent: AgentId; targetAgent: AgentId; tasks: TaskId[]; reason: string; status: 'planned' | 'executing' | 'completed' | 'failed'; startTime: Date; endTime?: Date; metrics: { tasksStolen: number; loadReduction: number; latencyImprovement: number; }; } export interface LoadPrediction { agentId: string; currentLoad: number; predictedLoad: number; confidence: number; timeHorizon: number; factors: Record<string, number>; } /** * Advanced load balancing system with work stealing and predictive capabilities */ export class LoadBalancer extends EventEmitter { private logger: ILogger; private eventBus: IEventBus; private config: LoadBalancerConfig; private workStealer: WorkStealingCoordinator; // Load tracking private agentLoads = new Map<string, AgentLoad>(); private loadHistory = new Map<string, Array<{ timestamp: Date; load: number }>>(); private taskQueues = new Map<string, TaskDefinition[]>(); // Monitoring and statistics private loadSamplingInterval?: NodeJS.Timeout; private rebalanceInterval?: NodeJS.Timeout; private decisions: LoadBalancingDecision[] = []; private stealOperations = new Map<string, WorkStealingOperation>(); // Predictive modeling private loadPredictors = new Map<string, LoadPredictor>(); private performanceBaselines = new Map<string, PerformanceBaseline>(); constructor(config: Partial<LoadBalancerConfig>, logger: ILogger, eventBus: IEventBus) { super(); this.logger = logger; this.eventBus = eventBus; this.config = { strategy: 'hybrid', enableWorkStealing: true, stealThreshold: 3, maxStealBatch: 5, rebalanceInterval: 10000, loadSamplingInterval: 5000, affinityWeight: 0.3, performanceWeight: 0.3, loadWeight: 0.25, latencyWeight: 0.15, queueDepthThreshold: 10, adaptiveThresholds: true, predictiveEnabled: true, debugMode: false, ...config, }; this.workStealer = new WorkStealingCoordinator( { enabled: this.config.enableWorkStealing, stealThreshold: this.config.stealThreshold, maxStealBatch: this.config.maxStealBatch, stealInterval: this.config.rebalanceInterval, }, this.eventBus, this.logger, ); this.setupEventHandlers(); } private setupEventHandlers(): void { this.eventBus.on('agent:load-update', (data) => { if (hasAgentLoad(data)) { this.updateAgentLoad(data.agentId, data.load); } }); this.eventBus.on('task:queued', (data) => { if (hasAgentTask(data)) { this.updateTaskQueue(data.agentId, data.task, 'add'); } }); this.eventBus.on('task:started', (data) => { if (hasAgentTask(data)) { this.updateTaskQueue(data.agentId, data.task, 'remove'); } }); this.eventBus.on('workstealing:request', (data) => { if (hasWorkStealingData(data)) { this.executeWorkStealing(data.sourceAgent, data.targetAgent, data.taskCount); } }); this.eventBus.on('agent:performance-update', (data) => { this.updatePerformanceBaseline(data.agentId, data.metrics); }); } async initialize(): Promise<void> { this.logger.info('Initializing load balancer', { strategy: this.config.strategy, workStealing: this.config.enableWorkStealing, predictive: this.config.predictiveEnabled, }); // Initialize work stealer await this.workStealer.initialize(); // Start monitoring this.startLoadSampling(); this.startRebalancing(); this.emit('loadbalancer:initialized'); } async shutdown(): Promise<void> { this.logger.info('Shutting down load balancer'); // Stop monitoring if (this.loadSamplingInterval) clearInterval(this.loadSamplingInterval); if (this.rebalanceInterval) clearInterval(this.rebalanceInterval); // Shutdown work stealer await this.workStealer.shutdown(); this.emit('loadbalancer:shutdown'); } // === AGENT SELECTION === async selectAgent( task: TaskDefinition, availableAgents: AgentState[], constraints?: { excludeAgents?: AgentId[]; preferredAgents?: AgentId[]; maxLoad?: number; requireCapabilities?: string[]; }, ): Promise<LoadBalancingDecision> { const startTime = Date.now(); try { // Filter agents based on constraints let candidates = this.filterAgentsByConstraints(availableAgents, task, constraints); if (candidates.length === 0) { throw new Error('No suitable agents available for task'); } // Apply selection strategy const decision = await this.applySelectionStrategy(task, candidates); // Record decision this.decisions.push(decision); // Keep only last 1000 decisions if (this.decisions.length > 1000) { this.decisions.shift(); } const selectionTime = Date.now() - startTime; this.logger.debug('Agent selected', { taskId: task.id.id, selectedAgent: decision.selectedAgent.id, reason: decision.reason, confidence: decision.confidence, selectionTime, }); this.emit('agent:selected', { task, decision, selectionTime }); return decision; } catch (error) { this.logger.error('Agent selection failed', { taskId: task.id.id, error }); throw error; } } private filterAgentsByConstraints( agents: AgentState[], task: TaskDefinition, constraints?: { excludeAgents?: AgentId[]; preferredAgents?: AgentId[]; maxLoad?: number; requireCapabilities?: string[]; }, ): AgentState[] { return agents.filter((agent) => { // Exclude specific agents if (constraints?.excludeAgents?.some((excluded) => excluded.id === agent.id.id)) { return false; } // Check maximum load const load = this.agentLoads.get(agent.id.id); if (constraints?.maxLoad && load && load.utilization > constraints.maxLoad) { return false; } // Check required capabilities if (constraints?.requireCapabilities) { const hasAllCapabilities = constraints.requireCapabilities.every( (cap) => agent.capabilities.domains.includes(cap) || agent.capabilities.tools.includes(cap) || agent.capabilities.languages.includes(cap), ); if (!hasAllCapabilities) { return false; } } // Check task type compatibility if (!this.isAgentCompatible(agent, task)) { return false; } return true; }); } private async applySelectionStrategy( task: TaskDefinition, candidates: AgentState[], ): Promise<LoadBalancingDecision> { const scores = new Map<string, number>(); const reasons = new Map<string, string>(); const loadBefore: Record<string, number> = {}; const predictedLoadAfter: Record<string, number> = {}; // Calculate scores for each candidate for (const agent of candidates) { const agentId = agent.id.id; const load = this.agentLoads.get(agentId) || this.createDefaultLoad(agentId); loadBefore[agentId] = load.utilization; let score = 0; const scoreComponents: string[] = []; switch (this.config.strategy) { case 'load-based': score = this.calculateLoadScore(agent, load); scoreComponents.push(`load:${score.toFixed(2)}`); break; case 'performance-based': score = this.calculatePerformanceScore(agent, load); scoreComponents.push(`perf:${score.toFixed(2)}`); break; case 'capability-based': score = this.calculateCapabilityScore(agent, task); scoreComponents.push(`cap:${score.toFixed(2)}`); break; case 'affinity-based': score = this.calculateAffinityScore(agent, task); scoreComponents.push(`affinity:${score.toFixed(2)}`); break; case 'cost-based': score = this.calculateCostScore(agent, task); scoreComponents.push(`cost:${score.toFixed(2)}`); break; case 'hybrid': score = this.calculateHybridScore(agent, task, load); scoreComponents.push(`hybrid:${score.toFixed(2)}`); break; default: score = Math.random(); // Random fallback scoreComponents.push(`random:${score.toFixed(2)}`); } // Apply predictive modeling if enabled if (this.config.predictiveEnabled) { const prediction = this.predictLoad(agentId, task); const predictiveScore = this.calculatePredictiveScore(prediction); score = score * 0.7 + predictiveScore * 0.3; predictedLoadAfter[agentId] = prediction.predictedLoad; scoreComponents.push(`pred:${predictiveScore.toFixed(2)}`); } else { predictedLoadAfter[agentId] = load.utilization + 0.1; // Simple estimate } scores.set(agentId, score); reasons.set(agentId, scoreComponents.join(',')); } // Select agent with highest score const sortedCandidates = candidates.sort((a, b) => { const scoreA = scores.get(a.id.id) || 0; const scoreB = scores.get(b.id.id) || 0; return scoreB - scoreA; }); const selectedAgent = sortedCandidates[0]; const selectedScore = scores.get(selectedAgent.id.id) || 0; const selectedReason = reasons.get(selectedAgent.id.id) || 'unknown'; // Build alternatives list const alternatives = sortedCandidates.slice(1, 4).map((agent) => ({ agent: agent.id, score: scores.get(agent.id.id) || 0, reason: reasons.get(agent.id.id) || 'unknown', })); // Calculate confidence based on score gap const secondBestScore = alternatives.length > 0 ? alternatives[0].score : 0; const confidence = Math.min(1, selectedScore - secondBestScore + 0.5); return { selectedAgent: selectedAgent.id, reason: selectedReason, confidence, alternatives, loadBefore, predictedLoadAfter, timestamp: new Date(), }; } // === SCORING ALGORITHMS === private calculateLoadScore(agent: AgentState, load: AgentLoad): number { // Higher score for lower load (inverted) return 1 - load.utilization; } private calculatePerformanceScore(agent: AgentState, load: AgentLoad): number { const baseline = this.performanceBaselines.get(agent.id.id); if (!baseline) return 0.5; // Combine throughput, efficiency, and response time const throughputScore = Math.min(1, load.throughput / baseline.expectedThroughput); const efficiencyScore = load.efficiency; const responseScore = Math.min(1, baseline.expectedResponseTime / load.averageResponseTime); return (throughputScore + efficiencyScore + responseScore) / 3; } private calculateCapabilityScore(agent: AgentState, task: TaskDefinition): number { let score = 0; let totalChecks = 0; // Check language compatibility if (task.requirements.capabilities.includes('coding')) { const hasLanguage = agent.capabilities.languages.some( (lang) => task.context.language === lang, ); score += hasLanguage ? 1 : 0; totalChecks++; } // Check framework compatibility if (task.context.framework) { const hasFramework = agent.capabilities.frameworks.includes(task.context.framework); score += hasFramework ? 1 : 0; totalChecks++; } // Check domain expertise const domainMatch = agent.capabilities.domains.some( (domain) => task.type.includes(domain) || task.requirements.capabilities.includes(domain), ); score += domainMatch ? 1 : 0; totalChecks++; // Check required tools const hasTools = task.requirements.tools.every((tool) => agent.capabilities.tools.includes(tool), ); score += hasTools ? 1 : 0; totalChecks++; return totalChecks > 0 ? score / totalChecks : 0; } private calculateAffinityScore(agent: AgentState, task: TaskDefinition): number { const load = this.agentLoads.get(agent.id.id); if (!load) return 0; return load.affinityScore || 0.5; } private calculateCostScore(agent: AgentState, task: TaskDefinition): number { // Simple cost model - could be enhanced const baseCost = 1.0; const performanceFactor = agent.capabilities.speed; const reliabilityFactor = agent.capabilities.reliability; const cost = baseCost / (performanceFactor * reliabilityFactor); return Math.max(0, 1 - cost / 2); // Normalize and invert } private calculateHybridScore(agent: AgentState, task: TaskDefinition, load: AgentLoad): number { const loadScore = this.calculateLoadScore(agent, load); const performanceScore = this.calculatePerformanceScore(agent, load); const capabilityScore = this.calculateCapabilityScore(agent, task); const affinityScore = this.calculateAffinityScore(agent, task); return ( loadScore * this.config.loadWeight + performanceScore * this.config.performanceWeight + capabilityScore * this.config.affinityWeight + affinityScore * this.config.latencyWeight ); } private calculatePredictiveScore(prediction: LoadPrediction): number { // Higher score for lower predicted load const loadScore = 1 - prediction.predictedLoad; const confidenceBonus = prediction.confidence * 0.2; return Math.min(1, loadScore + confidenceBonus); } // === WORK STEALING === private async executeWorkStealing( sourceAgentId: string, targetAgentId: string, taskCount: number, ): Promise<void> { const operationId = `steal-${Date.now()}-${Math.random().toString(36).slice(2)}`; const operation: WorkStealingOperation = { id: operationId, sourceAgent: { id: sourceAgentId, swarmId: 'default', type: 'coordinator', instance: 1 }, targetAgent: { id: targetAgentId, swarmId: 'default', type: 'coordinator', instance: 1 }, tasks: [], reason: 'load_imbalance', status: 'planned', startTime: new Date(), metrics: { tasksStolen: 0, loadReduction: 0, latencyImprovement: 0, }, }; this.stealOperations.set(operationId, operation); try { operation.status = 'executing'; // Get source queue const sourceQueue = this.taskQueues.get(sourceAgentId) || []; if (sourceQueue.length === 0) { throw new Error('Source agent has no tasks to steal'); } // Select tasks to steal (lowest priority first) const tasksToSteal = sourceQueue .sort((a, b) => (a.priority === b.priority ? 0 : a.priority === 'low' ? -1 : 1)) .slice(0, Math.min(taskCount, this.config.maxStealBatch)); // Remove tasks from source for (const task of tasksToSteal) { this.updateTaskQueue(sourceAgentId, task, 'remove'); this.updateTaskQueue(targetAgentId, task, 'add'); operation.tasks.push(task.id); } // Update metrics operation.metrics.tasksStolen = tasksToSteal.length; operation.metrics.loadReduction = this.calculateLoadReduction( sourceAgentId, tasksToSteal.length, ); operation.status = 'completed'; operation.endTime = new Date(); this.logger.info('Work stealing completed', { operationId, sourceAgent: sourceAgentId, targetAgent: targetAgentId, tasksStolen: operation.metrics.tasksStolen, }); this.emit('workstealing:completed', { operation }); } catch (error) { operation.status = 'failed'; operation.endTime = new Date(); this.logger.error('Work stealing failed', { operationId, sourceAgent: sourceAgentId, targetAgent: targetAgentId, error, }); this.emit('workstealing:failed', { operation, error }); } } // === LOAD MONITORING === private startLoadSampling(): void { this.loadSamplingInterval = setInterval(() => { this.sampleAgentLoads(); }, this.config.loadSamplingInterval); this.logger.info('Started load sampling', { interval: this.config.loadSamplingInterval, }); } private startRebalancing(): void { this.rebalanceInterval = setInterval(() => { this.performRebalancing(); }, this.config.rebalanceInterval); this.logger.info('Started rebalancing', { interval: this.config.rebalanceInterval, }); } private async sampleAgentLoads(): Promise<void> { // Sample current loads from all agents for (const [agentId, load] of this.agentLoads) { // Update load history const history = this.loadHistory.get(agentId) || []; history.push({ timestamp: new Date(), load: load.utilization }); // Keep only last 100 samples if (history.length > 100) { history.shift(); } this.loadHistory.set(agentId, history); // Update predictive models if (this.config.predictiveEnabled) { this.updateLoadPredictor(agentId, load); } } } private async performRebalancing(): Promise<void> { if (!this.config.enableWorkStealing) return; try { // Find overloaded and underloaded agents const loads = Array.from(this.agentLoads.entries()); const overloaded = loads.filter( ([_, load]) => load.utilization > 0.8 && load.queueDepth > this.config.queueDepthThreshold, ); const underloaded = loads.filter( ([_, load]) => load.utilization < 0.3 && load.queueDepth < 2, ); if (overloaded.length === 0 || underloaded.length === 0) { return; // No rebalancing needed } // Perform work stealing for (const [overloadedId, overloadedLoad] of overloaded) { // Find best underloaded target const target = underloaded.sort((a, b) => a[1].utilization - b[1].utilization)[0]; if (target) { const [targetId] = target; const tasksToSteal = Math.min( Math.floor((overloadedLoad.queueDepth - targetId.length) / 2), this.config.maxStealBatch, ); if (tasksToSteal > 0) { await this.executeWorkStealing(overloadedId, targetId, tasksToSteal); } } } } catch (error) { this.logger.error('Rebalancing failed', error); } } // === PREDICTIVE MODELING === private predictLoad(agentId: string, task: TaskDefinition): LoadPrediction { const predictor = this.loadPredictors.get(agentId); const currentLoad = this.agentLoads.get(agentId)?.utilization || 0; if (!predictor) { // Simple fallback prediction return { agentId, currentLoad, predictedLoad: Math.min(1, currentLoad + 0.1), confidence: 0.5, timeHorizon: 60000, // 1 minute factors: { task_complexity: 0.1 }, }; } return predictor.predict(task); } private updateLoadPredictor(agentId: string, load: AgentLoad): void { let predictor = this.loadPredictors.get(agentId); if (!predictor) { predictor = new LoadPredictor(agentId); this.loadPredictors.set(agentId, predictor); } predictor.update(load); } // === UTILITY METHODS === private isAgentCompatible(agent: AgentState, task: TaskDefinition): boolean { // Check basic type compatibility const typeCompatible = this.checkTypeCompatibility(agent.type, task.type); if (!typeCompatible) return false; // Check capability requirements const hasRequiredCapabilities = task.requirements.capabilities.every((cap) => { return ( agent.capabilities.domains.includes(cap) || agent.capabilities.tools.includes(cap) || agent.capabilities.languages.includes(cap) ); }); return hasRequiredCapabilities; } private checkTypeCompatibility(agentType: string, taskType: string): boolean { const compatibilityMap: Record<string, string[]> = { researcher: ['research', 'analysis', 'documentation'], coder: ['coding', 'testing', 'integration', 'deployment'], analyst: ['analysis', 'validation', 'review'], reviewer: ['review', 'validation', 'documentation'], coordinator: ['coordination', 'monitoring', 'management'], tester: ['testing', 'validation', 'integration'], specialist: ['custom', 'optimization', 'maintenance'], }; const compatibleTypes = compatibilityMap[agentType] || []; return compatibleTypes.some((type) => taskType.includes(type)); } private updateAgentLoad(agentId: string, loadData: Partial<AgentLoad>): void { const existing = this.agentLoads.get(agentId) || this.createDefaultLoad(agentId); const updated = { ...existing, ...loadData, lastUpdated: new Date() }; // Recalculate utilization updated.utilization = this.calculateUtilization(updated); this.agentLoads.set(agentId, updated); } private updateTaskQueue( agentId: string, task: TaskDefinition, operation: 'add' | 'remove', ): void { const queue = this.taskQueues.get(agentId) || []; if (operation === 'add') { queue.push(task); } else { const index = queue.findIndex((t) => t.id.id === task.id.id); if (index >= 0) { queue.splice(index, 1); } } this.taskQueues.set(agentId, queue); // Update agent load this.updateAgentLoad(agentId, { queueDepth: queue.length, taskCount: queue.length, }); } private updatePerformanceBaseline(agentId: string, metrics: any): void { const baseline = this.performanceBaselines.get(agentId) || { expectedThroughput: 10, expectedResponseTime: 5000, expectedQuality: 0.8, }; // Update baseline with exponential moving average const alpha = 0.1; baseline.expectedThroughput = baseline.expectedThroughput * (1 - alpha) + metrics.throughput * alpha; baseline.expectedResponseTime = baseline.expectedResponseTime * (1 - alpha) + metrics.responseTime * alpha; this.performanceBaselines.set(agentId, baseline); } private calculateUtilization(load: AgentLoad): number { // Combine multiple factors to calculate overall utilization const queueFactor = Math.min(1, load.queueDepth / 10); const cpuFactor = load.cpuUsage / 100; const memoryFactor = load.memoryUsage / 100; const taskFactor = Math.min(1, load.taskCount / load.capacity); return (queueFactor + cpuFactor + memoryFactor + taskFactor) / 4; } private calculateLoadReduction(agentId: string, tasksRemoved: number): number { const load = this.agentLoads.get(agentId); if (!load) return 0; const oldUtilization = load.utilization; const newUtilization = this.calculateUtilization({ ...load, queueDepth: load.queueDepth - tasksRemoved, taskCount: load.taskCount - tasksRemoved, }); return oldUtilization - newUtilization; } private createDefaultLoad(agentId: string): AgentLoad { return { agentId, queueDepth: 0, cpuUsage: 0, memoryUsage: 0, taskCount: 0, averageResponseTime: 5000, throughput: 0, lastUpdated: new Date(), capacity: 10, utilization: 0, efficiency: 1.0, affinityScore: 0.5, }; } // === PUBLIC API === getAgentLoad(agentId: string): AgentLoad | undefined { return this.agentLoads.get(agentId); } getAllLoads(): AgentLoad[] { return Array.from(this.agentLoads.values()); } getRecentDecisions(limit: number = 10): LoadBalancingDecision[] { return this.decisions.slice(-limit); } getStealOperations(): WorkStealingOperation[] { return Array.from(this.stealOperations.values()); } getLoadStatistics(): { totalAgents: number; averageUtilization: number; overloadedAgents: number; underloadedAgents: number; totalStealOperations: number; successfulSteals: number; } { const loads = Array.from(this.agentLoads.values()); const avgUtilization = loads.reduce((sum, load) => sum + load.utilization, 0) / loads.length || 0; const overloaded = loads.filter((load) => load.utilization > 0.8).length; const underloaded = loads.filter((load) => load.utilization < 0.3).length; const successfulSteals = Array.from(this.stealOperations.values()).filter( (op) => op.status === 'completed', ).length; return { totalAgents: loads.length, averageUtilization: avgUtilization, overloadedAgents: overloaded, underloadedAgents: underloaded, totalStealOperations: this.stealOperations.size, successfulSteals, }; } // Force rebalance async forceRebalance(): Promise<void> { await this.performRebalancing(); } } // === HELPER CLASSES === class LoadPredictor { private agentId: string; private history: Array<{ timestamp: Date; load: number }> = []; private model: SimpleLinearModel; constructor(agentId: string) { this.agentId = agentId; this.model = new SimpleLinearModel(); } update(load: AgentLoad): void { this.history.push({ timestamp: new Date(), load: load.utilization }); // Keep only last 50 samples if (this.history.length > 50) { this.history.shift(); } // Update model if we have enough data if (this.history.length >= 10) { this.model.train(this.history); } } predict(task: TaskDefinition): LoadPrediction { const currentLoad = this.history.length > 0 ? this.history[this.history.length - 1].load : 0; let predictedLoad = currentLoad; let confidence = 0.5; if (this.history.length >= 10) { const prediction = this.model.predict(); predictedLoad = prediction.value; confidence = prediction.confidence; } // Adjust for task complexity const taskComplexity = this.estimateTaskComplexity(task); predictedLoad = Math.min(1, predictedLoad + taskComplexity * 0.1); return { agentId: this.agentId, currentLoad, predictedLoad, confidence, timeHorizon: 60000, factors: { task_complexity: taskComplexity, historical_trend: predictedLoad - currentLoad, }, }; } private estimateTaskComplexity(task: TaskDefinition): number { // Simple complexity estimation let complexity = 0.5; if (task.requirements.estimatedDuration && task.requirements.estimatedDuration > 300000) { complexity += 0.3; // Long-running task } if (task.requirements.memoryRequired && task.requirements.memoryRequired > 512 * 1024 * 1024) { complexity += 0.2; // Memory-intensive } if (task.requirements.capabilities.length > 3) { complexity += 0.2; // Requires multiple capabilities } return Math.min(1, complexity); } } class SimpleLinearModel { private slope = 0; private intercept = 0; private r2 = 0; train(data: Array<{ timestamp: Date; load: number }>): void { if (data.length < 2) return; // Convert timestamps to relative time points const startTime = data[0].timestamp.getTime(); const points = data.map((point, index) => ({ x: index, // Use index as x for simplicity y: point.load, })); // Calculate linear regression const n = points.length; const sumX = points.reduce((sum, p) => sum + p.x, 0); const sumY = points.reduce((sum, p) => sum + p.y, 0); const sumXY = points.reduce((sum, p) => sum + p.x * p.y, 0); const sumXX = points.reduce((sum, p) => sum + p.x * p.x, 0); this.slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX); this.intercept = (sumY - this.slope * sumX) / n; // Calculate R² const meanY = sumY / n; const ssTotal = points.reduce((sum, p) => sum + Math.pow(p.y - meanY, 2), 0); const ssRes = points.reduce((sum, p) => { const predicted = this.slope * p.x + this.intercept; return sum + Math.pow(p.y - predicted, 2); }, 0); this.r2 = 1 - ssRes / ssTotal; } predict(): { value: number; confidence: number } { // Predict next value (x = n) const nextValue = this.slope * 1 + this.intercept; // Predict 1 step ahead const confidence = Math.max(0, this.r2); // Use R² as confidence return { value: Math.max(0, Math.min(1, nextValue)), confidence, }; } } interface PerformanceBaseline { expectedThroughput: number; expectedResponseTime: number; expectedQuality: number; }