Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions src/cascadia/TerminalSettingsEditor/AIAgents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
Automation::AutomationProperties::SetName(EmptyCustomModelProviders(), customModelsHeader);
Automation::AutomationProperties::SetName(CustomModelProvidersExpander(), customModelsHeader);

// Auto-error-detection caption + inline "supported shells" hyperlink.
AutoErrorDetectionCaptionPrefix().Text(RS_(L"AIAgents_AutoErrorDetectionCaptionPrefix"));
AutoErrorDetectionCaptionLink().Text(RS_(L"AIAgents_AutoErrorDetectionCaptionLink"));

const auto agentHeader = RS_(L"AIAgents_AcpAgent/Header");
AcpAgentHeaderText().Text(agentHeader);

Expand Down
144 changes: 59 additions & 85 deletions src/cascadia/TerminalSettingsEditor/AIAgents.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,42 @@
<TextBlock Text="{x:Bind EnumName, Mode=OneWay}" />
</DataTemplate>

<DataTemplate x:Key="AutoErrorHandlingComboBoxTemplate"
x:DataType="local:EnumEntry">
<TextBlock Text="{x:Bind EnumName, Mode=OneWay}"
TextWrapping="WrapWholeWords" />
</DataTemplate>

<DataTemplate x:Key="AcpModelEntryTemplate"
x:DataType="local:AcpModelEntry">
<TextBlock Text="{x:Bind DisplayName}" />
</DataTemplate>

<Style x:Key="AutoErrorHandlingSettingContainerStyle"
TargetType="local:SettingContainer">
<Setter Property="Margin" Value="0,4,0,0" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="MaxWidth" Value="{StaticResource StandardControlMaxWidth}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SettingContainer">
<Grid ColumnSpacing="24"
Style="{StaticResource NonExpanderGrid}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Margin="0,12,0,12"
Content="{TemplateBinding Header}" />
<ContentPresenter Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Content="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Page.Resources>

Expand Down Expand Up @@ -430,91 +462,33 @@
IsOn="{x:Bind ViewModel.ShowTokenUsageAndCost, Mode=TwoWay}" />
</local:SettingContainer>

