계획 모드 설정 제거와 플랜 승인 UX 정리
Some checks failed
Release Gate / gate (push) Has been cancelled

메인 설정과 AX Agent 내부 설정에서 계획 모드 UI를 숨기고 저장값을 항상 off로 고정했습니다.

AgentLoop 런타임도 계획 모드를 off로 고정해 코워크와 코드에서 자동 계획 승인 팝업이 반복 노출되지 않도록 정리했습니다.

PlanViewerWindow는 AX Agent 창 owner 리소스를 직접 받아 같은 테마 축을 따르도록 바꾸고 인라인 승인 버튼 중복 노출을 제거했습니다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\ 경고 0 오류 0
This commit is contained in:
2026-04-05 14:12:22 +09:00
parent 9fafcd0192
commit f53f35bbed
9 changed files with 45 additions and 41 deletions

View File

@@ -2098,20 +2098,7 @@ public partial class AgentLoopService
internal static string ResolveEffectivePlanMode(string? configuredPlanMode, string? activeTab, string? taskType)
{
var normalizedPlanMode = (configuredPlanMode ?? "off").Trim().ToLowerInvariant();
if (normalizedPlanMode is not ("off" or "auto" or "always"))
normalizedPlanMode = "off";
if (string.Equals(activeTab, "Cowork", StringComparison.OrdinalIgnoreCase)
&& string.Equals(taskType, "docs", StringComparison.OrdinalIgnoreCase)
&& normalizedPlanMode == "off")
{
// claw-code 레퍼런스처럼 문서형 코워크는 실행 전에 구조를 먼저 세우고,
// 그 계획을 바탕으로 실제 산출물 생성 단계까지 이어가도록 기본값을 보정합니다.
return "always";
}
return normalizedPlanMode;
return "off";
}
private static void InjectTaskTypeGuidance(List<ChatMessage> messages, TaskTypePolicy taskPolicy)

View File

@@ -196,7 +196,7 @@ public sealed class AppStateService
Permissions.FilePermission = PermissionModeCatalog.NormalizeGlobalMode(llm.FilePermission);
Permissions.AgentDecisionLevel = llm.AgentDecisionLevel ?? "detailed";
Permissions.PlanMode = llm.PlanMode ?? "off";
Permissions.PlanMode = "off";
Permissions.ToolOverrideCount = llm.ToolPermissions?.Count ?? 0;
Permissions.ToolOverrides = llm.ToolPermissions?
.OrderBy(x => x.Key, StringComparer.OrdinalIgnoreCase)

View File

@@ -370,11 +370,13 @@ public class SettingsViewModel : INotifyPropertyChanged
set { _agentDecisionLevel = value; OnPropertyChanged(); }
}
private string _planMode = "off";
public string PlanMode
{
get => _planMode;
set { _planMode = value; OnPropertyChanged(); }
get => "off";
set
{
OnPropertyChanged();
}
}
private bool _enableMultiPassDocument;
@@ -1138,7 +1140,6 @@ public class SettingsViewModel : INotifyPropertyChanged
_planDiffSeverityMediumRatioPercent = llm.PlanDiffSeverityMediumRatioPercent > 0 ? Math.Clamp(llm.PlanDiffSeverityMediumRatioPercent, 1, 100) : 25;
_planDiffSeverityHighRatioPercent = llm.PlanDiffSeverityHighRatioPercent > 0 ? Math.Clamp(llm.PlanDiffSeverityHighRatioPercent, 1, 100) : 60;
_agentDecisionLevel = llm.AgentDecisionLevel;
_planMode = string.IsNullOrEmpty(llm.PlanMode) ? "off" : llm.PlanMode;
_enableMultiPassDocument = llm.EnableMultiPassDocument;
_enableCoworkVerification = llm.EnableCoworkVerification;
_enableFilePathHighlight = llm.EnableFilePathHighlight;
@@ -1580,7 +1581,7 @@ public class SettingsViewModel : INotifyPropertyChanged
s.Llm.PlanDiffSeverityMediumRatioPercent = _planDiffSeverityMediumRatioPercent;
s.Llm.PlanDiffSeverityHighRatioPercent = _planDiffSeverityHighRatioPercent;
s.Llm.AgentDecisionLevel = _agentDecisionLevel;
s.Llm.PlanMode = _planMode;
s.Llm.PlanMode = "off";
s.Llm.EnableMultiPassDocument = _enableMultiPassDocument;
s.Llm.EnableCoworkVerification = _enableCoworkVerification;
s.Llm.EnableFilePathHighlight = _enableFilePathHighlight;

View File

