Skip to content

fix(telegram): stabilize streamed overflow markdown delivery - #52933

Closed
mrapac wants to merge 1 commit into
NousResearch:mainfrom
mrapac:fix/telegram-streamed-overflow-markdown-v2
Closed

fix(telegram): stabilize streamed overflow markdown delivery#52933
mrapac wants to merge 1 commit into
NousResearch:mainfrom
mrapac:fix/telegram-streamed-overflow-markdown-v2

Conversation

@mrapac

@mrapac mrapac commented Jun 26, 2026

Copy link
Copy Markdown

Bug Description

Long streamed Telegram replies could surface a lossy partial message before the clean final delivery completed.

In end-to-end testing this showed up as one or more of the following:

  • the prefix of a long reply being duplicated
  • the first visible chunk arriving as plain text while a later chunk was correctly formatted
  • a long reply being split into multiple messages where the first lost Markdown and the later one was correct

This was most noticeable on richly formatted responses that crossed Telegram's legacy edit limit and exercised overflow-split and retry / flood-control paths.

Root Cause

Several related delivery paths treated transient send/edit failures too similarly to real Markdown parse failures:

  1. partial-overflow handling could preserve and reuse an already-lossy prefix
  2. finalize-time MarkdownV2 fallback could downgrade to plain text on retry/flood-control style failures instead of reserving that fallback for true parse/entity errors
  3. overflow-split delivery had a parallel downgrade path that could still emit an unformatted first chunk under RetryAfter / flood-control conditions
  4. preview/final coordination around overflow could leave an extra visible partial message before clean final delivery

The net effect was that temporary delivery problems could become user-visible formatting loss.

Fix

This change narrows Telegram fallback behavior so long streamed replies fail more safely and consistently.

  • track lossy partial-overflow state and avoid reusing an unreliable prefix during final fallback delivery
  • freeze preview / prefer clean final delivery once streamed overflow reaches an unsafe edit boundary
  • only downgrade MarkdownV2 to plain text for real markdown/entity parse failures
  • do not downgrade to plain text on RetryAfter, flood-control, or other transient delivery failures
  • apply the same downgrade rule to both the normal finalize-edit path and the overflow-split path
  • add regression coverage for stream-consumer gating, overflow partial handling, and Telegram rich-message finalization behavior

How to Verify

  1. Run Hermes through the Telegram gateway.
  2. Send a prompt that produces a long, richly formatted response (for example: lists, code blocks, quotes, and tables).
  3. Confirm that:
    • the prefix is not duplicated
    • the first visible chunk is not downgraded to plain text
    • if Telegram splits the response, formatting remains consistent across parts
  4. Repeat with a response long enough to exercise overflow-split behavior.
  5. Repeat under conditions that trigger RetryAfter / flood-control delays and confirm they do not emit a plain-text first chunk.

Test Plan

  • Added regression tests for this bug class
  • Existing tests still pass
  • Manual verification of the fix

Manual / local verification completed:

  • python -m compileall on the touched gateway, adapter, and test files
  • targeted local regression harnesses for stream-consumer and Telegram overflow behavior
  • real end-to-end Telegram verification with multiple long formatted responses

Note: the full pytest suite was not available in the local Hermes venv used during debugging because pytest was not installed there.

Risk Assessment

Low to Medium — the change is scoped to Telegram long-message streaming, overflow handling, and markdown/plain-text fallback decisions. The main regression risk is in Telegram-specific long-form delivery rather than the wider gateway.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery platform/telegram Telegram bot adapter sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Jun 26, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for targeting a real Telegram delivery failure. The current main still unconditionally downgrades MarkdownV2 failures to plain text in both the final-edit path (plugins/platforms/telegram/adapter.py:4020) and overflow split path (plugins/platforms/telegram/adapter.py:4197, 4297).

Problems

  • The PR's stream-cap changes conflict with the newer design in 4f67ba88: current gateway/stream_consumer.py:1458 only permits Telegram's raised rich-message cap for native draft streaming, keeping edit streams at the legacy cap to avoid repeated overflow delivery.

