UNPKG

zai-mcp-server

Version:

🚀 REVOLUTIONARY AI-to-AI Collaboration Platform v6.1! NEW: Advanced Debugging Tools with Screenshot Analysis, Console Error Parsing, Automated Fix Generation, 5 Specialized Debugging Agents, Visual UI Analysis, JavaScript Error Intelligence, CSS/HTML Fix

1,290 lines (1,086 loc) 49.3 kB
/** * Adaptive Learning System * AI that learns from user feedback, adapts to coding styles, improves from project outcomes, and personalizes recommendations */ import { EventEmitter } from 'events'; import crypto from 'crypto'; import fs from 'fs/promises'; import path from 'path'; export class AdaptiveLearningSystem extends EventEmitter { constructor(options = {}) { super(); this.learningDir = options.learningDir || './learning'; this.maxLearningEntries = options.maxLearningEntries || 10000; this.adaptationThreshold = options.adaptationThreshold || 0.7; this.learningRate = options.learningRate || 0.1; this.personalityUpdateInterval = options.personalityUpdateInterval || 24 * 60 * 60 * 1000; // 24 hours this.userProfiles = new Map(); this.feedbackHistory = []; this.codingStyleProfiles = new Map(); this.projectOutcomes = []; this.learningModels = new Map(); this.adaptationRules = new Map(); this.personalizedRecommendations = new Map(); this.behaviorPatterns = new Map(); // Learning categories this.learningCategories = [ 'coding_style', 'preferences', 'feedback_patterns', 'success_metrics', 'error_patterns', 'tool_usage', 'collaboration_style', 'project_types' ]; // Adaptation weights this.adaptationWeights = { feedback: 0.30, outcomes: 0.25, usage_patterns: 0.20, coding_style: 0.15, collaboration: 0.10 }; console.log('🧠 Adaptive Learning System initialized'); // Initialize learning models immediately (synchronous) this.initializeLearningModels(); // Initialize directories and load data (async) this.initializeLearningSystem(); this.startPersonalityUpdates(); } async initializeLearningSystem() { try { await fs.mkdir(this.learningDir, { recursive: true }); await this.loadUserProfiles(); await this.loadFeedbackHistory(); await this.loadCodingStyleProfiles(); await this.loadProjectOutcomes(); console.log(`📁 Learning directory initialized: ${this.learningDir}`); } catch (error) { console.warn('⚠️ Failed to initialize learning system:', error.message); } } async loadUserProfiles() { try { const profilesFile = path.join(this.learningDir, 'user-profiles.json'); const data = await fs.readFile(profilesFile, 'utf8'); const profiles = JSON.parse(data); for (const [userId, profile] of Object.entries(profiles)) { this.userProfiles.set(userId, profile); } console.log(`📥 Loaded ${this.userProfiles.size} user profiles`); } catch (error) { console.log('📝 No existing user profiles found, starting fresh'); } } async loadFeedbackHistory() { try { const feedbackFile = path.join(this.learningDir, 'feedback-history.json'); const data = await fs.readFile(feedbackFile, 'utf8'); this.feedbackHistory = JSON.parse(data); console.log(`📥 Loaded ${this.feedbackHistory.length} feedback entries`); } catch (error) { console.log('📝 No existing feedback history found, starting fresh'); } } async loadCodingStyleProfiles() { try { const stylesFile = path.join(this.learningDir, 'coding-styles.json'); const data = await fs.readFile(stylesFile, 'utf8'); const styles = JSON.parse(data); for (const [userId, style] of Object.entries(styles)) { this.codingStyleProfiles.set(userId, style); } console.log(`📥 Loaded ${this.codingStyleProfiles.size} coding style profiles`); } catch (error) { console.log('📝 No existing coding styles found, starting fresh'); } } async loadProjectOutcomes() { try { const outcomesFile = path.join(this.learningDir, 'project-outcomes.json'); const data = await fs.readFile(outcomesFile, 'utf8'); this.projectOutcomes = JSON.parse(data); console.log(`📥 Loaded ${this.projectOutcomes.length} project outcomes`); } catch (error) { console.log('📝 No existing project outcomes found, starting fresh'); } } initializeLearningModels() { // Initialize feedback learning model this.learningModels.set('feedback', { name: 'Feedback Learning Model', accuracy: 0.75, trainingData: this.feedbackHistory.length, lastTrained: Date.now(), parameters: { positiveWeight: 1.2, negativeWeight: 0.8, neutralWeight: 1.0 } }); // Initialize style adaptation model this.learningModels.set('style', { name: 'Coding Style Adaptation Model', accuracy: 0.80, trainingData: this.codingStyleProfiles.size, lastTrained: Date.now(), parameters: { indentationWeight: 0.3, namingWeight: 0.25, structureWeight: 0.25, commentWeight: 0.2 } }); // Initialize outcome prediction model this.learningModels.set('outcomes', { name: 'Project Outcome Prediction Model', accuracy: 0.70, trainingData: this.projectOutcomes.length, lastTrained: Date.now(), parameters: { successFactors: ['team_size', 'complexity', 'timeline', 'resources'], failureFactors: ['scope_creep', 'poor_planning', 'resource_constraints'] } }); // Initialize personalization model this.learningModels.set('personalization', { name: 'Personalization Model', accuracy: 0.85, trainingData: this.userProfiles.size, lastTrained: Date.now(), parameters: { preferenceWeight: 0.4, behaviorWeight: 0.3, contextWeight: 0.3 } }); console.log(`🤖 Initialized ${this.learningModels.size} learning models`); } async recordUserFeedback(userId, feedbackData) { const feedbackId = crypto.randomBytes(8).toString('hex'); const feedback = { id: feedbackId, userId, type: feedbackData.type, // 'positive', 'negative', 'neutral' category: feedbackData.category, // 'suggestion', 'code_generation', 'analysis', etc. content: feedbackData.content, context: feedbackData.context || {}, rating: feedbackData.rating, // 1-5 scale timestamp: Date.now(), processed: false }; this.feedbackHistory.push(feedback); // Keep only recent feedback if (this.feedbackHistory.length > this.maxLearningEntries) { this.feedbackHistory = this.feedbackHistory.slice(-this.maxLearningEntries); } // Update user profile await this.updateUserProfile(userId, feedback); // Process feedback for learning await this.processFeedbackForLearning(feedback); console.log(`📝 Recorded feedback from ${userId}: ${feedbackData.type} (${feedbackData.rating}/5)`); this.emit('feedback:recorded', { feedbackId, userId, feedback }); return feedbackId; } async updateUserProfile(userId, feedback) { let profile = this.userProfiles.get(userId) || this.createDefaultUserProfile(userId); // Update feedback statistics profile.feedbackStats.total++; profile.feedbackStats[feedback.type]++; profile.feedbackStats.averageRating = (profile.feedbackStats.averageRating * (profile.feedbackStats.total - 1) + feedback.rating) / profile.feedbackStats.total; // Update category preferences if (!profile.categoryPreferences[feedback.category]) { profile.categoryPreferences[feedback.category] = { count: 0, averageRating: 0 }; } const categoryPref = profile.categoryPreferences[feedback.category]; categoryPref.averageRating = (categoryPref.averageRating * categoryPref.count + feedback.rating) / (categoryPref.count + 1); categoryPref.count++; // Update learning preferences if (feedback.rating >= 4) { profile.learningPreferences.preferredApproaches.push(feedback.context.approach || 'unknown'); } else if (feedback.rating <= 2) { profile.learningPreferences.avoidedApproaches.push(feedback.context.approach || 'unknown'); } // Update last activity profile.lastActivity = Date.now(); profile.totalInteractions++; this.userProfiles.set(userId, profile); // Save periodically if (profile.totalInteractions % 10 === 0) { await this.saveUserProfiles(); } } createDefaultUserProfile(userId) { return { userId, createdAt: Date.now(), lastActivity: Date.now(), totalInteractions: 0, feedbackStats: { total: 0, positive: 0, negative: 0, neutral: 0, averageRating: 3.0 }, categoryPreferences: {}, learningPreferences: { preferredApproaches: [], avoidedApproaches: [], adaptationLevel: 'medium', // low, medium, high personalityType: 'balanced' // analytical, creative, practical, balanced }, codingStyle: { indentation: 'spaces', // spaces, tabs indentSize: 2, namingConvention: 'camelCase', // camelCase, snake_case, PascalCase commentStyle: 'descriptive', // minimal, descriptive, verbose codeStructure: 'modular' // monolithic, modular, functional }, behaviorPatterns: { sessionDuration: [], preferredTimes: [], toolUsage: {}, collaborationStyle: 'independent' // independent, collaborative, mentoring }, adaptationHistory: [] }; } async processFeedbackForLearning(feedback) { // Update learning models based on feedback const feedbackModel = this.learningModels.get('feedback'); // Adjust model parameters based on feedback type if (feedback.type === 'positive' && feedback.rating >= 4) { feedbackModel.parameters.positiveWeight += this.learningRate * 0.1; } else if (feedback.type === 'negative' && feedback.rating <= 2) { feedbackModel.parameters.negativeWeight += this.learningRate * 0.1; } // Update model accuracy based on feedback consistency const recentFeedback = this.feedbackHistory .filter(f => f.userId === feedback.userId && f.category === feedback.category) .slice(-10); const consistency = this.calculateFeedbackConsistency(recentFeedback); feedbackModel.accuracy = Math.min(0.95, feedbackModel.accuracy + (consistency - 0.5) * this.learningRate); // Mark feedback as processed feedback.processed = true; // Generate adaptation rules await this.generateAdaptationRules(feedback); } calculateFeedbackConsistency(feedbackList) { if (feedbackList.length < 2) return 0.5; let consistencyScore = 0; for (let i = 1; i < feedbackList.length; i++) { const ratingDiff = Math.abs(feedbackList[i].rating - feedbackList[i-1].rating); consistencyScore += Math.max(0, 1 - ratingDiff / 4); // Normalize to 0-1 } return consistencyScore / (feedbackList.length - 1); } async generateAdaptationRules(feedback) { const ruleId = crypto.randomBytes(8).toString('hex'); const rule = { id: ruleId, userId: feedback.userId, category: feedback.category, condition: this.extractConditionFromFeedback(feedback), action: this.extractActionFromFeedback(feedback), confidence: this.calculateRuleConfidence(feedback), createdAt: Date.now(), appliedCount: 0, successRate: 0 }; this.adaptationRules.set(ruleId, rule); console.log(`🔧 Generated adaptation rule for ${feedback.userId}: ${rule.condition} → ${rule.action}`); this.emit('rule:generated', { ruleId, rule, feedback }); } extractConditionFromFeedback(feedback) { // Extract conditions based on feedback context const conditions = []; if (feedback.context.language) { conditions.push(`language=${feedback.context.language}`); } if (feedback.context.complexity) { conditions.push(`complexity=${feedback.context.complexity}`); } if (feedback.context.taskType) { conditions.push(`taskType=${feedback.context.taskType}`); } return conditions.join(' AND ') || 'general'; } extractActionFromFeedback(feedback) { // Extract actions based on feedback type and content if (feedback.type === 'positive') { return `increase_preference:${feedback.category}`; } else if (feedback.type === 'negative') { return `decrease_preference:${feedback.category}`; } else { return `maintain_preference:${feedback.category}`; } } calculateRuleConfidence(feedback) { // Calculate confidence based on feedback rating and context const baseConfidence = feedback.rating / 5.0; // Adjust based on context richness const contextScore = Object.keys(feedback.context).length / 10.0; // Adjust based on user's feedback history const userProfile = this.userProfiles.get(feedback.userId); const historyScore = userProfile ? Math.min(userProfile.feedbackStats.total / 100.0, 1.0) : 0; return Math.min(0.95, baseConfidence * 0.6 + contextScore * 0.2 + historyScore * 0.2); } async analyzeCodingStyle(userId, codeData) { const styleAnalysis = { userId, codeId: crypto.randomBytes(8).toString('hex'), language: codeData.language, timestamp: Date.now(), style: { indentation: this.detectIndentation(codeData.code), namingConvention: this.detectNamingConvention(codeData.code, codeData.language), commentStyle: this.detectCommentStyle(codeData.code), codeStructure: this.detectCodeStructure(codeData.code, codeData.language), complexity: this.calculateCodeComplexity(codeData.code) } }; // Update user's coding style profile await this.updateCodingStyleProfile(userId, styleAnalysis); console.log(`🎨 Analyzed coding style for ${userId}: ${styleAnalysis.style.namingConvention}, ${styleAnalysis.style.indentation}`); this.emit('style:analyzed', { userId, styleAnalysis }); return styleAnalysis; } detectIndentation(code) { const lines = code.split('\n').filter(line => line.trim().length > 0); let spaceCount = 0; let tabCount = 0; for (const line of lines) { if (line.startsWith(' ')) spaceCount++; if (line.startsWith('\t')) tabCount++; } if (tabCount > spaceCount) { return { type: 'tabs', size: 1 }; } else { // Detect space size const spaceSizes = [2, 4, 8]; let bestSize = 2; let maxMatches = 0; for (const size of spaceSizes) { const pattern = ' '.repeat(size); const matches = lines.filter(line => line.startsWith(pattern)).length; if (matches > maxMatches) { maxMatches = matches; bestSize = size; } } return { type: 'spaces', size: bestSize }; } } detectNamingConvention(code, language) { const identifiers = this.extractIdentifiers(code, language); let camelCaseCount = 0; let snakeCaseCount = 0; let pascalCaseCount = 0; for (const identifier of identifiers) { if (/^[a-z][a-zA-Z0-9]*$/.test(identifier)) camelCaseCount++; if (/^[a-z][a-z0-9_]*$/.test(identifier)) snakeCaseCount++; if (/^[A-Z][a-zA-Z0-9]*$/.test(identifier)) pascalCaseCount++; } if (camelCaseCount >= snakeCaseCount && camelCaseCount >= pascalCaseCount) { return 'camelCase'; } else if (snakeCaseCount >= pascalCaseCount) { return 'snake_case'; } else { return 'PascalCase'; } } extractIdentifiers(code, language) { // Simplified identifier extraction const identifierRegex = /\b[a-zA-Z_][a-zA-Z0-9_]*\b/g; const matches = code.match(identifierRegex) || []; // Filter out keywords const keywords = ['function', 'var', 'let', 'const', 'if', 'else', 'for', 'while', 'return', 'class', 'def', 'import']; return matches.filter(match => !keywords.includes(match.toLowerCase())); } detectCommentStyle(code) { const lines = code.split('\n'); let commentLines = 0; let totalCommentLength = 0; for (const line of lines) { const trimmed = line.trim(); if (trimmed.startsWith('//') || trimmed.startsWith('#') || trimmed.startsWith('*')) { commentLines++; totalCommentLength += trimmed.length; } } if (commentLines === 0) return 'minimal'; const avgCommentLength = totalCommentLength / commentLines; if (avgCommentLength > 50) return 'verbose'; if (avgCommentLength > 20) return 'descriptive'; return 'minimal'; } detectCodeStructure(code, language) { const functionCount = (code.match(/function\s+\w+|def\s+\w+/g) || []).length; const classCount = (code.match(/class\s+\w+/g) || []).length; const linesOfCode = code.split('\n').filter(line => line.trim().length > 0).length; if (classCount > 0 && functionCount / Math.max(classCount, 1) > 3) { return 'object_oriented'; } else if (functionCount > linesOfCode / 20) { return 'functional'; } else if (functionCount > 5) { return 'modular'; } else { return 'monolithic'; } } calculateCodeComplexity(code) { // Simplified complexity calculation const decisionPoints = (code.match(/\bif\b|\belse\b|\bwhile\b|\bfor\b|\bswitch\b|\bcase\b/g) || []).length; const linesOfCode = code.split('\n').filter(line => line.trim().length > 0).length; return Math.min(10, Math.round((decisionPoints / Math.max(linesOfCode / 10, 1)) * 10)); } async updateCodingStyleProfile(userId, styleAnalysis) { let profile = this.codingStyleProfiles.get(userId) || { userId, createdAt: Date.now(), analyses: [], dominantStyle: {}, consistency: 0, lastUpdated: Date.now() }; profile.analyses.push(styleAnalysis); // Keep only recent analyses if (profile.analyses.length > 50) { profile.analyses = profile.analyses.slice(-50); } // Calculate dominant style profile.dominantStyle = this.calculateDominantStyle(profile.analyses); profile.consistency = this.calculateStyleConsistency(profile.analyses); profile.lastUpdated = Date.now(); this.codingStyleProfiles.set(userId, profile); // Update user profile with coding style const userProfile = this.userProfiles.get(userId); if (userProfile) { userProfile.codingStyle = { indentation: profile.dominantStyle.indentation?.type || 'spaces', indentSize: profile.dominantStyle.indentation?.size || 2, namingConvention: profile.dominantStyle.namingConvention || 'camelCase', commentStyle: profile.dominantStyle.commentStyle || 'descriptive', codeStructure: profile.dominantStyle.codeStructure || 'modular' }; } // Save periodically if (profile.analyses.length % 5 === 0) { await this.saveCodingStyleProfiles(); } } calculateDominantStyle(analyses) { const styleCounts = { indentation: {}, namingConvention: {}, commentStyle: {}, codeStructure: {} }; // Count occurrences of each style for (const analysis of analyses) { const indentKey = `${analysis.style.indentation.type}_${analysis.style.indentation.size}`; styleCounts.indentation[indentKey] = (styleCounts.indentation[indentKey] || 0) + 1; styleCounts.namingConvention[analysis.style.namingConvention] = (styleCounts.namingConvention[analysis.style.namingConvention] || 0) + 1; styleCounts.commentStyle[analysis.style.commentStyle] = (styleCounts.commentStyle[analysis.style.commentStyle] || 0) + 1; styleCounts.codeStructure[analysis.style.codeStructure] = (styleCounts.codeStructure[analysis.style.codeStructure] || 0) + 1; } // Find dominant styles const dominantStyle = {}; for (const [category, counts] of Object.entries(styleCounts)) { const dominant = Object.entries(counts).reduce((a, b) => counts[a[0]] > counts[b[0]] ? a : b); if (category === 'indentation') { const [type, size] = dominant[0].split('_'); dominantStyle[category] = { type, size: parseInt(size) }; } else { dominantStyle[category] = dominant[0]; } } return dominantStyle; } calculateStyleConsistency(analyses) { if (analyses.length < 2) return 1.0; const dominantStyle = this.calculateDominantStyle(analyses); let consistentCount = 0; for (const analysis of analyses) { let matches = 0; let total = 0; // Check indentation consistency total++; if (analysis.style.indentation.type === dominantStyle.indentation.type && analysis.style.indentation.size === dominantStyle.indentation.size) { matches++; } // Check naming convention consistency total++; if (analysis.style.namingConvention === dominantStyle.namingConvention) { matches++; } // Check comment style consistency total++; if (analysis.style.commentStyle === dominantStyle.commentStyle) { matches++; } // Check code structure consistency total++; if (analysis.style.codeStructure === dominantStyle.codeStructure) { matches++; } if (matches / total >= 0.75) { consistentCount++; } } return consistentCount / analyses.length; } async recordProjectOutcome(userId, projectData) { const outcomeId = crypto.randomBytes(8).toString('hex'); const outcome = { id: outcomeId, userId, projectId: projectData.projectId, projectName: projectData.projectName, outcome: projectData.outcome, // 'success', 'failure', 'partial' metrics: { duration: projectData.duration, complexity: projectData.complexity, teamSize: projectData.teamSize, linesOfCode: projectData.linesOfCode, bugsFound: projectData.bugsFound || 0, userSatisfaction: projectData.userSatisfaction || 0 }, factors: { technologies: projectData.technologies || [], methodologies: projectData.methodologies || [], challenges: projectData.challenges || [], successFactors: projectData.successFactors || [] }, lessons: projectData.lessons || [], timestamp: Date.now() }; this.projectOutcomes.push(outcome); // Keep only recent outcomes if (this.projectOutcomes.length > this.maxLearningEntries) { this.projectOutcomes = this.projectOutcomes.slice(-this.maxLearningEntries); } // Update learning models await this.updateOutcomeLearning(outcome); console.log(`📊 Recorded project outcome for ${userId}: ${projectData.outcome} (${projectData.projectName})`); this.emit('outcome:recorded', { outcomeId, userId, outcome }); return outcomeId; } async updateOutcomeLearning(outcome) { const outcomeModel = this.learningModels.get('outcomes'); // Update success factors based on outcome if (outcome.outcome === 'success') { for (const factor of outcome.factors.successFactors) { if (!outcomeModel.parameters.successFactors.includes(factor)) { outcomeModel.parameters.successFactors.push(factor); } } } else if (outcome.outcome === 'failure') { for (const challenge of outcome.factors.challenges) { if (!outcomeModel.parameters.failureFactors.includes(challenge)) { outcomeModel.parameters.failureFactors.push(challenge); } } } // Update model accuracy based on prediction vs actual outcome const userProfile = this.userProfiles.get(outcome.userId); if (userProfile && userProfile.lastPrediction) { const predictionAccuracy = this.calculatePredictionAccuracy(userProfile.lastPrediction, outcome); outcomeModel.accuracy = (outcomeModel.accuracy + predictionAccuracy) / 2; } outcomeModel.trainingData = this.projectOutcomes.length; outcomeModel.lastTrained = Date.now(); } calculatePredictionAccuracy(prediction, actualOutcome) { // Compare predicted outcome with actual outcome if (prediction.outcome === actualOutcome.outcome) { return Math.min(1.0, prediction.confidence + 0.1); } else { return Math.max(0.1, prediction.confidence - 0.2); } } async generatePersonalizedRecommendations(userId, context = {}) { const userProfile = this.userProfiles.get(userId); if (!userProfile) { return this.generateDefaultRecommendations(context); } const recommendations = { userId, context, recommendations: [], confidence: 0, timestamp: Date.now() }; // Generate recommendations based on user profile recommendations.recommendations.push(...await this.generateStyleRecommendations(userProfile, context)); recommendations.recommendations.push(...await this.generateToolRecommendations(userProfile, context)); recommendations.recommendations.push(...await this.generateWorkflowRecommendations(userProfile, context)); recommendations.recommendations.push(...await this.generateLearningRecommendations(userProfile, context)); // If no specific recommendations generated, add general ones if (recommendations.recommendations.length === 0) { recommendations.recommendations.push({ type: 'general', category: 'engagement', message: 'Continue using the system to build your personalized profile', priority: 'medium', confidence: 0.7 }); recommendations.recommendations.push({ type: 'general', category: 'feedback', message: 'Provide more feedback to improve recommendation accuracy', priority: 'high', confidence: 0.8 }); } // Calculate overall confidence recommendations.confidence = this.calculateRecommendationConfidence(userProfile, recommendations.recommendations); // Apply adaptation rules recommendations.recommendations = await this.applyAdaptationRules(userId, recommendations.recommendations, context); // Store recommendations this.personalizedRecommendations.set(userId, recommendations); console.log(`💡 Generated ${recommendations.recommendations.length} personalized recommendations for ${userId}`); this.emit('recommendations:generated', { userId, recommendations }); return recommendations; } async generateStyleRecommendations(userProfile, context) { const recommendations = []; const codingStyle = userProfile.codingStyle; if (context.language && context.code) { // Recommend style consistency if (codingStyle.indentation === 'spaces') { recommendations.push({ type: 'style', category: 'indentation', message: `Use ${codingStyle.indentSize} spaces for indentation (matches your preferred style)`, priority: 'medium', confidence: 0.8 }); } if (codingStyle.namingConvention === 'camelCase') { recommendations.push({ type: 'style', category: 'naming', message: 'Use camelCase naming convention for variables and functions', priority: 'medium', confidence: 0.8 }); } if (codingStyle.commentStyle === 'descriptive') { recommendations.push({ type: 'style', category: 'comments', message: 'Add descriptive comments to explain complex logic', priority: 'low', confidence: 0.7 }); } } return recommendations; } async generateToolRecommendations(userProfile, context) { const recommendations = []; const behaviorPatterns = userProfile.behaviorPatterns; // Recommend tools based on usage patterns const mostUsedTools = Object.entries(behaviorPatterns.toolUsage || {}) .sort(([,a], [,b]) => b - a) .slice(0, 3); if (mostUsedTools.length > 0) { recommendations.push({ type: 'tool', category: 'productivity', message: `Consider using ${mostUsedTools[0][0]} for this task (your most used tool)`, priority: 'low', confidence: 0.6 }); } // Recommend new tools based on context if (context.taskType === 'testing' && !behaviorPatterns.toolUsage?.testing) { recommendations.push({ type: 'tool', category: 'testing', message: 'Consider using automated testing tools to improve code quality', priority: 'medium', confidence: 0.7 }); } return recommendations; } async generateWorkflowRecommendations(userProfile, context) { const recommendations = []; const feedbackStats = userProfile.feedbackStats; // Recommend workflows based on success patterns if (feedbackStats.averageRating > 4.0) { recommendations.push({ type: 'workflow', category: 'process', message: 'Your current workflow is highly effective - continue with similar approaches', priority: 'low', confidence: 0.9 }); } else if (feedbackStats.averageRating < 3.0) { recommendations.push({ type: 'workflow', category: 'improvement', message: 'Consider breaking down complex tasks into smaller, manageable steps', priority: 'high', confidence: 0.8 }); } // Recommend collaboration style if (userProfile.behaviorPatterns.collaborationStyle === 'independent' && context.teamSize > 1) { recommendations.push({ type: 'workflow', category: 'collaboration', message: 'Consider more collaborative approaches for team projects', priority: 'medium', confidence: 0.6 }); } return recommendations; } async generateLearningRecommendations(userProfile, context) { const recommendations = []; const learningPreferences = userProfile.learningPreferences; // Recommend learning approaches if (learningPreferences.adaptationLevel === 'high') { recommendations.push({ type: 'learning', category: 'adaptation', message: 'Try experimental approaches - you adapt well to new methods', priority: 'medium', confidence: 0.8 }); } else if (learningPreferences.adaptationLevel === 'low') { recommendations.push({ type: 'learning', category: 'stability', message: 'Stick with proven approaches that have worked well for you', priority: 'medium', confidence: 0.8 }); } // Recommend based on personality type if (learningPreferences.personalityType === 'analytical') { recommendations.push({ type: 'learning', category: 'approach', message: 'Focus on detailed analysis and systematic problem-solving', priority: 'low', confidence: 0.7 }); } else if (learningPreferences.personalityType === 'creative') { recommendations.push({ type: 'learning', category: 'approach', message: 'Explore innovative solutions and creative problem-solving techniques', priority: 'low', confidence: 0.7 }); } return recommendations; } generateDefaultRecommendations(context) { return { userId: 'unknown', context, recommendations: [ { type: 'general', category: 'getting_started', message: 'Start by providing feedback to help the system learn your preferences', priority: 'high', confidence: 0.9 }, { type: 'general', category: 'best_practices', message: 'Follow coding best practices for better maintainability', priority: 'medium', confidence: 0.8 } ], confidence: 0.5, timestamp: Date.now() }; } calculateRecommendationConfidence(userProfile, recommendations) { if (recommendations.length === 0) return 0; // Base confidence on user profile completeness let profileCompleteness = 0; profileCompleteness += userProfile.feedbackStats.total > 10 ? 0.3 : userProfile.feedbackStats.total * 0.03; profileCompleteness += userProfile.totalInteractions > 50 ? 0.3 : userProfile.totalInteractions * 0.006; profileCompleteness += Object.keys(userProfile.categoryPreferences).length > 5 ? 0.2 : Object.keys(userProfile.categoryPreferences).length * 0.04; profileCompleteness += userProfile.behaviorPatterns.sessionDuration.length > 10 ? 0.2 : userProfile.behaviorPatterns.sessionDuration.length * 0.02; // Average recommendation confidence const avgRecommendationConfidence = recommendations.reduce((sum, rec) => sum + rec.confidence, 0) / recommendations.length; return Math.min(0.95, profileCompleteness * 0.6 + avgRecommendationConfidence * 0.4); } async applyAdaptationRules(userId, recommendations, context) { const userRules = Array.from(this.adaptationRules.values()).filter(rule => rule.userId === userId); for (const rule of userRules) { if (this.ruleMatchesContext(rule, context)) { recommendations = this.applyRule(rule, recommendations); rule.appliedCount++; } } return recommendations; } ruleMatchesContext(rule, context) { // Simple rule matching - can be enhanced if (rule.condition === 'general') return true; const conditions = rule.condition.split(' AND '); for (const condition of conditions) { const [key, value] = condition.split('='); if (context[key] !== value) return false; } return true; } applyRule(rule, recommendations) { const [action, category] = rule.action.split(':'); if (action === 'increase_preference') { // Boost recommendations in this category recommendations.forEach(rec => { if (rec.category === category) { rec.priority = rec.priority === 'low' ? 'medium' : rec.priority === 'medium' ? 'high' : rec.priority; rec.confidence = Math.min(0.95, rec.confidence + 0.1); } }); } else if (action === 'decrease_preference') { // Lower recommendations in this category recommendations.forEach(rec => { if (rec.category === category) { rec.priority = rec.priority === 'high' ? 'medium' : rec.priority === 'medium' ? 'low' : rec.priority; rec.confidence = Math.max(0.1, rec.confidence - 0.1); } }); } return recommendations; } async predictProjectOutcome(userId, projectData) { const userProfile = this.userProfiles.get(userId); const outcomeModel = this.learningModels.get('outcomes'); let successProbability = 0.5; // Base probability // Adjust based on user's historical success rate if (userProfile) { const userOutcomes = this.projectOutcomes.filter(o => o.userId === userId); if (userOutcomes.length > 0) { const successCount = userOutcomes.filter(o => o.outcome === 'success').length; const historicalSuccessRate = successCount / userOutcomes.length; successProbability = historicalSuccessRate * 0.4 + successProbability * 0.6; } } // Adjust based on project factors for (const factor of projectData.technologies || []) { if (outcomeModel.parameters.successFactors.includes(factor)) { successProbability += 0.1; } } for (const challenge of projectData.challenges || []) { if (outcomeModel.parameters.failureFactors.includes(challenge)) { successProbability -= 0.1; } } // Adjust based on project metrics if (projectData.teamSize > 10) successProbability -= 0.1; if (projectData.complexity === 'high') successProbability -= 0.15; if (projectData.timeline && projectData.timeline < 30) successProbability -= 0.1; // Less than 30 days successProbability = Math.max(0.1, Math.min(0.9, successProbability)); const prediction = { userId, projectId: projectData.projectId, outcome: successProbability > 0.6 ? 'success' : successProbability < 0.4 ? 'failure' : 'partial', confidence: Math.abs(successProbability - 0.5) * 2, successProbability, factors: { userHistory: userProfile ? 'considered' : 'no_history', projectComplexity: projectData.complexity || 'unknown', teamSize: projectData.teamSize || 'unknown', timeline: projectData.timeline || 'unknown' }, recommendations: [], timestamp: Date.now() }; // Generate recommendations based on prediction if (successProbability < 0.5) { prediction.recommendations.push({ type: 'risk_mitigation', message: 'Consider reducing project scope or adding more resources', priority: 'high' }); } if (projectData.teamSize > 8) { prediction.recommendations.push({ type: 'team_management', message: 'Large team size may require additional coordination efforts', priority: 'medium' }); } // Store prediction for later accuracy assessment if (userProfile) { userProfile.lastPrediction = prediction; } console.log(`🔮 Predicted outcome for ${userId}: ${prediction.outcome} (${(successProbability * 100).toFixed(1)}% success probability)`); this.emit('prediction:generated', { userId, prediction }); return prediction; } startPersonalityUpdates() { setInterval(() => { this.updateUserPersonalities(); }, this.personalityUpdateInterval); console.log(`🧠 Personality updates started (${this.personalityUpdateInterval / (1000 * 60 * 60)}h interval)`); } async updateUserPersonalities() { for (const [userId, profile] of this.userProfiles) { const newPersonality = this.analyzeUserPersonality(profile); if (newPersonality !== profile.learningPreferences.personalityType) { profile.learningPreferences.personalityType = newPersonality; profile.adaptationHistory.push({ type: 'personality_update', from: profile.learningPreferences.personalityType, to: newPersonality, timestamp: Date.now() }); console.log(`🧠 Updated personality for ${userId}: ${newPersonality}`); this.emit('personality:updated', { userId, oldPersonality: profile.learningPreferences.personalityType, newPersonality }); } } } analyzeUserPersonality(profile) { const feedbackStats = profile.feedbackStats; const behaviorPatterns = profile.behaviorPatterns; const categoryPreferences = profile.categoryPreferences; let analyticalScore = 0; let creativeScore = 0; let practicalScore = 0; // Analyze feedback patterns if (feedbackStats.averageRating > 4.0) practicalScore += 2; if (feedbackStats.total > 50) analyticalScore += 2; // Analyze category preferences if (categoryPreferences.analysis?.averageRating > 4.0) analyticalScore += 3; if (categoryPreferences.code_generation?.averageRating > 4.0) creativeScore += 3; if (categoryPreferences.optimization?.averageRating > 4.0) practicalScore += 3; // Analyze behavior patterns const avgSessionDuration = behaviorPatterns.sessionDuration.length > 0 ? behaviorPatterns.sessionDuration.reduce((a, b) => a + b, 0) / behaviorPatterns.sessionDuration.length : 0; if (avgSessionDuration > 60) analyticalScore += 1; // Long sessions suggest analytical approach if (avgSessionDuration < 30) practicalScore += 1; // Short sessions suggest practical approach // Determine dominant personality if (analyticalScore > creativeScore && analyticalScore > practicalScore) { return 'analytical'; } else if (creativeScore > practicalScore) { return 'creative'; } else if (practicalScore > 0) { return 'practical'; } else { return 'balanced'; } } async saveUserProfiles() { try { const profilesFile = path.join(this.learningDir, 'user-profiles.json'); const profiles = Object.fromEntries(this.userProfiles); await fs.writeFile(profilesFile, JSON.stringify(profiles, null, 2)); } catch (error) { console.warn('⚠️ Failed to save user profiles:', error.message); } } async saveFeedbackHistory() { try { const feedbackFile = path.join(this.learningDir, 'feedback-history.json'); await fs.writeFile(feedbackFile, JSON.stringify(this.feedbackHistory, null, 2)); } catch (error) { console.warn('⚠️ Failed to save feedback history:', error.message); } } async saveCodingStyleProfiles() { try { const stylesFile = path.join(this.learningDir, 'coding-styles.json'); const styles = Object.fromEntries(this.codingStyleProfiles); await fs.writeFile(stylesFile, JSON.stringify(styles, null, 2)); } catch (error) { console.warn('⚠️ Failed to save coding style profiles:', error.message); } } async saveProjectOutcomes() { try { const outcomesFile = path.join(this.learningDir, 'project-outcomes.json'); await fs.writeFile(outcomesFile, JSON.stringify(this.projectOutcomes, null, 2)); } catch (error) { console.warn('⚠️ Failed to save project outcomes:', error.message); } } getLearningAnalytics() { const totalUsers = this.userProfiles.size; const totalFeedback = this.feedbackHistory.length; const totalOutcomes = this.projectOutcomes.length; const totalStyleAnalyses = Array.from(this.codingStyleProfiles.values()) .reduce((sum, profile) => sum + profile.analyses.length, 0); const avgFeedbackRating = this.feedbackHistory.length > 0 ? this.feedbackHistory.reduce((sum, f) => sum + f.rating, 0) / this.feedbackHistory.length : 0; const personalityDistribution = {}; for (const profile of this.userProfiles.values()) { const personality = profile.learningPreferences.personalityType; personalityDistribution[personality] = (personalityDistribution[personality] || 0) + 1; } const modelAccuracy = Array.from(this.learningModels.values()) .reduce((sum, model) => sum + model.accuracy, 0) / this.learningModels.size; return { totalUsers, totalFeedback, totalOutcomes, totalStyleAnalyses, avgFeedbackRating, personalityDistribution, modelAccuracy, adaptationRules: this.adaptationRules.size, learningModels: this.learningModels.size, learningCategories: this.learningCategories.length }; } getUserLearningProfile(userId) { const userProfile = this.userProfiles.get(userId); if (!userProfile) return null; const codingStyle = this.codingStyleProfiles.get(userId); const userOutcomes = this.projectOutcomes.filter(o => o.userId === userId); const userFeedback = this.feedbackHistory.filter(f => f.userId === userId); const userRules = Array.from(this.adaptationRules.values()).filter(r => r.userId === userId); return { userId, profile: userProfile, codingStyle: codingStyle || null, outcomes: userOutcomes, feedback: userFeedback.slice(-10), // Recent feedback adaptationRules: userRules, recommendations: this.personalizedRecommendations.get(userId) || null }; } }