AX Agent 계획 모드 잔재를 더 걷어내고 UI hover 안정화\n\n- AgentLoop 실행 경로에서 계획 모드 분기를 비활성 정책 기준으로 단순화해 기본 런타임이 설정값에 흔들리지 않게 정리\n- 내부 설정의 숨김 상태 계획 모드 버튼과 콤보 이벤트 연결 및 관련 dead code 제거\n- 작업유형 카드에서 hover 라벨과 ToolTip 충돌로 발생하던 깜박임을 해결\n- README와 DEVELOPMENT 문서에 parity 진척율, 남은 작업축, 설정 제거 후보를 반영\n\n검증 결과\n- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\\n- 경고 0 / 오류 0
Some checks failed
Release Gate / gate (push) Has been cancelled

This commit is contained in:
2026-04-05 16:51:24 +09:00
parent a315f587bf
commit f8e62bde2a
5 changed files with 16 additions and 43 deletions

View File

@@ -911,6 +911,10 @@ ow + toggle 시각 언어로 통일했습니다.
- 같은 점검에서 작업유형 카드 hover 깜박임 원인은 `hover 라벨`과 기본 WPF `ToolTip`이 동시에 켜져 마우스가 카드 경계와 툴팁 사이를 오가며 상태가 흔들리는 구조로 확인됐습니다. [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 에서 프리셋/기타/프리셋 추가 카드의 기본 `ToolTip` 을 제거하고 hover 라벨만 남겨 깜박임을 줄였습니다. - 같은 점검에서 작업유형 카드 hover 깜박임 원인은 `hover 라벨`과 기본 WPF `ToolTip`이 동시에 켜져 마우스가 카드 경계와 툴팁 사이를 오가며 상태가 흔들리는 구조로 확인됐습니다. [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 에서 프리셋/기타/프리셋 추가 카드의 기본 `ToolTip` 을 제거하고 hover 라벨만 남겨 깜박임을 줄였습니다.
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\` 경고 0 / 오류 0 - 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\` 경고 0 / 오류 0
- 업데이트: 2026-04-05 19:42 (KST) - 업데이트: 2026-04-05 19:42 (KST)
- `PlanMode` 잔재도 런타임 기준으로 한 단계 더 걷어냈습니다. [AgentLoopService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/AgentLoopService.cs) 에서 실행 전 plan prelude 진입은 비활성 플래그 기준으로만 남기고, 기본 실행 경로가 `planMode` 값에 의해 흔들리지 않도록 정리했습니다.
- [ChatWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml) 과 [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 에서는 숨김 상태였던 inline/overlay 계획 모드 click/selection 잔재를 제거해 dead UI code를 더 줄였습니다. 사용자 노출 정책은 그대로 `off` 고정입니다.
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\` 경고 0 / 오류 0
- 업데이트: 2026-04-05 19:49 (KST)
--- ---

View File

@@ -4673,3 +4673,8 @@ ow + toggle ?쒓컖 ?몄뼱濡??ㅼ떆 ?뺣젹?덈떎.
- 작업유형 카드 hover 깜박임도 원인을 확인해 즉시 보정했습니다. [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)의 `BuildTopicButtons()` 에서 프리셋/기타/프리셋 추가 카드의 기본 WPF `ToolTip` 할당을 제거해, custom hover 라벨과 기본 툴팁이 동시에 켜지며 깜박이던 구조를 정리했습니다. - 작업유형 카드 hover 깜박임도 원인을 확인해 즉시 보정했습니다. [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)의 `BuildTopicButtons()` 에서 프리셋/기타/프리셋 추가 카드의 기본 WPF `ToolTip` 할당을 제거해, custom hover 라벨과 기본 툴팁이 동시에 켜지며 깜박이던 구조를 정리했습니다.
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify\ -p:IntermediateOutputPath=obj\verify\` 경고 0 / 오류 0 - 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify\ -p:IntermediateOutputPath=obj\verify\` 경고 0 / 오류 0
- 업데이트: 2026-04-05 19:42 (KST) - 업데이트: 2026-04-05 19:42 (KST)
- `PlanMode` 런타임 잔재도 추가로 정리했습니다. [AgentLoopService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/AgentLoopService.cs) 에서 plan prelude 분기는 `shouldGeneratePlanPrelude = false` 기준의 비활성 경로로 바꿔 기본 실행 흐름이 설정값에 흔들리지 않게 했고, `requireApproval` 도 기본 false로 고정했습니다.
- [ChatWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml) 에서는 이미 숨김 상태였던 `BtnInlinePlanMode`, `CmbOverlayPlanMode` 의 event 연결을 제거했고, [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 에서는 `NextPlanMode`, `PlanModeLabel`, `BtnInlinePlanMode_Click`, `CmbOverlayPlanMode_SelectionChanged`, 관련 quick action 갱신 코드를 걷어내 dead code를 더 줄였습니다.
- 이번 정리로 `PlanMode` 는 정책상 `off` 고정이라는 사실과 실제 런타임/UI 흐름이 더 일치하게 됐습니다. 남은 잔재는 메인 설정 구형 카드와 상태 저장 구조 쪽이라 다음 단계에서 `AppSettings / SettingsViewModel / AppStateService` 축으로 계속 줄이면 됩니다.
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify\ -p:IntermediateOutputPath=obj\verify\` 경고 0 / 오류 0
- 업데이트: 2026-04-05 19:49 (KST)

View File

@@ -199,8 +199,8 @@ public partial class AgentLoopService
var recentTaskRetryQuality = TryGetRecentTaskRetryQuality(taskPolicy.TaskType); var recentTaskRetryQuality = TryGetRecentTaskRetryQuality(taskPolicy.TaskType);
maxRetry = ComputeQualityAwareMaxRetry(maxRetry, recentTaskRetryQuality, taskPolicy.TaskType); maxRetry = ComputeQualityAwareMaxRetry(maxRetry, recentTaskRetryQuality, taskPolicy.TaskType);
// 플랜 모드 설정 // 플랜 prelude는 현재 정책상 비활성
var planMode = ResolveEffectivePlanMode(llm.PlanMode, ActiveTab, taskPolicy.TaskType); // off | always | auto var shouldGeneratePlanPrelude = false;
var context = BuildContext(); var context = BuildContext();
InjectTaskTypeGuidance(messages, taskPolicy); InjectTaskTypeGuidance(messages, taskPolicy);
@@ -282,8 +282,8 @@ public partial class AgentLoopService
workFolder = context.WorkFolder workFolder = context.WorkFolder
})); }));
// ── 플랜 모드 "always": 첫 번째 호출은 계획만 생성 (도구 없이) ── // ── 과거 plan mode 잔재. 현재 정책상 비활성 ──
if (planMode == "always") if (shouldGeneratePlanPrelude)
{ {
iteration++; iteration++;
EmitEvent(AgentEventType.Thinking, "", "실행 계획 생성 중..."); EmitEvent(AgentEventType.Thinking, "", "실행 계획 생성 중...");
@@ -637,7 +637,7 @@ public partial class AgentLoopService
// 플랜 모드 "auto"에서만 승인 대기 // 플랜 모드 "auto"에서만 승인 대기
// - auto: 계획 감지 시 승인 대기 (단, 도구 호출이 함께 있으면 이미 실행 중이므로 스킵) // - auto: 계획 감지 시 승인 대기 (단, 도구 호출이 함께 있으면 이미 실행 중이므로 스킵)
// - off/always: 승인창 띄우지 않음 (off=자동 진행, always=앞에서 이미 처리됨) // - off/always: 승인창 띄우지 않음 (off=자동 진행, always=앞에서 이미 처리됨)
var requireApproval = planMode == "auto" && toolCalls.Count == 0; const bool requireApproval = false;
if (requireApproval && UserDecisionCallback != null) if (requireApproval && UserDecisionCallback != null)
{ {

View File

@@ -1929,8 +1929,7 @@
Visibility="Collapsed" Visibility="Collapsed"
IsEnabled="False" IsEnabled="False"
Margin="0,0,6,6" Margin="0,0,6,6"
Padding="9,4" Padding="9,4"/>
Click="BtnInlinePlanMode_Click"/>
<Button x:Name="BtnInlinePermission" <Button x:Name="BtnInlinePermission"
Style="{StaticResource OutlineHoverBtn}" Style="{StaticResource OutlineHoverBtn}"
Visibility="Collapsed" Visibility="Collapsed"
@@ -3019,8 +3018,7 @@
<ComboBox x:Name="CmbOverlayPlanMode" <ComboBox x:Name="CmbOverlayPlanMode"
Grid.Column="1" Grid.Column="1"
Visibility="Collapsed" Visibility="Collapsed"
Style="{StaticResource OverlayComboBox}" Style="{StaticResource OverlayComboBox}">
SelectionChanged="CmbOverlayPlanMode_SelectionChanged">
<ComboBoxItem Content="계획 · 끄기" Tag="off"/> <ComboBoxItem Content="계획 · 끄기" Tag="off"/>
<ComboBoxItem Content="계획 · 자동 계획" Tag="auto"/> <ComboBoxItem Content="계획 · 자동 계획" Tag="auto"/>
<ComboBoxItem Content="계획 · 항상 계획" Tag="always"/> <ComboBoxItem Content="계획 · 항상 계획" Tag="always"/>

View File

@@ -13904,18 +13904,6 @@ public partial class ChatWindow : Window
BtnModelSelector.ToolTip = $"현재 서비스: {serviceLabel}\n현재 모델: {GetCurrentModelDisplayName()}\n모델/추론 빠른 설정"; BtnModelSelector.ToolTip = $"현재 서비스: {serviceLabel}\n현재 모델: {GetCurrentModelDisplayName()}\n모델/추론 빠른 설정";
} }
private static string NextPlanMode(string current) => (current ?? "off").ToLowerInvariant() switch
{
"off" => "auto",
"auto" => "always",
_ => "off",
};
private static string PlanModeLabel(string value) => (value ?? "off").ToLowerInvariant() switch
{
"always" => "항상 계획",
"auto" => "자동 계획",
_ => "끄기",
};
private static string NextReasoning(string current) => (current ?? "normal").ToLowerInvariant() switch private static string NextReasoning(string current) => (current ?? "normal").ToLowerInvariant() switch
{ {
"minimal" => "normal", "minimal" => "normal",
@@ -14076,7 +14064,6 @@ public partial class ChatWindow : Window
BtnInlineFastMode.Content = GetQuickActionLabel("Fast", llm.FreeTierMode ? "켜짐" : "꺼짐"); BtnInlineFastMode.Content = GetQuickActionLabel("Fast", llm.FreeTierMode ? "켜짐" : "꺼짐");
BtnInlineReasoning.Content = GetQuickActionLabel("추론", ReasoningLabel(llm.AgentDecisionLevel)); BtnInlineReasoning.Content = GetQuickActionLabel("추론", ReasoningLabel(llm.AgentDecisionLevel));
BtnInlinePlanMode.Content = GetQuickActionLabel("계획", PlanModeLabel("off"));
BtnInlinePermission.Content = GetQuickActionLabel("권한", PermissionModeCatalog.ToDisplayLabel(llm.FilePermission)); BtnInlinePermission.Content = GetQuickActionLabel("권한", PermissionModeCatalog.ToDisplayLabel(llm.FilePermission));
BtnInlineSkill.Content = $"스킬 · {(llm.EnableSkillSystem ? "On" : "Off")}"; BtnInlineSkill.Content = $"스킬 · {(llm.EnableSkillSystem ? "On" : "Off")}";
BtnInlineCommandBrowser.Content = "명령/스킬 브라우저"; BtnInlineCommandBrowser.Content = "명령/스킬 브라우저";
@@ -14087,7 +14074,6 @@ public partial class ChatWindow : Window
ApplyQuickActionVisual(BtnInlineFastMode, llm.FreeTierMode, "#ECFDF5", "#166534"); ApplyQuickActionVisual(BtnInlineFastMode, llm.FreeTierMode, "#ECFDF5", "#166534");
ApplyQuickActionVisual(BtnInlineReasoning, !string.Equals(llm.AgentDecisionLevel, "normal", StringComparison.OrdinalIgnoreCase), "#EEF2FF", "#1D4ED8"); ApplyQuickActionVisual(BtnInlineReasoning, !string.Equals(llm.AgentDecisionLevel, "normal", StringComparison.OrdinalIgnoreCase), "#EEF2FF", "#1D4ED8");
ApplyQuickActionVisual(BtnInlinePlanMode, false, "#EEF2FF", "#4338CA");
ApplyQuickActionVisual(BtnInlinePermission, ApplyQuickActionVisual(BtnInlinePermission,
!string.Equals(PermissionModeCatalog.NormalizeGlobalMode(llm.FilePermission), PermissionModeCatalog.Deny, StringComparison.OrdinalIgnoreCase), !string.Equals(PermissionModeCatalog.NormalizeGlobalMode(llm.FilePermission), PermissionModeCatalog.Deny, StringComparison.OrdinalIgnoreCase),
"#FFF7ED", "#FFF7ED",
@@ -16323,7 +16309,6 @@ public partial class ChatWindow : Window
SelectComboTag(CmbOverlayOperationMode, OperationModePolicy.Normalize(_settings.Settings.OperationMode)); SelectComboTag(CmbOverlayOperationMode, OperationModePolicy.Normalize(_settings.Settings.OperationMode));
SelectComboTag(CmbOverlayFolderDataUsage, _folderDataUsage); SelectComboTag(CmbOverlayFolderDataUsage, _folderDataUsage);
SelectComboTag(CmbOverlayPermission, PermissionModeCatalog.NormalizeGlobalMode(llm.FilePermission)); SelectComboTag(CmbOverlayPermission, PermissionModeCatalog.NormalizeGlobalMode(llm.FilePermission));
SelectComboTag(CmbOverlayPlanMode, "off");
SelectComboTag(CmbOverlayReasoning, llm.AgentDecisionLevel); SelectComboTag(CmbOverlayReasoning, llm.AgentDecisionLevel);
SelectComboTag(CmbOverlayFastMode, llm.FreeTierMode ? "on" : "off"); SelectComboTag(CmbOverlayFastMode, llm.FreeTierMode ? "on" : "off");
SelectComboTag(CmbOverlayDefaultOutputFormat, llm.DefaultOutputFormat ?? "auto"); SelectComboTag(CmbOverlayDefaultOutputFormat, llm.DefaultOutputFormat ?? "auto");
@@ -16834,15 +16819,6 @@ public partial class ChatWindow : Window
PersistOverlaySettingsState(refreshOverlayDeferredInputs: false); PersistOverlaySettingsState(refreshOverlayDeferredInputs: false);
} }
private void CmbOverlayPlanMode_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (_isOverlaySettingsSyncing)
return;
_settings.Settings.Llm.PlanMode = "off";
PersistOverlaySettingsState(refreshOverlayDeferredInputs: false);
}
private void CmbOverlayPermission_SelectionChanged(object sender, SelectionChangedEventArgs e) private void CmbOverlayPermission_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
if (_isOverlaySettingsSyncing || CmbOverlayPermission.SelectedItem is not ComboBoxItem selected || selected.Tag is not string tag) if (_isOverlaySettingsSyncing || CmbOverlayPermission.SelectedItem is not ComboBoxItem selected || selected.Tag is not string tag)
@@ -17049,16 +17025,6 @@ public partial class ChatWindow : Window
RefreshOverlayVisualState(loadDeferredInputs: false); RefreshOverlayVisualState(loadDeferredInputs: false);
} }
private void BtnInlinePlanMode_Click(object sender, RoutedEventArgs e)
{
var llm = _settings.Settings.Llm;
llm.PlanMode = "off";
_settings.Save();
_appState.LoadFromSettings(_settings);
RefreshInlineSettingsPanel();
RefreshOverlayVisualState(loadDeferredInputs: false);
}
private void BtnInlinePermission_Click(object sender, RoutedEventArgs e) private void BtnInlinePermission_Click(object sender, RoutedEventArgs e)
{ {
var llm = _settings.Settings.Llm; var llm = _settings.Settings.Llm;