Suggested changes

  • Salvage the transient-error classifier and lossy-prefix handling into the current adapter paths, but retain the current legacy-cap/draft gate and final-flood recovery (gateway/stream_consumer.py:1871).
  • Cover RetryAfter and transient network errors against those current paths, alongside a real Markdown parse failure that still uses the plain-text fallback.

Automated hermes-sweeper review.

@teknium1 teknium1 added the sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform label Jul 15, 2026
@mrapac

mrapac commented Jul 15, 2026

Copy link
Copy Markdown
Author

Thanks — I updated the branch to keep the current stream consumer gating intact and focused the fix on the adapter overflow paths. I also preserved RetryAfter details in overflow continuation failures, and verified the targeted gateway tests pass locally.

@teknium1 teknium1 added the area/streaming Streaming responses: gateway delivery, provider wire label Jul 19, 2026
@mrapac

mrapac commented Jul 19, 2026

Copy link
Copy Markdown
Author

Resolved the merge conflict with current main and pushed the updated branch.

The resolution keeps both sides of the recent gateway changes:

  • preserves the streamed-overflow partial/fallback behavior from this PR,
  • keeps current main's fallback flood-retry and rich-message redaction updates.

Verification after the merge:

  • scripts/run_tests.sh tests/gateway/test_telegram_overflow_partial.py tests/gateway/test_telegram_rich_messages.py -q81 tests passed, 0 failed

@mrapac
mrapac force-pushed the fix/telegram-streamed-overflow-markdown-v2 branch from 91b0cd8 to 431e580 Compare August 2, 2026 15:24
@mrapac

mrapac commented Aug 2, 2026

Copy link
Copy Markdown
Author

Updated this branch onto current main and resolved the test-only conflicts while keeping the PR scoped to the existing Telegram streaming/overflow recovery paths.

Scope is still the intended 4 files:

gateway/stream_consumer.py
plugins/platforms/telegram/adapter.py
tests/gateway/test_telegram_overflow_partial.py
tests/gateway/test_telegram_rich_messages.py

Verification on the refreshed branch:

scripts/run_tests.sh tests/gateway/test_telegram_overflow_partial.py tests/gateway/test_telegram_rich_messages.py -q
→ 36 tests passed, 0 failed

One small test-conflict cleanup was included in test_telegram_rich_messages.py: the redaction regression now uses an unredacted fake Bot API token in the input fixture so the assertion actually proves redaction instead of comparing against a pre-redacted *** string.

GitHub now reports the PR as mergeable again.

@mrapac

mrapac commented Aug 7, 2026

Copy link
Copy Markdown
Author

Closing this PR because upstream v0.20.0 has addressed the split-delivery / overflow bug class more comprehensively. Specifically:

  • 392e3a8c5 — "finish the split-delivery bug class so the fix cannot duplicate or still swallow" — fixes 6 code paths that set _turn_split_delivery, where this PR covered 2-3
  • 30878411b — "stop stale streamed finalize from suppressing the complete Telegram response"
  • c46027b04 — "stop payload-less split delivery from swallowing finals"
  • 68ebb198c — "don't claim deleted head chunks as delivered in the empty-fallback recovery"
  • bd93ccb89 — shared fence-aware markdown chunker core
  • 240afd0b7 — batch near-limit command chunks

Together these root-cause the duplicate/swallow/markdown-formatting issues across the full gateway split-delivery surface, where this PR took a more targeted approach. The one residual edge case — flood-controlled turn-final edits leaving a raw streaming preview on screen — we're carrying as a small local commit (_fallback_lossy_prefix flag, ~15 lines) for now.

Thanks for the review time, and great work on the v0.20.0 gateway overhaul!

@mrapac mrapac closed this Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/streaming Streaming responses: gateway delivery, provider wire comp/gateway Gateway runner, session dispatch, delivery 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.

3 participants