Update PipelineAgent/ChangesChecker/ChangesCheckerAgent.cs
This commit is contained in:
@@ -6,17 +6,13 @@ using PipelineAgent.ChangesChecker.Models;
|
||||
using Services.Gitea;
|
||||
using Services.OpenAI;
|
||||
using Services.Vault;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace PipelineAgent.ChangesChecker;
|
||||
|
||||
public class ChangesCheckerAgent(IOpenAiService openAiService, IVaultService vaultService, IGiteaService giteaService, ILogger<ChangesCheckerAgent> logger)
|
||||
public class ChangesCheckerAgent(IOpenAiService openAiService, IVaultService vaultService, IGiteaService giteaService)
|
||||
: IChangesCheckerAgent
|
||||
{
|
||||
private readonly ILogger<ChangesCheckerAgent> _logger = logger;
|
||||
|
||||
public async Task<int> CheckChangesAsync(string repositoryPath, CancellationToken cancellationToken = default)
|
||||
public async Task<int> CheckChangesAsync(string repositoryPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -24,29 +20,30 @@ public class ChangesCheckerAgent(IOpenAiService openAiService, IVaultService vau
|
||||
.ConfigureAwait(false);
|
||||
var giteaConfiguration = GetGiteaConfiguration(repositoryPath, giteaApiToken);
|
||||
var giteaClient = giteaService.CreateGiteaClient(giteaConfiguration);
|
||||
var lastChangesFromGitea = await GetLastChangesFromGiteaAsync(giteaClient, giteaConfiguration, cancellationToken).ConfigureAwait(false);
|
||||
var lastChangesFromGitea =
|
||||
await GetLastChangesFromGiteaAsync(giteaClient, giteaConfiguration).ConfigureAwait(false);
|
||||
|
||||
if (lastChangesFromGitea.Count == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var chatRequest = lastChangesFromGitea.Select(x => new ChatRequest(x.Key, x.Value));
|
||||
var chatRequest = lastChangesFromGitea.Select(x => new ChatRequest(x.Value.Item1, x.Key, x.Value.Item2));
|
||||
var promptPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Prompts", "ChangesChecker.txt");
|
||||
var prompt = await File.ReadAllTextAsync(promptPath, cancellationToken).ConfigureAwait(false);
|
||||
var prompt = await File.ReadAllTextAsync(promptPath).ConfigureAwait(false);
|
||||
|
||||
var decisionDoc = await openAiService.GetResponseFromChat(chatRequest, prompt).ConfigureAwait(false);
|
||||
|
||||
if (decisionDoc is null)
|
||||
if (decisionDoc == null)
|
||||
{
|
||||
_logger.LogWarning("AI–Gate: no response from LLM, continuing by default.");
|
||||
Console.WriteLine("AI–Gate: no response from LLM, continuing by default.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!decisionDoc.RootElement.TryGetProperty("decision", out var decisionElement) ||
|
||||
decisionElement.ValueKind == JsonValueKind.Null)
|
||||
{
|
||||
_logger.LogWarning("AI–Gate: decision property missing or null in LLM response, continuing by default.");
|
||||
Console.WriteLine("AI–Gate: decision property missing or null in LLM response, continuing by default.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -57,71 +54,66 @@ public class ChangesCheckerAgent(IOpenAiService openAiService, IVaultService vau
|
||||
}
|
||||
|
||||
var content = GetFormattedJsonRequest(changesElement);
|
||||
var (isSuccess, response) = await giteaService.SendRequestAsync(giteaConfiguration, "contents", content)
|
||||
var (status, response) = await giteaService.SendRequestAsync(giteaConfiguration, "contents", content)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (isSuccess)
|
||||
if (status)
|
||||
{
|
||||
_logger.LogInformation("AI–Gate: created PR with suggested changes.");
|
||||
_logger.LogInformation(response);
|
||||
Console.WriteLine("AI–Gate: created PR with suggested changes.");
|
||||
Console.WriteLine(response);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError("AI–Gate: failed to create PR with suggested changes.");
|
||||
_logger.LogError(response);
|
||||
Console.WriteLine("AI–Gate: failed to create PR with suggested changes.");
|
||||
Console.WriteLine(response);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_logger.LogInformation("AI–Gate: operation was canceled.");
|
||||
Console.WriteLine("AI–Gate: operation was canceled.");
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "AI–Gate: while processing: {Message}", ex.Message);
|
||||
Console.WriteLine($"AI–Gate: while processing: {ex.Message}");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Dictionary<string, string>> GetLastChangesFromGiteaAsync(RepositoryApi giteaClient, GiteaConfiguration giteaConfiguration, CancellationToken cancellationToken = default)
|
||||
private async Task<Dictionary<string, (string, string)>> GetLastChangesFromGiteaAsync(RepositoryApi giteaClient,
|
||||
GiteaConfiguration giteaConfiguration)
|
||||
{
|
||||
var lastChanges = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
|
||||
var allBranches = await giteaService.GetAllBranchesAsync(giteaClient, giteaConfiguration).ConfigureAwait(false);
|
||||
|
||||
var lastUpdatedBranch = allBranches
|
||||
.Where(x => x.Name != "master" && x.Name.StartsWith("feature/"))
|
||||
.OrderByDescending(x => x.Commit.Timestamp)
|
||||
var lastChanges = new Dictionary<string, (string, string)>(StringComparer.Ordinal);
|
||||
var lastUpdatedBranch =
|
||||
(await giteaService.GetAllBranchesAsync(giteaClient, giteaConfiguration).ConfigureAwait(false))
|
||||
.Where(x => x.Name != "master" && x.Name.StartsWith("feature/")).OrderByDescending(x => x.Commit.Timestamp)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (lastUpdatedBranch is null ||
|
||||
if (lastUpdatedBranch == null ||
|
||||
lastUpdatedBranch.Commit.Message.Contains("LLM: Code review suggestions", StringComparison.Ordinal))
|
||||
{
|
||||
return lastChanges;
|
||||
}
|
||||
|
||||
var lastCommit = await giteaService
|
||||
.GetCommitByIdAsync(giteaClient, giteaConfiguration, lastUpdatedBranch.Commit.Id)
|
||||
.ConfigureAwait(false);
|
||||
.GetCommitByIdAsync(giteaClient, giteaConfiguration, lastUpdatedBranch.Commit.Id).ConfigureAwait(false);
|
||||
|
||||
if (lastCommit is null)
|
||||
if (lastCommit == null)
|
||||
{
|
||||
return lastChanges;
|
||||
}
|
||||
|
||||
foreach (CommitAffectedFiles commitAffectedFile in lastCommit.Files)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var fileContent = await giteaService
|
||||
.GetFileContentAsync(giteaClient, giteaConfiguration, commitAffectedFile.Filename, lastUpdatedBranch.Name)
|
||||
.ConfigureAwait(false);
|
||||
.GetFileContentAsync(giteaClient, giteaConfiguration, commitAffectedFile.Filename,
|
||||
lastUpdatedBranch.Name).ConfigureAwait(false);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(fileContent.Content) && !lastChanges.ContainsKey(commitAffectedFile.Filename))
|
||||
if (!string.IsNullOrEmpty(fileContent.Content) && !lastChanges.ContainsKey(commitAffectedFile.Filename))
|
||||
{
|
||||
lastChanges.Add(commitAffectedFile.Filename, Base64Decode(fileContent.Content));
|
||||
lastChanges.Add(commitAffectedFile.Filename, (lastUpdatedBranch.Name, Base64Decode(fileContent.Content)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,50 +130,41 @@ public class ChangesCheckerAgent(IOpenAiService openAiService, IVaultService vau
|
||||
? repoSpan.Slice(secondLastSlash + 1, lastSlash - secondLastSlash - 1).ToString()
|
||||
: string.Empty;
|
||||
string repository = lastSlash >= 0 ? repoSpan.Slice(lastSlash + 1).ToString() : repositoryPath;
|
||||
|
||||
const string defaultBranch = "master";
|
||||
const string defaultHost = "https://git.modwad.pl";
|
||||
const string branch = "master";
|
||||
const string host = "https://git.modwad.pl";
|
||||
|
||||
return new GiteaConfiguration
|
||||
{
|
||||
Owner = owner,
|
||||
Repository = repository,
|
||||
Branch = defaultBranch,
|
||||
Branch = branch,
|
||||
ApiToken = giteaApiToken,
|
||||
Host = defaultHost
|
||||
Host = host
|
||||
};
|
||||
}
|
||||
|
||||
private string Base64Decode(string base64EncodedData)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] bytes = Convert.FromBase64String(base64EncodedData);
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
catch (FormatException ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Invalid Base64 data encountered.");
|
||||
return string.Empty;
|
||||
}
|
||||
byte[] bytes = Convert.FromBase64String(base64EncodedData);
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
|
||||
private StringContent GetFormattedJsonRequest(JsonElement json)
|
||||
{
|
||||
string branch = json.GetProperty("branch").GetString() ?? string.Empty;
|
||||
string newBranch = json.GetProperty("new_branch").GetString() ?? string.Empty;
|
||||
string message = json.GetProperty("message").GetString() ?? string.Empty;
|
||||
var branch = json.GetProperty("branch").GetString();
|
||||
var newBranch = json.GetProperty("new_branch").GetString();
|
||||
var message = json.GetProperty("message").GetString();
|
||||
|
||||
var filesJson = json.GetProperty("files");
|
||||
var files = new List<object>(filesJson.GetArrayLength());
|
||||
|
||||
foreach (var fileEl in filesJson.EnumerateArray())
|
||||
{
|
||||
string operation = fileEl.GetProperty("operation").GetString() ?? string.Empty;
|
||||
string path = fileEl.GetProperty("path").GetString() ?? string.Empty;
|
||||
string contentPlain = fileEl.GetProperty("content").GetString() ?? string.Empty;
|
||||
var operation = fileEl.GetProperty("operation").GetString();
|
||||
var path = fileEl.GetProperty("path").GetString();
|
||||
var contentPlain = fileEl.GetProperty("content").GetString() ?? string.Empty;
|
||||
|
||||
string contentBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(contentPlain));
|
||||
var contentBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(contentPlain));
|
||||
|
||||
files.Add(new
|
||||
{
|
||||
@@ -199,7 +182,7 @@ public class ChangesCheckerAgent(IOpenAiService openAiService, IVaultService vau
|
||||
files
|
||||
};
|
||||
|
||||
string jsonPayload = JsonSerializer.Serialize(payload);
|
||||
var jsonPayload = JsonSerializer.Serialize(payload);
|
||||
|
||||
return new StringContent(jsonPayload, Encoding.UTF8, "application/json");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user