hermes - 💡(How to fix) Fix [Bug]: Typing indicator lingers ~5s after streamed reply finishes [1 pull requests]

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

Additional Logs / Traceback (optional)

Root Cause

Root Cause Analysis (optional)

Fix Action

Fixed

RAW_BUFFERClick to expand / collapse

Bug Description

After a streamed reply completes on Telegram (and likely Discord), the "typing…" indicator continues to display for ~5 seconds until the platform-side typing state expires on its own. The user sees the final reply arrive and a "still typing" signal at the same time — a confusing UX that makes it look like the bot is still working when it has already finished.

Steps to Reproduce

  1. Run the gateway with a Telegram bot.
  2. Send the bot a message that triggers a multi-chunk streamed response (e.g. "summarise this long article").
  3. Observe the chat header in Telegram while the bot replies.

Expected vs Actual

Expected: When the final reply is delivered, the "typing…" indicator should clear immediately.

Actual: The "typing…" indicator continues to show for ~5 seconds after the final message has appeared, until Telegram's server-side timeout expires it.

Operating System

macOS 15.4 (Darwin 25.4.0)

Python Version

3.11.14

Hermes Version

Working off main (HEAD 6a6766fb8, "test(cli): cover Brave binary CDP launch detection")

Additional Logs / Traceback (optional)

No exceptions — purely a UX/timing bug.

Root Cause Analysis (optional)

BasePlatformAdapter starts a background _keep_typing task that fires send_typing every 2 seconds for the duration of message handling. The task is only cancelled at the end of message handling — after send/send_multiple_images/etc. have already delivered the final content.

In the window between "final message sent" and "background refresher cancelled", one or more late send_typing calls can still fire and re-arm the typing state on the platform. Because Telegram's typing state is sticky for ~5 s, the indicator visibly survives past the final reply.

Two cleanup gaps make this worse:

  1. GatewayStreamConsumer has no way to tell the adapter "the model is done streaming, stop refreshing typing right now".
  2. BasePlatformAdapter._handle_message cancels the typing task only in its finally block, well after every delivery path (text / TTS / images / media / files) has already run.

Proposed Fix (optional)

  • Add a per-chat _typing_stop_events: Dict[str, asyncio.Event] to BasePlatformAdapter.
  • Expose request_typing_stop(chat_id) so other code can signal the refresher to stop promptly.
  • Introduce _stop_typing_before_final_delivery() that combines the stop signal with an explicit stop_typing call, and invoke it before every final-delivery point (text, TTS, single image, batched images, non-image media, auto-detected files).
  • In GatewayStreamConsumer, call adapter.request_typing_stop(chat_id) as soon as the stream finishes, so the refresher halts before the formatting / send work runs.

PR #29172 implements this approach with tests.

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR — already opened as #29172.

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