* Added OpenAI to the PipelineAgent

This commit is contained in:
2026-01-20 05:45:24 +01:00
parent d3998dea31
commit f72d5cc134
3 changed files with 67 additions and 23 deletions

View File

@@ -50,6 +50,9 @@ steps:
depends_on: [restore]
ai-agent-gate:
image: mcr.microsoft.com/dotnet/sdk:latest
environment:
OPENAI_API_KEY:
from_secret: openai_api_key
commands:
- |
set -euf

View File

@@ -7,4 +7,8 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenAI" Version="2.8.0" />
</ItemGroup>
</Project>

View File

@@ -1,4 +1,7 @@
using System.Xml.Linq;
using System.Text.Json;
using System.Xml.Linq;
using OpenAI;
using OpenAI.Chat;
if (args.Length == 0)
{
@@ -30,36 +33,70 @@ try
.Descendants(ns + "UnitTestResult")
.Count();
Console.WriteLine($"AIGate: total tests = {total}, failed = {failed.Count}");
if (failed.Count == 0)
var failuresForModel = failed.Select(f => new
{
Console.WriteLine("AIGate: All tests passed proceeding.");
return 0;
}
Console.WriteLine("AIGate: Listing up to 5 failing tests:");
foreach (var f in failed.Take(5))
{
var name = (string?)f.Attribute("testName") ?? "<no name>";
var message = f
TestName = (string?)f.Attribute("testName") ?? "<no name>",
Message = f
.Element(ns + "Output")?
.Element(ns + "ErrorInfo")?
.Element(ns + "Message")?
.Value;
.Value
}).ToList();
Console.WriteLine($" - {name}");
if (!string.IsNullOrWhiteSpace(message))
Console.WriteLine($" {message.Trim()}");
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY");
if (string.IsNullOrWhiteSpace(apiKey))
{
Console.WriteLine("AIGate: OPENAI_API_KEY not set, blocking by default.");
return 1;
}
Console.WriteLine("AIGate: Blocking pipeline because there are failing tests.");
return 1;
var client = new OpenAIClient(apiKey);
var systemPrompt = """
Jesteś asystentem DevOps oceniającym wyniki testów .NET.
Na podstawie listy błędów:
- sklasyfikuj każdy błąd jako: CriticalBug, InfraOrConfig, FlakyTest
- zwróć JEDEN obiekt JSON w formacie:
{
"decision": "block" | "allow" | "allow-with-warning",
"reason": "krótkie wyjaśnienie po polsku"
}
Decyzja:
- "block" gdy jest choć jeden CriticalBug.
- "allow-with-warning" gdy tylko InfraOrConfig lub FlakyTest, ale wygląda to na coś, co trzeba sprawdzić.
- "allow" gdy wszystko wskazuje na drobne lub znane flaky testy.
Nie dodawaj żadnego tekstu poza JSON.
""";
var userContent = JsonSerializer.Serialize(failuresForModel);
var chat = client.GetChatClient("gpt-4.1-mini");
var response = await chat.CompleteChatAsync(new SystemChatMessage(systemPrompt),
new UserChatMessage($"Błędy testów:\n{userContent}"));
var json = response.Value.Content[0].Text;
Console.WriteLine("AIGate LLM raw response:");
Console.WriteLine(json);
var decisionDoc = JsonDocument.Parse(json);
var decision = decisionDoc.RootElement.GetProperty("decision").GetString();
var reason = decisionDoc.RootElement.GetProperty("reason").GetString();
Console.WriteLine($"AIGate decision: {decision}");
Console.WriteLine($"Reason: {reason}");
return decision switch
{
"allow" => 0,
"allow-with-warning" => 0,
_ => 1
};
}
catch (Exception ex)
{
Console.WriteLine($"AIGate: error while reading TRX: {ex.Message}");
// Bezpieczniej zablokować pipeline, niż przepuścić w ciemno
return 1;
}