Skip to content

Add yolo mode: auto-approve tool-call permission requests - #505

Open
vanzue wants to merge 8 commits into
mainfrom
dev/vanzue/yolo-mode
Open

Add yolo mode: auto-approve tool-call permission requests#505
vanzue wants to merge 8 commits into
mainfrom
dev/vanzue/yolo-mode

Conversation

@vanzue

@vanzue vanzue commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds "yolo mode" (auto-approve tool-call permission requests) for the agent pane.

Two independent, additive enable paths, both gated by the AllowYoloMode GPO policy:

  1. Global Settings toggle — Settings → AI Agents → "Auto-approve tool calls". Applies to every new agent pane helper via a --auto-approve-tools flag.
  2. /yolo slash command — scoped to the current session only. Does not persist across /new (fresh session_id) and is cleared on /restart.

Two enforcement layers

  1. Agent-native (preferred, when available)permission_select.rs detects whether the connected ACP agent advertises a per-session config_options entry (category: "permissions", id: "allow_all") in its session/new response. Verified live against Copilot CLI (copilot --acp --stdio): calling session/set_config_option(configId: "allow_all", value: "on") makes the agent stop sending session/request_permission entirely for that session — a real protocol-native, per-session auto-approve, with zero permission round-trips observed. This is applied automatically whenever a session is (or becomes) in yolo mode, at every session-creation call site, plus retroactively via a new MasterExtRequest::SetSessionAllowAll when /yolo is typed on an already-live session.
  2. Client-side interception (fallback) — implemented at the ACP client layer (WtaClient::request_permission in tools/wta/src/protocol/acp/client.rs), so it applies uniformly across Copilot, Claude, Gemini, and Codex regardless of whether the agent supports the native option. When active, it skips the permission UI prompt and picks the best "allow" option (preferring allow_always over allow_once).

Agents that don't advertise the native config (Claude/Gemini/Codex ACP adapters today, as far as tested) transparently fall back to layer 2 — no behavior change for them.

Changes

  • C++: AgentPolicy.h (AllowYoloMode policy), MTSMSettings.h / GlobalAppSettings.idl/.h/.cpp (AgentPaneYoloMode setting), TerminalPage.cpp (helper cmdline passthrough), Settings UI (AIAgentsViewModel, AIAgents.xaml).
  • Rust (wta): shared yolo_sessions state between App and WtaClient, /yolo command, auto-approve logic in request_permission, session cleanup on /new and /restart, new permission_select.rs module for agent-native allow-all detection/application, MasterExtRequest::SetSessionAllowAll round-trip.
  • Tests: new C++ policy unit tests (CustomAgentAndPolicyTests.cpp) and Rust unit tests (mock_agent_tests.rs, permission_select.rs).
  • Localization: new strings added to en-US.yml and translated across all other locale files.
  • Docs: new "Yolo mode" section in doc/specs/Multi-window-agent-pane.md.

Testing

  • cargo test --manifest-path tools/wta/Cargo.toml — 1183 passed, 0 failed.
  • C++ TerminalSettingsModel, TerminalSettingsEditor (and previously TerminalApp, UnitTests_SettingsModel) built successfully with 0 errors.
  • Manual live ACP protocol probe against copilot --acp --stdio confirming session/set_config_option(allow_all, on) suppresses session/request_permission for that session only (fresh sessions default to off, no cross-session leakage).

Closes #326

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 28, 2026 01:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds “yolo mode” for the agent pane, enabling automatic approval of tool-call permission requests at the ACP client layer, with two enable paths (global setting + per-session /yolo) and enforcement via the new AllowYoloMode admin policy (GPO).

Changes:

  • Adds a new global setting (agentPane.yoloMode) and Settings UI toggle to launch helpers with --auto-approve-tools, gated by AllowYoloMode.
  • Adds a per-session /yolo slash command and shared yolo_sessions state so auto-approve can be enabled for a single ACP session.
  • Adds policy plumbing + unit tests, plus localized strings and spec documentation for yolo mode.

