Skip to content

fix(cli): catch KeyboardInterrupt during slash commands to prevent session exit#32017

Merged
teknium1 merged 2 commits into
mainfrom
fix/slash-command-keyboardinterrupt
May 25, 2026
Merged

fix(cli): catch KeyboardInterrupt during slash commands to prevent session exit#32017
teknium1 merged 2 commits into
mainfrom
fix/slash-command-keyboardinterrupt

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Ctrl+C during a slow slash command (/skills browse, /sessions list against a large SQLite DB, /history on long conversations) no longer kills the session. Previously the KeyboardInterrupt unwound past self.process_command() to the outer prompt_toolkit event loop, losing all conversation state.

Fix

Wrap the slash-command dispatch in try / except KeyboardInterrupt so Ctrl+C aborts the command and returns to the prompt without taking the session with it. Other exceptions still propagate normally so real bugs aren't silently swallowed.

Changes

  • cli.py — 6 lines of try/except KeyboardInterrupt around self.process_command(user_input) in the dispatch shape at line ~14236.
  • tests/cli/test_slash_command_interrupt.py — 4 tests covering: KBI during slash command leaves _should_exit False; truthy return keeps session alive; falsy return still sets exit (the legit /exit path); non-KBI exceptions propagate normally.

Validation

Before After
/skills browse + Ctrl+C session dies, all history lost "Command interrupted." → prompt returns
/sessions list + Ctrl+C session dies command aborts, session continues
/exit (returns False) session exits session exits (unchanged)
Real bug raises RuntimeError propagates to global handler propagates to global handler (unchanged)

Targeted tests: tests/cli/test_slash_command_interrupt.py — 4/4 passing.

Salvage notes

Surgical reapply of PR #5189 by @ygd58 (commit 9437a46f9, buraysandro9@gmail.com). The original branch was many months stale against current main and a direct cherry-pick would have reverted 3,764 unrelated files (−1,084,940 LOC), including the entire kanban tutorial, image assets, dozens of skill files, and hundreds of test files. The substantive ~6 LOC change in cli.py plus a new 113-line test file were reapplied by hand onto current main with the contributor's authorship preserved via git commit --author=.

Original PR #5189 will be closed pointing to this one.

Infographic

slash-command-keyboardinterrupt

https://v3b.fal.media/files/b/0a9b9dd5/f7dMP6Uh5eFm7_U0El0KC_ZPtXi4CE.png

ygd58 and others added 2 commits May 25, 2026 03:53
…ssion exit

A Ctrl+C during a slow slash command (e.g. /skills browse on a large
skill tree, /sessions list against a multi-GB SQLite DB) used to unwind
past self.process_command() to the outer prompt_toolkit event loop,
which killed the entire session — losing all conversation state.

Fix: wrap the slash-command dispatch in try/except KeyboardInterrupt
so Ctrl+C aborts the command but the prompt loop continues. Other
exceptions still propagate so real bugs aren't silently swallowed.

Surgical reapply of PR #5189. Original branch was many months stale
(3764 files / 1M+ LOC of unrelated reverts); the substantive ~6 LOC
change in cli.py was reapplied by hand onto current main with the
contributor's authorship preserved via --author.
4 tests: KBI during slash command does not set _should_exit; truthy
return keeps session alive; falsy return still sets exit (legit
/exit path); non-KBI exceptions propagate normally.
@github-actions

Copy link
Copy Markdown
Contributor

🔎 Lint report: fix/slash-command-keyboardinterrupt vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 9256 on HEAD, 9256 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 4909 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@hclsys

hclsys commented May 25, 2026

Copy link
Copy Markdown

Fix is correct and well-scoped. I checked the main risk — that catching KeyboardInterrupt here might swallow a Ctrl+C the user means for stopping agent generation — and it doesn't: the try/except is strictly inside the _looks_like_slash_command(user_input) branch, which ends in continue, so the agent-turn interrupt path further down process_loop is untouched. Ctrl+C during a slow /skills browse / /sessions list now aborts just the command, and real generation interrupts still work. Other exceptions still propagate, so genuine bugs aren't masked. Good.

One note on the tests: they exercise a local _dispatch helper that mirrors the production dispatch shape rather than driving the real process_loop. That's a reasonable way to avoid spinning up prompt_toolkit, but it means the test passes even if the real call site's try/except is later moved or removed — the mirror can drift from cli.py:~14203. A small hardening option: assert against the real structure (e.g. a regression test that greps/AST-checks the process_command dispatch is wrapped, or a thin integration test through the real loop), or at minimum a comment in both places cross-referencing each other so a future edit to the call site flags the test. Not blocking — the fix itself is sound and the contract the tests assert (KI → no exit, falsy → exit, truthy → stay) is the right one. LGTM.

@talwayh1

Copy link
Copy Markdown

CI Fix: _YOLO_MODE_FROZEN monkeypatch (Trap #18)

test_yolo_overrides_cron_deny is failing because monkeypatch.setenv(HERMES_YOLO_MODE, 1) has no effect on the import-time frozen _YOLO_MODE_FROZEN constant in tools/approval.py (line 29). The yolo fast-path at line 948 never fires.

Root cause: _YOLO_MODE_FROZEN: bool = is_truthy_value(os.getenv(HERMES_YOLO_MODE, )) — frozen at import time. monkeypatch.setenv only modifies os.environ; the already-captured constant is untouched.

Fix: Add monkeypatch.setattr(approval_module, _YOLO_MODE_FROZEN, True) alongside the setenv.

Available at 0e268c403 on talwayh1/hermes-agent:fix/slash-command-keyboardinterrupt:

git fetch https://github.com/talwayh1/hermes-agent.git fix/slash-command-keyboardinterrupt
git cherry-pick 0e268c403

See ci-self-heal Trap #18 for the full pattern.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/cli CLI entry point, hermes_cli/, setup wizard labels May 25, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Salvage reapply of stale PR #5189. Fixes #5142.

@teknium1 teknium1 merged commit 8697471 into main May 25, 2026
25 of 26 checks passed
@teknium1 teknium1 deleted the fix/slash-command-keyboardinterrupt branch May 25, 2026 12:06
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 P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants