Skip to content

fix(telegram): stop typing after final reply - #33631

Open
kuil09 wants to merge 2 commits into
NousResearch:mainfrom
kuil09:fix/telegram-final-typing
Open

fix(telegram): stop typing after final reply#33631
kuil09 wants to merge 2 commits into
NousResearch:mainfrom
kuil09:fix/telegram-final-typing

Conversation

@kuil09

@kuil09 kuil09 commented May 28, 2026

Copy link
Copy Markdown

Problem

After the final Telegram reply is delivered, Hermes can still appear to be typing for a few extra seconds.

#37556 fixed the post-delivery callback boundary in base.py, but there is still a smaller Telegram-specific residual gap after that fix:

  • the streamed trailing-footer send can re-arm the typing bubble after the answer has already landed
  • Telegram terminal sends still need a coherent suppression contract so final replies do not re-trigger typing

Why this PR is intentionally narrow

There are broader proposals in this area (for example #33606 / #29172), but after #37556 the remaining gap here is smaller and more localized. This PR keeps the delta focused on that residual Telegram behavior instead of expanding into stream-consumer / typing-lifecycle redesign.

This also differs from #29595: that PR reuses metadata["notify"] as the final-send marker, while this PR preserves the existing notify=True terminal-send contract and adds a dedicated suppress_post_send_typing flag for footer-specific residual paths.

Fix

Keep Telegram post-send typing suppression coherent by treating these as terminal-send markers:

  • notify=True for the existing final-send contract used by stream-consumer paths
  • suppress_post_send_typing=True for trailing-footer / residual terminal-send paths that are final but not notify-driven

Covered paths:

  • final text send behavior in plugins/platforms/telegram/adapter.py
  • streamed trailing footer send in gateway/run.py
  • existing final-send metadata contracts used by stream-consumer paths

Why the dedicated flag still helps

  • notify already means "deliver this as a notify-worthy/user-visible message"
  • suppress_post_send_typing means "this send is terminal and must not re-arm Telegram typing", even when the send is not notification-driven
  • keeping the footer-specific suppression signal explicit avoids depending on notification policy for every residual post-send path

Tests

Added / updated regression coverage for:

  • tests/gateway/test_telegram_post_send_typing.py
    • default/intermediate sends still re-trigger typing
    • notify=True final sends still suppress typing refresh
    • footer-style sends with suppress_post_send_typing=True also suppress typing refresh
  • tests/gateway/test_telegram_footer_post_send_typing.py
    • streamed trailing footer sends carry suppress_post_send_typing=True
  • tests/gateway/test_base_topic_sessions.py
    • topic-session final-delivery metadata propagation includes the suppression flag
  • tests/gateway/test_run_progress_topics.py
    • verified alongside the existing #37556 callback-boundary coverage
  • tests/gateway/test_telegram_format.py
    • existing final-send notify=True contract remains intact
  • tests/gateway/test_stream_consumer_thread_routing.py
    • stream-consumer final sends still mark terminal metadata with notify=True

Validation

python -m pytest tests/gateway/test_telegram_post_send_typing.py \
  tests/gateway/test_telegram_footer_post_send_typing.py \
  tests/gateway/test_base_topic_sessions.py \
  tests/gateway/test_run_progress_topics.py \
  tests/gateway/test_telegram_format.py \
  tests/gateway/test_stream_consumer_thread_routing.py -q -o addopts=''

Result: 168 passed

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists platform/telegram Telegram bot adapter comp/gateway Gateway runner, session dispatch, delivery labels May 28, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Related: fixes #29175 (canonical issue). Competing with PRs #33606, #29172, #29595, #25210, #24983, #21688 — all addressing the same Telegram typing indicator lingers after final reply. This PR uses a suppress_post_send_typing metadata flag approach.

@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Thanks for this. A fix for the post-delivery typing-stop boundary in base.py has landed on main via #37556 (merged as 6a30cfca8): it moves _stop_typing_task() ahead of the post-delivery callback and bounds the callback with a timeout, which also closes the root-cause issue #24971.

This PR overlaps that area but also touches paths #37556 didn't (e.g. the stream-consumer / final-delivery path), so I'm not closing it — could you rebase on current main and let me know if there's still a residual gap your change covers after #37556? Happy to take the remaining delta as a focused follow-up if so.

@kuil09
kuil09 force-pushed the fix/telegram-final-typing branch 2 times, most recently from 89863f9 to 0a39c62 Compare July 7, 2026 23:52
@kuil09

kuil09 commented Jul 7, 2026

Copy link
Copy Markdown
Author

@kshitijk4poor Sorry for the late reply — I only just saw your comment.

I rebased this branch onto current main and re-checked it against the fix from #37556. That change does cover the post-delivery callback boundary in base.py, but there was still a residual Telegram gap here:

  • the Telegram adapter still re-triggered typing after terminal/final sends
  • the streamed trailing-footer path could also re-arm the typing bubble after the answer had already landed

I updated this PR branch to keep the remaining delta focused on those paths and added regression coverage for:

  • final send suppression in the Telegram adapter
  • streamed trailing-footer suppression
  • topic-session metadata propagation
  • the existing post-delivery callback path alongside these cases

Validation I ran locally:

python -m pytest tests/gateway/test_telegram_post_send_typing.py \
  tests/gateway/test_telegram_footer_post_send_typing.py \
  tests/gateway/test_base_topic_sessions.py \
  tests/gateway/test_run_progress_topics.py -q -o addopts=

Result: 49 passed.

So after rebasing, I do still see a remaining gap that this PR covers; the branch is now updated to reflect only that residual fix.

@kuil09
kuil09 force-pushed the fix/telegram-final-typing branch from 0a39c62 to e81d5e4 Compare July 8, 2026 00:14
@kuil09

kuil09 commented Jul 8, 2026

Copy link
Copy Markdown
Author

@kshitijk4poor Thanks again — I tightened this PR further to make the residual scope clearer.

Why I still think this is a meaningful follow-up after #37556:

  • #37556 fixed the post-delivery callback boundary in base.py.
  • This PR is aimed at a different residual Telegram-specific gap that still exists after that fix:
    • the Telegram adapter can re-trigger typing after a terminal/final send
    • the streamed trailing-footer send can also re-arm the typing bubble after the answer already landed
  • I kept this intentionally narrow instead of expanding into a broader typing-lifecycle redesign, since your ask was whether there was still a remaining delta worth taking as a focused follow-up.

I also strengthened the regression coverage and updated the PR body accordingly. In particular, the tests now explicitly show that notify=True by itself does not suppress typing refresh; only the dedicated suppress_post_send_typing flag does. That keeps notification semantics separate from typing-lifecycle semantics.

Latest targeted validation:

python -m pytest tests/gateway/test_telegram_post_send_typing.py \
  tests/gateway/test_telegram_footer_post_send_typing.py \
  tests/gateway/test_base_topic_sessions.py \
  tests/gateway/test_run_progress_topics.py -q -o addopts=

Result: 50 passed.

@kuil09

kuil09 commented Jul 8, 2026

Copy link
Copy Markdown
Author

For convenience, here is the scope comparison against the other related PRs mentioned on this thread:

  • vs #37556: that PR fixes the callback-hang / post-delivery cleanup boundary in base.py; this PR addresses the remaining Telegram-specific post-send re-arm paths after that fix.
  • vs #33606 / #29172: those are broader typing-lifecycle / stream-consumer proposals; this PR is deliberately smaller and only carries the residual Telegram delta.
  • vs #29595: that PR uses metadata["notify"] as the final-send marker; this PR uses a dedicated suppress_post_send_typing flag so notification policy and typing suppression stay decoupled.

Why I think that matters:

  • notify already has an established meaning: make the final/user-visible message notification-worthy.
  • Suppressing post-send typing is a separate concern.
  • Keeping those signals orthogonal makes the Telegram behavior easier to reason about and test.

Additional strengthening I added while rebasing this branch:

  • regression coverage for the streamed trailing-footer path
  • regression coverage proving notify=True alone still re-triggers typing
  • topic-session metadata propagation checks for the suppression flag

So the value proposition of this PR is not “solve the whole typing lifecycle”; it is “keep the already-merged #37556 fix, then land the smallest remaining Telegram-specific delta that still looks user-visible.”

@alt-glitch alt-glitch added the sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages label Jul 8, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related to canonical issue #29175 and part of the saturated Telegram "typing indicator lingers after final reply" cluster: competing (not duplicate) with #33606, #29172, #29595, #25210, #24983, #21688, and the merged base.py fix #37556 (which this PR is intentionally narrower than). This PR keeps typing-suppression semantics separate from metadata['notify'] via a dedicated suppress_post_send_typing flag — a distinct mechanism from #29595. Flagging the cluster for a maintainer to pick the canonical approach; not closing either.

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for narrowing the remaining streamed-footer path. Current main does still have that specific gap: gateway/run.py:12189-12193 sends the streamed trailing footer with thread metadata only, while plugins/platforms/telegram/adapter.py:3849-3853 refreshes typing when notify is absent.

Problems

  • The new guard in plugins/platforms/telegram/adapter.py would regress terminal stream sends. gateway/stream_consumer.py:242-247 marks final sends with notify=True, and its final-send paths at gateway/stream_consumer.py:1078-1082, 1173-1177, and 1541-1545 do not carry suppress_post_send_typing. They would now re-arm typing.
  • This also contradicts the existing regression contract in tests/gateway/test_telegram_format.py:217-230, which requires a notify=True final send not to invoke typing. The proposed notify-only test asserts the opposite.

Suggested changes

  • Keep the terminal metadata contract coherent: either preserve notify as the suppression signal and mark the footer accordingly, or propagate the new suppression flag through every terminal producer, starting with StreamConsumer._metadata_for_send(final=True).
  • Add a StreamConsumer-to-Telegram regression covering a streamed final/fallback send, not only the runner footer.

Automated hermes-sweeper review.

@alt-glitch alt-glitch added the comp/plugins Plugin system and bundled plugins label Jul 13, 2026
@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 13, 2026
@kuil09

kuil09 commented Jul 14, 2026

Copy link
Copy Markdown
Author

@teknium1 Thanks — that review was correct. I had over-tightened the adapter-side suppression rule and broken the existing terminal final-send contract that uses notify=True.

I pushed a follow-up commit to fix that:

  • preserved the existing notify=True => no post-send typing refresh behavior for terminal/final sends
  • kept the dedicated suppress_post_send_typing=True path for the streamed trailing-footer residual case
  • updated the focused regression coverage accordingly

Validation run locally after the change:

python -m pytest tests/gateway/test_telegram_post_send_typing.py \
  tests/gateway/test_telegram_footer_post_send_typing.py \
  tests/gateway/test_base_topic_sessions.py \
  tests/gateway/test_run_progress_topics.py \
  tests/gateway/test_telegram_format.py \
  tests/gateway/test_stream_consumer_thread_routing.py -q -o addopts=''

Result: 168 passed.

So the branch is now positioned as: keep the long-standing notify final-send suppression contract, and add the dedicated suppression flag only for the footer-specific residual path that #37556 still leaves behind.

@alt-glitch alt-glitch removed the sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades label Jul 14, 2026
@kuil09
kuil09 force-pushed the fix/telegram-final-typing branch from ac99923 to 3c3b904 Compare July 31, 2026 02:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins P2 Medium — degraded but workaround exists platform/telegram Telegram bot adapter sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants