Skip to content

fix(cli): recover terminal state after interrupting a running turn (#33271) - #54058

Merged
teknium1 merged 2 commits into
mainfrom
hermes/hermes-f0181051
Jun 28, 2026
Merged

fix(cli): recover terminal state after interrupting a running turn (#33271)#54058
teknium1 merged 2 commits into
mainfrom
hermes/hermes-f0181051

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Interrupting a running CLI turn by typing a new message no longer freezes the terminal. After an interrupt, the CLI now drains stray escape bytes from stdin and forces a clean prompt_toolkit repaint, so a leaked CSI 6n cursor-position reply can't stall the input parser.

Closes #33271. Salvaged from #34064 (@zccyman).

Root cause

process_loop's finally block only called app.invalidate(). On an interrupt, prompt_toolkit could have an in-flight CSI 6n query whose reply (ESC[<row>;<col>R) arrived on stdin after the parser tore down — leaking as literal ^[[19;1R and stalling the VT100 parser, accepting no further keystrokes. The existing CPR-suppression machinery (#13870/#48309) only engages on SSH/tunnel terminals, leaving local terminals (where the bug also reproduces) unprotected on the interrupt path.

Changes

  • cli.py: after an interrupted turn (_last_turn_interrupted), call flush_stdin() (termios.tcflush(TCIFLUSH), no-op on non-TTY) then _force_full_redraw(). Extracted into a testable _recover_terminal_after_interrupt() helper.
  • tests/cli/test_terminal_interrupt_recovery.py: tests exercise the real helper (drain-then-redraw order, redraw survives a flush failure, TTY-gating) plus a source guard that process_loop actually invokes it behind the _last_turn_interrupted gate.

Validation

Before After
Interrupt-path recovery none (only app.invalidate()) flush_stdin + _force_full_redraw
tests/cli/test_terminal_interrupt_recovery.py tautological (re-implemented logic) 6 passed, exercise real helper
tests/cli/test_cli_force_redraw.py 9 passed (no regression)

Infographic

terminal-freeze-fixed

zccyman and others added 2 commits June 28, 2026 00:45
…ol sequence freeze

When the agent is interrupted during processing, prompt_toolkit's
renderer and VT100 input parser can be left in an inconsistent state.
CSI 6n cursor position report responses leak as literal text
(^[[19;1R) and the terminal stops accepting keyboard input.

Fix: in process_loop's finally block, after an interrupted turn:
- flush_stdin() to drain stray escape bytes from the OS input buffer
- _force_full_redraw() to reset prompt_toolkit's renderer cache

Closes #33271
Pull the #33271 post-interrupt recovery (flush_stdin + _force_full_redraw)
out of process_loop's finally block into _recover_terminal_after_interrupt(),
and replace the inline-logic-copy tests with ones that exercise the real
helper plus a source guard that process_loop still invokes it behind the
_last_turn_interrupted gate.
@alt-glitch alt-glitch added type/bug Something isn't working comp/cli CLI entry point, hermes_cli/, setup wizard P1 High — major feature broken, no workaround labels Jun 28, 2026

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review Summary

Verdict: Approved

Adds terminal recovery after user-interrupted agent turns. When the user types during a running turn, prompt_toolkit's in-flight CSI 6n cursor query can leak as literal text and stall the VT100 parser. The recovery path drains stray escape bytes (flush_stdin) and forces a clean redraw (_force_full_redraw). Both steps are independently safe. Tests cover the helper, ordering, TTY gating, and process_loop wiring behind the _last_turn_interrupted guard.


Reviewed by Hermes Agent

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

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P1 High — major feature broken, no workaround type/bug Something isn't working

Projects

None yet

4 participants