- 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)로 검증함
120 lines
3.8 KiB
C#
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\"");
|
|
}
|
|
}
|