diff --git a/doc/specs/Multi-window-agent-pane.md b/doc/specs/Multi-window-agent-pane.md index e1bd6d79d9..4dea9c73da 100644 --- a/doc/specs/Multi-window-agent-pane.md +++ b/doc/specs/Multi-window-agent-pane.md @@ -905,6 +905,65 @@ work: - **Pre-warming**: not implemented. First user toggle creates the helper on demand. +### Z-R9. Yolo mode (auto-approve tool-call permission requests) + +Implements GitHub issue #326 ("Allow agent pane to run with options such +as `--allow-all`"). Rather than passing agent-CLI-specific flags +(`--allow-all`/`--yolo`, which differ per agent and don't exist for all +of them), auto-approve is implemented once at the ACP client layer +(`WtaClient::request_permission` in `tools/wta/src/protocol/acp/client.rs`), +so it works uniformly across Copilot/Claude/Gemini/Codex/custom agents +without depending on each CLI's own flag surface. + +Two independent, additive enable paths, both gated by the same +`AllowYoloMode` admin policy (`src/cascadia/inc/AgentPolicy.h`): + +1. **Global Settings toggle** — "Auto-approve tool calls" in the Settings + UI (`AIAgents.xaml`, backed by `agentPane.yoloMode` / + `GlobalAppSettings::EffectiveAgentPaneYoloMode()`). When on (and not + policy-blocked), `TerminalPage.cpp` appends `--auto-approve-tools` to + the helper's command line, which every ACP session on every tab of + every window inherits for the lifetime of the setting. +2. **Per-session `/yolo` slash command** — scoped to the *current tab's + current* ACP `session_id` only. Implemented as a shared + `Arc>>` (`App::yolo_sessions`, also held by + `WtaClient`'s `ClientState`): `/yolo` inserts the active session_id; + `request_permission` checks membership. Keying by `session_id` rather + than `tab_id` means the override does **not** persist across `/new` + (a fresh session_id is simply absent from the set) — the user must + run `/yolo` again after starting a new conversation. `/restart` clears + the whole set (every session is being torn down anyway). + +Policy enforcement on the Rust side: since wta has no direct registry +access, `TerminalPage.cpp` also passes `--yolo-command-blocked` whenever +`AllowYoloMode` is `Blocked`, independent of whatever the global toggle +happens to be — this lets `/yolo` itself refuse with a clear +"disabled by your organization's policy" message (`cmd_yolo` in +`tools/wta/src/app.rs`) even when the global setting is off. + +When either path is active for a given request, `request_permission` +skips the blocking `PermissionRequest` UI event entirely and picks the +best "allow" option (`allow_always` preferred over `allow_once` — see +`pick_allow_option`), responding immediately with no user-visible +notification: auto-approval is deliberately silent so tool calls don't +clutter the conversation with a message per approval. + +**Agent-native allow-all (preferred over client-side interception, when +available).** Some agents' ACP servers advertise a per-session +`config_options` entry (category `permissions`, id `allow_all`) in their +`session/new` response — confirmed for Copilot CLI's ACP server. +`permission_select.rs` detects this and, whenever a session is (or +becomes) in yolo mode, calls `session/set_config_option(allow_all, "on")` +for that `session_id` so the agent itself stops sending +`session/request_permission` entirely, rather than WTA intercepting and +auto-answering each request. This is applied at every session-creation +call site in `client.rs`, plus retroactively via +`MasterExtRequest::SetSessionAllowAll` when `/yolo` is typed on an +already-live session. Agents without this option (Claude/Gemini/Codex +adapters, as far as tested) are unaffected — the client-side +`request_permission` interception above remains the unconditional +fallback for every agent. + ## What this does NOT solve (out of scope) - **Cross-process Terminal instances**: if WT is configured for diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index cd4a194b25..8e92b9ec5f 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -2172,6 +2172,26 @@ namespace winrt::TerminalApp::implementation { helperCmd.append(L" --no-autofix"); } + // Global "Yolo mode" — auto-approve every ACP permission request on + // this pane without prompting. Policy-gated via + // EffectiveAgentPaneYoloMode() (AgentPolicy::IsYoloModeAllowed()), so + // a GPO-blocked org never spawns a helper with this flag set even if + // the user's settings.json has agentPane.yoloMode: true. This is + // independent from the per-session `/yolo` slash command, which the + // helper enforces itself at runtime against the same policy. + if (globals.EffectiveAgentPaneYoloMode()) + { + helperCmd.append(L" --auto-approve-tools"); + } + // Independent of the global toggle above: tell the helper whether + // org policy blocks yolo mode outright, so its own `/yolo` slash + // command (a per-session override the user can flip at runtime) can + // refuse and explain why, instead of silently enabling unattended + // tool-call approval in a GPO-managed environment. + if (globals.IsYoloModePolicyLocked()) + { + helperCmd.append(L" --yolo-command-blocked"); + } if (const auto lang = _ResolveEffectiveLanguage(globals); !lang.empty()) { appendHelperFlagValue(L"--language", lang); diff --git a/src/cascadia/TerminalSettingsEditor/AIAgents.xaml b/src/cascadia/TerminalSettingsEditor/AIAgents.xaml index 7ef021fb83..777c6e2bdd 100644 --- a/src/cascadia/TerminalSettingsEditor/AIAgents.xaml +++ b/src/cascadia/TerminalSettingsEditor/AIAgents.xaml @@ -9,6 +9,7 @@ xmlns:local="using:Microsoft.Terminal.Settings.Editor" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:muxc="using:Microsoft.UI.Xaml.Controls" + xmlns:mtu="using:Microsoft.Terminal.UI" mc:Ignorable="d"> @@ -178,6 +179,25 @@ Style="{StaticResource ComboBoxSettingStyle}" /> + + + + + + + +