<!-- Automatic error detection (parent) + Automatic error
suggestion (dependent child). Modeled as an Expander so the
hierarchy is explicit: detection's master toggle lives in the
always-visible header; suggestion is nested in the expand body
and stays disabled until detection is on (ViewModel.
CanSuggestErrors). Hand-built header (vs. ExpanderSetting
ContainerStyle) because that style's header-right slot is a
read-only text preview and can't host the master toggle. -->
<muxc:Expander x:Name="AutoErrorDetectionExpander"
Margin="0,4,0,0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
IsExpanded="True">
<muxc:Expander.Header>
<Grid MinHeight="64">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"
VerticalAlignment="Center"
Spacing="2">
<TextBlock x:Uid="AIAgents_AutoErrorDetectionTitle"
FontWeight="SemiBold"
TextWrapping="Wrap" />
<!-- Caption hosts an inline Hyperlink to the full
supported-shells list, so it is built from
Run + Hyperlink populated in code-behind (RS_)
rather than a single x:Uid (x:Uid on inline Run
is not honored in this codebase). The muted
"secondary" foreground is applied only to the
prefix Run so the Hyperlink keeps its full theme
accent contrast (matches the page-subtitle
pattern above). -->
<TextBlock Style="{StaticResource CaptionTextBlockStyle}"
TextWrapping="Wrap">
<Run x:Name="AutoErrorDetectionCaptionPrefix"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" /><Hyperlink NavigateUri="https://aka.ms/intelligent-terminal-dependency#4-shell-integration">
<Run x:Name="AutoErrorDetectionCaptionLink" />
</Hyperlink>
</TextBlock>
</StackPanel>
<ToggleSwitch Grid.Column="1"
MinWidth="0"
VerticalAlignment="Center"
AutomationProperties.AccessibilityView="Content"
IsOn="{x:Bind ViewModel.AutoErrorDetectionEnabled, Mode=TwoWay}" />
</Grid>
</muxc:Expander.Header>
<!-- Nested dependent setting: suggestion. Plain rows (no nested
SettingContainer) so it sits inside the detection Expander
body with no "card-in-card" background. Greyed out
whenever detection is off or auto-fix is GPO-locked
(ViewModel.CanSuggestErrors). Its On/Off reflects the
user's own value and is independent of the detection
toggle. -->
<StackPanel Margin="0,4,0,0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"
VerticalAlignment="Center"
Spacing="2">
<TextBlock x:Uid="AIAgents_AutoErrorSuggestionTitle"
TextWrapping="Wrap" />
<TextBlock x:Uid="AIAgents_AutoErrorSuggestionCaption"
Style="{StaticResource CaptionTextBlockStyle}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
TextWrapping="Wrap" />
</StackPanel>
<ToggleSwitch Grid.Column="1"
MinWidth="0"
VerticalAlignment="Center"
AutomationProperties.AccessibilityView="Content"
IsOn="{x:Bind ViewModel.AutoFixEnabled, Mode=TwoWay}"
IsEnabled="{x:Bind ViewModel.CanSuggestErrors, Mode=OneWay}" />
</Grid>
<TextBlock x:Uid="AIAgents_PolicyLocked"
Visibility="{x:Bind ViewModel.IsAutoFixPolicyLocked, Mode=OneWay}"
Opacity="0.6"
Margin="0,4,0,0" />
</StackPanel>
</muxc:Expander>
<local:SettingContainer x:Name="AutoErrorHandling"
Style="{StaticResource AutoErrorHandlingSettingContainerStyle}">
<local:SettingContainer.Header>
<StackPanel>
<TextBlock x:Uid="AIAgents_AutoErrorHandlingTitle"
Style="{StaticResource SettingsPageItemHeaderStyle}"
TextWrapping="Wrap" />
<TextBlock x:Uid="AIAgents_AutoErrorHandlingDescription"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
TextWrapping="Wrap" />
<TextBlock x:Uid="AIAgents_PolicyLocked"
Visibility="{x:Bind ViewModel.IsAutoErrorHandlingPolicyRestricted, Mode=OneWay}"
Opacity="0.6"
Margin="0,4,0,0" />
</StackPanel>
</local:SettingContainer.Header>
<Grid>
<ComboBox x:Uid="AIAgents_AutoErrorHandlingComboBox"
AutomationProperties.AccessibilityView="Content"
Width="{StaticResource StandardBoxMinWidth}"
ItemTemplate="{StaticResource AutoErrorHandlingComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.AutoErrorHandlingList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentAutoErrorHandling, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</Grid>
</local:SettingContainer>

<!-- Agent session tracking (hooks) — last entry in the Agent pane group.
Collapsible SettingContainer (Expander style). When expanded:
Expand Down
109 changes: 55 additions & 54 deletions src/cascadia/TerminalSettingsEditor/AIAgentsViewModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Microsoft::Terminal::Settings::Model;

namespace
{
constexpr std::wstring_view AutoErrorHandlingDetect{ L"detect" };
constexpr std::wstring_view AutoErrorHandlingSuggest{ L"suggest" };
constexpr std::wstring_view AutoErrorHandlingOff{ L"off" };
}

namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
CustomModelProviderEntry::CustomModelProviderEntry(
Expand Down Expand Up @@ -594,6 +601,24 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
_agentPanePositionList = winrt::single_threaded_observable_vector<Editor::EnumEntry>(std::move(posEntries));

std::vector<Editor::EnumEntry> autoErrorHandlingEntries;
const std::pair<winrt::hstring, std::wstring_view> autoErrorHandlingOptions[] = {
{ RS_(L"AIAgents_AutoErrorHandling_DetectErrorsAutomatically"), AutoErrorHandlingDetect },
{ RS_(L"AIAgents_AutoErrorHandling_DetectErrorsAndSendToAgentForFixesAutomatically"), AutoErrorHandlingSuggest },
{ RS_(L"AIAgents_AutoErrorHandling_Off"), AutoErrorHandlingOff },
};
for (const auto& [displayName, value] : autoErrorHandlingOptions)
{
if (value == AutoErrorHandlingSuggest && _GlobalSettings.IsAutoFixPolicyLocked())
{
continue;
}
autoErrorHandlingEntries.emplace_back(winrt::make<implementation::EnumEntry>(
displayName,
winrt::box_value(winrt::hstring{ value })));
}
_autoErrorHandlingList = winrt::single_threaded_observable_vector<Editor::EnumEntry>(std::move(autoErrorHandlingEntries));

// Populate the Agent Hooks section's per-CLI detection + install
// state so the UI displays meaningful labels on first paint. The
// actual status query shells out to `wta hooks status --json`
Expand Down Expand Up @@ -1599,68 +1624,44 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
}

// ── Auto error detection ───────────────────────────────────────────────

bool AIAgentsViewModel::AutoErrorDetectionEnabled() const
{
return _GlobalSettings.EffectiveAutoErrorDetectionEnabled();
}

void AIAgentsViewModel::AutoErrorDetectionEnabled(bool value)
{
if (_GlobalSettings.AutoErrorDetectionEnabled() == value) return;
_GlobalSettings.AutoErrorDetectionEnabled(value);
// Master-detail: detection drives both the suggestion toggle's enabled
// state (CanSuggestErrors) and its effective value (EffectiveAutoFix
// Enabled flips to false when detection is off), so refresh both. The
// stored autoFixEnabled preference is preserved, so re-enabling
// detection restores the previous suggestion value rather than forcing
// it on.
_NotifyChanges(L"HasAutoErrorDetectionEnabled", L"AutoErrorDetectionEnabled",
L"CanSuggestErrors", L"AutoFixEnabled");
// Shell integration installation is triggered on Save, not on toggle.
}

bool AIAgentsViewModel::HasAutoErrorDetectionEnabled() const
{
return _GlobalSettings.HasAutoErrorDetectionEnabled();
}

// ── AutoFix (auto-suggest) ─────────────────────────────────────────────
// ── Auto error handling ────────────────────────────────────────────────

bool AIAgentsViewModel::AutoFixEnabled() const
winrt::Windows::Foundation::IInspectable AIAgentsViewModel::CurrentAutoErrorHandling()
{
// Master-detail: suggestion follows detection. EffectiveAutoFixEnabled
// returns false whenever detection is off (or GPO blocks autofix), so
// the toggle reads Off when the master is off; when detection is on it
// reflects the user's stored autoFixEnabled preference.
return _GlobalSettings.EffectiveAutoFixEnabled();
}

void AIAgentsViewModel::AutoFixEnabled(bool value)
{
// Reject writes when policy blocks autofix or detection is off (the
// toggle is disabled in those cases, but guard against races).
if (_GlobalSettings.IsAutoFixPolicyLocked() ||
!_GlobalSettings.EffectiveAutoErrorDetectionEnabled())
const std::wstring_view current =
!_GlobalSettings.EffectiveAutoErrorDetectionEnabled() ? AutoErrorHandlingOff :
_GlobalSettings.EffectiveAutoFixEnabled() ? AutoErrorHandlingSuggest :
AutoErrorHandlingDetect;
for (const auto& entry : _autoErrorHandlingList)
{
return;
if (winrt::unbox_value<winrt::hstring>(entry.EnumValue()) == current)
{
return winrt::box_value(entry);
}
}
if (_GlobalSettings.AutoFixEnabled() == value) return;
_GlobalSettings.AutoFixEnabled(value);
_NotifyChanges(L"HasAutoFixEnabled", L"AutoFixEnabled");
// Shell integration installation is now triggered on Save, not on toggle.
return winrt::box_value(_autoErrorHandlingList.GetAt(0));
}
Comment thread
DDKinger marked this conversation as resolved.

