Skip to content

[Bug]: CLI input locks up unrecoverably on lazy-dep install prompt (lazy_deps.py uses bare input() under prompt_toolkit) #40490

@SaguaroDev

Description

@SaguaroDev

Description

In CLI mode, the interactive prompt locks up the terminal completely whenever
Hermes's lazy dependency installer fires. Observed via vision_analyze on a
fresh install where Pillow was not present. The CLI becomes fully unresponsive:
no keyboard input is accepted, Ctrl-C does nothing, and the quit commands do not
work. Recovery requires killing the process from another terminal. Reproduces
every time.

The on-screen state when wedged:

Feature 'tool.vision' requires: Pillow==12.2.0
Install into the active venv now? [Y/n]

Root cause (confirmed from source)

This is NOT pip prompting. It is Hermes's own lazy-install confirmation in
tools/lazy_deps.py. The prompt is emitted with a bare builtin input():

# tools/lazy_deps.py  (around lines 459-465)
if prompt and sys.stdin.isatty() and sys.stdout.isatty():
    spec_list = ", ".join(missing)
    try:
        answer = input(
            f"\nFeature {feature!r} requires: {spec_list}\n"
            f"Install into the active venv now? [Y/n] "
        ).strip().lower()
    except (EOFError, KeyboardInterrupt):
        answer = "n"

In CLI mode sys.stdin and sys.stdout ARE TTYs, so the isatty() guard
passes and the branch runs. But the interactive CLI runs prompt_toolkit, which
owns stdin. A raw blocking input() competes with prompt_toolkit's event loop
for the same stdin: keystrokes are consumed by prompt_toolkit, the input()
call never receives the answer, and the whole session wedges with no way to
answer, interrupt, or quit.

This is the same failure mode as the closed confirmation-prompt hangs
#23694 / #24343 (daemon-thread input() vs prompt_toolkit stdin). Those
fixes covered Hermes slash-command prompts; the lazy_deps.py prompt is a
separate code path that was not covered, so it still hangs.

The isatty() check is the wrong gate. It detects "attached to a terminal" but
not "another reader (prompt_toolkit) already owns stdin." Any lazy-install
trigger in an interactive CLI session hits this (vision/Pillow is just the
common one).

Steps to reproduce

  1. Fresh install where a lazy feature dependency is missing (e.g. Pillow absent,
    so tool.vision is unsatisfied).
  2. Launch hermes in interactive CLI mode.
  3. Trigger the feature (call vision_analyze on any image).
  4. Hermes prints Install into the active venv now? [Y/n] and blocks on
    input(). The CLI accepts no input: cannot answer, cannot Ctrl-C, cannot
    quit. Recover only by killing the process from another terminal.

Expected

When running under the interactive CLI, the confirmation must be routed through
prompt_toolkit (the same mechanism the slash-command confirmation fix uses)
rather than a bare input(), OR the prompt should be suppressed in favor of the
security.allow_lazy_installs config gate when prompt_toolkit owns stdin. The
session must stay answerable, interruptible, and quittable.

Actual

Bare input() blocks under prompt_toolkit and never receives the keystroke.
Total input lockup; external kill is the only recovery. Reproduces every time.

Workaround

Pre-install the dependency so the lazy path never triggers, e.g.
~/.hermes/hermes-agent/venv/bin/python -m pip install "Pillow==12.2.0".
(My earlier pip install --no-input suggestion does NOT help, because pip is
not the thing prompting; Hermes is.)

Environment

  • Hermes Agent v0.15.1 (2026.5.29)
  • macOS 26.5.1 (build 25F80), Apple Silicon
  • Python 3.11.15 (Hermes runtime)

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High — major feature broken, no workaroundcomp/cliCLI entry point, hermes_cli/, setup wizardcomp/toolsTool registry, model_tools, toolsetstype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions