AX Agent 상태 메시지 내러티브 고도화 및 코워크/코드 진행 이력 개선

- AgentStatusNarrativeCatalog를 추가해 agent event를 탭(Cowork/Code), 도구 카테고리, 대상 힌트 기준으로 해석하고 상태 메시지/상세 설명/phase label/meta를 한 곳에서 생성하도록 정리함
- ChatWindow의 live pulse 상태, idle 진행 힌트, readable process feed 요약이 동일 narrative 카탈로그를 재사용하도록 변경해 단조로운 도구명 중심 문구를 작업 의도 중심 문구로 치환함
- README, DEVELOPMENT, NEXT_ROADMAP에 2026-04-15 12:14 (KST) 기준 이력과 남은 UX 마감 메모를 반영함

검증 결과
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_status_narrative\\ -p:IntermediateOutputPath=obj\\verify_status_narrative\\ : 경고 0 / 오류 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentStatusNarrativeCatalogTests|AgentLoopIterationPreparationServiceTests|AgentToolResultBudgetTests|ChatStorageServiceTests|AgentMessageInvariantHelperTests" -p:OutputPath=bin\\verify_status_narrative_tests\\ -p:IntermediateOutputPath=obj\\verify_status_narrative_tests\\ : 통과 15
This commit is contained in:
2026-04-15 12:15:58 +09:00
parent 717d0f2143
commit 5e40204e80
8 changed files with 681 additions and 103 deletions

View File

@@ -0,0 +1,93 @@
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentStatusNarrativeCatalogTests
{
[Fact]
public void BuildFromEvent_ShouldDescribeCodeReadWithTargetDetail()
{
var evt = new AgentEvent
{
Type = AgentEventType.ToolCall,
ToolName = "file_read",
Summary = "관련 파일 읽기",
ToolInput = "{\"path\":\"src/AxCopilot/Views/ChatWindow.xaml.cs\"}"
};
var narrative = AgentStatusNarrativeCatalog.BuildFromEvent(evt, "Code");
narrative.Message.Should().Contain("코드");
narrative.Detail.Should().Contain("ChatWindow.xaml.cs");
narrative.Category.Should().Be("read");
}
[Fact]
public void BuildFromEvent_ShouldExplainPermissionWaitClearly()
{
var evt = new AgentEvent
{
Type = AgentEventType.PermissionRequest,
ToolName = "file_edit",
Summary = "권한 확인 필요(Deny) · 대상: src/AxCopilot/Views/ChatWindow.xaml.cs"
};
var narrative = AgentStatusNarrativeCatalog.BuildFromEvent(evt, "Code");
narrative.Message.Should().Contain("권한");
narrative.Detail.Should().NotBeNullOrWhiteSpace();
narrative.Category.Should().Be("permission");
}
[Fact]
public void BuildIdle_ShouldReflectLastExecutionCategory()
{
var evt = new AgentEvent
{
Type = AgentEventType.ToolResult,
ToolName = "build_run",
Summary = "빌드 결과 확인"
};
var narrative = AgentStatusNarrativeCatalog.BuildIdle(
evt,
"Code",
TimeSpan.FromSeconds(16),
TimeSpan.FromSeconds(24),
pendingPostCompaction: false);
narrative.Message.Should().Contain("실행");
narrative.Detail.Should().Contain("로그");
narrative.Category.Should().Be("execute");
}
[Fact]
public void BuildProgressStepLabel_ShouldPromoteDocumentWorkToReadableSummary()
{
var evt = new AgentEvent
{
Type = AgentEventType.ToolCall,
ToolName = "html_create",
Summary = "html_create 실행"
};
var label = AgentStatusNarrativeCatalog.BuildProgressStepLabel(evt, "문서", "HTML 생성");
label.Should().Contain("문서");
}
[Fact]
public void BuildProgressPhaseMeta_ShouldExposeReadableEditCompletionLabel()
{
var evt = new AgentEvent
{
Type = AgentEventType.ToolResult,
ToolName = "file_edit",
Summary = "파일 수정 완료"
};
AgentStatusNarrativeCatalog.BuildProgressPhaseMeta(evt).Should().Be("수정 완료");
}
}