MarketAlly.AIPlugin.Extensions/MarketAlly.AIPlugin.Learning/Services/LearningOrchestrator.cs

789 lines
37 KiB
C#
Executable File

using MarketAlly.AIPlugin.Analysis.Plugins;
using MarketAlly.AIPlugin.Learning.Configuration;
using MarketAlly.AIPlugin.Learning.Exceptions;
using MarketAlly.AIPlugin.Learning.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Collections.Concurrent;
using System.Diagnostics;
namespace MarketAlly.AIPlugin.Learning.Services
{
/// <summary>
/// Orchestrates the entire learning session with proper resource management
/// </summary>
public interface ILearningOrchestrator : IDisposable
{
Task<ComprehensiveLearningResult> ExecuteCompleteLearningSessionAsync(ComprehensiveLearningSession session);
}
public class LearningOrchestrator : ILearningOrchestrator, IDisposable
{
private readonly ILogger<LearningOrchestrator> _logger;
private readonly LearningConfiguration _config;
private readonly ISecurityService _securityService;
private readonly ILLMContextService _llmContextService;
private readonly IUnifiedContextService _unifiedContextService;
private readonly GitManager _gitManager;
private readonly CompilationManager _compilationManager;
private readonly ReportsManager _reportsManager;
private readonly RefactorIQIntegration _refactorIQIntegration;
private readonly string _correlationId;
private readonly ConcurrentDictionary<string, int> _fileAttempts;
private LearningSessionContext? _sessionContext;
private bool _disposed = false;
public LearningOrchestrator(
ILogger<LearningOrchestrator> logger,
IOptions<LearningConfiguration> configOptions,
ISecurityService securityService,
ILLMContextService llmContextService,
IUnifiedContextService unifiedContextService,
GitManager gitManager,
CompilationManager compilationManager,
ReportsManager reportsManager,
RefactorIQIntegration refactorIQIntegration)
{
_logger = logger;
_config = configOptions.Value;
_securityService = securityService;
_llmContextService = llmContextService;
_unifiedContextService = unifiedContextService;
_gitManager = gitManager;
_compilationManager = compilationManager;
_reportsManager = reportsManager;
_refactorIQIntegration = refactorIQIntegration;
_correlationId = Guid.NewGuid().ToString("N")[..8];
_fileAttempts = new ConcurrentDictionary<string, int>();
_logger.LogInformation("Learning orchestrator initialized with correlation ID: {CorrelationId}", _correlationId);
}
public async Task<ComprehensiveLearningResult> ExecuteCompleteLearningSessionAsync(ComprehensiveLearningSession session)
{
using var activity = new Activity("LearningSession");
activity.Start();
activity.SetTag("session.id", session.SessionId.ToString());
activity.SetTag("correlation.id", _correlationId);
var result = new ComprehensiveLearningResult
{
SessionId = session.SessionId,
StartTime = session.StartTime,
ProjectName = Path.GetFileNameWithoutExtension(session.SolutionPath),
Iterations = new List<LearningIteration>(),
FailedAttempts = new List<FailedAttempt>()
};
try
{
_logger.LogInformation("🚀 Starting comprehensive learning session for: {ProjectName} [CorrelationId: {CorrelationId}]",
result.ProjectName, _correlationId);
// Validate inputs
await ValidateSessionInputsAsync(session);
// Phase 0: Initialize Unified Context System
_logger.LogInformation("🧠 Phase 0: Initialize Context System [CorrelationId: {CorrelationId}]", _correlationId);
_sessionContext = await _unifiedContextService.InitializeLearningSessionAsync(
session.SolutionPath,
$"Learning session: {session.LearningMode} mode for {result.ProjectName}");
// Phase 1: Git Safety Setup
_logger.LogInformation("🌿 Phase 1: Git Safety Setup [CorrelationId: {CorrelationId}]", _correlationId);
result.GitInfo = await ExecuteGitSafetySetupAsync(session);
// Phase 2: Initial Analysis
_logger.LogInformation("📊 Phase 2: Initial Analysis [CorrelationId: {CorrelationId}]", _correlationId);
await ExecuteInitialAnalysisAsync(result, session);
// Phase 3: Initial Warnings Analysis (if enabled)
if (!session.SkipWarningsAnalysis)
{
_logger.LogInformation("⚠️ Phase 3: Initial Warnings Analysis [CorrelationId: {CorrelationId}]", _correlationId);
await ExecuteWarningsAnalysisAsync(result, "initial");
}
// Phase 4: Enhanced Semantic Analysis with Historical Context
if (session.EnableSemanticSearch && !string.IsNullOrEmpty(session.OpenAIApiKey))
{
_logger.LogInformation("🔍 Phase 4: Enhanced Semantic Code Analysis [CorrelationId: {CorrelationId}]", _correlationId);
await ExecuteEnhancedSemanticAnalysisAsync(result, session);
}
// Phase 5: Learning Iterations
_logger.LogInformation("🧠 Phase 5: Learning Iterations [CorrelationId: {CorrelationId}]", _correlationId);
await ExecuteLearningIterationsAsync(result, session);
// Phase 6: Final Analysis & Merge
_logger.LogInformation("📈 Phase 6: Final Analysis & Git Merge [CorrelationId: {CorrelationId}]", _correlationId);
await ExecuteFinalAnalysisAndMergeAsync(result, session);
// Phase 7: Generate Reports
_logger.LogInformation("📄 Phase 7: Generate Reports [CorrelationId: {CorrelationId}]", _correlationId);
await GenerateComprehensiveReportsAsync(result, session);
// Phase 8: Finalize Session with Context Storage
_logger.LogInformation("📝 Phase 8: Finalize Session Context [CorrelationId: {CorrelationId}]", _correlationId);
await FinalizeSessionContextAsync(result, session);
result.Success = true;
result.EndTime = DateTime.UtcNow;
result.TotalDuration = result.EndTime - result.StartTime;
_logger.LogInformation("✅ Learning session completed successfully! Duration: {Duration:F1} minutes [CorrelationId: {CorrelationId}]",
result.TotalDuration.TotalMinutes, _correlationId);
return result;
}
catch (Exception ex)
{
result.CriticalError = true;
result.ErrorMessage = ex.Message;
result.EndTime = DateTime.UtcNow;
_logger.LogError(ex, "❌ Critical error in learning session [CorrelationId: {CorrelationId}]", _correlationId);
await GenerateErrorReportAsync(result, ex);
return result;
}
}
private async Task ValidateSessionInputsAsync(ComprehensiveLearningSession session)
{
if (string.IsNullOrWhiteSpace(session.SolutionPath))
throw new ConfigurationException("SolutionPath", "Solution path cannot be empty");
if (!_securityService.IsPathSafe(session.SolutionPath))
throw new SecurityException("ValidateInput", session.SolutionPath, "Solution path failed security validation");
if (!File.Exists(session.SolutionPath))
throw new FileNotFoundException($"Solution file not found: {session.SolutionPath}");
// Validate learning mode configuration
var modeSettings = GetLearningModeSettings(session.LearningMode);
if (modeSettings == null)
throw new ConfigurationException("LearningMode", $"Unknown learning mode: {session.LearningMode}");
_logger.LogInformation("✅ Session inputs validated successfully [CorrelationId: {CorrelationId}]", _correlationId);
}
private LearningModeSettings? GetLearningModeSettings(string learningMode)
{
return learningMode?.ToLower() switch
{
"conservative" => _config.LearningModes.Conservative,
"moderate" => _config.LearningModes.Moderate,
"aggressive" => _config.LearningModes.Aggressive,
_ => null
};
}
private async Task<GitBranchInfo> ExecuteGitSafetySetupAsync(ComprehensiveLearningSession session)
{
try
{
var gitSetup = await _gitManager.SetupLearningBranchesAsync(session.SessionId);
if (!gitSetup.Success)
{
throw new GitOperationException("BranchSetup", session.SolutionPath, gitSetup.Error ?? "Unknown error");
}
_logger.LogInformation("✅ Git safety setup completed [CorrelationId: {CorrelationId}]", _correlationId);
return gitSetup;
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to setup Git safety [CorrelationId: {CorrelationId}]", _correlationId);
throw;
}
}
private async Task ExecuteInitialAnalysisAsync(ComprehensiveLearningResult result, ComprehensiveLearningSession session)
{
try
{
// Baseline compilation check
_logger.LogInformation("🔨 Checking baseline compilation [CorrelationId: {CorrelationId}]", _correlationId);
var baselineCompilation = await _compilationManager.ValidateCompilationAsync(session.SolutionPath);
result.BaselineCompilation = baselineCompilation;
if (baselineCompilation.Status == CompilationStatus.Failed)
{
throw new CompilationException(
baselineCompilation.ErrorCount,
baselineCompilation.WarningCount,
Array.Empty<string>());
}
_logger.LogInformation("📊 Baseline: {Status} ({ErrorCount} errors, {WarningCount} warnings) [CorrelationId: {CorrelationId}]",
baselineCompilation.Status, baselineCompilation.ErrorCount, baselineCompilation.WarningCount, _correlationId);
// RefactorIQ Database Population
_logger.LogInformation("🔍 Populating RefactorIQ database [CorrelationId: {CorrelationId}]", _correlationId);
var refactorIQResult = await _refactorIQIntegration.IndexSolutionAsync(session.SolutionPath);
result.InitialRefactorIQAnalysis = refactorIQResult;
if (refactorIQResult.Success)
{
_logger.LogInformation("✅ RefactorIQ analysis completed: {SymbolCount} symbols indexed [CorrelationId: {CorrelationId}]",
refactorIQResult.SymbolCount, _correlationId);
}
else
{
_logger.LogWarning("⚠️ RefactorIQ analysis failed: {Error} [CorrelationId: {CorrelationId}]",
refactorIQResult.Error, _correlationId);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed initial analysis [CorrelationId: {CorrelationId}]", _correlationId);
throw;
}
}
private async Task ExecuteWarningsAnalysisAsync(ComprehensiveLearningResult result, string phase)
{
try
{
_logger.LogInformation("⚠️ Analyzing {Phase} warnings [CorrelationId: {CorrelationId}]", phase, _correlationId);
// This would be implemented with the actual warnings analysis logic
// For now, it's a placeholder
await Task.Delay(100); // Simulate processing
_logger.LogInformation("✅ {Phase} warnings analysis completed [CorrelationId: {CorrelationId}]", phase, _correlationId);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "⚠️ {Phase} warnings analysis error (non-blocking) [CorrelationId: {CorrelationId}]", phase, _correlationId);
}
}
private async Task ExecuteEnhancedSemanticAnalysisAsync(ComprehensiveLearningResult result, ComprehensiveLearningSession session)
{
try
{
_logger.LogInformation("🔍 Starting enhanced semantic code analysis with historical context [CorrelationId: {CorrelationId}]", _correlationId);
result.AIFeaturesEnabled = true;
// Use unified context service for comprehensive analysis
var comprehensiveContext = await _unifiedContextService.PrepareFullContextAsync(
"analyze code for refactoring opportunities",
null,
_config.AI.MaxContextTokens);
// Extract current code analysis
if (comprehensiveContext.CurrentCodeAnalysis != null)
{
// CodeChunks is List<object>, need to handle appropriately
result.SemanticSearchResults = comprehensiveContext.CurrentCodeAnalysis.CodeChunks
.Select(chunk =>
{
// If chunk is already a CodeChunk, use it; otherwise create a placeholder
if (chunk is CodeChunk codeChunk)
return LearningVectorSearchResultExtensions.FromCodeChunk(codeChunk);
else
return new LearningVectorSearchResult
{
SymbolName = chunk?.ToString() ?? "Unknown",
SimilarityScore = 0.5
};
})
.ToList();
}
// Store insights about historical patterns found
if (comprehensiveContext.HistoricalInsights.Any())
{
var insight = $"Found {comprehensiveContext.HistoricalInsights.Count} relevant historical insights for refactoring analysis. " +
$"Previous patterns include: {string.Join(", ", comprehensiveContext.HistoricalInsights.Take(3).Select(h => h.Summary))}";
await _unifiedContextService.StoreLearningInsightAsync(
insight,
"historical-patterns",
null,
new Dictionary<string, object>
{
["historicalInsightCount"] = comprehensiveContext.HistoricalInsights.Count,
["sessionId"] = session.SessionId.ToString()
});
}
// Check for related decisions that might affect current analysis
if (comprehensiveContext.RelatedDecisions.Any())
{
var successfulDecisions = comprehensiveContext.RelatedDecisions.Where(d => d.Successful).ToList();
var failedDecisions = comprehensiveContext.RelatedDecisions.Where(d => !d.Successful).ToList();
if (failedDecisions.Any())
{
_logger.LogWarning("⚠️ Found {FailedCount} previous failed refactoring decisions that may affect current analysis [CorrelationId: {CorrelationId}]",
failedDecisions.Count, _correlationId);
}
if (successfulDecisions.Any())
{
_logger.LogInformation("✅ Found {SuccessfulCount} previous successful refactoring patterns to leverage [CorrelationId: {CorrelationId}]",
successfulDecisions.Count, _correlationId);
}
}
_logger.LogInformation("✅ Enhanced semantic analysis completed: {ResultCount} patterns identified, {HistoricalCount} historical insights, {DecisionCount} related decisions [CorrelationId: {CorrelationId}]",
result.SemanticSearchResults.Count,
comprehensiveContext.HistoricalInsights.Count,
comprehensiveContext.RelatedDecisions.Count,
_correlationId);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "⚠️ Enhanced semantic analysis error (non-blocking) [CorrelationId: {CorrelationId}]", _correlationId);
result.AIFeaturesEnabled = false;
}
}
private async Task ExecuteLearningIterationsAsync(ComprehensiveLearningResult result, ComprehensiveLearningSession session)
{
var sessionTimeout = TimeSpan.FromMinutes(session.SessionTimeoutMinutes);
var sessionStartTime = DateTime.UtcNow;
var modeSettings = GetLearningModeSettings(session.LearningMode)!;
var discoveredFiles = await DiscoverFilesForProcessingAsync(session.SolutionPath);
_logger.LogInformation("📁 Discovered {FileCount} files for processing [CorrelationId: {CorrelationId}]",
discoveredFiles.Count, _correlationId);
for (int iteration = 1; iteration <= modeSettings.MaxIterations; iteration++)
{
if (DateTime.UtcNow - sessionStartTime > sessionTimeout)
{
_logger.LogWarning("⏰ Session timeout reached ({TimeoutMinutes} minutes) [CorrelationId: {CorrelationId}]",
session.SessionTimeoutMinutes, _correlationId);
break;
}
_logger.LogInformation("🔄 Learning Iteration {Iteration}/{MaxIterations} [CorrelationId: {CorrelationId}]",
iteration, modeSettings.MaxIterations, _correlationId);
var iterationResult = await ExecuteSingleLearningIterationAsync(iteration, discoveredFiles, modeSettings, session);
result.Iterations.Add(iterationResult);
result.FailedAttempts.AddRange(iterationResult.FailedAttempts);
if (iterationResult.ShouldStopSession)
{
_logger.LogInformation("🛑 Stopping session due to iteration result [CorrelationId: {CorrelationId}]", _correlationId);
break;
}
// Commit successful iterations
if (iterationResult.Success && iterationResult.CompilationResult?.Status == CompilationStatus.Success)
{
await _gitManager.CommitSuccessfulIterationAsync(iteration, iterationResult.Summary ?? "Learning iteration");
await _gitManager.MergeToAIBranchIfStable();
}
}
_logger.LogInformation("🏁 Learning iterations completed: {IterationCount} iterations executed [CorrelationId: {CorrelationId}]",
result.Iterations.Count, _correlationId);
}
private async Task<LearningIteration> ExecuteSingleLearningIterationAsync(
int iterationNumber,
List<string> availableFiles,
LearningModeSettings modeSettings,
ComprehensiveLearningSession session)
{
var iteration = new LearningIteration
{
IterationNumber = iterationNumber,
StartTime = DateTime.UtcNow,
FailedAttempts = new List<FailedAttempt>()
};
try
{
// Select next file to work on
var targetFile = SelectNextFileForProcessing(availableFiles, _fileAttempts);
if (string.IsNullOrEmpty(targetFile))
{
iteration.Summary = "No more files available for processing";
iteration.ShouldStopSession = true;
return iteration;
}
iteration.TargetFile = targetFile;
_logger.LogInformation("🎯 Processing: {FileName} [CorrelationId: {CorrelationId}]",
Path.GetFileName(targetFile), _correlationId);
// Validate file security
if (!_securityService.IsFileAllowed(targetFile))
{
throw new SecurityException("FileAccess", targetFile, "File access denied by security policy");
}
// Get comprehensive context for this file including historical patterns
var fileContext = await _unifiedContextService.PrepareFullContextAsync(
$"analyze and refactor {Path.GetFileName(targetFile)}",
targetFile,
_config.AI.MaxContextTokens);
// Check for previous issues with this file
var similarIssues = await _unifiedContextService.FindSimilarPastIssuesAsync(
$"refactoring {Path.GetFileName(targetFile)}",
session.SolutionPath);
if (similarIssues.Any())
{
_logger.LogInformation("📚 Found {Count} similar past issues for guidance [CorrelationId: {CorrelationId}]",
similarIssues.Count, _correlationId);
}
// Attempt refactoring with context-informed approach
var refactoringDecision = "Enhanced refactoring with historical context";
var success = await AttemptContextInformedRefactoringAsync(targetFile, fileContext, similarIssues);
iteration.Success = success;
iteration.Summary = success ?
$"Successfully processed {Path.GetFileName(targetFile)} with historical context" :
$"Failed to process {Path.GetFileName(targetFile)}";
iteration.FixesApplied = success ? 1 : 0;
// Validate compilation after changes
var compilationResult = await _compilationManager.ValidateCompilationAsync(session.SolutionPath);
iteration.CompilationResult = compilationResult;
if (compilationResult.Status == CompilationStatus.Failed)
{
await _gitManager.RollbackLastChangeAsync();
iteration.Success = false;
// Store failed decision for future learning
await _unifiedContextService.StoreRefactoringDecisionAsync(
refactoringDecision,
"Compilation failed after refactoring attempt",
targetFile,
false);
}
else if (iteration.Success)
{
// Store successful decision for future learning
await _unifiedContextService.StoreRefactoringDecisionAsync(
refactoringDecision,
"Successful refactoring with historical context guidance",
targetFile,
true);
}
}
catch (Exception ex)
{
iteration.CriticalError = true;
iteration.ErrorMessage = ex.Message;
iteration.Summary = $"Critical error: {ex.Message}";
_logger.LogError(ex, "Critical error in iteration {Iteration} [CorrelationId: {CorrelationId}]",
iterationNumber, _correlationId);
}
finally
{
iteration.EndTime = DateTime.UtcNow;
iteration.Duration = iteration.EndTime - iteration.StartTime;
}
return iteration;
}
private async Task<List<string>> DiscoverFilesForProcessingAsync(string solutionPath)
{
var allFiles = Directory.GetFiles(Path.GetDirectoryName(solutionPath) ?? "", "*.cs", SearchOption.AllDirectories);
var processableFiles = allFiles.Where(file =>
{
if (!_securityService.IsFileAllowed(file))
return false;
var fileName = Path.GetFileName(file);
return !_config.Security.ForbiddenDirectories.Any(forbidden =>
file.Contains(forbidden, StringComparison.OrdinalIgnoreCase));
}).ToList();
_logger.LogInformation("📁 Found {ProcessableCount} processable files (excluded {ExcludedCount} files) [CorrelationId: {CorrelationId}]",
processableFiles.Count, allFiles.Length - processableFiles.Count, _correlationId);
return processableFiles;
}
private string? SelectNextFileForProcessing(List<string> availableFiles, ConcurrentDictionary<string, int> fileAttempts)
{
// Prioritize files that haven't been attempted yet
var unattemptedFiles = availableFiles.Where(f => !fileAttempts.ContainsKey(f)).ToList();
if (unattemptedFiles.Count > 0)
{
return unattemptedFiles.First();
}
// Then files with fewer attempts
var retryableFiles = availableFiles.Where(f =>
fileAttempts.GetValueOrDefault(f, 0) < _config.LearningModes.Conservative.MaxAttemptsPerFile
).OrderBy(f => fileAttempts[f]).ToList();
return retryableFiles.FirstOrDefault();
}
private async Task<bool> AttemptContextInformedRefactoringAsync(
string targetFile,
ComprehensiveContext fileContext,
List<HistoricalInsight> similarIssues)
{
try
{
_logger.LogDebug("Attempting context-informed refactoring for {FileName} [CorrelationId: {CorrelationId}]",
Path.GetFileName(targetFile), _correlationId);
// For now, this is a simplified implementation
// In a real implementation, this would use the comprehensive context to:
// 1. Understand the code structure and dependencies
// 2. Apply lessons learned from historical insights
// 3. Avoid patterns that previously failed
// 4. Use successful patterns from similar past refactorings
if (similarIssues.Any(i => i.Tags.Contains("failed") || i.Content.ContainsKey("failed")))
{
_logger.LogWarning("⚠️ Previous attempts on similar files failed - using conservative approach [CorrelationId: {CorrelationId}]",
_correlationId);
// Use more conservative refactoring approach
}
// Simulate refactoring work
await Task.Delay(100);
// Store insight about this refactoring attempt
var insight = $"Attempted context-informed refactoring on {Path.GetFileName(targetFile)}. " +
$"Had {similarIssues.Count} historical insights to guide the approach. " +
$"Context included {fileContext.CurrentCodeAnalysis?.CodeChunks?.Count ?? 0} code chunks.";
await _unifiedContextService.StoreLearningInsightAsync(
insight,
"context-informed-refactoring",
targetFile,
new Dictionary<string, object>
{
["historicalInsightCount"] = similarIssues.Count,
["codeChunkCount"] = fileContext.CurrentCodeAnalysis?.CodeChunks?.Count ?? 0,
["fileName"] = Path.GetFileName(targetFile)
});
// For demonstration, return success based on whether we have good historical guidance
return similarIssues.Any(i => i.Tags.Contains("successful"));
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in context-informed refactoring [CorrelationId: {CorrelationId}]", _correlationId);
return false;
}
}
private async Task FinalizeSessionContextAsync(ComprehensiveLearningResult result, ComprehensiveLearningSession session)
{
try
{
_logger.LogInformation("📝 Finalizing session context and storing insights [CorrelationId: {CorrelationId}]", _correlationId);
// Prepare session summary
var sessionSummary = $"Learning session completed for {result.ProjectName}. " +
$"Mode: {session.LearningMode}, " +
$"Duration: {result.TotalDuration.TotalMinutes:F1} minutes, " +
$"Iterations: {result.Iterations.Count}, " +
$"Successful: {result.Iterations.Count(i => i.Success)}, " +
$"Failed: {result.FailedAttempts.Count}";
// Prepare metrics
var metrics = new Dictionary<string, object>
{
["sessionId"] = session.SessionId.ToString(),
["projectName"] = result.ProjectName,
["learningMode"] = session.LearningMode,
["durationMinutes"] = result.TotalDuration.TotalMinutes,
["totalIterations"] = result.Iterations.Count,
["successfulIterations"] = result.Iterations.Count(i => i.Success),
["failedAttempts"] = result.FailedAttempts.Count,
["aiFeatures"] = result.AIFeaturesEnabled,
["semanticResults"] = result.SemanticSearchResults?.Count ?? 0,
["compilationStatus"] = result.FinalCompilation?.Status.ToString() ?? "Unknown",
["correlationId"] = _correlationId
};
// Store key insights from this session
var keyInsights = new List<string>();
if (result.AIFeaturesEnabled && result.SemanticSearchResults?.Any() == true)
{
keyInsights.Add($"AI-powered semantic analysis identified {result.SemanticSearchResults.Count} refactoring opportunities");
}
if (result.Iterations.Any(i => i.Success))
{
keyInsights.Add($"Successfully completed {result.Iterations.Count(i => i.Success)} refactoring iterations");
}
if (result.FailedAttempts.Any())
{
var failurePatterns = result.FailedAttempts
.GroupBy(f => f.FixApproach)
.OrderByDescending(g => g.Count())
.Take(3)
.Select(g => $"{g.Key} ({g.Count()} failures)");
keyInsights.Add($"Common failure patterns: {string.Join(", ", failurePatterns)}");
}
if (result.FinalCompilation?.Status == CompilationStatus.Success)
{
keyInsights.Add("Session completed with successful final compilation");
}
// Store each key insight
foreach (var insight in keyInsights)
{
await _unifiedContextService.StoreLearningInsightAsync(
insight,
"session-summary",
null,
metrics);
}
// Finalize the session
await _unifiedContextService.FinalizeLearningSessionAsync(sessionSummary, metrics);
_logger.LogInformation("✅ Session context finalized with {InsightCount} key insights stored [CorrelationId: {CorrelationId}]",
keyInsights.Count, _correlationId);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error finalizing session context [CorrelationId: {CorrelationId}]", _correlationId);
// Don't throw - session finalization errors shouldn't break the main flow
}
}
private async Task ExecuteFinalAnalysisAndMergeAsync(ComprehensiveLearningResult result, ComprehensiveLearningSession session)
{
try
{
// Final compilation check
_logger.LogInformation("🔨 Final compilation validation [CorrelationId: {CorrelationId}]", _correlationId);
var finalCompilation = await _compilationManager.ValidateCompilationAsync(session.SolutionPath);
result.FinalCompilation = finalCompilation;
_logger.LogInformation("📊 Final: {Status} ({ErrorCount} errors, {WarningCount} warnings) [CorrelationId: {CorrelationId}]",
finalCompilation.Status, finalCompilation.ErrorCount, finalCompilation.WarningCount, _correlationId);
// Merge to AI branch if we have successful iterations
var successfulIterations = result.Iterations.Count(i => i.Success);
if (successfulIterations > 0)
{
_logger.LogInformation("🌿 Merging {SuccessfulIterations} successful iterations to AI branch [CorrelationId: {CorrelationId}]",
successfulIterations, _correlationId);
var mergeResult = await _gitManager.FinalMergeToAIBranchAsync();
result.GitInfo.FinalMergeSuccess = mergeResult.Success;
result.GitInfo.FinalMergeMessage = mergeResult.Message;
if (mergeResult.Success)
{
_logger.LogInformation("✅ Successfully merged to AI branch [CorrelationId: {CorrelationId}]", _correlationId);
}
else
{
_logger.LogWarning("⚠️ Merge to AI branch failed: {Message} [CorrelationId: {CorrelationId}]",
mergeResult.Message, _correlationId);
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed final analysis and merge [CorrelationId: {CorrelationId}]", _correlationId);
throw;
}
}
private async Task GenerateComprehensiveReportsAsync(ComprehensiveLearningResult result, ComprehensiveLearningSession session)
{
try
{
await _reportsManager.GenerateSessionReportAsync(result, session.VerboseReporting);
if (result.FailedAttempts.Count > 0)
{
var sessionDate = result.StartTime.ToString("yyyy-MM-dd");
await _reportsManager.GenerateFailuresReportAsync(result.FailedAttempts, result.ProjectName, sessionDate);
}
await _reportsManager.UpdateCumulativeProgressAsync(result);
_logger.LogInformation("📄 Reports generated successfully [CorrelationId: {CorrelationId}]", _correlationId);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to generate reports [CorrelationId: {CorrelationId}]", _correlationId);
throw;
}
}
private async Task GenerateErrorReportAsync(ComprehensiveLearningResult result, Exception ex)
{
try
{
await _reportsManager.GenerateErrorReportAsync(result, ex);
}
catch (Exception reportEx)
{
_logger.LogError(reportEx, "Failed to generate error report [CorrelationId: {CorrelationId}]", _correlationId);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed && disposing)
{
try
{
_refactorIQIntegration?.Dispose();
_logger.LogInformation("Learning orchestrator disposed [CorrelationId: {CorrelationId}]", _correlationId);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error during disposal [CorrelationId: {CorrelationId}]", _correlationId);
}
}
_disposed = true;
}
}
// Extension method for creating LearningVectorSearchResult from CodeChunk
public static class LearningVectorSearchResultExtensions
{
public static LearningVectorSearchResult FromCodeChunk(CodeChunk chunk)
{
return new LearningVectorSearchResult
{
FilePath = chunk.FilePath,
SymbolName = chunk.Symbols.FirstOrDefault() ?? "",
SymbolType = chunk.Type.ToString(),
Content = chunk.Content,
SimilarityScore = chunk.RelevanceScore,
LineNumber = chunk.LineStart,
ProjectName = Path.GetFileNameWithoutExtension(chunk.FilePath),
Metadata = new Dictionary<string, object>
{
["EstimatedTokens"] = chunk.EstimatedTokens,
["ChunkType"] = chunk.Type.ToString()
}
};
}
}
}