AX Agent MCP 명령 확장 및 에이전트 복구/슬래시 UX 보강

- /mcp 하위 명령 확장: add/remove/reset 지원, 도움말/상태 문구 동기화

- add 파서 추가: stdio(command+args), sse(url) 형식 검증 및 중복 서버명 방지

- remove all/단건 및 reset(세션 MCP 오버라이드 초기화) 실행 경로 구현

- Agentic loop 복구 프롬프트 강화: 미등록/비허용 도구 상황에서 tool_search 우선 가이드 적용

- 반복 실패 중단 응답에 재시도 루트 명시로 루프 복구 가능성 개선

- 슬래시 팝업 힌트 밀도 개선: agentUiExpressionLevel(rich/balanced/simple) 연동

- 테스트 보강: ChatWindowSlashPolicyTests(/mcp add/remove/reset, add 파서, 토크나이저), AgentLoopCodeQualityTests(tool_search 복구 가이드)

- 문서 반영: docs/DEVELOPMENT.md, docs/AGENT_ROADMAP.md에 2026-04-04 추가 진행 이력 기록
This commit is contained in:
2026-04-04 01:20:34 +09:00
parent 1256fdc43f
commit 52e9e34ade
6 changed files with 420 additions and 10 deletions

View File

@@ -399,6 +399,24 @@ public class AgentLoopCodeQualityTests
guidance.Should().Contain("NRE");
}
[Fact]
public void UnknownAndDisallowedRecoveryPrompts_ShouldGuideToolSearch()
{
var unknownPrompt = InvokePrivateStatic<string>(
"BuildUnknownToolRecoveryPrompt",
"read_file_typo",
new[] { "file_read", "file_edit", "tool_search" });
var disallowedPrompt = InvokePrivateStatic<string>(
"BuildDisallowedToolRecoveryPrompt",
"shell_exec",
new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "file_read", "tool_search" },
new[] { "file_read", "tool_search" });
unknownPrompt.Should().Contain("tool_search");
disallowedPrompt.Should().Contain("tool_search");
}
[Fact]
public void IsFailurePatternForTaskType_MatchesCaseInsensitiveTaskToken()
{
@@ -1756,6 +1774,28 @@ public class AgentLoopCodeQualityTests
resolved.Should().Be("Write");
}
[Fact]
public void ResolveRequestedToolName_MapsRgAliasToGrep()
{
var resolved = InvokePrivateStatic<string>(
"ResolveRequestedToolName",
"rg",
new List<string> { "file_read", "grep", "glob" });
resolved.Should().Be("grep");
}
[Fact]
public void ResolveRequestedToolName_MapsCodeSearchAliasToSearchCodebase()
{
var resolved = InvokePrivateStatic<string>(
"ResolveRequestedToolName",
"code_search",
new List<string> { "search_codebase", "file_read" });
resolved.Should().Be("search_codebase");
}
[Fact]
public void ShouldRunPostToolVerification_MatchesTabAndToolTypeRules()
{

View File

@@ -21,6 +21,9 @@ public class ChatWindowSlashPolicyTests
[InlineData("/mcp", "status", "")]
[InlineData("enable all", "enable", "all")]
[InlineData("reconnect chrome", "reconnect", "chrome")]
[InlineData("add chrome :: stdio node server.js", "add", "chrome :: stdio node server.js")]
[InlineData("remove all", "remove", "all")]
[InlineData("reset", "reset", "")]
[InlineData("status", "status", "")]
public void ParseMcpAction_ShouldParseExpected(string displayText, string expectedAction, string expectedTarget)
{
@@ -74,4 +77,46 @@ public class ChatWindowSlashPolicyTests
files.Count.Should().Be(expectedFileCount);
message.Should().Be(expectedMessage);
}
[Fact]
public void ParseMcpAddTarget_ShouldParseStdioEntry()
{
var (success, entry, error) = ChatWindow.ParseMcpAddTarget("chrome :: stdio node server.js --port 3000");
success.Should().BeTrue(error);
entry.Should().NotBeNull();
entry!.Name.Should().Be("chrome");
entry.Transport.Should().Be("stdio");
entry.Command.Should().Be("node");
entry.Args.Should().ContainInOrder("server.js", "--port", "3000");
}
[Fact]
public void ParseMcpAddTarget_ShouldParseSseEntry()
{
var (success, entry, error) = ChatWindow.ParseMcpAddTarget("internal-sse :: sse https://intra.example.local/mcp/sse");
success.Should().BeTrue(error);
entry.Should().NotBeNull();
entry!.Name.Should().Be("internal-sse");
entry.Transport.Should().Be("sse");
entry.Url.Should().Be("https://intra.example.local/mcp/sse");
}
[Fact]
public void ParseMcpAddTarget_ShouldFailWithoutSeparator()
{
var (success, _, error) = ChatWindow.ParseMcpAddTarget("chrome stdio node server.js");
success.Should().BeFalse();
error.Should().Contain("::");
}
[Fact]
public void TokenizeCommand_ShouldKeepQuotedSegments()
{
var tokens = ChatWindow.TokenizeCommand("stdio \"C:\\\\Program Files\\\\node.exe\" \"server path.js\" --flag");
tokens.Should().ContainInOrder("stdio", "C:\\\\Program Files\\\\node.exe", "server path.js", "--flag");
}
}