bool AIAgentsViewModel::HasAutoFixEnabled() const
void AIAgentsViewModel::CurrentAutoErrorHandling(const winrt::Windows::Foundation::IInspectable& value)
{
return _GlobalSettings.HasAutoFixEnabled();
}
if (const auto entry = value.try_as<Editor::EnumEntry>())
{
const auto selected = winrt::unbox_value<winrt::hstring>(entry.EnumValue());
if (selected == AutoErrorHandlingSuggest && _GlobalSettings.IsAutoFixPolicyLocked())
{
return;
}

bool AIAgentsViewModel::CanSuggestErrors() const
{
return !_GlobalSettings.IsAutoFixPolicyLocked() &&
_GlobalSettings.EffectiveAutoErrorDetectionEnabled();
const bool detectionEnabled = selected != AutoErrorHandlingOff;
const bool autoFixEnabled = selected == AutoErrorHandlingSuggest;
if (_GlobalSettings.AutoErrorDetectionEnabled() != detectionEnabled ||
_GlobalSettings.AutoFixEnabled() != autoFixEnabled)
{
_GlobalSettings.AutoErrorDetectionEnabled(detectionEnabled);
_GlobalSettings.AutoFixEnabled(autoFixEnabled);
_NotifyChanges(L"CurrentAutoErrorHandling");
}
}
}

// ── Yolo mode (provider-native ACP mode) ─────────────────────────────
Expand Down
13 changes: 5 additions & 8 deletions src/cascadia/TerminalSettingsEditor/AIAgentsViewModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void CancelCustomModelProvider();
bool ShowDelegateModel();
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, DelegateModel);
bool AutoErrorDetectionEnabled() const;
void AutoErrorDetectionEnabled(bool value);
bool HasAutoErrorDetectionEnabled() const;
bool AutoFixEnabled() const;
void AutoFixEnabled(bool value);
bool HasAutoFixEnabled() const;
winrt::Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> AutoErrorHandlingList() const { return _autoErrorHandlingList; }
winrt::Windows::Foundation::IInspectable CurrentAutoErrorHandling();
void CurrentAutoErrorHandling(const winrt::Windows::Foundation::IInspectable& value);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, ShowTokenUsageAndCost);
bool CanSuggestErrors() const;

bool AgentPaneYoloMode() const;
void AgentPaneYoloMode(bool value);
Expand All @@ -177,7 +173,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// GPO policy lock indicators
bool IsAgentPolicyLocked() const { return _GlobalSettings.IsAgentPolicyLocked(); }
bool IsCustomAgentPolicyLocked() const { return _GlobalSettings.IsCustomAgentPolicyLocked(); }
bool IsAutoFixPolicyLocked() const { return _GlobalSettings.IsAutoFixPolicyLocked(); }
bool IsAutoErrorHandlingPolicyRestricted() const { return _GlobalSettings.IsAutoFixPolicyLocked(); }
bool IsAgentSessionHooksPolicyLocked() const { return _GlobalSettings.IsAgentSessionHooksPolicyLocked(); }
bool IsYoloModePolicyLocked() const { return _GlobalSettings.IsYoloModePolicyLocked(); }

Expand Down Expand Up @@ -247,6 +243,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation

winrt::Windows::Foundation::Collections::IObservableVector<winrt::Microsoft::Terminal::Settings::Editor::EnumEntry> _agentPanePositionList;
winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Microsoft::Terminal::Settings::Editor::EnumEntry> _agentPanePositionMap;
winrt::Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> _autoErrorHandlingList;

bool _isAddingCustomAcpAgent{ false };
bool _isAddingCustomDelegateAgent{ false };
Expand Down
Loading
Loading