hermes - 💡(How to fix) Fix Telegram gateway can silently drop turn after /stop with response=0 chars while internal work continues

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…

Error Message

  • If a run returns empty after a non-command inbound message, log it as an error and send a fallback message such as “The previous run was interrupted and this turn produced no deliverable response. Please retry.”

Root Cause

Root Cause Hypothesis

Code Example

2026-05-25 06:35:07,181 INFO gateway.run: Invalidated run generation for agent:main:telegram:dm:<chat>4 (stop_command)
2026-05-25 06:35:07,181 INFO gateway.run: STOP for session agent:main:telegram:dm:<chat> — agent interrupted, session lock released
2026-05-25 06:35:07,216 INFO gateway.platforms.base: [Telegram] Sending command '/stop' response (41 chars) to <chat>

2026-05-25 06:35:23,483 INFO gateway.platforms.telegram: [Telegram] Flushing text batch agent:main:telegram:dm:<chat> (78 chars)
2026-05-25 06:35:23,487 INFO gateway.run: inbound message: platform=telegram user=<user> chat=<chat> msg='<normal user instruction redacted>'
2026-05-25 06:35:23,560 INFO gateway.run: response ready: platform=telegram chat=<chat> time=0.1s api_calls=0 response=0 chars

---

{
  "session_id": "20260525_062858_41c62779",
  "platform": "telegram",
  "updated_at": "2026-05-25T06:35:23.560658",
  "last_prompt_tokens": 51777,
  "suspended": false,
  "resume_pending": false
}

---

2026-05-01 15:11:33,751 INFO gateway.run: response ready: platform=telegram chat=<chat> time=5.1s api_calls=0 response=0 chars
2026-05-12 16:55:58,369 INFO gateway.run: response ready: platform=telegram chat=<chat> time=145.0s api_calls=15 response=0 chars
2026-05-12 16:58:43,115 INFO gateway.run: response ready: platform=telegram chat=<chat> time=161.3s api_calls=12 response=0 chars
2026-05-12 17:11:19,074 INFO gateway.run: response ready: platform=telegram chat=<chat> time=344.6s api_calls=9 response=0 chars
2026-05-12 17:18:12,506 INFO gateway.run: response ready: platform=telegram chat=<chat> time=409.8s api_calls=15 response=0 chars
2026-05-17 21:41:19,371 INFO gateway.run: response ready: platform=telegram chat=<chat> time=132.7s api_calls=11 response=0 chars
2026-05-24 21:57:36,913 INFO gateway.run: response ready: platform=telegram chat=<chat> time=131.5s api_calls=12 response=0 chars
2026-05-25 06:35:23,560 INFO gateway.run: response ready: platform=telegram chat=<chat> time=0.1s api_calls=0 response=0 chars
RAW_BUFFERClick to expand / collapse

Bug Description

Telegram gateway can accept a user message immediately after /stop, mark the turn complete with response=0 chars, send nothing to Telegram, and then continue doing internal agent/tool work whose final assistant answer is never delivered.

From the user's perspective the bot simply goes silent. This is not Telegram transport latency: the inbound message is logged instantly and the gateway explicitly records a completed zero-length response.

This looks distinct from #25010: there is no incomplete streamed message and no non-empty final response suppression in the visible gateway log. The gateway records an empty response immediately, while the transcript later contains real tool work and a substantive assistant conclusion that never reaches Telegram.

Impact

High. A Telegram user can issue an operational instruction, Hermes silently consumes it, performs hidden work, and never sends the result. There is no visible failure, fallback message, or retry. The user has to notice the silence and inspect logs manually.

Expected Behavior

After a Telegram inbound text message, Hermes should do one of the following:

  1. send the final assistant response to Telegram;
  2. send a clear failure/interrupted message if the run was cancelled or invalidated;
  3. keep the turn pending until a deliverable response exists.

A non-command user message should not be marked response ready with response=0 chars and then silently dropped, especially if agent/tool work continues afterward.

Actual Behavior

Observed live failure:

  • /stop was handled and the session lock was released.
  • 16 seconds later, a normal Telegram text message arrived.
  • Gateway immediately logged response ready ... response=0 chars with api_calls=0.
  • No Telegram response was sent.
  • Session transcript/history showed internal terminal/tool work continued after that message and eventually produced a substantive assistant answer, but there was no matching Telegram send for that final answer.
  • Session metadata was not stuck in the older resume_pending zombie state: resume_pending=false, suspended=false.

Evidence

Redacted gateway log excerpt:

2026-05-25 06:35:07,181 INFO gateway.run: Invalidated run generation for agent:main:telegram:dm:<chat> → 4 (stop_command)
2026-05-25 06:35:07,181 INFO gateway.run: STOP for session agent:main:telegram:dm:<chat> — agent interrupted, session lock released
2026-05-25 06:35:07,216 INFO gateway.platforms.base: [Telegram] Sending command '/stop' response (41 chars) to <chat>

2026-05-25 06:35:23,483 INFO gateway.platforms.telegram: [Telegram] Flushing text batch agent:main:telegram:dm:<chat> (78 chars)
2026-05-25 06:35:23,487 INFO gateway.run: inbound message: platform=telegram user=<user> chat=<chat> msg='<normal user instruction redacted>'
2026-05-25 06:35:23,560 INFO gateway.run: response ready: platform=telegram chat=<chat> time=0.1s api_calls=0 response=0 chars

Session metadata immediately after inspection:

{
  "session_id": "20260525_062858_41c62779",
  "platform": "telegram",
  "updated_at": "2026-05-25T06:35:23.560658",
  "last_prompt_tokens": 51777,
  "suspended": false,
  "resume_pending": false
}

Additional evidence that this zero-length completion pattern has occurred before in the same gateway logs:

2026-05-01 15:11:33,751 INFO gateway.run: response ready: platform=telegram chat=<chat> time=5.1s api_calls=0 response=0 chars
2026-05-12 16:55:58,369 INFO gateway.run: response ready: platform=telegram chat=<chat> time=145.0s api_calls=15 response=0 chars
2026-05-12 16:58:43,115 INFO gateway.run: response ready: platform=telegram chat=<chat> time=161.3s api_calls=12 response=0 chars
2026-05-12 17:11:19,074 INFO gateway.run: response ready: platform=telegram chat=<chat> time=344.6s api_calls=9 response=0 chars
2026-05-12 17:18:12,506 INFO gateway.run: response ready: platform=telegram chat=<chat> time=409.8s api_calls=15 response=0 chars
2026-05-17 21:41:19,371 INFO gateway.run: response ready: platform=telegram chat=<chat> time=132.7s api_calls=11 response=0 chars
2026-05-24 21:57:36,913 INFO gateway.run: response ready: platform=telegram chat=<chat> time=131.5s api_calls=12 response=0 chars
2026-05-25 06:35:23,560 INFO gateway.run: response ready: platform=telegram chat=<chat> time=0.1s api_calls=0 response=0 chars

Steps to Reproduce

This is an observed live production failure, not yet reduced to a deterministic unit test. The likely trigger sequence is:

  1. Run Hermes Telegram gateway in polling mode with an active DM session.
  2. Start a tool-heavy turn or long-running gateway turn.
  3. Send /stop from Telegram.
  4. Immediately after the stop response, send a normal text instruction in the same Telegram chat.
  5. Inspect ~/.hermes/logs/gateway.log.
  6. Observe that the new inbound message can be marked complete with response=0 chars, while the later internal transcript contains tool/assistant work that is not delivered to Telegram.

Root Cause Hypothesis

This looks like a run-generation/session-lock/final-delivery race after /stop:

  • /stop invalidates the current run generation and releases the session lock.
  • The next user message is accepted under a state that returns an empty immediate result to the gateway front-end path.
  • Internal agent/tool processing is still allowed to continue or is attached to a path no longer connected to Telegram delivery.
  • The gateway treats the empty front-end result as final and never sends the eventual assistant answer.

Possible suspect areas:

  • stop-command generation invalidation and next-turn setup in gateway/run.py;
  • paths that treat empty string / empty sentinel / interrupted result as a normal completed response;
  • mismatch between internal session transcript continuation and platform delivery lifecycle;
  • lack of a guardrail for response=0 chars after a non-command inbound user message.

Suggested Fix Direction

  • Do not silently drop zero-length responses for normal user messages.
  • If a run returns empty after a non-command inbound message, log it as an error and send a fallback message such as “The previous run was interrupted and this turn produced no deliverable response. Please retry.”
  • After /stop, ensure any subsequent user message starts a clean generation and cannot inherit a cancelled/invalidated output path.
  • Add a regression test around: /stop -> immediate next Telegram text -> no zero-length silent completion.
  • Add logging that correlates inbound message ID, generation ID, session lock lifecycle, response length, and platform send attempt/result.
  • If internal tool work continues after the gateway has already finalized a zero-length response, either cancel that work or reconnect final delivery so exactly one final response is sent.

Environment

  • Hermes Agent: v0.14.0 (2026.5.16)
  • Local checkout commit: 186bf25cb
  • Python: 3.11.15
  • OpenAI SDK: 2.24.0
  • OS: macOS 26.1 build 25B78
  • Platform: Telegram gateway, polling mode
  • Provider/model path: OpenAI Codex provider, gpt-5.5
  • Session prompt size at failure: last_prompt_tokens=51777

Related Issues

  • #25010: related Telegram final-send/drop class, but that issue is about streaming leaving an incomplete partial message while suppressing a non-empty final response. This report is the zero-length immediate completion + orphaned internal work variant.
  • #23983: similar silent drop class in voice/TTS flow.

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…

Still need to ship something?

×6

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

Back to top recommendations

TRENDING