fix(telegram): streamed overflow finals lost under flood control are silently marked delivered - #70740
Conversation
Sibling production reproduction: final send suppressed after max-iteration fallbackWe observed a related Telegram delivery failure after a long agent run exhausted its iteration budget:
The user reported that the bot stopped without a usable final response. No Telegram The final response was below Telegram's normal 4,096-character message limit, so this appears to be a sibling false-positive delivery-state path, not only an overflow-final case. It may be worth ensuring that the final-delivery suppression decision verifies that the complete finalized response—not merely a streamed preview/progress message—was actually delivered. Operational workaround used locally: |
|
Thanks for the careful investigation and focused regressions. Automated hermes-sweeper review found this delivery guarantee is already implemented on current
The PR's outcome—preventing a clipped preview from being silently treated as completed delivery—is therefore already provided on main. |
Summary
When a streamed Telegram final response overflows the 4096-char limit and the final split then hits flood control (429), the gateway falsely concludes the message was fully delivered. The user sees only the truncated
(1/2)preview; the(2/2)chunk is silently lost, no retry fires, and the delivery-obligation ledger (#67181) never engages.Root cause
truncate_message(...)[0]— only the visible first chunk — but returnssuccess=Truewithout reporting the truncated text.GatewayStreamConsumertherefore records the full oversized input in_last_sent_text, even though Telegram only displayed chunk 1._visible_prefix() == final_text, falsely sets_final_content_delivered=True, and suppresses both fallback delivery and the ledger obligation.Observed in production (0.19.0,
3ef6bbd20): a 4,681-char response delivered(1/2)only;gateway.runloggedcontent_delivered=Truewhiledelivery_obligationsheld no row for the session, so the loss was silent and unrecoverable.Fix
The Telegram adapter now reports
raw_response["delivered_text"]for truncated/deduplicated streaming previews, and the stream consumer records what actually landed rather than what was submitted. A flood-controlled final split therefore enters full fallback delivery instead of declaring a clipped preview complete.Changed:
gateway/platforms/base.py,gateway/stream_consumer.py,plugins/platforms/telegram/adapter.py, plus focused regressions intests/gateway/test_stream_consumer_fresh_final.pyandtests/gateway/test_telegram_format.py.Verification
final_response_sent=Trueandfinal_content_delivered=True.🤖 Generated with Claude Code