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:
2026-04-14 17:52:46 +09:00
parent fa33b98f7e
commit 8cb08576d5
200 changed files with 13522 additions and 5764 deletions

View File

@@ -158,11 +158,27 @@ public sealed class ChatSessionStateService
var normalizedTab = NormalizeTab(tab);
var created = new ChatConversation { Tab = normalizedTab };
// Code/Cowork 탭: 매 대화마다 폴더를 새로 선택하도록 빈 상태로 시작
// ── 버그 수정: 현재 사용자가 선택한 권한(FilePermission)을 새 대화에 승계 ──
// 이전 버그: Permission=null인 상태로 생성되면 LoadConversationSettings가
// DefaultAgentPermission(별도 필드, 기본 "Deny")으로 폴백하고
// _settings.Llm.FilePermission을 덮어써버림.
// → UI엔 "권한 건너뛰기"가 표시돼도 실제 실행 시엔 Default/Deny 모드라
// html_create/document_plan 등에서 승인 창이 뜸.
// Chat 탭은 기본 Deny가 안전하므로 승계하지 않음 (기존 동작 유지).
if (string.Equals(normalizedTab, "Code", StringComparison.OrdinalIgnoreCase)
|| string.Equals(normalizedTab, "Cowork", StringComparison.OrdinalIgnoreCase))
{
created.WorkFolder = "";
try
{
var currentPerm = AxCopilot.Services.Agent.PermissionModeCatalog.NormalizeGlobalMode(
settings.Settings.Llm.FilePermission);
// Deny는 새 대화의 기본으로는 부적절(사용자가 의도적으로 Deny를 선택했을 가능성도 있지만
// Cowork/Code에서는 에이전트 실행 자체가 주 목적이므로 그대로 두면 혼란).
// 단, 단순 승계가 사용자 의도에 가장 부합하므로 그대로 반영.
created.Permission = currentPerm;
}
catch { /* 설정 접근 실패 시 Permission=null 유지 (fallback 경로) */ }
CurrentConversation = created;
return created;
}
@@ -271,13 +287,20 @@ public sealed class ChatSessionStateService
{
var normalizedTab = NormalizeTab(tab);
conversation.Tab = normalizedTab;
NormalizeLoadedConversation(conversation);
var normalized = NormalizeLoadedConversation(conversation);
CurrentConversation = conversation;
if (remember && !string.IsNullOrWhiteSpace(conversation.Id))
RememberConversation(normalizedTab, conversation.Id);
try { storage?.Save(conversation); } catch { }
// 대화 "선택"만으로는 대화 내용이 변하지 않음. 기존에는 무조건 Save()를 호출해
// storage.Save()가 UpdatedAt = DateTime.Now로 갱신 → 목록에서 맨 위로 올라가는 부작용.
// 실제 정규화(NormalizeLoadedConversation)가 일어난 경우에만 저장한다.
// — 다른 경로(EnsureCurrentConversation 등)도 이미 if(normalized) 패턴을 따른다.
if (normalized)
{
try { storage?.Save(conversation); } catch { }
}
return conversation;
}