789 lines
37 KiB
C#
Executable File
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()
|
|
}
|
|
};
|
|
}
|
|
}
|
|
} |