Reviewed changes

Copilot reviewed 109 out of 109 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tools/wta/src/protocol/acp/client.rs Implements yolo-mode auto-approval selection logic in request_permission and threads yolo state into the ACP client.
tools/wta/src/protocol/acp/mock_agent_tests.rs Adds unit tests covering global/per-session yolo behavior and allow-always preference.
tools/wta/src/main.rs Adds hidden helper flags (--auto-approve-tools, --yolo-command-blocked) and wires shared yolo session state into the app/client.
tools/wta/src/commands.rs Registers /yolo slash command and help summary key.
tools/wta/src/app.rs Stores global/per-session yolo mode state, adds /yolo handler, and clears yolo state on /new + /restart.
tools/wta/src/app_events.rs Adds handling for a new session-scoped system message event type.
tools/wta/src/app_tests.rs Updates test harness app construction for new yolo-related App fields.
tools/wta/locales/*.yml Adds localized strings for yolo mode and /yolo command summary across locales.
src/cascadia/inc/AgentPolicy.h Adds AllowYoloMode policy reading + query helpers.
src/cascadia/TerminalSettingsModel/MTSMSettings.h Adds AgentPaneYoloMode setting definition (agentPane.yoloMode).
src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl Exposes AgentPaneYoloMode, EffectiveAgentPaneYoloMode, and IsYoloModePolicyLocked.
src/cascadia/TerminalSettingsModel/GlobalAppSettings.h Declares new effective accessor + policy lock accessor.
src/cascadia/TerminalSettingsModel/GlobalAppSettings.cpp Implements effective yolo-mode gating and lock-state query.
src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw Adds UI strings for the global “Auto-approve tool calls (Yolo mode)” toggle and help text.
src/cascadia/TerminalSettingsEditor/AIAgentsViewModel.idl Adds viewmodel properties for yolo mode and its policy lock indicator.
src/cascadia/TerminalSettingsEditor/AIAgentsViewModel.h Adds corresponding C++/WinRT viewmodel method declarations.
src/cascadia/TerminalSettingsEditor/AIAgentsViewModel.cpp Implements yolo-mode property get/set with policy lock guarding and change notifications.
src/cascadia/TerminalSettingsEditor/AIAgents.xaml Adds the yolo-mode toggle UI and disables it when policy-locked.
src/cascadia/TerminalApp/TerminalPage.cpp Plumbs global yolo setting and policy lock into helper command line (--auto-approve-tools, --yolo-command-blocked).
src/cascadia/UnitTests_SettingsModel/CustomAgentAndPolicyTests.cpp Adds SettingsModel unit tests for yolo-mode roundtripping and policy gating behavior.
doc/specs/Multi-window-agent-pane.md Documents yolo mode behavior, enable paths, policy gating, and lifecycle semantics.

Comment thread tools/wta/src/protocol/acp/client.rs
Comment thread tools/wta/src/app.rs
Comment thread tools/wta/src/protocol/acp/mock_agent_tests.rs
…en available

Verified live against copilot --acp --stdio: session/new advertises a
per-session config_options entry (category=permissions, id=allow_all).
Setting it via session/set_config_option makes the agent stop sending
session/request_permission for that session entirely - zero round-trips
observed for a subsequent tool call.

Add permission_select module (mirrors model_select's config-option
detection pattern) to record this capability from NewSessionResponse and
apply it to a session via session/set_config_option. Wire it into every
new_session call site so a session already in yolo mode (global toggle or
a /yolo that raced ahead) gets it applied at creation time, and add a
MasterExtRequest::SetSessionAllowAll round-trip so /yolo on an
already-live session retroactively applies it too.

Agents that don't advertise the config (Claude/Gemini/Codex adapters
today) are unaffected: the existing client-side request_permission
auto-approve in client.rs remains as the unconditional fallback.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 28, 2026 03:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 111 out of 111 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (4)

tools/wta/src/protocol/acp/client.rs:1621

  • In yolo mode the code immediately selects an allow option, but it doesn't emit any user-visible signal (despite adding AppEvent::SessionSystemMessage and localized system.yolo_auto_approved). This makes the new event variant and locale strings unused and contradicts the documented behavior of posting a passive approval message.
    tools/wta/src/app.rs:5918
  • /yolo currently enables the session override but stays silent. This leaves the localized system.yolo_enabled string unused and provides no confirmation to the user that auto-approval is now active for the session.
    tools/wta/src/protocol/acp/mock_agent_tests.rs:1893
  • These yolo-mode tests assert that auto-approval emits no events at all, but the feature adds AppEvent::SessionSystemMessage + system.yolo_auto_approved specifically to inform the user what was auto-approved. Once the client emits that message, these assertions should be updated to expect a SessionSystemMessage (and still ensure no PermissionRequest UI prompt is raised).
    tools/wta/src/protocol/acp/mock_agent_tests.rs:1914
  • This test also assumes yolo auto-approval produces no events. If yolo mode emits a SessionSystemMessage for the auto-approved request, consume/assert that message before continuing to the normal interactive flow for the non-yolo session.

Comment thread tools/wta/src/protocol/acp/permission_select.rs
Copilot AI review requested due to automatic review settings July 28, 2026 04:38
…otification plumbing

- permission_select::allow_all_option_id now requires the matched config
  option to also be SessionConfigKind::Select (mirrors
  model_select::model_option_from_config's guard), so a same-named/
  categorized non-Select entry can no longer shadow a later valid Select.
  Added a regression test for this shape.
- Removed the never-constructed AppEvent::SessionSystemMessage variant and
  its dispatch arm, plus the never-referenced system.yolo_auto_approved /
  system.yolo_enabled locale strings (all 85 locales) -- leftover plumbing
  from an earlier iteration of yolo mode's UX that was intentionally made
  silent (no chat notification on auto-approve, per product decision) but
  left the now-dead wiring in place. Client-side auto-approve in
  request_permission and the /yolo command are otherwise unchanged.
- Corrected a stale/misleading comment in cmd_yolo that claimed /yolo
  would retroactively apply once a session_id exists when typed before one
  is assigned -- it does not; documented the actual (no-op-until-later)
  behavior instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@vanzue
vanzue force-pushed the dev/vanzue/yolo-mode branch from f9cc10b to f1a66c6 Compare July 28, 2026 04:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 110 out of 110 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

tools/wta/src/protocol/acp/permission_select.rs:59

  • The selector match is too broad: category == "permissions" || id == "allow_all" can select an unrelated permissions-category Select option (if an agent adds more permission-related config options), and WTA would then call session/set_config_option with the wrong config_id. Prefer matching the stable id == "allow_all" (optionally validating the category when present) and require Select.

Comment thread doc/specs/Multi-window-agent-pane.md Outdated
Comment thread tools/wta/locales/en-GB.yml Outdated
Copilot AI review requested due to automatic review settings July 28, 2026 04:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 110 out of 110 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

doc/specs/Multi-window-agent-pane.md:949

  • This spec claims yolo-mode auto-approval posts an AppEvent::SessionSystemMessage so the user can see what was approved, but the current implementation (and tests) intentionally keep yolo auto-approval silent (no extra events/messages). The spec should match the shipped behavior.
skips the blocking `PermissionRequest` UI event entirely, picks the best
"allow" option (`allow_always` preferred over `allow_once` — see
`pick_allow_option`), responds immediately, and posts a passive
`AppEvent::SessionSystemMessage` to that session's tab chat so the user
still sees what was approved.

- doc/specs/Multi-window-agent-pane.md: yolo mode section described a
  now-removed AppEvent::SessionSystemMessage notification. Updated to
  describe the actual (silent) client-side auto-approve, and added the
  missing description of the agent-native allow_all delegation channel
  (permission_select.rs) added earlier this session.
- system.yolo_blocked_by_policy carried a {Locked="/yolo"} annotation
  in all 90 locale files, but no translation (including en-US) ever
  spells out the literal "/yolo" token in this string -- it says
  "yolo mode"/localized equivalent instead. Removed the stale
  annotation everywhere; pre-existing issue, unrelated to this PR's
  other changes but surfaced by this round's review once line numbers
  shifted.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 28, 2026 05:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 110 out of 110 changed files in this pull request and generated 1 comment.

Comment thread tools/wta/src/protocol/acp/client.rs
`PermOption.kind` is always the PascalCase `format!("{:?}", …)` rendering
of ACP's PermissionOptionKind (see PermOption::is_allow's docs), so the
"allow_always" (snake_case) branch in pick_allow_option could never match
-- only the "AllowAlways" branch did anything, confirmed by the existing
request_permission_yolo_prefers_allow_always_over_allow_once test. Removed
the dead branch and updated the docstring to say AllowAlways/AllowOnce
instead of the never-matching snake_case forms.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 28, 2026 05:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 110 out of 110 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (3)

tools/wta/src/protocol/acp/permission_select.rs:59

  • allow_all_option_id currently matches any Select option in category permissions even if its id is not allow_all. If an agent ever advertises multiple permission-related config options, this could toggle the wrong setting when yolo mode is enabled. It’s safer to key detection exclusively off the well-known id (allow_all) and treat category as informational only.
    tools/wta/src/protocol/acp/client.rs:1600
  • This comment refers to allow_always/allow_once, but the code (and PermOption.kind) uses the ACP enum debug renderings like AllowAlways/AllowOnce. Updating the comment avoids confusion when reading the selection logic.
    tools/wta/src/protocol/acp/permission_select.rs:46
  • The doc comment for allow_all_option_id says it matches by category permissions OR id allow_all. Since matching on category alone is risky (it may match unrelated permission config options), the comment should align with the safer id-based detection.

This issue also appears on line 55 of the same file.

PR #504 refactored run_acp_app out of main.rs into helper/runtime.rs.
Reapply the yolo-mode additions (yolo_sessions set, --auto-approve-tools
/ --yolo-command-blocked passthrough to run_acp_client_over_pipe and
App::new) onto their new location.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 28, 2026 05:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 111 out of 111 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

tools/wta/src/protocol/acp/permission_select.rs:59

  • allow_all_option_id currently treats any Select config option in category permissions as the native allow-all toggle. If an agent advertises multiple permission-related config options, this can pick the wrong id and then attempt to session/set_config_option(..., "on") against an unrelated setting. Since the ACP schema always requires an id, this should primarily key off the id (optionally normalizing it), not the free-form category string.
    tools/wta/src/app.rs:2158
  • This field comment says entries are removed when a session ends or is replaced (including session/load), but the current implementation only removes on /new (cmd_new) and clears on /restart. The SessionAttached handler overwrites tab.session_id without removing the previous id from yolo_sessions (see tools/wta/src/app_events.rs SessionAttached arm), so stale ids can linger and could unexpectedly re-enable yolo if an agent ever reuses a session_id. Consider removing the prior session_id from yolo_sessions whenever a tab is re-bound to a new session_id (and on session end), or update the comment to match the actual cleanup semantics.

@vanzue vanzue mentioned this pull request Jul 30, 2026
17 tasks
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 30, 2026 08:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 119 out of 119 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

tools/wta/src/protocol/acp/permission_select.rs:62

  • allow_all_option_id will treat any configOptions entry with category permissions as the allow-all selector, even if its id is not allow_all. That means a future agent that adds additional permissions-related config options could cause WTA to record the wrong config id and call session/set_config_option on an unrelated option.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow agent pane to run with options such as --allow-all

2 participants