fix(telegram): split oversized stream buffer mid-flight

Cherry-picked from #3311 (stutiredboy). Streaming edits called
edit_message_text(text=buf.text) without chunking, so once accumulated
deltas crossed Telegram's 4096-char limit an ongoing stream would fail
with BadRequest.

Extracts _flush_stream_overflow helper that edits the first chunk in
place, sends any middle chunks, and re-anchors the buffer to a new
message for the tail so subsequent deltas keep streaming.

Co-Authored-By: stutiredboy <stutiredboy@users.noreply.github.com>
This commit is contained in:
stutiredboy
2026-04-20 16:58:46 +08:00
committed by Xubin Ren
co-authored by stutiredboy
parent fd8f08cc83
commit 2eea82f5ee
2 changed files with 86 additions and 51 deletions
+33
View File
@@ -574,6 +574,39 @@ async def test_send_delta_incremental_edit_treats_not_modified_as_success() -> N
assert channel._stream_bufs["123"].last_edit > 0.0
@pytest.mark.asyncio
async def test_send_delta_incremental_edit_splits_oversized_buffer() -> None:
"""Mid-stream overflow: once buf.text exceeds Telegram's limit, split into
chunks, edit the current message with the first chunk, and re-anchor the
buffer to a new message for the tail so further deltas keep streaming."""
from nanobot.channels.telegram import TELEGRAM_MAX_MESSAGE_LEN
channel = TelegramChannel(
TelegramConfig(enabled=True, token="123:abc", allow_from=["*"]),
MessageBus(),
)
channel._app = _FakeApp(lambda: None)
channel._app.bot.edit_message_text = AsyncMock()
channel._app.bot.send_message = AsyncMock(return_value=SimpleNamespace(message_id=99))
oversized = "x" * (TELEGRAM_MAX_MESSAGE_LEN + 500)
channel._stream_bufs["123"] = _StreamBuf(
text=oversized, message_id=7, last_edit=0.0, stream_id="s:0"
)
await channel.send_delta("123", "y", {"_stream_delta": True, "_stream_id": "s:0"})
channel._app.bot.edit_message_text.assert_called_once()
edit_text = channel._app.bot.edit_message_text.call_args.kwargs.get("text", "")
assert len(edit_text) <= TELEGRAM_MAX_MESSAGE_LEN
channel._app.bot.send_message.assert_called_once()
buf = channel._stream_bufs["123"]
assert buf.message_id == 99
assert len(buf.text) <= TELEGRAM_MAX_MESSAGE_LEN
assert buf.last_edit > 0.0
@pytest.mark.asyncio
async def test_send_delta_initial_send_keeps_message_in_thread() -> None:
channel = TelegramChannel(