AX Agent 도구·스킬 정합성 재구성 및 실행 품질 보강
변경 목적: - AX Agent의 도구 이름, 내부 설정, 스킬 정책, 실행 루프 사이의 불일치를 줄이고 전체 동작 품질을 높인다. - claw-code 수준의 일관된 동작 품질을 참고하되 AX 구조에 맞는 고유한 카탈로그·정규화 레이어로 재구성한다. 핵심 수정사항: - 도구 canonical id, legacy alias, 탭 노출, 설정 카테고리, read-only 분류를 중앙 카탈로그로 통합했다. - ToolRegistry, AgentLoopService, 병렬 실행 분류, 권한 처리, 훅 처리, 스킬 allowed-tools 해석이 같은 이름 체계를 사용하도록 정리했다. - Agent 설정/일반 설정/도움말의 도구 카드와 훅 편집기, 스킬 설명을 현재 런타임 구조에 맞게 갱신했다. - 컨텍스트 압축, intent gate, spawn agents, session learning, model prompt adapter, workspace context 관련 변경과 테스트 추가를 함께 반영했다. - 문서 이력과 비교/로드맵 문서를 최신 상태로 갱신했다. 검증 결과: - dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_toolcat\ -p:IntermediateOutputPath=obj\verify_toolcat\ : 경고 0 / 오류 0 - dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter AgentToolCatalogTests -p:OutputPath=bin\verify_toolcat_tests\ -p:IntermediateOutputPath=obj\verify_toolcat_tests\ : 통과 8
This commit is contained in:
@@ -15,7 +15,7 @@ public class ToolRegistry : IDisposable
|
||||
|
||||
/// <summary>도구를 이름으로 찾습니다.</summary>
|
||||
public IAgentTool? Get(string name) =>
|
||||
_tools.TryGetValue(name, out var tool) ? tool : null;
|
||||
_tools.TryGetValue(AgentToolCatalog.Canonicalize(name), out var tool) ? tool : null;
|
||||
|
||||
/// <summary>도구를 등록합니다.</summary>
|
||||
public void Register(IAgentTool tool) => _tools[tool.Name] = tool;
|
||||
@@ -60,7 +60,7 @@ public class ToolRegistry : IDisposable
|
||||
public IReadOnlyCollection<IAgentTool> GetActiveTools(IEnumerable<string>? disabledNames = null)
|
||||
{
|
||||
if (disabledNames == null) return All;
|
||||
var disabled = new HashSet<string>(disabledNames, StringComparer.OrdinalIgnoreCase);
|
||||
var disabled = new HashSet<string>(AgentToolCatalog.CanonicalizeMany(disabledNames), StringComparer.OrdinalIgnoreCase);
|
||||
if (disabled.Count == 0) return All;
|
||||
return OrderToolsForExposure(_tools.Values.Where(t => !disabled.Contains(t.Name)))
|
||||
.ToList()
|
||||
@@ -71,7 +71,7 @@ public class ToolRegistry : IDisposable
|
||||
public IReadOnlyCollection<IAgentTool> GetActiveToolsForTab(string activeTab, IEnumerable<string>? disabledNames = null)
|
||||
{
|
||||
var disabled = disabledNames != null
|
||||
? new HashSet<string>(disabledNames, StringComparer.OrdinalIgnoreCase)
|
||||
? new HashSet<string>(AgentToolCatalog.CanonicalizeMany(disabledNames), StringComparer.OrdinalIgnoreCase)
|
||||
: null;
|
||||
|
||||
return OrderToolsForExposure(_tools.Values.Where(t =>
|
||||
@@ -90,17 +90,7 @@ public class ToolRegistry : IDisposable
|
||||
|
||||
private static int GetToolExposureBucket(IAgentTool tool)
|
||||
{
|
||||
return tool.Name switch
|
||||
{
|
||||
"file_read" or "file_write" or "file_edit" or "glob" or "grep" or "document_read"
|
||||
or "process" or "dev_env_detect" or "build_run" or "git_tool" or "lsp_code_intel"
|
||||
or "document_plan" or "document_assemble" or "docx_create" or "html_create" or "markdown_create"
|
||||
or "excel_create" or "csv_create" or "pptx_create" or "chart_create" => 0,
|
||||
"folder_map" or "document_review" or "format_convert" or "tool_search" or "code_search" => 1,
|
||||
"mcp_list_resources" or "mcp_read_resource" or "spawn_agent" or "wait_agents" => 2,
|
||||
_ when tool.Name.StartsWith("task_", StringComparison.OrdinalIgnoreCase) => 3,
|
||||
_ => 1
|
||||
};
|
||||
return AgentToolCatalog.GetExposureBucket(tool.Name);
|
||||
}
|
||||
|
||||
/// <summary>도구가 해당 탭에서 사용 가능한지 확인합니다.</summary>
|
||||
@@ -122,114 +112,14 @@ public class ToolRegistry : IDisposable
|
||||
/// IAgentTool.TabCategory가 null인 도구는 이 맵을 참조합니다.
|
||||
/// 키: 도구 이름, 값: 허용 탭 (쉼표 구분). 맵에 없으면 = 모든 탭.
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, string> ToolTabOverrides = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
// ════════════════════════════════════════════════════════════
|
||||
// Chat = 순수 대화 (도구 없음). 아래 맵에 없는 공통 도구도
|
||||
// Chat에선 제외하려면 여기에 "Cowork,Code"로 등록.
|
||||
// ════════════════════════════════════════════════════════════
|
||||
|
||||
// ── 파일/검색 기본 도구: Cowork + Code ──
|
||||
["file_read"] = "Cowork,Code",
|
||||
["file_write"] = "Cowork,Code",
|
||||
["file_edit"] = "Cowork,Code",
|
||||
["glob"] = "Cowork,Code",
|
||||
["grep"] = "Cowork,Code",
|
||||
["process"] = "Cowork,Code",
|
||||
["folder_map"] = "Cowork,Code",
|
||||
["document_read"] = "Cowork,Code",
|
||||
["file_manage"] = "Cowork,Code",
|
||||
["file_info"] = "Cowork,Code",
|
||||
["multi_read"] = "Cowork,Code",
|
||||
["zip"] = "Cowork,Code",
|
||||
["open_external"] = "Cowork,Code",
|
||||
|
||||
// ── 데이터/유틸리티: Cowork + Code ──
|
||||
["json"] = "Cowork,Code",
|
||||
["regex"] = "Cowork,Code",
|
||||
["base64"] = "Cowork,Code",
|
||||
["hash"] = "Cowork,Code",
|
||||
["datetime"] = "Cowork,Code",
|
||||
["math"] = "Cowork,Code",
|
||||
["encoding"] = "Cowork,Code",
|
||||
["http"] = "Cowork,Code",
|
||||
["clipboard"] = "Cowork,Code",
|
||||
["env"] = "Cowork,Code",
|
||||
["notify"] = "Cowork,Code",
|
||||
["user_ask"] = "Cowork,Code",
|
||||
["memory"] = "Cowork,Code",
|
||||
["skill_manager"] = "Cowork,Code",
|
||||
["tool_search"] = "Cowork,Code",
|
||||
["mcp_list_resources"] = "Cowork,Code",
|
||||
["mcp_read_resource"] = "Cowork,Code",
|
||||
|
||||
// ── 문서 생성/처리: Cowork 전용 ──
|
||||
["xlsx_create"] = "Cowork",
|
||||
["excel_create"] = "Cowork",
|
||||
["docx_create"] = "Cowork",
|
||||
["csv_create"] = "Cowork",
|
||||
["md_create"] = "Cowork",
|
||||
["markdown_create"] = "Cowork",
|
||||
["html_create"] = "Cowork",
|
||||
["chart_create"] = "Cowork",
|
||||
["batch_create"] = "Cowork",
|
||||
["pptx_create"] = "Cowork",
|
||||
["document_plan"] = "Cowork",
|
||||
["document_assemble"] = "Cowork",
|
||||
["document_review"] = "Cowork",
|
||||
["format_convert"] = "Cowork",
|
||||
["data_pivot"] = "Cowork",
|
||||
["template_render"] = "Cowork",
|
||||
["text_summarize"] = "Cowork",
|
||||
["sql"] = "Cowork",
|
||||
["xml"] = "Cowork",
|
||||
["image_analyze"] = "Cowork",
|
||||
|
||||
// ── 개발 도구: Code 전용 ──
|
||||
["dev_env_detect"] = "Code",
|
||||
["build_run"] = "Code",
|
||||
["git"] = "Code",
|
||||
["lsp"] = "Code",
|
||||
["code_search"] = "Code",
|
||||
["code_review"] = "Code",
|
||||
["project_rule"] = "Code",
|
||||
["snippet_run"] = "Code",
|
||||
["diff"] = "Code",
|
||||
["diff_preview"] = "Code",
|
||||
["sub_agent"] = "Code",
|
||||
["wait_agents"] = "Code",
|
||||
["test_loop"] = "Code",
|
||||
["file_watch"] = "Code",
|
||||
|
||||
// ── 태스크/워크트리/팀: Code 전용 ──
|
||||
["task_tracker"] = "Code",
|
||||
["todo_write"] = "Code",
|
||||
["task_create"] = "Code",
|
||||
["task_get"] = "Code",
|
||||
["task_list"] = "Code",
|
||||
["task_update"] = "Code",
|
||||
["task_stop"] = "Code",
|
||||
["task_output"] = "Code",
|
||||
["enter_worktree"] = "Code",
|
||||
["exit_worktree"] = "Code",
|
||||
["team_create"] = "Code",
|
||||
["team_delete"] = "Code",
|
||||
["cron_create"] = "Code",
|
||||
["cron_delete"] = "Code",
|
||||
["cron_list"] = "Code",
|
||||
["checkpoint"] = "Code",
|
||||
["suggest_actions"] = "Code",
|
||||
["playbook"] = "Code",
|
||||
};
|
||||
|
||||
/// <summary>도구의 실질 탭 카테고리를 결정합니다 (IAgentTool.TabCategory → 오버라이드 맵 순).</summary>
|
||||
private static string? ResolveTabCategory(IAgentTool tool)
|
||||
{
|
||||
// 도구 자체에 TabCategory가 명시되어 있으면 우선
|
||||
if (!string.IsNullOrEmpty(tool.TabCategory))
|
||||
return tool.TabCategory;
|
||||
// 오버라이드 맵에서 조회
|
||||
return ToolTabOverrides.TryGetValue(tool.Name, out var cat) ? cat : null;
|
||||
|
||||
return AgentToolCatalog.GetTabCategory(tool.Name);
|
||||
}
|
||||
|
||||
/// <summary>IDisposable 도구를 모두 해제합니다.</summary>
|
||||
@@ -286,6 +176,7 @@ public class ToolRegistry : IDisposable
|
||||
registry.Register(new GitTool());
|
||||
registry.Register(new LspTool());
|
||||
registry.Register(new SubAgentTool());
|
||||
registry.Register(new SpawnAgentsTool());
|
||||
registry.Register(new WaitAgentsTool());
|
||||
registry.Register(new CodeSearchTool());
|
||||
registry.Register(new TestLoopTool());
|
||||
|
||||
Reference in New Issue
Block a user