From d45698d3978c49256638104eae10d7ba59994da8 Mon Sep 17 00:00:00 2001 From: lacvet Date: Mon, 6 Apr 2026 15:28:29 +0900 Subject: [PATCH] =?UTF-8?q?AX=20Agent=20=EC=B0=BD=20=EB=93=9C=EB=9E=98?= =?UTF-8?q?=EA=B7=B8=20=EC=84=B1=EB=8A=A5=20=EA=B0=9C=EC=84=A0=20=EB=B0=8F?= =?UTF-8?q?=20=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=20=EC=9E=AC=EA=B3=84?= =?UTF-8?q?=EC=82=B0=20=EC=A7=80=EC=97=B0=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ChatWindow에 WM_ENTERSIZEMOVE/WM_EXITSIZEMOVE 감지를 추가해 창 이동·리사이즈 루프를 별도로 관리함 - 이동 중에는 루트 visual을 BitmapCache로 전환하고 무거운 transcript/layout 재계산을 지연시켜 드래그 버벅임을 줄임 - SizeChanged에서 주제 스크롤/반응형 레이아웃/메시지 재렌더를 즉시 수행하지 않고 종료 시 한 번만 반영하도록 정리함 - README와 DEVELOPMENT 문서에 변경 목적과 검증 결과를 로컬 시각 기준으로 기록함 - 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\ (경고 0, 오류 0) --- README.md | 4 ++ docs/DEVELOPMENT.md | 2 + src/AxCopilot/Views/ChatWindow.xaml.cs | 57 ++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/README.md b/README.md index 7a014a8..27be34b 100644 --- a/README.md +++ b/README.md @@ -1248,3 +1248,7 @@ MIT License - IBM 연동형 vLLM 인증 경로를 점검한 결과, 기존 AX Agent는 등록 모델 인증 방식으로 `Bearer`와 `CP4D`만 지원하고 `IBM IAM` 토큰 교환은 지원하지 않았다. 이 때문에 IBM Cloud 계열 watsonx/vLLM 게이트웨이에 API 키를 직접 Bearer로 보내면 `인증 실패 - API 키가 유효하지 않습니다.` 오류가 발생할 수 있었다. - [IbmIamTokenService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/IbmIamTokenService.cs)를 추가하고 [LlmService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/LlmService.cs)에 `ibm_iam` 인증 타입을 연결해, 등록 모델의 API 키를 IBM IAM access token으로 교환한 뒤 Bearer 헤더에 넣도록 보강했다. - [ModelRegistrationDialog.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ModelRegistrationDialog.cs), [SettingsViewModel.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/ViewModels/SettingsViewModel.cs), [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs), [AppSettings.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Models/AppSettings.cs)도 함께 갱신해 등록 모델 인증 방식에 `IBM IAM (토큰 교환)`이 보이고 저장/표시되도록 맞췄다. +- 업데이트: 2026-04-06 15:26 (KST) + - AX Agent 창을 PC에서 드래그로 이동할 때 버벅이던 문제를 줄이기 위해 [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)에 `WM_ENTERSIZEMOVE` / `WM_EXITSIZEMOVE` 기반 이동·리사이즈 감지를 추가했다. + - 이동/리사이즈 루프 중에는 창 루트를 `BitmapCache`로 묶고, `SizeChanged`에 연결돼 있던 `UpdateTopicPresetScrollMode()`, `UpdateResponsiveChatLayout()`, `RenderMessages()` 재계산은 잠시 지연시킨 뒤 루프 종료 시 한 번만 반영하도록 바꿨다. + - 이 변경으로 창을 끌 때마다 무거운 transcript/레이아웃이 반복 갱신되던 경로를 줄여, AX Agent 창 이동 체감 속도를 개선했다. diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 23b00ed..277d995 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -4960,3 +4960,5 @@ ow + toggle ?쒓컖 ?몄뼱濡??ㅼ떆 ?뺣젹?덈떎. - Document update: 2026-04-06 13:36 (KST) - Made file-backed transcript actions state-aware in `ChatWindow.AgentEventRendering.cs`. The inline preview button now changes label by context, such as `변경 확인`, `작성 내용 보기`, `부분 결과 보기`, `오류 파일 보기`, or `승인 전 미리보기`, instead of showing the same generic action for every case. - Document update: 2026-04-06 14:06 (KST) - Diagnosed IBM-connected vLLM authentication failures and confirmed AX only supported `bearer` and `cp4d` registered-model auth modes. Added `IbmIamTokenService.cs` and wired a new `ibm_iam` auth mode into `LlmService.cs` so IBM Cloud API keys are exchanged for IAM access tokens before being sent as Bearer credentials. - Document update: 2026-04-06 14:06 (KST) - Updated the registered-model schema and UI surfaces to expose the new auth mode. `AppSettings.cs`, `SettingsViewModel.cs`, `ModelRegistrationDialog.cs`, and the AX Agent overlay model list in `ChatWindow.xaml.cs` now save/display `IBM IAM` alongside existing `Bearer` and `CP4D` modes. +- Document update: 2026-04-06 15:26 (KST) - Improved AX Agent window drag performance by handling `WM_ENTERSIZEMOVE` / `WM_EXITSIZEMOVE` in `ChatWindow.xaml.cs`. The window now enters a lightweight move-size mode while being dragged or resized. +- Document update: 2026-04-06 15:26 (KST) - During move-size loops the root visual is temporarily cached with `BitmapCache`, and the expensive `UpdateTopicPresetScrollMode()`, `UpdateResponsiveChatLayout()`, and `RenderMessages()` refresh path is deferred until the move/resize operation ends. This reduces the “heavy” feeling when moving the AX Agent window on desktop PCs. diff --git a/src/AxCopilot/Views/ChatWindow.xaml.cs b/src/AxCopilot/Views/ChatWindow.xaml.cs index f51fcff..2d9e4d5 100644 --- a/src/AxCopilot/Views/ChatWindow.xaml.cs +++ b/src/AxCopilot/Views/ChatWindow.xaml.cs @@ -35,6 +35,9 @@ public partial class ChatWindow : Window private bool _isStreaming; private bool _sidebarVisible = true; private double _sidebarExpandedWidth = 262; + private bool _isInWindowMoveSizeLoop; + private bool _pendingResponsiveLayoutRefresh; + private CacheMode? _cachedRootCacheModeBeforeMove; private string _selectedCategory = ""; // "" = 전체 private readonly Dictionary _tabSelectedCategory = new(StringComparer.OrdinalIgnoreCase) { @@ -274,6 +277,9 @@ public partial class ChatWindow : Window KeyDown += ChatWindow_KeyDown; MouseMove += (_, _) => { + if (_isInWindowMoveSizeLoop) + return; + if (TokenUsagePopup?.IsOpen == true) CloseTokenUsagePopupIfIdle(); }; @@ -389,6 +395,12 @@ public partial class ChatWindow : Window }; SizeChanged += (_, _) => { + if (_isInWindowMoveSizeLoop) + { + _pendingResponsiveLayoutRefresh = true; + return; + } + UpdateTopicPresetScrollMode(); if (UpdateResponsiveChatLayout()) RenderMessages(preserveViewport: true); @@ -1067,6 +1079,15 @@ public partial class ChatWindow : Window private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { + if (msg == 0x0231) // WM_ENTERSIZEMOVE + { + BeginWindowMoveSizeLoop(); + } + else if (msg == 0x0232) // WM_EXITSIZEMOVE + { + EndWindowMoveSizeLoop(); + } + // WM_GETMINMAXINFO — 최대화 시 작업 표시줄 영역 확보 if (msg == 0x0024) { @@ -1087,6 +1108,42 @@ public partial class ChatWindow : Window return IntPtr.Zero; } + private void BeginWindowMoveSizeLoop() + { + if (_isInWindowMoveSizeLoop) + return; + + _isInWindowMoveSizeLoop = true; + _pendingResponsiveLayoutRefresh = false; + + if (Content is UIElement rootElement) + { + _cachedRootCacheModeBeforeMove = rootElement.CacheMode; + rootElement.CacheMode = new BitmapCache(); + } + } + + private void EndWindowMoveSizeLoop() + { + if (!_isInWindowMoveSizeLoop) + return; + + _isInWindowMoveSizeLoop = false; + + if (Content is UIElement rootElement) + rootElement.CacheMode = _cachedRootCacheModeBeforeMove; + + _cachedRootCacheModeBeforeMove = null; + + if (_pendingResponsiveLayoutRefresh) + { + _pendingResponsiveLayoutRefresh = false; + UpdateTopicPresetScrollMode(); + if (UpdateResponsiveChatLayout()) + RenderMessages(preserveViewport: true); + } + } + private void BtnMinimize_Click(object sender, RoutedEventArgs e) => WindowState = WindowState.Minimized; private void BtnMaximize_Click(object sender, RoutedEventArgs e) {