@@ -2880,7 +2880,7 @@
<ComboBoxItem Content="계획 · 항상 계획" Tag="always"/>
</ComboBox>
</Grid>
<Grid>
<Grid Visibility="Collapsed">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>

View File

@@ -8735,7 +8735,8 @@ public partial class ChatWindow : Window
sb.AppendLine("You are AX Copilot Agent. You can read, write, and edit files using the provided tools.");
sb.AppendLine($"Today's date: {DateTime.Now:yyyy년 M월 d일} ({DateTime.Now:yyyy-MM-dd}, {DateTime.Now:dddd}).");
sb.AppendLine("Available skills: excel_create (.xlsx), docx_create (.docx), csv_create (.csv), markdown_create (.md), html_create (.html), script_create (.bat/.ps1), document_review (품질 검증), format_convert (포맷 변환).");
sb.AppendLine("Always produce a concrete execution plan before major Cowork tasks. For document/report/proposal/manual requests, create a 3-7 step plan first, then execute it.");
sb.AppendLine("Only present a step-by-step execution plan when the user explicitly asks for a plan or when the session is already in plan mode.");
sb.AppendLine("For ordinary Cowork requests, proceed directly with the work instead of stopping for plan approval.");
sb.AppendLine("After creating files, summarize what was created and include the actual output path.");
sb.AppendLine("Do not stop after a single step. Continue autonomously until the request is completed or a concrete blocker (permission denial, missing dependency, hard error) is encountered.");
sb.AppendLine("When adapting external references, rewrite names/structure/comments to AX Copilot style. Avoid clone-like outputs.");
@@ -9858,7 +9859,7 @@ public partial class ChatWindow : Window
// PlanViewerWindow 생성 또는 재사용
if (_planViewerWindow == null || !IsWindowAlive(_planViewerWindow))
{
_planViewerWindow = new PlanViewerWindow();
_planViewerWindow = new PlanViewerWindow(this);
_planViewerWindow.Closing += (_, e) =>
{
e.Cancel = true;
@@ -9869,9 +9870,6 @@ public partial class ChatWindow : Window
// 계획 표시 + 승인 대기
_planViewerWindow.ShowPlanAsync(planSummary, steps, tcs);
// 채팅 창에 간략 배너 추가 + 인라인 승인 버튼도 표시
AddDecisionButtons(tcs, options);
// 하단 바 계획 버튼 표시
ShowPlanButton(true);
});
@@ -14091,7 +14089,7 @@ public partial class ChatWindow : Window
BtnInlineFastMode.Content = GetQuickActionLabel("Fast", llm.FreeTierMode ? "켜짐" : "꺼짐");
BtnInlineReasoning.Content = GetQuickActionLabel("추론", ReasoningLabel(llm.AgentDecisionLevel));
BtnInlinePlanMode.Content = GetQuickActionLabel("계획", PlanModeLabel(llm.PlanMode));
BtnInlinePlanMode.Content = GetQuickActionLabel("계획", PlanModeLabel("off"));
BtnInlinePermission.Content = GetQuickActionLabel("권한", PermissionModeCatalog.ToDisplayLabel(llm.FilePermission));
BtnInlineSkill.Content = $"스킬 · {(llm.EnableSkillSystem ? "On" : "Off")}";
BtnInlineCommandBrowser.Content = "명령/스킬 브라우저";
@@ -14102,7 +14100,7 @@ public partial class ChatWindow : Window
ApplyQuickActionVisual(BtnInlineFastMode, llm.FreeTierMode, "#ECFDF5", "#166534");
ApplyQuickActionVisual(BtnInlineReasoning, !string.Equals(llm.AgentDecisionLevel, "normal", StringComparison.OrdinalIgnoreCase), "#EEF2FF", "#1D4ED8");
ApplyQuickActionVisual(BtnInlinePlanMode, !string.Equals(llm.PlanMode, "off", StringComparison.OrdinalIgnoreCase), "#EEF2FF", "#4338CA");
ApplyQuickActionVisual(BtnInlinePlanMode, false, "#EEF2FF", "#4338CA");
ApplyQuickActionVisual(BtnInlinePermission,
!string.Equals(PermissionModeCatalog.NormalizeGlobalMode(llm.FilePermission), PermissionModeCatalog.Deny, StringComparison.OrdinalIgnoreCase),
"#FFF7ED",
@@ -16337,7 +16335,7 @@ public partial class ChatWindow : Window
SelectComboTag(CmbOverlayOperationMode, OperationModePolicy.Normalize(_settings.Settings.OperationMode));
SelectComboTag(CmbOverlayFolderDataUsage, _folderDataUsage);
SelectComboTag(CmbOverlayPermission, PermissionModeCatalog.NormalizeGlobalMode(llm.FilePermission));
SelectComboTag(CmbOverlayPlanMode, llm.PlanMode);
SelectComboTag(CmbOverlayPlanMode, "off");
SelectComboTag(CmbOverlayReasoning, llm.AgentDecisionLevel);
SelectComboTag(CmbOverlayFastMode, llm.FreeTierMode ? "on" : "off");
SelectComboTag(CmbOverlayDefaultOutputFormat, llm.DefaultOutputFormat ?? "auto");
@@ -16835,10 +16833,10 @@ public partial class ChatWindow : Window
private void CmbOverlayPlanMode_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (_isOverlaySettingsSyncing || CmbOverlayPlanMode.SelectedItem is not ComboBoxItem selected || selected.Tag is not string tag)
if (_isOverlaySettingsSyncing)
return;
_settings.Settings.Llm.PlanMode = tag;
_settings.Settings.Llm.PlanMode = "off";
PersistOverlaySettingsState(refreshOverlayDeferredInputs: false);
}
@@ -17051,7 +17049,7 @@ public partial class ChatWindow : Window
private void BtnInlinePlanMode_Click(object sender, RoutedEventArgs e)
{
var llm = _settings.Settings.Llm;
llm.PlanMode = NextPlanMode(llm.PlanMode);
llm.PlanMode = "off";
_settings.Save();
_appState.LoadFromSettings(_settings);
RefreshInlineSettingsPanel();

View File

@@ -49,28 +49,37 @@ internal sealed class PlanViewerWindow : Window
private bool _isExecuting;
private readonly string _uiExpressionLevel;
public PlanViewerWindow()
public PlanViewerWindow(Window? owner = null)
{
if (owner != null)
{
Owner = owner;
WindowStartupLocation = WindowStartupLocation.CenterOwner;
Resources.MergedDictionaries.Add(owner.Resources);
}
_uiExpressionLevel = ResolveUiExpressionLevel();
Width = 640;
Height = 520;
MinWidth = 480;
MinHeight = 360;
WindowStartupLocation = WindowStartupLocation.CenterScreen;
WindowStartupLocation = owner == null
? WindowStartupLocation.CenterScreen
: WindowStartupLocation.CenterOwner;
WindowStyle = WindowStyle.None;
AllowsTransparency = true;
Background = Brushes.Transparent;
ResizeMode = ResizeMode.CanResize; // WndProc로 직접 처리
ShowInTaskbar = false;
var bgBrush = Application.Current.TryFindResource("LauncherBackground") as Brush
var bgBrush = TryFindResource("LauncherBackground") as Brush
?? new SolidColorBrush(Color.FromRgb(0x1A, 0x1B, 0x2E));
var primaryText = Application.Current.TryFindResource("PrimaryText") as Brush ?? Brushes.White;
var secondaryText = Application.Current.TryFindResource("SecondaryText") as Brush ?? Brushes.Gray;
var accentBrush = Application.Current.TryFindResource("AccentColor") as Brush
var primaryText = TryFindResource("PrimaryText") as Brush ?? Brushes.White;
var secondaryText = TryFindResource("SecondaryText") as Brush ?? Brushes.Gray;
var accentBrush = TryFindResource("AccentColor") as Brush
?? new SolidColorBrush(Color.FromRgb(0x4B, 0x5E, 0xFC));
var borderBrush = Application.Current.TryFindResource("BorderColor") as Brush ?? Brushes.Gray;
var borderBrush = TryFindResource("BorderColor") as Brush ?? Brushes.Gray;
var root = new Border
{
@@ -151,7 +160,7 @@ internal sealed class PlanViewerWindow : Window
mainGrid.Children.Add(_statusBar);
// ── 툴바: 모두 열기 / 모두 닫기 ──
var hoverBgTb = Application.Current.TryFindResource("ItemHoverBackground") as Brush
var hoverBgTb = TryFindResource("ItemHoverBackground") as Brush
?? new SolidColorBrush(Color.FromArgb(0x18, 0xFF, 0xFF, 0xFF));
var toolBar = new StackPanel
{

View File

@@ -4653,7 +4653,7 @@
</StackPanel>
</Grid>
</Border>
<Border Style="{StaticResource AgentSettingsRow}">
<Border Style="{StaticResource AgentSettingsRow}" Visibility="Collapsed">
<Grid>
<StackPanel HorizontalAlignment="Left" Margin="0,0,180,0">
<StackPanel Orientation="Horizontal">