SQL 리뷰 계층과 AgentLoop 응답 분해 helper를 추가해 코드 탭 마감 품질을 높임
- SqlReviewService를 추가해 SQL fallback 결과에 review severity, key findings, review checklist를 붙이고 schema migration, seed/reference data, reporting query마다 다른 검토 포인트를 안내하도록 확장했습니다. - SqlAnalysisService와 CodeLanguageCatalog를 업데이트해 SQL fallback summary와 workflow summary가 rollback notes, dependency order, row-count guard 같은 리뷰 힌트를 직접 포함하도록 보강했습니다. - AgentLoopResponseClassificationService를 추가해 LLM 응답에서 text/tool_use 분리, no-tool 연속 카운트 계산, thinking summary 생성을 helper로 분리했고 AgentLoopService 본체는 해당 helper를 사용하도록 정리했습니다. - README, docs/DEVELOPMENT.md, docs/NEXT_ROADMAP.md에 2026-04-15 11:50 (KST) 기준 이력을 반영했습니다. 검증 결과 - dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_loop_sql_finalize\\ -p:IntermediateOutputPath=obj\\verify_loop_sql_finalize\\ : 경고 0 / 오류 0 - dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentLoopResponseClassificationServiceTests|AgentLoopLlmRequestPreparationServiceTests|AgentLoopIterationPreparationServiceTests|SqlAnalysisServiceTests|SqlReviewServiceTests|CodeLanguageCatalogTests|WorkspaceContextGeneratorTests" -p:OutputPath=bin\\verify_loop_sql_finalize_tests\\ -p:IntermediateOutputPath=obj\\verify_loop_sql_finalize_tests\\ : 통과 48
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
using AxCopilot.Services;
|
||||
using AxCopilot.Services.Agent;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace AxCopilot.Tests.Services;
|
||||
|
||||
public class AgentLoopResponseClassificationServiceTests
|
||||
{
|
||||
[Fact]
|
||||
public void Classify_ShouldSplitTextAndToolCalls_AndResetNoToolCounter()
|
||||
{
|
||||
var blocks = new List<ContentBlock>
|
||||
{
|
||||
new() { Type = "text", Text = "I will inspect the repository." },
|
||||
new() { Type = "tool_use", ToolName = "file_read", ToolId = "tool-1" }
|
||||
};
|
||||
|
||||
var result = AgentLoopResponseClassificationService.Classify(blocks, consecutiveNoToolResponses: 2);
|
||||
|
||||
result.TextResponse.Should().Contain("inspect the repository");
|
||||
result.ToolCalls.Should().HaveCount(1);
|
||||
result.NextConsecutiveNoToolResponses.Should().Be(0);
|
||||
result.BuildThinkingSummary().Should().Contain("inspect the repository");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Classify_ShouldIncrementNoToolCounter_WhenOnlyTextBlocksArePresent()
|
||||
{
|
||||
var blocks = new List<ContentBlock>
|
||||
{
|
||||
new() { Type = "text", Text = "Plan step one." },
|
||||
new() { Type = "text", Text = "Plan step two." }
|
||||
};
|
||||
|
||||
var result = AgentLoopResponseClassificationService.Classify(blocks, consecutiveNoToolResponses: 1);
|
||||
|
||||
result.ToolCalls.Should().BeEmpty();
|
||||
result.TextParts.Should().HaveCount(2);
|
||||
result.NextConsecutiveNoToolResponses.Should().Be(2);
|
||||
}
|
||||
}
|
||||
@@ -105,5 +105,6 @@ public class CodeLanguageCatalogTests
|
||||
summary.Should().Contain("dialect");
|
||||
summary.Should().Contain("migration order");
|
||||
summary.Should().Contain("dependencies");
|
||||
summary.Should().Contain("rollback");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ public class SqlAnalysisServiceTests
|
||||
summary.Should().Contain("users");
|
||||
summary.Should().Contain("script:");
|
||||
summary.Should().Contain("review focus:");
|
||||
summary.Should().Contain("review severity:");
|
||||
summary.Should().Contain("review checklist:");
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
50
src/AxCopilot.Tests/Services/SqlReviewServiceTests.cs
Normal file
50
src/AxCopilot.Tests/Services/SqlReviewServiceTests.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using AxCopilot.Services;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace AxCopilot.Tests.Services;
|
||||
|
||||
public class SqlReviewServiceTests
|
||||
{
|
||||
[Fact]
|
||||
public void Review_ShouldMarkDestructiveMigrationAsHighSeverity()
|
||||
{
|
||||
var report = new SqlAnalysisReport(
|
||||
"PostgreSQL",
|
||||
"schema migration",
|
||||
["ALTER TABLE", "DROP TABLE"],
|
||||
["orders", "legacy_orders"],
|
||||
["customer_dim"],
|
||||
["Destructive DROP statement is present."],
|
||||
["Run the script in a disposable database and confirm rollback strategy first."],
|
||||
["Review forward migration order and any missing rollback note."]);
|
||||
|
||||
var review = SqlReviewService.Review(report);
|
||||
|
||||
review.Severity.Should().Be("high");
|
||||
review.Findings.Should().Contain(f => f.Contains("schema change", StringComparison.OrdinalIgnoreCase)
|
||||
|| f.Contains("rollback", StringComparison.OrdinalIgnoreCase));
|
||||
review.Checklist.Should().Contain(c => c.Contains("rollback", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Review_ShouldRecommendIdempotencyChecksForSeedScript()
|
||||
{
|
||||
var report = new SqlAnalysisReport(
|
||||
"Generic SQL",
|
||||
"seed / reference data",
|
||||
["INSERT", "UPDATE"],
|
||||
["seed_status", "users"],
|
||||
["account_status_map"],
|
||||
["Explicit transaction boundaries are not visible in the script."],
|
||||
["Confirm the script is safe to rerun and that seed data remains idempotent."],
|
||||
["Verify the script is idempotent before rerunning seed data."]);
|
||||
|
||||
var review = SqlReviewService.Review(report);
|
||||
|
||||
review.Severity.Should().Be("medium");
|
||||
review.Findings.Should().Contain(f => f.Contains("idempotent", StringComparison.OrdinalIgnoreCase));
|
||||
review.Checklist.Should().Contain(c => c.Contains("rerun", StringComparison.OrdinalIgnoreCase)
|
||||
|| c.Contains("idempotent", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user