Skip to content

Add Ctrl-X keybinding that sends session/cancel to abort an in-flight turn #4

@lsaether

Description

@lsaether

Problem

While a session/prompt is in flight (the input is disabled, placeholder reads agent is processing…), there's no way to abort the turn from the TUI short of Ctrl-C, which quits the whole app and tears down the WS connection. Killing the connection is sufficient on the wire — acp-mux sees the WS close, sweeps the active turn — but it's a coarse hammer: you lose any other session state, any queued log scrollback, and you can't immediately reattach without re-doing initialize / session/new.

ACP defines a dedicated cancel channel for this: session/cancel is a notification (client → agent, no response expected) carrying just { sessionId }. The agent is expected to abort whatever it was doing and complete the turn with stopReason: "cancelled". acp-tui doesn't send this today.

Proposed solution

Bind Ctrl-X (or whatever key feels right — Ctrl-D conflicts with EOF, Ctrl-C is already taken by quit, Esc is consumed by the permission prompt) at the app level. When pressed:

  1. If there's no active turn, no-op (or log a hint "no turn in flight").
  2. If there's an active turn, send cli.notify("session/cancel", {"sessionId": self.acp_session_id}) and log [bold yellow]cancel requested[/] in the log.
  3. Leave the input disabled — the agent's eventual stopReason: "cancelled" response will re-enable it via the existing on_input_submitted finally block.

Optional: while we wait for the cancel to take effect (some agents are slow to honor it), update the placeholder to cancelling… so the user knows the keystroke registered.

Implementation notes

  • ACPClient.notify(method, params) already exists in src/acp_tui/acp_client.py:101-107. No new client code needed.
  • The binding goes on ACPApp.BINDINGS with priority=True so it works even when PromptInput has focus.
  • An action method action_cancel_turn is the handler. It needs to check self._prompt_in_flight (or whatever tracks "input disabled because a prompt is running") — currently the disabled state is the only signal. Either add an explicit flag on ACPApp or read prompt_input.disabled and assume the only thing that disables it is a turn-in-flight. The flag is cleaner.

Scope: ~20 lines plus a paragraph in the README.

Out of scope

  • Sending session/cancel while a permission prompt is pending — that's a different mode (the prompt is the in-flight thing, not the agent's turn), and the existing [esc] cancel already covers it.
  • Cancel-during-turn that interrupts a tool call mid-execution. ACP delegates the actual cancellation semantics to the agent; the TUI's job is just to send the notification.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions