hermes - ✅(Solved) Fix hermes -z (oneshot) returns empty stdout despite successful API response [4 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#22975Fetched 2026-05-11 03:31:57
View on GitHub
Comments
0
Participants
1
Timeline
9
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×4labeled ×3referenced ×2

hermes -z "prompt" --provider <any> -m <model> exits with code 0 but produces zero bytes on stdout. The agent successfully calls the API and receives a valid response, but the output is never written to the terminal. Reproducible across all providers (anthropic, mlx-primary, grok-vertex, gemini-vertex).

Root Cause

Suspected root cause

Fix Action

Workaround

Call _run_agent() directly from Python, or use hermes chat interactively.

PR fix notes

PR #23007: fix(oneshot): write response to stdout instead of silently dropping it

Description (problem / solution / changelog)

Summary

Fixes #22975 — hermes -z (oneshot mode) returns empty stdout despite a successful API response.

Root Cause

run_oneshot() wraps the entire agent call tree in redirect_stdout(open(os.devnull, 'w')) to suppress diagnostic output. However, AIAgent.__init__ calls _install_safe_stdio(), which wraps sys.stdout in a _SafeWriter proxy. The proxy's __getattr__ forwards attribute lookups to the inner stream — when that stream is a devnull file handle, it lacks text-stream attributes like .encoding (returns None on some platforms) and .buffer (absent entirely). Downstream SDK code and logging formatters that inspect these attributes silently malfunction, causing agent.chat() to return an empty string.

Fix

  1. Replace open(os.devnull) with io.StringIO() as the redirect target. StringIO is a well-behaved in-memory text stream that exposes all standard file-object attributes, avoiding the edge cases that devnull triggers through _SafeWriter's proxy.

  2. Set agent._print_fn = lambda: None to route all agent-internal print calls (_safe_print, _vprint) through a no-op, eliminating a second vector for stdout interference during response capture.

Testing

  • All existing oneshot tests pass (11 passed, 7 skipped)
  • The fix is minimal (1 file, +22/-8 lines) and confined to hermes_cli/oneshot.py

Checklist

  • Scope: 1 file changed
  • Tests pass
  • SSH-signed commit

Changed files

  • hermes_cli/oneshot.py (modified, +22/-8)

PR #23006: fix(cli): add /sessions handler + recover oneshot response (#22951, #22975)

Description (problem / solution / changelog)

Closing in favor of individual PRs per issue. Will split into separate focused PRs as per project guidelines.

Changed files

  • cli.py (modified, +82/-1)
  • hermes_cli/oneshot.py (modified, +17/-1)
  • ui-tui/package.json (modified, +1/-1)
  • ui-tui/src/app/useMainApp.ts (modified, +6/-0)
  • web/src/pages/SessionsPage.tsx (modified, +7/-1)

PR #23033: fix(oneshot): recover response from agent internal state when streaming returns empty

Description (problem / solution / changelog)

Problem

When streaming is active (stream_delta_callback set), agent.chat(prompt) returns an empty string because the response is consumed by the streaming callback. The oneshot CLI (hermes -z) then outputs nothing.

Solution

Capture the response before clearing callbacks, then fall back to agent._last_full_response and conversation_history when the direct return is empty.

Changes

  • _run_agent() now returns (agent, response) tuple
  • Added fallback chain: direct response → _last_full_response → last assistant message in history → empty string

Fixes #22975

Changed files

  • hermes_cli/oneshot.py (modified, +17/-1)

PR #23067: fix(oneshot): hermes -z returns empty stdout; fix(cron): whatsapp delivery silently dropped

Description (problem / solution / changelog)

Fixes #22975 and #22997.

fix(oneshot): hermes -z returns empty stdout (#22975)

Root cause: In _run_agent(), agent.stream_delta_callback = None suppresses token callbacks but _has_stream_consumers() returns False — so _use_streaming stays True. The response is emitted as stream deltas into the void; chat() returns "".

Fix: Set agent._disable_streaming = True before calling chat(). This forces the non-streaming path which returns the full response object directly.

Test: test_oneshot_disables_streaming_to_prevent_empty_stdout — asserts _disable_streaming is True when chat() is invoked.

fix(cron): whatsapp delivery silently dropped (#22997)

Root cause: 'whatsapp' was absent from _HOME_TARGET_ENV_VARS in cron/scheduler.py. _resolve_home_env_var('whatsapp') returned '', _resolve_delivery_targets() returned [], and the job was silently marked successful with no message sent.

Fix: One-line addition: 'whatsapp': 'WHATSAPP_HOME_CHANNEL' in _HOME_TARGET_ENV_VARS.

Test: test_whatsapp_deliver_resolves_home_channel — verifies the resolver returns a valid target when WHATSAPP_HOME_CHANNEL is set.

Changed files

  • cron/scheduler.py (modified, +1/-0)
  • hermes_cli/oneshot.py (modified, +4/-0)
  • tests/cron/test_scheduler.py (modified, +17/-0)
  • tests/hermes_cli/test_tui_resume_flow.py (modified, +69/-0)

Code Example

# All providers produce empty output:
hermes -z "Say hello" --provider anthropic -m claude-haiku-4-5-20251001
# Exit 0, stdout empty

hermes -z "Say hello" --provider mlx-primary -m "unsloth/Qwen3.6-35B-A3B-UD-MLX-4bit"
# Exit 0, stdout empty

hermes -z "Say hello" --provider grok-vertex -m "xai/grok-4.1-fast-non-reasoning"
# Exit 0, stdout empty

---

from hermes_cli.oneshot import _run_agent
r = _run_agent('Say exactly: HELLO', model='claude-haiku-4-5-20251001', provider='anthropic')
print(f"RESP: |{r}|")
# Output: RESP: |HELLO|

---

real_stdout = sys.stdout
devnull = open(os.devnull, "w", encoding="utf-8")

try:
    with redirect_stdout(devnull), redirect_stderr(devnull):
        response = _run_agent(prompt, model=model, provider=provider, ...)
finally:
    devnull.close()

if response:
    real_stdout.write(response)
RAW_BUFFERClick to expand / collapse

Environment

  • Hermes Agent: v0.13.0 (2026.5.7)
  • Python: 3.11.15
  • OpenAI SDK: 2.36.0
  • Anthropic SDK: 0.92.0
  • OS: macOS 26.3, arm64 (Apple Silicon M1 Max)

Summary

hermes -z "prompt" --provider <any> -m <model> exits with code 0 but produces zero bytes on stdout. The agent successfully calls the API and receives a valid response, but the output is never written to the terminal. Reproducible across all providers (anthropic, mlx-primary, grok-vertex, gemini-vertex).

Reproduction

# All providers produce empty output:
hermes -z "Say hello" --provider anthropic -m claude-haiku-4-5-20251001
# Exit 0, stdout empty

hermes -z "Say hello" --provider mlx-primary -m "unsloth/Qwen3.6-35B-A3B-UD-MLX-4bit"
# Exit 0, stdout empty

hermes -z "Say hello" --provider grok-vertex -m "xai/grok-4.1-fast-non-reasoning"
# Exit 0, stdout empty

Evidence that the API call succeeds

Running _run_agent() directly (bypassing run_oneshot()'s stdout redirect) returns correct responses:

from hermes_cli.oneshot import _run_agent
r = _run_agent('Say exactly: HELLO', model='claude-haiku-4-5-20251001', provider='anthropic')
print(f"RESP: |{r}|")
# Output: RESP: |HELLO|

Debug logging confirms 200 OK from the API with correct content in the response body.

Suspected root cause

In hermes_cli/oneshot.py, run_oneshot():

real_stdout = sys.stdout
devnull = open(os.devnull, "w", encoding="utf-8")

try:
    with redirect_stdout(devnull), redirect_stderr(devnull):
        response = _run_agent(prompt, model=model, provider=provider, ...)
finally:
    devnull.close()

if response:
    real_stdout.write(response)

_run_agent() returns agent.chat(prompt) or "" (line 336). When called through run_oneshot(), chat() appears to return None or "" — likely because the streaming path consumes the response content before chat() can capture it as a return value, even with suppress_status_output = True and stream_delta_callback = None set.

When the same _run_agent() is called directly from Python (outside the redirect_stdout(devnull) context), chat() returns the expected content. This suggests the redirect_stdout context manager interferes with the response capture path inside the agent.

Expected behavior

hermes -z "prompt" should print the model's response to stdout.

Actual behavior

Exit code 0, zero bytes on stdout, zero bytes on stderr.

Workaround

Call _run_agent() directly from Python, or use hermes chat interactively.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

hermes -z "prompt" should print the model's response to stdout.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix hermes -z (oneshot) returns empty stdout despite successful API response [4 pull requests, 1 participants]