Skip to content

fix(chat): require interactive TTY for cmd_chat - #7865

Closed
madsmmfu wants to merge 1 commit into
NousResearch:mainfrom
madsmmfu:fix/chat-require-tty
Closed

fix(chat): require interactive TTY for cmd_chat#7865
madsmmfu wants to merge 1 commit into
NousResearch:mainfrom
madsmmfu:fix/chat-require-tty

Conversation

@madsmmfu

Copy link
Copy Markdown

Without this guard, running hermes chat in any environment where stdin
is not a real TTY (pipe, detached parent, kqueue-unfriendly fd, etc.)
crashes inside prompt_toolkit's Vt100Input._attached_input with:

OSError: [Errno 22] Invalid argument
  at loop.add_reader(fd, callback_wrapper)

prompt_toolkit only catches PermissionError there (which epoll raises
on Linux for /dev/null); the macOS kqueue selector raises OSError
instead, and nothing in the chat run() try/except handles it, so the
process dies after printing the welcome banner and exit summary.

This mirrors the existing _require_tty() guards already used by the
other interactive commands (setup, model, whatsapp, uninstall,
tools, skills config). Single-shot mode (-q/--query or
-i/--image) still works without a TTY, since those paths never enter
prompt_toolkit's interactive loop.

Without this guard, running `hermes chat` in any environment where stdin
is not a real TTY (pipe, detached parent, kqueue-unfriendly fd, etc.)
crashes inside prompt_toolkit's `Vt100Input._attached_input` with:

    OSError: [Errno 22] Invalid argument
      at loop.add_reader(fd, callback_wrapper)

prompt_toolkit only catches `PermissionError` there (which epoll raises
on Linux for /dev/null); the macOS kqueue selector raises `OSError`
instead, and nothing in the chat run() try/except handles it, so the
process dies after printing the welcome banner and exit summary.

This mirrors the existing `_require_tty()` guards already used by the
other interactive commands (`setup`, `model`, `whatsapp`, `uninstall`,
`tools`, `skills config`). Single-shot mode (`-q/--query` or
`-i/--image`) still works without a TTY, since those paths never enter
prompt_toolkit's interactive loop.
@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 Apr 29, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Multiple competing PRs for the same fix: #8420, #8842, #10558 — all add TTY guard for hermes chat to prevent prompt_toolkit crash on non-TTY stdin.

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for identifying the macOS stdin-registration failure. This is now covered by a lower-level fix on main, so this PR is redundant.

Automated hermes-sweeper review evidence:

  • cli.py:15477-15514 probes KqueueSelector for stdin and switches to a SelectSelector event-loop policy when kqueue cannot register fd 0.
  • cli.py:15538-15556 catches the exact OSError(EINVAL) / Invalid argument fallback path and emits actionable guidance instead of a traceback.
  • The implementation landed in eabd8c1fd12d6e386d636e564444ef661ce99e81 (fix(cli): fall back to SelectSelector when kqueue can't watch stdin) and is contained in release v2026.5.16.

This preserves usable headless paths rather than rejecting every non-TTY chat invocation.

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 sweeper:implemented-on-main Sweeper: behavior already present on current main type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants