fix(telegram): stop typing before command delivery - #73063
Conversation
teknium1
left a comment
There was a problem hiding this comment.
Thanks for isolating the normal final-delivery boundary and adding a stalled-send regression.
Problems
- The change does not cover the active-session
/newand/resetroute.gateway/platforms/base.py:5458sends that command reply at:5504before cancelling the existing processing task at:5518; that existing task owns the typing refresh created by_process_message_background(:5796). A stalled command send can therefore still leave typing active. - The new
/newtest calls_process_message_backgrounddirectly, so it bypasseshandle_message's active-session dispatch atgateway/platforms/base.py:5586-5601and cannot cover that route.
Suggested changes
- Stop or pause the existing typing refresh before the active-command sends at
gateway/platforms/base.py:5504and:5615, preserving the documented send-before-cancel ordering. - Add a
handle_messageregression with an active turn, a blocked/newsend, and an assertion that typing is already stopped.
Automated hermes-sweeper review.
| # Stop typing before every final delivery, including slash | ||
| # commands. A command send can still stall after Telegram has | ||
| # accepted the message but before its HTTP acknowledgement | ||
| # returns; leaving typing alive until the coroutine tail would |
There was a problem hiding this comment.
This only covers the ordinary _process_message_background path. An active-session /new uses _dispatch_active_session_command, which sends at current gateway/platforms/base.py:5504 before cancelling the old typing-owning task at :5518; a blocked command send there still leaves typing active. Please cover that dispatch path too.
410a863 to
2d47025
Compare
|
Addressed the active-session The adapter now tracks each session's typing refresh task separately from its processing task. The new regression test enters through Validation on the rebased branch:
|
2d47025 to
a596572
Compare
|
Rebased both typing-lifecycle commits onto current and force-pushed the refreshed branch. : 35 tests passed, 0 failures. |
a596572 to
7e1264f
Compare
|
Maintenance refresh: rebased both typing-lifecycle commits onto current upstream main (b359db7) and force-pushed head 7e1264fb47. Verification: tests/gateway/test_command_bypass_active_session.py — 35 passed; Ruff and git diff --check passed. |
7e1264f to
2f796cc
Compare
|
Maintenance refresh: rebased onto current upstream main (40643cb) and force-pushed head 2f796ccc58. Verification: 35 active-session command tests; Ruff and git diff --check passed. |
2f796cc to
60fea6f
Compare
|
Rebased onto official main f3cbb26 (2026-08-28). No conflicts; gateway typing tests 58 passed / 5 skipped; ruff clean. |
9a5fc10 to
39f1e18
Compare
Telegram command replies such as /new and /reset were excluded from the existing pre-delivery typing shutdown. If Telegram accepted the reply but the HTTP acknowledgement stalled on a half-closed connection, the command coroutine remained in delivery while its typing refresh task continued indefinitely. Apply the pre-delivery typing stop to every final response, including slash commands. Keep the active-session guard, pending-message drain, delivery retry, and final notification metadata behavior unchanged. Add a regression test that holds a slash-command delivery open forever and proves typing is already stopped before the send starts. Replace a brittle two-event-loop-tick assertion in the split-brain command test with a bounded readiness loop so the extra cleanup hop is tested by outcome rather than scheduler timing. Verification: - 139 focused topic/session/Telegram-format/voice-notify tests passed - 219 gateway typing/session-reset/slash-command tests passed, 2 skipped - Ruff passed - git diff --check passed
…ete scheduling The pre-delivery typing stop originally awaited _stop_typing_before_delivery inline before the final send. _stop_typing_refresh waits up to 0.5s on the cancelled typing task, and that inline wait reordered the loop scheduler: the ephemeral-reply test's detached delete task no longer completed within its pump window, so tests/gateway/test_ephemeral_reply.py ::test_process_message_unwraps_ephemeral_before_send failed on official CI (deleted list empty at assert time). Convert the stop to a fire-and-forget background task registered in _background_tasks (official discard-callback convention). The stop still begins before the send yields to the network, so the typing-indicator stall the PR fixes remains fixed, while the turn no longer blocks on the 0.5s cancel-wait. Verification: test_ephemeral_reply 5 passed; typing/ephemeral focused 76 passed / 5 skipped; command bypass + ephemeral 40 passed; ruff clean.
|
Rebased onto official main (2026-08-28, post-v0.20.6). Scope change: dropped the second commit (per-session typing-task registry for reset replies) — official main has since reworked the command/reset typing path (slash_commands mixin now clears typing when no active agent owns the session), and the carried registry implementation deadlocked test_active_session_text_merge on the current tree (300s CI timeout, deterministic). The remaining two commits carry the still-unabsorbed value: stop typing before slash-command delivery without stalling ephemeral delete scheduling. active_session_text_merge 7 passed; typing/ephemeral/command-bypass focused suite 119 passed / 5 skipped; ruff clean. |
Summary
Root cause
The existing pre-delivery typing lifecycle fix excluded slash commands because their replies are normally instant. That assumption fails when Telegram accepts a command reply but the HTTP acknowledgement stalls on a half-closed connection.
In that state:
sendChatAction, so the bot appears to type indefinitely.PR #25210 was closed as superseded by the post-delivery cleanup in #37556, but post-delivery cleanup cannot run while the delivery acknowledgement itself is stuck. This change closes that remaining boundary by stopping typing before the send begins.
Behavior
The change does not add a delivery timeout or alter retries. It does not release the active-session guard early. Messages arriving during delivery remain queued and drain after the current turn.
Two scheduler-sensitive tests now wait for their observable reply with a short bounded loop instead of assuming a fixed number of event-loop ticks; the extra ticks come from the pre-delivery cleanup itself.
Verification
139 passedacross topic sessions, split-brain command handling, Telegram formatting, and voice notify coverage242 passed, 2 skippedfor gateway tests selected bytyping or session_reset or slash_command, with an isolatedHERMES_HOMEgit diff --checkpassedRegression test
test_command_stops_typing_before_a_stuck_deliveryholds a/newdelivery open forever and asserts that the typing task has already stopped when delivery starts. It fails on currentmainand passes with this patch.