Files
AX-Copilot-Codex/src/AxCopilot.Tests/Services/AgentLoopLlmRequestPreparationServiceTests.cs
lacvet f0f1f76f48 코드탭 tool trace 사전 정규화와 인코딩 정리 적용
- AgentMessageInvariantHelper에 전송 직전 structured tool trace 정규화 로직을 추가해 missing tool_result assistant와 orphan tool_result를 plain transcript로 평탄화함

- AgentLoopLlmRequestPreparationService에서 query view를 clone한 뒤 normalization을 적용하고 query_context 로그에 tool_trace_repair 메타를 남기도록 확장함

- SessionLearningCollector와 AgentLoopDiagnosticsFormatter의 깨진 문자열과 주석을 영어 기준으로 정리해 active Code 경로의 mojibake 노출을 줄임

- AgentMessageInvariantHelperTests, AgentLoopLlmRequestPreparationServiceTests를 보강하고 dotnet build 및 targeted dotnet test(34 통과, 경고/오류 0)로 검증함
2026-04-16 01:59:16 +09:00

120 lines
3.8 KiB
C#

using AxCopilot.Models;
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentLoopLlmRequestPreparationServiceTests
{
[Fact]
public void Prepare_ShouldInjectToolReminderOnFirstForcedCall()
{
var queryMessages = new List<ChatMessage>
{
new()
{
Role = "user",
Content = "inspect the repository"
}
};
var result = AgentLoopLlmRequestPreparationService.Prepare(
queryMessages,
totalToolCalls: 0,
forceInitialToolCallEnabled: true,
injectPreCallToolReminder: true,
noToolCallLoopRetry: 0);
result.ForceInitialToolCall.Should().BeTrue();
result.InjectedToolReminder.Should().BeTrue();
result.SendMessages.Should().HaveCount(2);
result.SendMessages.Last().Content.Should().Contain("[TOOL_REQUIRED]");
}
[Fact]
public void Prepare_ShouldSkipReminderWhenRetryLoopIsAlreadyActive()
{
var queryMessages = new List<ChatMessage>
{
new()
{
Role = "user",
Content = "inspect the repository"
}
};
var result = AgentLoopLlmRequestPreparationService.Prepare(
queryMessages,
totalToolCalls: 0,
forceInitialToolCallEnabled: true,
injectPreCallToolReminder: true,
noToolCallLoopRetry: 1);
result.ForceInitialToolCall.Should().BeTrue();
result.InjectedToolReminder.Should().BeFalse();
result.SendMessages.Should().HaveCount(1);
}
[Fact]
public void Prepare_ShouldAppendSupplementalMessagesBeforeReminder()
{
var queryMessages = new List<ChatMessage>
{
new()
{
Role = "user",
Content = "fix the latest build failure"
}
};
var supplemental = new ChatMessage
{
Role = "system",
MetaKind = "code_working_set",
Content = "[code-working-set]\n- Active diagnostic: MC4005 - Themes/ControlStyles.xaml"
};
var result = AgentLoopLlmRequestPreparationService.Prepare(
queryMessages,
totalToolCalls: 0,
forceInitialToolCallEnabled: true,
injectPreCallToolReminder: true,
noToolCallLoopRetry: 0,
supplementalMessages: [supplemental]);
result.SupplementalMessageCount.Should().Be(1);
result.SendMessages[1].MetaKind.Should().Be("code_working_set");
result.SendMessages.Last().Content.Should().Contain("[TOOL_REQUIRED]");
}
[Fact]
public void Prepare_ShouldNormalizeBrokenHistoricalToolTraceBeforeSend()
{
var queryMessages = new List<ChatMessage>
{
new()
{
Role = "assistant",
Content = """{"_tool_use_blocks":[{"type":"text","text":"Inspecting source"},{"type":"tool_use","id":"call-missing","name":"file_read","input":{"path":"App.xaml"}}]}"""
},
new()
{
Role = "user",
Content = "fix the latest build failure"
}
};
var result = AgentLoopLlmRequestPreparationService.Prepare(
queryMessages,
totalToolCalls: 1,
forceInitialToolCallEnabled: true,
injectPreCallToolReminder: true,
noToolCallLoopRetry: 0);
result.FlattenedStructuredAssistantCount.Should().Be(1);
result.ConvertedOrphanToolResultCount.Should().Be(0);
result.SendMessages[0].Content.Should().Be("Inspecting source\n[previous tool call] file_read");
queryMessages[0].Content.Should().StartWith("{\"_tool_use_blocks\"");
}
}