docs/plans/2026-06-09-003-fix-telegram-stream-overflow-continuations-plan.md
Fix a Telegram gateway bug where a long streamed assistant reply can appear to stop mid-answer in a topic after the first overflow chunk. The reported screenshot shows a long Hermes response in the Nehemiah - Coding Telegram topic ending at - The visible tool-call summary, followed by the user noting that the previous message did not finish streaming to that Telegram topic.
The plan targets the streamed edit overflow path, not general model generation. A completed assistant response must either reach Telegram in full across all continuation messages or leave enough state for the gateway fallback path to deliver the remaining content instead of marking the turn complete after a partial delivery.
Telegram limits message text to 4096 UTF-16 code units. Hermes streams gateway responses by editing a message and, when a streamed message grows past the limit, splitting the overflow into additional Telegram messages. The adapter already has a split-and-deliver path for oversized edits, but the partial-continuation failure contract is weak: if chunk 1 is edited successfully and a later continuation fails, the adapter can still report success for the operation. The stream consumer may then mark the final response delivered even though the visible topic only contains the first part.
This is especially visible in Telegram forum topics because a long final response can be split below tool-progress bubbles, and a missing continuation looks exactly like the stream stopped mid-answer.
_edit_overflow_split should only return a successful final-delivery result when every planned chunk reaches Telegram. Partial delivery is a distinct outcome that downstream code can recover from.SendResult.raw_response rather than adding a new public dataclass field unless implementation proves the existing result shape is insufficient. The stream consumer already inspects SendResult after adapter edits, so a small raw response contract can keep the change contained._final_response_sent, _final_content_delivered, _fallback_prefix, and fallback final-send behaviour._thread_kwargs_for_send(...) with metadata-derived message_thread_id and reply anchors so forum topic behaviour stays consistent.sequenceDiagram
participant C as GatewayStreamConsumer
participant T as TelegramAdapter.edit_message
participant B as Telegram Bot API
C->>T: finalize/edit long accumulated response
T->>B: edit original message with chunk 1
loop remaining chunks
T->>B: send continuation in same topic/thread
end
alt all chunks delivered
T-->>C: success, last message id, continuation ids
C->>C: mark final response delivered
else any continuation failed
T-->>C: partial overflow failure with delivered prefix metadata
C->>C: do not mark final delivered
C->>B: fallback sends missing tail or full final response safely
end
Goal: Make TelegramAdapter._edit_overflow_split distinguish complete overflow delivery from partial delivery.
Requirements: R1, R2, R4
Dependencies: None
Files:
gateway/platforms/telegram.pytests/gateway/test_telegram_send.py or the existing Telegram adapter test module that already covers edit_message overflow behaviourApproach:
SendResult(success=True, message_id=<last chunk>, continuation_message_ids=(...)).success=False, retryable=True, and raw_response metadata such as delivered chunk count, total chunk count, last delivered message id, and the visible delivered prefix.Patterns to follow:
TelegramAdapter.edit_message and _edit_overflow_split.SendResult semantics in gateway/platforms/base.py, especially retryable, raw_response, and continuation_message_ids.Test scenarios:
Verification: Adapter tests prove complete overflow remains successful and partial overflow is observable by the caller.
Goal: Ensure a partial Telegram overflow does not set _final_response_sent or _final_content_delivered unless the full response reached the user.
Requirements: R1, R2, R4, R5
Dependencies: U1
Files:
gateway/stream_consumer.pytests/gateway/test_stream_consumer.py or a focused new tests/gateway/test_stream_consumer_telegram_overflow.pyApproach:
_send_or_edit, when adapter.edit_message(...) returns a partial-overflow failure, update consumer state to reflect the last visible prefix/message and enter fallback delivery for the missing content._already_sent as final delivery. A partial visible message can be true while final delivery is false._send_fallback_final(...) sends only the missing tail. If implementation finds the prefix is unreliable after Markdown formatting, prefer sending the complete final response as a fresh fallback message rather than silently dropping the tail.continuation_message_ids when the adapter delivered all chunks.Patterns to follow:
GatewayStreamConsumer._send_or_edit and _send_fallback_final._final_response_sent, _final_content_delivered, and _fallback_prefix for prior partial-delivery regressions.Test scenarios:
Verification: Stream consumer tests reproduce the screenshot shape by simulating first chunk visible and continuation failure, then assert the final answer is not suppressed.
Goal: Ensure overflow recovery messages land in the same Telegram forum topic or DM topic fallback context.
Requirements: R3
Dependencies: U1, U2
Files:
gateway/platforms/telegram.pygateway/stream_consumer.pytests/gateway/test_stream_consumer_thread_routing.pyApproach:
metadata through every overflow continuation and fallback send.message_thread_id for normal forum topics.Patterns to follow:
TelegramAdapter._thread_kwargs_for_send(...).Test scenarios:
message_thread_id for a forum topic.reply message not found keeps forum topic routing when allowed.Verification: Thread-routing assertions inspect fake bot calls and confirm all continuation/fallback messages carry the expected topic metadata.
Goal: Make the upstream issue and PR clearly trace the user-visible bug and verification evidence.
Requirements: R5
Dependencies: U1, U2, U3
Files:
gh issue create.github/PULL_REQUEST_TEMPLATE.mdApproach:
Nehemiah - Coding Telegram topic stops at - The visible tool-call summary, and the user's reply says the previous message did not finish streaming to that Telegram topic.Fixes #..., describe the split-delivery contract change, and include the screenshot or attach it if GitHub upload is available.CONTRIBUTING.md and the repository PR template exactly.Patterns to follow:
.github/ISSUE_TEMPLATE/bug_report.yml.github/PULL_REQUEST_TEMPLATE.mdTest scenarios:
Verification: The GitHub issue exists with screenshot evidence or an explicit screenshot reference, and the PR body links the issue and lists the tests run.
run_agent.py.message_thread_id and reply behaviour./root/.hermes/image_cache/img_f664e68f6ddf.jpg.gateway/stream_consumer.py streamed edit, overflow, fallback, and final-delivery state handling.gateway/platforms/telegram.py Telegram send/edit overflow splitting and topic routing helpers.gateway/platforms/base.py SendResult contract and shared message chunking helper.tests/gateway/test_stream_consumer.py, tests/gateway/test_stream_consumer_thread_routing.py, and Telegram adapter tests for focused regression coverage.git diff contains only the plan, implementation, tests, and PR/issue-relevant documentation for this bug.