Skip to content

feat(ui): make active-agent Escape opt-in - #113

Open
jsgrrchg wants to merge 9 commits into
zeronsh:mainfrom
jsgrrchg:feature/escape-cancel-active-agent
Open

feat(ui): make active-agent Escape opt-in#113
jsgrrchg wants to merge 9 commits into
zeronsh:mainfrom
jsgrrchg:feature/escape-cancel-active-agent

Conversation

@jsgrrchg

@jsgrrchg jsgrrchg commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds an opt-in Escape shortcut that interrupts only the currently selected active agent, while preserving all existing contextual Escape behavior.

The shortcut is disabled by default for both new users and existing users with older settings files.

What changed

  • Adds a device-local Stop active agent with Escape preference under Settings → Shortcuts.
  • Defaults the preference to false.
  • Persists the preference in ui-settings.json.
  • Keeps Escape contextual behavior higher priority.
  • When enabled, Escape interrupts only the selected chat if it is Working or AwaitingInput.
  • Captures the selected chat_id before dispatching the durable interrupt command.
  • Preserves per-chat idempotency and failure handling from the existing Stop button.
  • Keeps interrupt state isolated between concurrent chats.
  • Places the new preference below the keyboard shortcut list.
  • Centers the existing shortcut helper text.
  • “Restore defaults” also disables the Escape preference.

Escape consumer protections

The active-agent interrupt is intentionally the final Escape fallback. Other Escape consumers remain protected through multiple layers:

  • Shell-owned menus and overlays are handled during the capture phase before the focused child receives the event.
  • Menus and dialogs that already use Escape to close themselves stop propagation, so they never reach the interrupt fallback.
  • Blocking overlays consume Escape without triggering any agent action.
  • Composer mention and slash completions retain ownership of Escape.
  • The question wizard retains its existing Escape behavior.
  • Pickers, rename dialogs, Changes ref/scope menus, and other contextual surfaces keep their existing cancellation behavior.
  • The integrated terminal continues to receive Escape and sends the ANSI 0x1b byte when appropriate.
  • The fallback only runs on the Chat route, only when the selected chat is Working or AwaitingInput, and only when the opt-in preference is enabled.
  • The selected chat_id is captured before dispatch, preventing navigation from redirecting the interrupt to another session.
  • Per-chat in-flight tracking prevents duplicate interrupts while allowing independent interrupts for other chats.

This makes the agent interrupt a non-invasive fallback rather than a global Escape handler.

User behavior

With the preference disabled, Escape behaves exactly as it did before this feature.

With the preference enabled:

  • Escape stops the active agent in the selected session.
  • Escape does nothing when there is no selected active session.
  • Escape does not stop agents in other sessions.
  • Escape does not override menus, dialogs, pickers, completion UI, or the terminal.

Compatibility

  • Existing settings files without the new field load with the preference disabled.
  • New users also start with the preference disabled.
  • No engine protocol, document format, sync behavior, or iOS behavior changes.
  • Interrupts continue to use the existing durable QueueCommand(Interrupt) flow.

Validation

  • cargo fmt --all -- --check
  • cargo test -p zeron-ui --lib — 432 passed
  • cargo test -p zeron-engine interrupt --test e2e — 3 passed
  • cargo test -p zeron-harness interrupt — 2 passed
  • git diff --check
  • Manual queue validation confirmed contextual Escape precedence and chat-scoped interruption.

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@jsgrrchg
jsgrrchg marked this pull request as ready for review August 15, 2026 19:03
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.

1 participant