# AX Copilot - 개발 문서 > 최종 업데이트: 2026-04-13 · 버전 0.7.3 ## 업데이트 로그 - 업데이트: 2026-04-14 17:46 (KST) - 도구 이름 정합성 문제를 줄이기 위해 `src/AxCopilot/Services/Agent/AgentToolCatalog.cs`를 추가했습니다. canonical id, legacy alias, 탭 노출, 설정 카테고리, 병렬 read-only 분류를 한곳에서 관리하도록 정리했습니다. - `ToolRegistry`, `AgentLoopService`, `AgentLoopParallelExecution`, `IAgentTool`, `AgentHookRunner`, `SkillService`가 모두 같은 카탈로그를 사용하도록 연결했습니다. 이에 따라 `git/lsp/zip/project_rule/snippet_run` 같은 예전 이름도 런타임에서 자동 정규화됩니다. - 내부설정 연동도 함께 반영했습니다. `AgentSettingsWindow`와 `SettingsWindow`의 도구 카드, 훅 편집기, 비활성 도구 저장, 도구 권한 저장이 canonical 이름 기준으로 동작하며 기존 저장값은 alias 호환으로 흡수합니다. - 스킬 관련 설명은 현재 구조에 맞게 완화했습니다. 기본 스킬 폴더와 추가 폴더를 함께 로드하는 흐름, 직접 호출 스킬과 런타임 정책 연결 스킬을 같이 보여주는 방향으로 설정/헬프 문구를 보정했습니다. - 검증: `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 - 참고: 테스트 빌드 중 기존 파일 `src/AxCopilot.Tests/Services/WorkspaceContextGeneratorTests.cs`의 nullable 경고 1건이 함께 표시되었으나, 이번 변경에서 새 경고를 추가하지는 않았습니다. --- ## 1. 프로젝트 개요 AX Copilot은 Windows용 생산성 런처 + AI 에이전트 데스크톱 앱입니다. - **런처**: Alfred/Raycast 스타일의 퍼지 검색, 명령 실행, 위젯 - **에이전트**: LLM 기반 대화형 코드/문서 작업 자동화 (도구 호출 루프) - **독 바**: 시스템 리소스, 클립보드, 스크린샷 등 빠른 접근 --- ## 2. 기술 스택 | 항목 | 값 | |------|-----| | 프레임워크 | .NET 8 (net8.0-windows10.0.17763.0) | | UI | WPF + Windows Forms (하이브리드) | | 언어 | C# 12 | | 패턴 | MVVM, 이벤트 기반, 싱글톤 서비스 | | 테스트 | xUnit 2.9 + FluentAssertions 6.12 | | 빌드 | dotnet CLI, PublishSingleFile | ### 주요 NuGet 패키지 | 패키지 | 용도 | |--------|------| | DocumentFormat.OpenXml 3.2.0 | DOCX/XLSX/PPTX 생성 | | Markdig 0.37.0 | Markdown → HTML 렌더링 | | Microsoft.Data.Sqlite 8.0 | SQLite (대화 저장소) | | Microsoft.Web.WebView2 | HTML 미리보기, 가이드 뷰어 | | QRCoder 1.6.0 | QR 코드 생성 | | System.Security.Cryptography.ProtectedData | DPAPI 암호화 | | UglyToad.PdfPig | PDF 읽기 | --- ## 3. 솔루션 구조 ``` src/ ├── AxCopilot/ # 메인 WPF 앱 (v0.7.3) │ ├── Assets/ # 아이콘, 프리셋 JSON, 암호화된 가이드, 마스코트 │ ├── Core/ # FuzzyEngine, CommandResolver, InputListener, PluginHost │ ├── Handlers/ # 136개 빌트인 명령 핸들러 │ ├── Models/ # AppSettings, ChatModels, McpSettings │ ├── Security/ # AntiTamper (디버거/디컴파일러 탐지) │ ├── Services/ # 60개 서비스 │ │ └── Agent/ # 에이전트 루프 + 114개 도구 │ ├── Themes/ # 9개 테마 (Dark, Light, OLED, Nord, Monokai 등) │ ├── ViewModels/ # LauncherViewModel, SettingsViewModel, StatisticsViewModel │ └── Views/ # 30개 XAML 윈도우 ├── AxCopilot.SDK/ # 플러그인 SDK (IActionHandler 인터페이스) ├── AxCopilot.Installer/ # Windows Forms 설치 프로그램 (.NET Framework 4.8) ├── AxCopilot.Tests/ # xUnit 단위/통합 테스트 └── AxKeyEncryptor/ # API 키 DPAPI 암호화 유틸리티 ``` --- ## 4. 앱 시작 흐름 (App.xaml.cs) ``` OnStartup() ├─ AntiTamper 디버거 감지 (Release 빌드) ├─ 단일 인스턴스 뮤텍스 확인 ├─ SettingsService 초기화 + 설정 로드 ├─ ChatStorageService 보관 정책 실행 (만료 대화 정리) ├─ L10n 언어 초기화 ├─ 서비스 초기화 │ ├─ AgentMemoryService │ ├─ ChatSessionStateService │ ├─ AppStateService │ ├─ IndexService (백그라운드 파일 인덱싱) │ ├─ FuzzyEngine + CommandResolver │ ├─ ContextManager │ ├─ SessionTrackingService │ ├─ WorktimeReminderService │ └─ ClipboardHistoryService ├─ 빌트인 핸들러 등록 (136개) ├─ SchedulerService + PluginHost 초기화 ├─ InputListener 시작 (글로벌 핫키) └─ 런처/설정/트레이 윈도우 생성 ``` --- ## 5. 핵심 아키텍처 ### 5.1 런처 (Launcher) **검색 파이프라인**: 사용자 입력 → `CommandResolver` (접두어 매칭) → `FuzzyEngine` (퍼지 검색) → 결과 정렬 → UI 렌더링 - `FuzzyEngine`: 파일 인덱스 기반 퍼지 매칭, 점수 순위 - `CommandResolver`: 핸들러 라우팅 (접두어 `@`, `!`, `#`, `~`, `>`, `$` 등) - `IndexService`: 백그라운드 파일 인덱싱 (`.git`, `node_modules` 등 제외) **위젯**: 성능 모니터, 포모도로, 메모, 날씨, 캘린더, 배터리 ### 5.2 에이전트 (Agent Loop) ``` 사용자 메시지 → LlmService.StreamAsync() (LLM API 호출) → 응답 스트리밍 수신 → 도구 호출 감지 시: → ToolRegistry에서 도구 조회 → 권한 확인 (AskPermissionCallback) → 도구 실행 → 결과를 컨텍스트에 추가 → LLM 재호출 (반복) → 최종 텍스트 응답 반환 ``` **핵심 클래스**: - `AgentLoopService` — 루프 엔진 (반복, 일시정지/재개, 이벤트 발행) - `AxAgentExecutionEngine` — 도구 실행 조율 - `AgentLoopParallelExecution` — 병렬 도구 실행 - `AgentLoopTransitions` / `.Execution` — 상태 전이 로직 - `ToolRegistry` — 도구 등록/조회 - `ContextCondenser` — 컨텍스트 압축 (토큰 관리) **도구 카테고리** (114개): | 카테고리 | 예시 | |---------|------| | 파일 I/O | FileReadTool, FileEditTool, FileManageTool, FileWriteTool | | 검색 | GlobTool, GrepTool, CodeSearchTool, FileSearchTool | | 문서 | DocumentReaderTool, ExcelSkill, DocxSkill, PptxSkill, CsvSkill, HtmlSkill | | 코드 | BuildRunTool, SnippetRunnerTool, CodeReviewTool, TestLoopTool, LspTool | | 데이터 | JsonTool, XmlTool, SqlTool, DataPivotTool, RegexTool | | 시스템 | ProcessTool, EnvTool, ZipTool, ClipboardTool | | 계획/추적 | TodoWriteTool, TaskTrackerTool, CheckpointTool, PlaybookTool | | 사용자 | UserAskTool, SuggestActionsTool, NotifyTool | | MCP | McpTool, McpListResourcesTool, McpReadResourceTool | **탭별 도구 필터링** (`ToolRegistry.ToolTabOverrides`): `IAgentTool.TabCategory` 또는 `ToolTabOverrides` 딕셔너리로 도구를 탭별로 분류합니다. `GetActiveToolsForTab(activeTab)` 메서드가 현재 탭에 맞는 도구만 LLM에 전송하여 토큰을 절약합니다. | 탭 | 활성 도구 범위 | 설명 | |------|--------------|------| | **Chat** | 0개 | 순수 대화. 도구 없이 LLM만 응답 | | **Cowork** | ~50개 | 파일/검색 + 문서생성(xlsx, docx, pptx...) + 데이터/유틸 | | **Code** | ~50개 | 파일/검색 + 개발(git, build, lsp...) + 태스크/워크트리 + 유틸 | - Chat 탭 토큰 절약: ~14,400토큰 → 0 (도구 정의 완전 제거) - Cowork/Code: 교차 제외로 각 ~3,600토큰 추가 절약 ### 5.3 LLM 서비스 **지원 공급자**: | 서비스 | 설명 | |--------|------| | `claude` / `sigmoid` | Anthropic Claude (Sigmoid API 경유) | | `gemini` | Google Gemini API | | `vllm` | OpenAI 호환 vLLM (IBM CP4D 지원 포함) | | `ollama` | 로컬 Ollama 모델 | **모델 라우팅**: `ModelRouterService`를 통한 오버라이드 스택 — 대화 중 모델/서비스를 동적으로 전환 가능 **토큰 관리**: `TokenEstimator`로 컨텍스트 길이 추정, 오버플로우 시 `ContextCondenser`가 자동 압축 - `EstimateBaseOverhead(systemPromptLength, toolCount)`: 시스템 프롬프트 + 도구 정의 오버헤드 추정 - `_tool_use_blocks` 메시지 0.6x, `tool_result` 메시지 0.7x 할인 적용 - 컨텍스트 사용량 표시에 시스템 프롬프트 + 도구 오버헤드 포함 ### 5.4 대화 저장소 - `ChatStorageService`: SQLite 기반 대화 영속화 - `ChatSessionStateService`: 메모리 내 세션 상태 관리 - `ChatConversation`: 메시지 목록 + 실행 이벤트 타임라인 + `Archived` 아카이브 플래그 --- ## 6. UI 계층 ### 주요 윈도우 | 윈도우 | 역할 | |--------|------| | `LauncherWindow` | 메인 런처 (검색, 위젯, 결과 목록) | | `ChatWindow` | AI 에이전트 대화 (채팅/Cowork/코드 탭) | | `DockBarWindow` | 독 바 (시스템 리소스, 빠른 접근) | | `SettingsWindow` | 설정 관리 | | `AgentSettingsWindow` | 에이전트 전용 설정 | | `AgentStatsDashboardWindow` | 에이전트 통계 대시보드 | | `SkillEditorWindow` | 스킬 편집기 | | `SkillGalleryWindow` | 스킬 갤러리 | | `TrayMenuWindow` | 시스템 트레이 메뉴 | | `PreviewWindow` | 문서 미리보기 (WebView2) | ### ChatWindow 분할 구조 `ChatWindow.xaml.cs`는 partial class로 기능별 분할: | 파일 | 역할 | |------|------| | `ChatWindow.xaml.cs` | 메인 오케스트레이션, 스트리밍, 입력 처리 | | `ChatWindow.AgentEventProcessor.cs` | 에이전트 이벤트 수신/라우팅 | | `ChatWindow.AgentEventRendering.cs` | 에이전트 이벤트 배너/카드 렌더링 (SessionStart/UserPromptSubmit 숨김) | | `ChatWindow.AgentStatusPresentation.cs` | 에이전트 실시간 상태 표시 | | `ChatWindow.ComposerQueuePresentation.cs` | 작성기 큐 UI | | `ChatWindow.ContextUsagePresentation.cs` | 컨텍스트 사용량 링/팝업 | | `ChatWindow.ConversationFilterPresentation.cs` | 대화 필터링 | | `ChatWindow.ConversationListPresentation.cs` | 사이드바 대화 목록 | | `ChatWindow.ConversationManagementPresentation.cs` | 대화 생성/삭제/관리 | | `ChatWindow.FileBrowserPresentation.cs` | 파일 브라우저 UI | | `ChatWindow.FooterPresentation.cs` | 하단 바 (폴더, 권한) | | `ChatWindow.GitBranchPresentation.cs` | Git 브랜치 표시/전환 | | `ChatWindow.LiveProgressPresentation.cs` | 실시간 진행 상태 | | `ChatWindow.MessageBubblePresentation.cs` | 메시지 버블 렌더링 | | `ChatWindow.MessageInteractions.cs` | 메시지 복사/편집/재전송 | | `ChatWindow.PermissionPresentation.cs` | 권한 팝업/배너 UI | | `ChatWindow.PlanApprovalPresentation.cs` | 계획 승인 카드 | | `ChatWindow.PopupPresentation.cs` | 공통 팝업 구성 | | `ChatWindow.PreviewPresentation.cs` | 파일 미리보기 탭 | | `ChatWindow.SelectionPopupPresentation.cs` | 워크트리 선택 팝업 | | `ChatWindow.SidebarInteractionPresentation.cs` | 사이드바 상호작용 | | `ChatWindow.StatusPresentation.cs` | 상태 배지/스트립 | | `ChatWindow.SurfaceVisualPresentation.cs` | 시각 효과 (글로우, 펄스 등) | | `ChatWindow.TaskSummary.cs` | 작업 요약 카드 | | `ChatWindow.TimelinePresentation.cs` | 타임라인 정렬, 캐시, 이벤트 필터링 | | `ChatWindow.TopicPresetPresentation.cs` | 주제 프리셋 UI | | `ChatWindow.TranscriptHost.cs` | 트랜스크립트 호스트 컨테이너 | | `ChatWindow.TranscriptPolicy.cs` | 트랜스크립트 표시 정책 | | `ChatWindow.TranscriptRenderExecution.cs` | 트랜스크립트 렌더 실행 | | `ChatWindow.TranscriptRenderPlanner.cs` | 트랜스크립트 렌더 계획 | | `ChatWindow.TranscriptRendering.cs` | 트랜스크립트 렌더링 | | `ChatWindow.TranscriptVirtualization.cs` | 트랜스크립트 가상화 (대규모 대화) | | `ChatWindow.SystemPromptBuilder.cs` | 시스템 프롬프트 동적 조립 (탭/프리셋/컨텍스트 주입) | | `ChatWindow.OverlaySettingsPresentation.cs` | 인라인 설정 팝업 (모델, 빠른액션) | | `ChatWindow.UserAskPresentation.cs` | 사용자 질문 인라인 카드 | | `ChatWindow.VisualInteractionHelpers.cs` | 시각 상호작용 헬퍼 | ### 테마 시스템 9개 테마 XAML 리소스 딕셔너리: `Dark`, `Light`, `OLED`, `Nord`, `Monokai`, `Catppuccin`, `Sepia`, `Alfred`, `AlfredLight` 런타임 테마 전환: `SettingsService.Settings.Launcher.Theme` 변경 → 리소스 딕셔너리 교체 --- ## 7. 설정 구조 (AppSettings) ### 최상위 설정 | 속성 | 기본값 | 설명 | |------|--------|------| | `AiEnabled` | true | AI 기능 활성화 | | `OperationMode` | "internal" | 운영 모드 (internal/external) | | `Hotkey` | "Alt+Space" | 런처 단축키 | | `CleanupPeriodDays` | 30 | 대화 보관 기간 (일) | | `InternalModeEnabled` | true | 사내 모드 여부 | ### LauncherSettings (중첩) | 그룹 | 주요 속성 | |------|----------| | 표시 | `Theme`, `Opacity`, `Position`, `Width`, `MaxResults` | | 글로우 | `EnableRainbowGlow`, `EnableSelectionGlow`, `ShowLauncherBorder` | | 위젯 | `ShowWidgetPerf`, `ShowWidgetPomo`, `ShowWidgetNote`, `ShowWidgetWeather`, `ShowWidgetCalendar`, `ShowWidgetBattery` | | 독 바 | `DockBarItems`, `DockBarAutoShow`, `DockBarOpacity`, `DockBarRainbowGlow` | | 기능 | `EnableFavorites`, `EnableRecent`, `EnableActionMode`, `EnableClipboardAutoCategory` | ### LlmSettings (중첩) 에이전트의 LLM 연결 설정: 서비스 선택, 모델, API 키 (DPAPI 암호화), 엔드포인트, 온도, 최대 토큰 등 | 속성 | 기본값 | 설명 | |------|--------|------| | `UseAutomaticProfileTemperature` | true | 등록 모델 프로파일의 자동 temperature 정책 | | `EnableDetailedLog` | false | 워크플로우 상세 로그 (LLM 요청/응답, 도구 이력) | | `DetailedLogRetentionDays` | 3 | 상세 로그 보관 기간 (일) | | `EnableRawLlmLog` | false | LLM 요청/응답 원문 기록 (디버깅용) | ### RegisteredModel 실행 프로파일 모델별 `ExecutionProfile`로 도구 호출 강도, 재시도, 메모리/압축 주입량을 조절: | 프로파일 | 설명 | |---------|------| | `balanced` | 기본 균형 모드 | | `tool_call_strict` | 도구 호출 강제/엄격 모드 | | `reasoning_first` | 추론 우선 모드 | | `fast_readonly` | 빠른 읽기 전용 모드 | | `document_heavy` | 문서 처리 집중 모드 | --- ## 8. 플러그인 시스템 ### SDK (AxCopilot.SDK) ```csharp public interface IActionHandler { string? Prefix { get; } // 접두어 (null이면 퍼지 검색만) PluginMetadata Metadata { get; } Task> GetItemsAsync(string query, CancellationToken ct); Task ExecuteAsync(LauncherItem item, CancellationToken ct); } ``` ### 개발 방법 1. `AxCopilot.SDK` 참조하여 `IActionHandler` 구현 2. 빌드된 `.dll`을 `settings.json`의 `Plugins` 배열에 경로 등록 3. `PluginHost`가 앱 시작 시 동적 로드 --- ## 9. 빌드 및 실행 ### 개발 빌드 ```bash dotnet build src/AxCopilot/AxCopilot.csproj ``` ### 빠른 빌드 (암호화/설치프로그램 생략) ```bash ./build-quick.sh ``` 메인 앱만 self-contained 단일 파일로 빌드합니다. AxKeyEncryptor/Installer/난독화를 건너뛰어 빠른 개발 반복에 적합합니다. ### 릴리스 빌드 (단일 파일) ```bash dotnet publish src/AxCopilot/AxCopilot.csproj -c Release -r win-x64 --self-contained ``` 릴리스 빌드 옵션: - `PublishSingleFile`: 단일 실행 파일 - `EnableCompressionInSingleFile`: 압축 적용 - `PublishReadyToRun`: AOT 프리컴파일 - `DebugType=none`: 디버그 심볼 제거 - `TrimMode=partial`: IL 트리밍 ### 테스트 ```bash dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj ``` --- ## 10. 버전 관리 - `AxCopilot.csproj`의 `` 태그 하나만 변경하면 앱 전체에 반영 - 설정 스키마 버전은 `SettingsService.cs` → `CurrentSettingsVersion`에서 별도 관리 - 마이그레이션: `SettingsService`가 이전 버전 설정 파일을 자동 업그레이드 --- ## 11. 보안 | 항목 | 구현 | |------|------| | API 키 저장 | DPAPI 암호화 (System.Security.Cryptography.ProtectedData) | | 키 관리 도구 | AxKeyEncryptor (별도 유틸리티) | | 안티 탬퍼 | 디버거/디컴파일러 감지 (Release 빌드, `Security/AntiTamper.cs`) | | Unsafe 코드 | `AllowUnsafeBlocks=true` (ScreenCaptureHandler 포인터 연산용) | --- ## 12. 성능 최적화 내역 ### 유휴 CPU 최적화 (2026-04-09) | 대상 | 변경 전 | 변경 후 | |------|---------|---------| | PerformanceMonitorService 폴링 | 2초 | 5초 | | 위젯 타이머 | 1초 | 3초 | | 레인보우 글로우 타이머 | 150ms | 300ms | | ServerStatusService 핑 | 15초 | 60초 | ### 스트리밍 렌더링 최적화 (2026-04-09) - **TypingTimer**: 50ms → 80ms, `string.Concat` → `char[]` 버퍼 재사용 - **CursorTimer**: 전체 문자열 재생성 → 마지막 문자만 교체 - **StringBuilder.ToString()**: 30ms 최소 간격 쓰로틀링 - **RenderMessages**: 스트리밍 중 불필요한 전체 재렌더링 방지 (조기 반환) - **타임라인 이벤트**: 접힌 모드에서 연속 동일 ToolCall 병합 ### 런타임 안정성 수정 (2026-04-09) | 파일 | 수정 내용 | |------|----------| | `CsvSkill.cs` | JSON 배열 첫 요소 `ValueKind` 검증 추가 | | `HtmlSkill.cs` | gradient `Split(',')` 결과 `Length >= 2` 가드 추가 | | `ChatWindow.xaml.cs` | `ParseGenericAction` 빈 배열 가드, `ShowDropActionMenu` null 가드, `GetAgentLoop` `.FirstOrDefault()` 전환 | | `ChatWindow.GitBranchPresentation.cs` | async void 핸들러 try/catch 보호 | | `ChatWindow.xaml.cs` (BtnGitBranch_Click) | async void 핸들러 try/catch 보호 | ### UI 스레드 부하 최적화 2차 (2026-04-09) | 대상 | 변경 전 | 변경 후 | 효과 | |------|---------|---------|------| | 스크롤 애니메이션 | 매번 새 16ms 타이머 생성 | 재사용 32ms 타이머 1개 | GC 압력 + 타이머 누적 해소 | | 사이드바 애니메이션 | 매번 새 10ms 타이머 생성 | 재사용 32ms 타이머 1개 | 동일 | | Git 브랜치 UI | `Dispatcher.Invoke` (블로킹) | `Dispatcher.InvokeAsync` (논블로킹) | UI 스레드 차단 해소 | | 토큰 사용량 호 | 매 250ms PathGeometry 재생성 | 1% 미만 변화 시 렌더링 생략 | 불필요한 레이아웃 연산 제거 | | 대화 검색 타이머 | 140ms | 300ms | 초당 7회 → 3회 | | 에이전트 이벤트 타이머 | 140ms (스트리밍: 300/420) | 200ms (스트리밍: 350/500) | 이벤트 처리 빈도 완화 | | 반응형 레이아웃 타이머 | 120ms | 250ms | 리사이즈 디바운스 강화 | | 대화 목록 LINQ | Where×2 + Count×3 = 리스트 5회 순회 | Where 1회 병합 + 단일 루프 카운트 | 할당/순회 대폭 감소 | ### 구조적 메모리/안정성 수정 (2026-04-09) | 문제 | 위치 | 수정 | |------|------|------| | Events 컬렉션 무한 성장 | `AgentLoopService.cs` | 500개 초과 시 오래된 이벤트 자동 제거 | | 파일 브라우저 타이머 좀비 | `ChatWindow.FileBrowserPresentation.cs` | 매번 새 타이머 생성 → 재사용 패턴 | | 엘리먼트 캐시 미정리 | `ChatWindow.TranscriptVirtualization.cs` | 보유 한도 240→120, 1.5배 초과 시 정리 | | WorkflowAnalyzer UI 블로킹 | `WorkflowAnalyzerWindow.xaml.cs` | `Dispatcher.Invoke` → `InvokeAsync` | ### 구조적 리팩토링 P1 (2026-04-09) | 대상 | 파일 | 변경 | |------|------|------| | 인크리멘탈 렌더 hiddenCount 안정화 | `ChatWindow.TranscriptRenderPlanner.cs` | 스트리밍 중 hiddenCount 감소 차단 → prefix 키 불일치로 인한 전체 재빌드 폴백 방지 | | 비가시 렌더 차단 | `ChatWindow.TranscriptRendering.cs` | 최소화/숨김 상태에서 RenderMessages 즉시 반환 → 불필요한 UI 재구축 제거 | | ConversationList 이벤트 위임 | `ChatWindow.ConversationListPresentation.cs` | 항목당 5개 람다 핸들러 → ConversationPanel에 단일 위임 핸들러 (Tag 기반 분기). 탭 전환 시 250개 핸들러 누적 해소 | | TopicPreset 이벤트 위임 | `ChatWindow.TopicPresetPresentation.cs` | 카드당 3개 람다 핸들러 → TopicButtonPanel에 단일 위임 핸들러. 탭 전환 시 45개 핸들러 누적 해소 | | 공통 VisualTree 헬퍼 | `ChatWindow.VisualInteractionHelpers.cs` | `FindAncestorWithTag`, `FindAncestor` 유틸 추가 | ### 구조적 리팩토링 P2 (2026-04-09) | 대상 | 파일 | 변경 | |------|------|------| | _agentLiveContainer 인크리멘탈 허용 | `TranscriptRenderPlanner.cs`, `TranscriptRenderExecution.cs` | 라이브 컨테이너를 expectedChildCount에 포함, 인크리멘탈 시 임시 분리/재삽입 → `hasExternalChildren` 차단 해소 | | 스트리밍 append-only 렌더 | `TranscriptRenderExecution.cs`, `TranscriptRendering.cs` | prefix 비교 우회하는 `TryApplyStreamingAppendRender` 추가 — stable 키 부분집합 관계만 확인, 새 항목만 추가 | | Permission 이벤트 위임 | `ChatWindow.PermissionPresentation.cs` | 행당 4개 람다 → PermissionItems에 단일 위임 핸들러 + `PermissionItemTag` | | Preview 탭 이벤트 위임 | `ChatWindow.PreviewPresentation.cs` | 탭당 7개 람다 → PreviewTabPanel에 단일 위임 핸들러 + `PreviewTabTag` | | GitBranch 이벤트 위임 | `ChatWindow.GitBranchPresentation.cs`, `SelectionPopupPresentation.cs` | `CreateFlatPopupRow`/`CreatePopupMenuRow` 행의 람다 → GitBranchItems에 단일 위임 + `PopupRowTag` | ### 구조적 리팩토링 P3 (2026-04-09) | 대상 | 파일 | 변경 | |------|------|------| | FileBrowser 명시적 해제 | `ChatWindow.FileBrowserPresentation.cs` | TreeViewItem 람다→명명 메서드(`FileTreeItem_Expanded/DoubleClick/RightClick`) 전환. `BuildFileTree()` 시 `DetachFileTreeHandlers()` 재귀 호출로 Clear 전 핸들러 해제. 트리 재구축당 300개 핸들러 누적 해소 | > 전체 계획 완료. `docs/STRUCTURAL_REFACTORING_PLAN.md` 참조. ### 런처 · 에이전트 리소스/안정성 수정 (2026-04-09) | 대상 | 파일 | 변경 | |------|------|------| | LauncherWindow 이벤트 누수 | `LauncherWindow.xaml.cs` | `vm.CloseRequested`, `vm.PropertyChanged`, `app.IndexService.IndexRebuilt` 핸들러를 필드 저장 → `OnClosed`에서 `-=` 해제. ViewModel보다 Window가 먼저 닫힐 때 GC 누수 방지 | | ChatWindow 타이머 정리 | `ChatWindow.xaml.cs` | `Closed` 핸들러에 누락된 8개 타이머 명시적 `Stop()` 추가 + `StopAgentEventProcessor()` 호출 | | Events 스레드 안전 | `AgentLoopService.cs` | Dispatcher 없을 때 `Events` 접근에 `lock(Events)` 추가 — 동시 EmitEvent 호출 시 IndexOutOfRange 크래시 방지 | | NotifyTool 타이머 누적 | `NotifyTool.cs` | 알림당 `new DispatcherTimer` → `DoubleAnimation.Completed` 콜백으로 대체. 100개 알림 시 100개 타이머 동시 존재 해소 | | LauncherWindow 토스트 타이머 | `LauncherWindow.xaml.cs` | `ShowToast()` 매 호출 `new DispatcherTimer` → 재사용 패턴 + 명명 메서드(`ToastTimer_Tick`) | | LauncherWindow 타이머 정리 | `LauncherWindow.xaml.cs` | `OnClosed`에 `_toastTimer?.Stop()`, `_indexStatusTimer?.Stop()` 추가 | ### Hot path · 리소스 추가 최적화 (2026-04-09) | 대상 | 파일 | 변경 | |------|------|------| | GetRuntimeActiveTools 캐시 | `AgentLoopService.cs` | 반복당 1~4회 호출 → `cachedActiveTools` 로컬 변수로 1회 캐시. foreach 내 `activeToolNames` 계산도 루프 밖으로 호이스트 | | SubAgentTool 취소 전파 | `SubAgentTool.cs` | `CancellationTokenSource.CreateLinkedTokenSource(ct)` 연동. Task.Run + loop.RunAsync에 토큰 전달. 부모 중지 시 자식 즉시 취소 | | 아이콘 애니메이션 재귀 제어 | `LauncherWindow.xaml.cs` | `sb.Completed`에서 즉시 재귀 → `_iconAnimationDelayTimer` 8초 딜레이. 할당 빈도 75% 감소. 클릭 시 딜레이 취소 후 즉시 전환 | | JsonSerializerOptions 공유 | `AgentLoopService.cs` | `s_jsonOpts` 정적 필드 추가, 4개 `JsonSerializer.Serialize` 호출에 적용. L4096 `System.Text.Json.` 접두사 정규화 | ### Claude Desktop 스타일 UI 개선 (2026-04-09) | 항목 | 파일 | 수정 내용 | |------|------|----------| | 미리보기 Split Button | `ChatWindow.xaml` | 기존 `BtnPreviewToggle` (Ellipse 점 + "프리뷰") → `[▶ 미리보기 | ∨]` Split Button으로 교체. 좌측 토글, 우측 셰브론 드롭다운 | | 미리보기 드롭다운 | `ChatWindow.PreviewPresentation.cs` | `ShowPreviewTabDropdown()` — 열린 탭 목록 팝업, 파일 확장자별 아이콘, 활성 탭 하이라이트 | | PreviewDot → PreviewIcon | `ChatWindow.PreviewPresentation.cs` | `PreviewDot.Fill` 4곳 → `PreviewIcon.Foreground` (AccentColor/SecondaryText) 전환 | | 셰브론 동기화 | `ChatWindow.PreviewPresentation.cs` | `UpdatePreviewChevronState()` — `_previewTabs.Count` 기반 IsHitTestVisible/Opacity 제어 | | 계획 버튼 이동 | `ChatWindow.xaml` | MoodIconPanel 동적 주입 → StatusBar XAML 선언 요소 `BtnPlanViewer`로 이동 | | ShowPlanButton 리팩토링 | `ChatWindow.PlanApprovalPresentation.cs` | 동적 Add/Remove → `Visibility` 토글 단순화 + 레거시 정리 유지 | ### UX 개선 및 탭별 도구 필터링 (2026-04-09) | 항목 | 파일 | 수정 내용 | |------|------|----------| | 탭별 도구 필터링 | `IAgentTool.cs`, `ToolRegistry.cs`, `AgentLoopService.cs` | `TabCategory` 속성 + `ToolTabOverrides` 딕셔너리로 Chat/Cowork/Code 탭별 도구 분류. Chat=0개, Cowork=문서/데이터, Code=개발/태스크 | | FolderMapTool 기본값 변경 | `FolderMapTool.cs` | `include_files` 기본값 `false` → `true`. Description에 사용 제한 가이드 추가 | | 에이전트 이벤트 숨김 | `AgentEventRendering.cs`, `TimelinePresentation.cs` | `SessionStart`/`UserPromptSubmit` 내부 이벤트 타임라인 비표시 | | 사용자 메시지 렌더링 | `ChatWindow.xaml.cs` | 전송 시 `InvalidateTimelineCache()` + `preserveViewport:false`로 즉시 표시 보장 | | 아카이브 기능 | `ChatModels.cs`, `ConversationManagementPresentation.cs`, `ConversationFilterPresentation.cs`, `ConversationListPresentation.cs` | `Archived` 속성, 컨텍스트 메뉴 아카이브 토글, 사이드바 필터 버튼 | | 커스텀 슬림 스크롤바 | `ChatWindow.xaml` | 6px 슬림 ScrollBar + Thumb 라운드, ScrollViewer 마우스 오버 fade in/out 애니메이션 | | 스트리밍 메트릭 레이블 | `ChatWindow.xaml`, `StatusPresentation.cs` | 입력 박스 위에 `StreamMetricsLabel` (경과시간 · ↓ 토큰 수) 실시간 표시 | | 프리셋 카드 클릭 안정화 | `ChatWindow.xaml`, `ChatWindow.xaml.cs` | WrapPanel `Background="Transparent"` + Dispatcher 우선순위 `Loaded`로 상향 | | 컨텍스트 토큰 정확도 | `TokenEstimator.cs`, `ContextUsagePresentation.cs`, `ILlmService.cs` | 시스템 프롬프트 + 도구 오버헤드 추정, `_tool_use_blocks`/`tool_result` 할인 | | UI 프리징 방지 | `ChatWindow.xaml.cs` | `SaveLastConversations()`/`PersistConversationSnapshot()` → 렌더링 후 `Task.Run()` 비동기 실행 | | 빠른 빌드 스크립트 | `build-quick.sh` | 암호화/난독화/설치프로그램 건너뛰는 개발용 빌드 스크립트 | ### 에이전트 루프 문서 생성 흐름 수정 (2026-04-09) | 파일 | 수정 내용 | |------|----------| | `AgentLoopTransitions.Documents.cs` | `TryHandleTerminalDocumentCompletionTransitionAsync`에서 `document_plan` 없이 바로 문서 도구 호출 시 조기 종료 방지 — LLM이 추가 반복으로 내용을 보강할 수 있도록 허용 | | `HtmlSkill.cs` | `MarkdownToHtml`에서 LLM이 삽입한 `
` 태그가 이스케이프되는 버그 수정 — 이스케이프 전 플레이스홀더로 보존 후 복원 | ### Cowork 문서 미생성 · 스크롤 · 전송 후 10초 멈춤 수정 (2026-04-09) #### 문서 생성 탐색 정책 수정 | 파일 | 수정 내용 | |------|----------| | `AgentLoopExplorationPolicy.cs` | `ExplorationScope.DirectCreation` 신규 스코프 추가. `HasDocumentCreationIntent()`로 "작성해줘/만들어줘/써줘" 등 생성 동사 + 문서/보고서 대상 키워드 감지 | | `AgentLoopExplorationPolicy.cs` | `DirectCreation` 스코프에서 glob/grep/folder_map 탐색 차단 → `document_plan → docx_create/html_create` 바로 이동 | | `AgentLoopExplorationPolicy.cs` | `FilterExplorationToolsForCurrentIteration`에서 문서 생성 도구를 최우선 순위로 배치 | | `AgentLoopExplorationPolicy.cs` | `ShouldInjectExplorationCorrection`에서 DirectCreation 시 탐색 도구 1회 호출만으로 즉시 교정 주입 | | `TaskTypePolicy.cs` | docs 가이던스를 생성 vs 읽기로 분기 — 생성 시 "반드시 실제 파일을 만들어라" 명시 | | `AgentLoopService.cs` | DirectCreation 스코프 이벤트 메시지: "문서 생성 모드 · 바로 문서를 만드는 중" | #### 스크롤 버그 수정 | 파일 | 수정 내용 | |------|----------| | `ChatWindow.xaml.cs` | 메시지 전송/슬래시 커맨드/컴팩트 후 `RenderMessages(preserveViewport: true)` + `ForceScrollToEnd()` 조합 → `RenderMessages(preserveViewport: false)`로 변경. viewport 복원과 ForceScrollToEnd 경합 제거 | **원인**: `preserveViewport: true`는 렌더링 후 이전 스크롤 위치를 복원하는 코드를 `DispatcherPriority.Background`로 예약. `ForceScrollToEnd()`도 같은 우선순위로 하단 스크롤을 예약하여 두 코드가 경합, 스크롤이 하단으로 안 가는 문제 발생. #### 전송 후 10초 멈춤 수정 (Critical Performance Fix) | 파일 | 수정 내용 | |------|----------| | `ChatWindow.AgentStatusPresentation.cs` | `BuildFeedbackContext()` — `_storage.LoadAllMeta()` (모든 .axchat 파일 복호화) + `_storage.Load()` x20회를 매 전송마다 동기 실행 → 1분 캐시 + 현재 대화 피드백만 즉시 반영 + 전체 갱신은 백그라운드 | | `ChatWindow.xaml.cs` | `Dispatcher.Invoke()` (동기 블로킹) → `Dispatcher.InvokeAsync()` (비동기). background task에서 UI 스레드 블로킹 제거 | | `ChatWindow.xaml.cs` | `PrepareExecutionForConversation()` (시스템 프롬프트 빌드: 프로젝트 규칙/메모리/피드백 디스크 I/O) → `await Task.Run()`으로 백그라운드 실행. UI 스레드 즉시 해방 | **원인 분석**: `BuildFeedbackContext()`가 `LoadAllMeta()` (모든 `.axchat` 파일 복호화·파싱) + `Load()` x20 (20개 대화 전체 로드·복호화) 를 UI 스레드에서 동기 실행. 대화 30개 이상이면 5~10초 블로킹 발생. ### 스트리밍 중 UI 버벅임 대폭 개선 (2026-04-09) Claude Desktop(React)은 도구 호출이 수십 건이어도 매끄러운 반면, WPF 앱은 심하게 버벅이는 문제의 원인 분석 및 수정. **근본 원인**: React virtual DOM은 변경된 부분만 diff/patch하지만, WPF는 매 렌더마다 전체 시각적 트리를 파괴 후 재생성. | 원인 | 파일 | 수정 | |------|------|------| | `ItemsSource = null/재연결` — 전체 시각적 트리 파괴 + VirtualizingStackPanel 컨테이너 재생성 | `TranscriptRenderExecution.cs` | 스트리밍 중에는 ItemsSource 분리/재연결 건너뜀 — ObservableCollection 직접 변경으로 레이아웃 패스 최소화 | | 라이브 진행 카드 매번 재생성 — 헤더/구분선/스텝 전체를 0부터 다시 생성 + 애니메이션 재적용 | `AgentEventRendering.cs` | `_liveProgressCard` 캐시 + `UpdateLiveProgressStepsInPlace()` — 카드 1회 생성 후 새 스텝만 추가, 기존 스텝은 터치 안 함 | | 렌더 타이머 간격 1.5~2.2초 — WPF 전체 재빌드에 비해 너무 공격적 | `ChatWindow.xaml.cs` | lightweight: 2.2s→4s, normal: 1.5s→3s — 렌더 간 충분한 여유 확보 | | 매 렌더마다 3개 애니메이션(Opacity + ScaleX + ScaleY) 재적용 | `AgentEventRendering.cs` | 라이브 카드 in-place 업데이트로 기존 애니메이션 보존, 새 스텝에만 애니메이션 적용 | **비교**: | 항목 | 수정 전 (WPF) | 수정 후 | Claude Desktop (React) | |------|-------------|---------|----------------------| | 업데이트 전략 | 전체 트리 파괴→재생성 | 4단계: StreamingAppend → Incremental → **DiffRender** → FullRender | Virtual DOM diff | | 렌더 간격 | 1.5~2.2초 | 3~4초 | ~16ms (requestAnimationFrame) | | 요소 재사용 | Clear→재생성 | 캐시→재사용 + 키 기반 diff | Recycled/Memoized | | 애니메이션 | 매번 재적용 (3개/요소) | 1회 적용 후 보존 | CSS transform (GPU) | --- ### 12-3. Virtual DOM Diff 렌더 (`TryApplyDiffRender`) React의 reconciliation과 동일한 원리를 WPF에 적용한 키 기반 diff 렌더입니다. **렌더 체인 (우선순위 순):** ``` StreamingAppend → Incremental(prefix-match) → DiffRender(key-based) → FullRender ``` | 단계 | 조건 | 동작 | |------|------|------| | StreamingAppend | 스트리밍 중 + 기존 stable 키가 부분집합 | 새 키만 append | | Incremental | prefix가 완전 일치 | 꼬리 부분만 추가 | | **DiffRender** | hiddenCount 동일 + 키 집합 변화 있음 | old에만 있는 키 삭제(뒤→앞) + new에만 있는 키 추가 | | FullRender | 위 3개 모두 실패 | 전체 Clear→재생성 | **핵심 알고리즘:** 1. `oldKeys` → index 딕셔너리 / `newKeys` → HashSet 구축 2. 라이브 컨테이너 임시 분리 3. `oldKeys` 뒤에서부터 순회하며 `newKeySet`에 없는 항목 제거 (인덱스 안정성) 4. `renderPlan.VisibleTimeline`에서 `oldKeyIndex`에 없는 항목만 `Render()` 5. 라이브 컨테이너 재삽입 **파일:** `ChatWindow.TranscriptRenderExecution.cs`, `ChatWindow.TranscriptRendering.cs` (체인 삽입) --- ### 12-4. LSP 코드 인텔리전스 도구 확장 `lsp_code_intel` 도구를 6개 액션에서 9개로 확장하여 구조적 코드 탐색을 대폭 강화했습니다. | 액션 | 용도 | 신규 | |------|------|------| | `goto_definition` | 심볼 정의 위치 | | | `find_references` | 심볼 사용 위치 | | | `hover` | 타입/문서 정보 | ✅ | | `goto_implementation` | 인터페이스/추상 구현 위치 | ✅ | | `symbols` | 파일 내 심볼 목록 | | | `workspace_symbols` | 워크스페이스 전체 심볼 검색 | ✅ | | `prepare_call_hierarchy` | 호출 계층 기준 심볼 | ✅ | | `incoming_calls` | 상위 호출자 | ✅ | | `outgoing_calls` | 하위 호출 대상 | ✅ | **주요 변경:** - `line`/`character` 입력: 1-based 기대 → 내부에서 0-based 자동 변환 (`NormalizePosition`) - `query` 파라미터 추가 (workspace_symbols용) - 결과에 파일 수, 대표 위치, 첫 결과 요약 포함 - LSP 프로토콜: `textDocument/implementation`, `textDocument/hover`, `workspace/symbol`, `textDocument/prepareCallHierarchy`, `callHierarchy/incomingCalls`, `callHierarchy/outgoingCalls` **파일:** `LspTool.cs`, `LspClientService.cs` --- ### 12-5. IBM/Qwen 도구 이력 평탄화 IBM watsonx + Qwen 배포형에서 `tool_calls`/`role=tool` 이력 검사가 엄격한 문제를 해결합니다. **변경 전:** ``` assistant { tool_calls: [...] } → tool { tool_call_id, content } ``` **변경 후 (평탄 transcript):** ``` assistant: "텍스트\n\n{name,arguments}\n" user: "[Tool Result: tool_name] (id=xxx)\ncontent" ``` **핵심 메서드:** - `BuildIbmAssistantTranscript()` — tool_use 블록 → `` 태그 직렬화 - `BuildIbmToolResultTranscript()` — tool_result → `[Tool Result]` 헤더 + 내용 - `TryExtractTextContent()` — string/array/nested 형태 모두 텍스트 추출 - `TryParseContentArrayToolBlock()` — content 배열 내 tool_use/tool_call 블록 파싱 **파일:** `LlmService.ToolUse.cs` --- ### 12-6. 도구 노출 순서 정렬 및 프롬프트 완화 **도구 순서 (`ToolRegistry.OrderToolsForExposure`):** | 버킷 | 도구 | |------|------| | 0 (최우선) | file_read, file_edit, glob, grep, lsp_code_intel, build_run, document_plan, 생성 도구 등 | | 1 | document_review, format_convert, tool_search, code_search | | 2 | mcp_*, spawn_agent, wait_agents | | 3 | task_* | **프롬프트 완화 (SystemPromptBuilder):** - "Tools First, Always" → "Tools First When Needed" - `tool_search`: 후보에서 바로 선택 가능하면 직접 호출, 모호할 때만 사용 - `spawn_agent`: 병렬 조사가 실제로 도움이 될 때만 사용 - `document_review`: 큰 문서/명시적 요청 시에만 권장 - Code 탐색: 정의/참조/구현/호출관계 → `lsp_code_intel` 우선 **파일:** `ToolRegistry.cs`, `ChatWindow.SystemPromptBuilder.cs`, `AgentLoopService.cs`, `TaskTypePolicy.cs`, `AgentLoopExplorationPolicy.cs` --- ## 13. 디렉토리별 가이드 | 디렉토리 | 수정 시 주의사항 | |---------|----------------| | `Core/` | `FuzzyEngine` 점수 공식 변경 시 검색 품질에 직접 영향 | | `Handlers/` | 새 핸들러 추가 시 `App.xaml.cs`에 등록 필요 | | `Services/Agent/` | 새 도구 추가 시 `ToolRegistry`에 등록 + 스킬 파일(`.skill.md`) 작성 + `ToolTabOverrides`에 탭 카테고리 지정 | | `Themes/` | 리소스 키 변경 시 모든 테마에 동일하게 적용 필요 | | `Models/AppSettings.cs` | 속성 추가 시 `SettingsService` 마이그레이션 고려 | | `Views/ChatWindow.*` | partial class 분할 — 관련 기능은 해당 파일에서 수정 | --- ### 12-7. PPT 고품질 템플릿 시스템 `template` 파라미터로 8개 고품질 양식의 색상/레이아웃을 사용할 수 있습니다. **현재 구현 (방법 1 — 내장 메타데이터):** - 각 템플릿의 테마 색상을 `FullThemes` 딕셔너리에 하드코딩 (0KB 추가) - 원본 .pptx 없이도 동일 색상+레이아웃으로 PPT 생성 가능 - 원본 .pptx가 `Assets/ppt/` 또는 `%APPDATA%/AXCopilot/templates/ppt/`에 있으면 마스터 복제(고품질) 자동 업그레이드 | 템플릿 이름 | 원본 파일 | 색상 특징 | |------------|----------|----------| | `basic100` | BASIC100 기준 템플릿 V1.pptx (67MB) | 모던 블루 (#2572EF) | | `core100` | CORE100 기준템플릿 V1.pptx (141MB) | 딥 블루 (#266DF1) | | `frame_blue` | 프레임디자인 블루 (19MB) | 프레임 블루 (#126BF6) + 카드 | | `mr_ppt_01` | 미스터 피피티 01 (18MB) | 다크 네이비 + 블루 (#0049F0) | | `mr_ppt_02` | 미스터 피피티 02 (24MB) | 블루 + 그레이 카드 (#2269F7) | | `mr_ppt_03` | 미스터 피피티 03 (5.5MB) | 네이비 + 골드 (#F4BB05) | | `mr_ppt_04` | 미스터 피피티 04 (8.8MB) | 딥 인디고 + 스카이블루 (#0583F2) | | `mr_ppt_05` | 미스터 피피티 05 (16MB) | 모던 블랙 + 블루 (#007AF9) | **향후 구현 옵션:** #### 방법 2 — 자동 다운로드 (권장) ``` 첫 사용 시 사내 NAS/서버에서 템플릿 자동 다운로드 → %APPDATA%/AXCopilot/templates/ppt/ 캐시 구현 포인트: - AppSettings에 TemplateServerUrl 설정 추가 (예: https://nas.internal/ax-templates/) - ResolveTemplatePath에서 파일 미발견 시 다운로드 트리거 - 다운로드 진행률 UI (ChatWindow 또는 설정 화면) - 오프라인 폴백: 내장 메타데이터(방법 1)로 자동 전환 - 버전 관리: 서버에 manifest.json → 로컬 캐시 버전과 비교 예상 작업량: 중 (다운로드 서비스 + UI + 설정) 파일: PptxSkill.cs, AppSettings.cs, SettingsService.cs ``` #### 방법 3 — 빌드에 포함 ``` csproj에 Content로 등록하여 배포 패키지에 포함 구현: 1. AxCopilot.csproj에 아래 추가: PreserveNewest 2. 설치파일 용량 영향: +~200MB (압축 후) - 현재 설치파일 ~107MB → ~307MB 예상 3. 선택적 포함 (용량 절충): - 경량 템플릿만 포함 (mr_ppt_03: 5.5MB, mr_ppt_04: 8.8MB 등) - 대형 템플릿 (core100: 141MB)은 방법 2로 다운로드 PreserveNewest 주의: build.bat의 payload.zip 압축 단계에서 자동 포함됨 ``` --- ## 14. 지능형 에이전트 고도화 (oh-my-openagent 참조) > 상세 계획: `docs/AGENT_ROADMAP.md` 8절 참조 ### 즉시 개발 (P1~P5) | 순위 | 기능 | 핵심 파일 | 설명 | |------|------|----------|------| | P1 | **IntentGate** (의도 분류기) | `IntentGateService.cs`(신규) | 사용자 입력 → 작업 유형 자동 분류 → 최적 실행 프로파일(temperature/tool 권한/반복 상한) 자동 적용. 기존 `ClassifyTaskType` + `IntentDetector` 통합 확장 | | P2 | **카테고리 서브에이전트 프로파일** | `SubAgentProfile.cs`(신규), `SubAgentTool.cs` | 단일 모델 + 다른 system prompt/tool 권한/temperature 조합으로 가상 멀티에이전트. researcher/coder/writer/reviewer/planner 5개 프로파일 | | P3 | **누적 학습** | `SessionLearningCollector.cs`(신규) | 세션 내 발견사항(빌드 에러, 파일 구조, 패턴)을 자동 수집하여 후속 반복에 컨텍스트로 주입. 반복 실수 방지 | | P4 | **워크스페이스 컨텍스트 자동 생성** | `WorkspaceContextGenerator.cs`(신규) | 작업 폴더 구조/기술스택을 `.ax-context.md`로 자동 생성. 서브에이전트 컨텍스트 효율화 | | P5 | **병렬 서브에이전트 확장** | `SpawnAgentsTool.cs`(신규) | 여러 서브에이전트를 한 번에 생성/실행. IntentGate 연동으로 복합 요청 자동 분해 | ### 추후 개발 (P6~P7) | 순위 | 기능 | 선행 조건 | 설명 | |------|------|----------|------| | P6 | **폴백 체인** | P1 + P2 | 실행 실패 시 다른 프로파일/전략으로 자동 재시도 (최대 2회) | | P7 | **모델 성격 매칭** | P1 + 멀티모델 | 작업 유형별 최적 모델 자동 선택 (RegisteredModel.strengths 매칭) | ### 구현 의존 관계 ``` P1 (IntentGate) ─────┬──→ P2 (카테고리 프로파일) ──→ P5 (병렬 확장) ├──→ P3 (누적 학습) [독립] └──→ P4 (워크스페이스 컨텍스트) [독립] P1 + P2 완료 후 ──→ P6 (폴백 체인) P1 + 멀티모델 후 ──→ P7 (모델 성격 매칭) ``` --- ## 15. 복원 체크포인트 UI 디자인 대규모 리팩토링 등 위험 작업 전 기록한 안전 복원 지점입니다. | 날짜 | 커밋 해시 | 설명 | 복원 명령 | |------|-----------|------|-----------| | 2026-04-13 | `4d1d160` | UI 디자인 개선 직전 — 테마 교정, IBM 진단 로깅, 뷰어 명칭 변경 완료 (704 tests pass) | `git checkout 4d1d160 -- src/AxCopilot/` | > **전체 롤백**: `git revert <커밋>` 또는 `git reset --hard 4d1d160` (주의: 이후 작업 모두 소실) > **부분 복원**: `git checkout 4d1d160 -- <파일경로>` 로 특정 파일만 되돌리기 --- ## 16. 관련 문서 | 문서 | 내용 | |------|------| | `docs/AGENT_ROADMAP.md` | 에이전트 기능 로드맵 (지능형 고도화 P1~P7 상세 포함) | | `docs/LAUNCHER_ROADMAP.md` | 런처 기능 로드맵 | | `docs/OPENCODE_PARITY_PLAN.md` | OpenCode 기능 대응 계획 | | `docs/TOOL_PARITY_REPORT.md` | 도구 호환성 리포트 | | `docs/AX_AGENT_UI_CHECKLIST.md` | 에이전트 UI 체크리스트 | | `docs/UI_UX_CHECKLIST.md` | UI/UX 체크리스트 | > 업데이트: 2026-04-14 18:08 (KST) > - 스킬 시스템 Phase 2 1~6번을 반영했습니다. `SkillService`는 프로젝트 `.claude/skills` 재귀 로드, namespaced `SKILL.md`, 번들 스킬 주입, `$ARGUMENTS`/named args/스킬 폴더 변수 치환, inline shell block 실행까지 지원하도록 확장했습니다. > - `ChatWindow` 런타임 경로도 함께 정리했습니다. 슬래시 호출은 `BuildSlashInvocationAsync`를 통해 컴파일된 스킬 프롬프트를 사용하고, 일반 대화는 `when_to_use`/`paths`/`user-invocable` 메타데이터를 바탕으로 선택된 자동 스킬 가이드를 보조 시스템 프롬프트로 붙입니다. > - 설정/UI 연결도 새 스킬 모델 기준으로 맞췄습니다. Agent 설정, 일반 설정, 오버레이, 스킬 관리자 도구는 번들/프로젝트/사용자 스킬 분류와 프로젝트 `.claude/skills` 경로를 반영해 설명과 리스트를 구성합니다. > - 도구 노출 단계는 `AgentLoopService.GetRuntimeActiveTools()`에서 blanket deny 권한을 먼저 적용하도록 보강했습니다. 패턴 기반 규칙은 call-time 검사를 유지하고, 단순 deny 도구는 모델 노출 전 필터링으로 정리했습니다. > - 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_phase2\\ -p:IntermediateOutputPath=obj\\verify_phase2\\` 경고 0 / 오류 0 > - 검증: `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentToolCatalogTests|SkillServiceRuntimePolicyTests" -p:OutputPath=bin\\verify_phase2_tests\\ -p:IntermediateOutputPath=obj\\verify_phase2_tests\\` 통과 16 > - 참고: 테스트 프로젝트의 기존 nullable 경고 `src/AxCopilot.Tests/Services/WorkspaceContextGeneratorTests.cs(76)` 1건은 유지됩니다. > 업데이트: 2026-04-14 18:22 (KST) > - 스킬 소스 확장 Phase 3을 반영했습니다. `SkillService`는 상위 디렉터리까지 포함한 프로젝트 `.claude/skills` 탐색, 플러그인 스킬 폴더 탐색, 추가 공용 폴더 목록, `.claude/commands` markdown command를 legacy skill로 변환하는 경로를 함께 지원합니다. > - 파일형 스킬은 body를 즉시 메모리에 올리지 않고 필요 시점에만 읽는 lazy prompt body 캐시를 추가했습니다. `SkillManagerTool`, `SkillEditorWindow`, `SkillGalleryWindow`는 이 경로를 통해 실제 본문을 표시합니다. > - 인자 모델도 확장했습니다. `arguments`와 `argument-hint`를 함께 해석해 named placeholder 치환을 강화했고, 인자가 부족하면 usage 가이드를 프롬프트 앞에 붙여 실행 품질을 보완합니다. > - 도구 deny 필터는 `AgentToolCatalog` 공통 메서드로 이동해 런타임과 설정 UI가 같은 blanket deny 규칙을 공유하도록 정리했습니다. > - 설정 저장에는 `additionalSkillFolders`를 추가했고, 일반 설정/AX Agent 설정 UI에 줄 단위 입력 필드를 넣어 여러 공용 스킬 폴더를 연결할 수 있게 했습니다. > - 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_phase3\\ -p:IntermediateOutputPath=obj\\verify_phase3\\` 경고 0 / 오류 0 > - 검증: `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentToolCatalogTests|SkillServiceRuntimePolicyTests" -p:OutputPath=bin\\verify_phase3_tests\\ -p:IntermediateOutputPath=obj\\verify_phase3_tests\\` 통과 18 > - 참고: 테스트 프로젝트의 기존 nullable 경고 `src/AxCopilot.Tests/Services/WorkspaceContextGeneratorTests.cs(76)` 1건은 유지됩니다. > 업데이트: 2026-04-14 18:33 (KST) > - 스킬 정책 제어를 추가했습니다. `LlmSettings`에 `enableProjectSkillDiscovery`, `enablePluginSkillDiscovery`, `enableLegacyCommandSkills`, `enableSkillInlineShell`, `skillInlineShellTimeoutSeconds`, `skillInlineShellMaxOutputChars`를 추가하고 일반 설정/AX Agent 설정 UI에 연결했습니다. > - 스킬 로드 시그니처는 이제 소스 디렉터리 목록뿐 아니라 실제 스킬 파일 수와 최근 수정 시각을 함께 반영합니다. 같은 폴더 구성이라도 파일 내용이 바뀌면 다음 로드 요청에서 재탐색됩니다. > - inline shell 실행기는 설정 기반 비활성화, timeout, 출력 길이 제한을 적용하도록 보강했습니다. 비활성 상태나 시간 초과는 프롬프트 안에서 식별 가능한 안내 문자열로 반환합니다. > - `SkillEditorWindow`와 `SkillGalleryWindow`는 lazy prompt body 경로를 사용하도록 맞췄고, 설정 변경 후 `ReloadFromCurrentSettings()`를 통해 현재 스킬 소스를 다시 읽도록 정리했습니다. > - 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_phase4b\\ -p:IntermediateOutputPath=obj\\verify_phase4b\\` 경고 0 / 오류 0 > - 검증: `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentToolCatalogTests|SkillServiceRuntimePolicyTests" -p:OutputPath=bin\\verify_phase4b_tests\\ -p:IntermediateOutputPath=obj\\verify_phase4b_tests\\` 통과 18 > - 참고: 테스트 프로젝트의 기존 nullable 경고 `src/AxCopilot.Tests/Services/WorkspaceContextGeneratorTests.cs(76)` 1건은 유지됩니다. - 업데이트: 2026-04-14 18:37 (KST) - claude-code 로컬 스냅샷을 다시 확인했지만, 현재 스냅샷에는 PPT/문서 전용 번들 스킬이 뚜렷하지 않았습니다. 대신 AX가 기본 포함하고 있는 문서형 managed skill 세트를 중심으로 배포 자산 품질을 다듬었습니다. - pptx-creator, docx-creator, report-writer, prd-generator, meeting-minutes, weekly-report, markdown-to-doc에 when_to_use와 argument-hint 메타를 추가해 proactive skill 선택과 슬래시 호출 가이드를 보강했습니다. - 일반 설정과 AX Agent 설정의 스킬 목록은 managed 스코프를 별도 기본 제공 스킬 그룹으로 분리했고, 스킬 갤러리도 기본 제공 / 프로젝트 / 플러그인 / 사용자 / 고급 필터와 배지를 사용하도록 정리했습니다. - 이 변경으로 문서·프레젠테이션 스킬은 빌드 출력 skills 폴더를 통해 기본 배포되면서도, UI에서 사용자 스킬과 구분된 상태로 확인할 수 있습니다. - 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_docskills\\ -p:IntermediateOutputPath=obj\\verify_docskills\\ 경고 0 / 오류 0 - 업데이트: 2026-04-14 18:45 (KST) - AX Agent 내부 설정의 스킬 탭 안내 블록에 커스텀 라벨을 추가했습니다. 이제 .claude/skills/.../SKILL.md 프로젝트 호환 경로가 스킬 탭 첫 화면에서 바로 보여, 워크스페이스에 같은 구조가 있으면 AX가 함께 읽는다는 점을 UI에서도 확인할 수 있습니다. - 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_skilllabel\\ -p:IntermediateOutputPath=obj\\verify_skilllabel\\ 경고 0 / 오류 0