Some checks failed
Release Gate / gate (push) Has been cancelled
- claude-code 선택적 탐색 흐름을 참고해 Cowork/Code 시스템 프롬프트에서 folder_map 상시 선행 지시를 완화하고 glob/grep 기반 좁은 탐색을 우선하도록 조정함 - FolderMapTool 기본 depth를 2로, include_files 기본값을 false로 낮추고 MultiReadTool 최대 파일 수를 8개로 줄여 초기 과탐색 폭을 보수적으로 조정함 - AgentLoopExplorationPolicy partial을 추가해 탐색 범위 분류, broad-scan corrective hint, exploration_breadth 성능 로그를 연결함 - AgentLoopService에 탐색 범위 가이드 주입과 실행 중 탐색 폭 추적을 추가하고, 좁은 질문에서 반복적인 folder_map/대량 multi_read를 교정하도록 정리함 - DocxToHtmlConverter nullable 경고를 수정해 Release 빌드 경고 0 / 오류 0 기준을 다시 충족함 - README와 docs/DEVELOPMENT.md에 2026-04-09 10:36 (KST) 기준 개발 이력을 반영함
507 lines
26 KiB
Markdown
507 lines
26 KiB
Markdown
# AX Copilot - 개발 문서
|
||
|
||
> 최종 업데이트: 2026-04-09 · 버전 0.7.3
|
||
|
||
---
|
||
|
||
## 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 |
|
||
|
||
### 5.3 LLM 서비스
|
||
|
||
**지원 공급자**:
|
||
| 서비스 | 설명 |
|
||
|--------|------|
|
||
| `claude` / `sigmoid` | Anthropic Claude (Sigmoid API 경유) |
|
||
| `gemini` | Google Gemini API |
|
||
| `vllm` | OpenAI 호환 vLLM (IBM CP4D 지원 포함) |
|
||
| `ollama` | 로컬 Ollama 모델 |
|
||
|
||
**모델 라우팅**: `ModelRouterService`를 통한 오버라이드 스택 — 대화 중 모델/서비스를 동적으로 전환 가능
|
||
|
||
**토큰 관리**: `TokenEstimator`로 컨텍스트 길이 추정, 오버플로우 시 `ContextCondenser`가 자동 압축
|
||
|
||
### 5.4 대화 저장소
|
||
|
||
- `ChatStorageService`: SQLite 기반 대화 영속화
|
||
- `ChatSessionStateService`: 메모리 내 세션 상태 관리
|
||
- `ChatConversation`: 메시지 목록 + 실행 이벤트 타임라인
|
||
|
||
---
|
||
|
||
## 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` | 에이전트 이벤트 배너/카드 렌더링 |
|
||
| `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.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<IEnumerable<LauncherItem>> 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
|
||
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`의 `<Version>` 태그 하나만 변경하면 앱 전체에 반영
|
||
- 설정 스키마 버전은 `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<T>`, `FindAncestor<T>` 유틸 추가 |
|
||
|
||
### 구조적 리팩토링 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` 토글 단순화 + 레거시 정리 유지 |
|
||
|
||
### 에이전트 루프 문서 생성 흐름 수정 (2026-04-09)
|
||
|
||
| 파일 | 수정 내용 |
|
||
|------|----------|
|
||
| `AgentLoopTransitions.Documents.cs` | `TryHandleTerminalDocumentCompletionTransitionAsync`에서 `document_plan` 없이 바로 문서 도구 호출 시 조기 종료 방지 — LLM이 추가 반복으로 내용을 보강할 수 있도록 허용 |
|
||
| `HtmlSkill.cs` | `MarkdownToHtml`에서 LLM이 삽입한 `<br>` 태그가 이스케이프되는 버그 수정 — 이스케이프 전 플레이스홀더로 보존 후 복원 |
|
||
|
||
---
|
||
|
||
## 13. 디렉토리별 가이드
|
||
|
||
| 디렉토리 | 수정 시 주의사항 |
|
||
|---------|----------------|
|
||
| `Core/` | `FuzzyEngine` 점수 공식 변경 시 검색 품질에 직접 영향 |
|
||
| `Handlers/` | 새 핸들러 추가 시 `App.xaml.cs`에 등록 필요 |
|
||
| `Services/Agent/` | 새 도구 추가 시 `ToolRegistry`에 등록 + 스킬 파일(`.skill.md`) 작성 |
|
||
| `Themes/` | 리소스 키 변경 시 모든 테마에 동일하게 적용 필요 |
|
||
| `Models/AppSettings.cs` | 속성 추가 시 `SettingsService` 마이그레이션 고려 |
|
||
| `Views/ChatWindow.*` | partial class 분할 — 관련 기능은 해당 파일에서 수정 |
|
||
|
||
---
|
||
|
||
## 14. 관련 문서
|
||
|
||
| 문서 | 내용 |
|
||
|------|------|
|
||
| `docs/AGENT_ROADMAP.md` | 에이전트 기능 로드맵 |
|
||
| `docs/LAUNCHER_ROADMAP.md` | 런처 기능 로드맵 |
|
||
| `docs/CLAW_CODE_PARITY_PLAN.md` | Claude Code 기능 대응 계획 |
|
||
| `docs/TOOL_PARITY_REPORT.md` | 도구 호환성 리포트 |
|
||
| `docs/AX_AGENT_UI_CHECKLIST.md` | 에이전트 UI 체크리스트 |
|
||
| `docs/UI_UX_CHECKLIST.md` | UI/UX 체크리스트 |
|
||
---
|
||
|
||
### 선택적 탐색 구조 개선 (2026-04-09 10:36 KST)
|
||
|
||
- `claude-code`의 `Glob/Grep/FileRead` 프롬프트와 `toolOrchestration.ts` 흐름을 다시 대조한 결과, AX는 `folder_map`을 너무 쉽게 먼저 호출하도록 유도하는 규칙 때문에 질문과 무관한 전체 워크스페이스를 훑는 경향이 있었습니다.
|
||
- `src/AxCopilot/Views/ChatWindow.xaml.cs`
|
||
- Cowork/Code 시스템 프롬프트에서 `folder_map`을 항상 첫 단계로 요구하던 문구를 완화했습니다.
|
||
- 좁은 범위의 질문은 `glob/grep + targeted file_read`를 우선하고, 저장소 전체 구조가 정말 필요할 때만 `folder_map`을 쓰도록 바꿨습니다.
|
||
- `src/AxCopilot/Services/Agent/FolderMapTool.cs`
|
||
- 기본 탐색 depth를 `3 -> 2`로 낮췄습니다.
|
||
- `include_files` 기본값을 `true -> false`로 바꿔 첫 패스에서 구조 확인 위주로 동작하게 했습니다.
|
||
- `src/AxCopilot/Services/Agent/MultiReadTool.cs`
|
||
- 한 번에 읽을 수 있는 최대 파일 수를 `20 -> 8`로 낮춰 초기 과탐색과 토큰 낭비를 줄였습니다.
|
||
- `src/AxCopilot/Services/Agent/AgentLoopExplorationPolicy.cs`
|
||
- 새 partial 파일을 추가해 탐색 범위를 `Localized / TopicBased / RepoWide / OpenEnded`로 분류하는 정책을 도입했습니다.
|
||
- `folder_map` 반복, 대량 `multi_read`, broad scan 패턴이 나오면 관련 파일만 다시 고르도록 corrective hint를 주입하는 규칙을 넣었습니다.
|
||
- `src/AxCopilot/Services/Agent/AgentLoopService.cs`
|
||
- 루프 시작 시 탐색 범위 가이드를 시스템 메시지로 주입합니다.
|
||
- 도구 실행 중 `folder_map` 호출 수, `multi_read` 파일 수, 총 읽은 파일 수를 추적합니다.
|
||
- 좁은 범위 질문에서 broad scan이 감지되면 `탐색 범위를 좁히는 중 · 관련 파일만 다시 선택합니다` 진행 메시지를 남기고 선택적 탐색으로 되돌립니다.
|
||
- `src/AxCopilot/Services/AgentPerformanceLogService.cs`
|
||
- `%APPDATA%\\AxCopilot\\perf`에 `exploration_breadth` 성능 로그를 남겨 broad scan 여부와 selective hit 여부를 실사용 기준으로 검증할 수 있게 했습니다.
|