From 4006ca072fb91dfc137e92caadc32cbaa652c480 Mon Sep 17 00:00:00 2001 From: FanouZeng-TT <124567600+FanouZeng-TT@users.noreply.github.com> Date: Wed, 30 Sep 2026 10:17:46 +0800 Subject: [PATCH] fix(channels): keep the delimiter newline when splitting long Discord replies (#6062) * fix(channels): preserve Discord split boundaries * test(channels): cover Discord split at leading remainder newline Signed-off-by: Willem Jiang --------- Signed-off-by: Willem Jiang Co-authored-by: Willem Jiang --- backend/app/channels/discord.py | 6 +++++- backend/tests/test_channels.py | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/backend/app/channels/discord.py b/backend/app/channels/discord.py index 35cf228406..32699216fb 100644 --- a/backend/app/channels/discord.py +++ b/backend/app/channels/discord.py @@ -876,8 +876,12 @@ class DiscordChannel(Channel): split_at = remaining.rfind("\n", 0, _DISCORD_MAX_MESSAGE_LEN) if split_at <= 0: split_at = _DISCORD_MAX_MESSAGE_LEN + else: + # Keep the delimiter on this chunk's tail so consecutive + # Discord messages reconstruct the original text exactly. + split_at += 1 chunks.append(remaining[:split_at]) - remaining = remaining[split_at:].lstrip("\n") + remaining = remaining[split_at:] if remaining: chunks.append(remaining) diff --git a/backend/tests/test_channels.py b/backend/tests/test_channels.py index f045a54e3c..5ffdfe6606 100644 --- a/backend/tests/test_channels.py +++ b/backend/tests/test_channels.py @@ -6131,6 +6131,30 @@ class TestHandleChatWithArtifacts: class TestDiscordChannel: + @pytest.mark.parametrize( + "text", + [ + "x" * 1990 + "\n\n" + "y" * 30, + "x" * 2000 + "\n\n\n" + "y" * 30, + "x" * 2000 + "\n" + "y" * 2000, + ("第一段\n\n" + "句" * 1990 + "\n\n最后一段") * 3, + "x" * 4500, + ], + ) + def test_split_text_preserves_content_within_discord_limit(self, text: str): + from app.channels.discord import _DISCORD_MAX_MESSAGE_LEN, DiscordChannel + + chunks = DiscordChannel._split_text(text) + + assert all(0 < len(chunk) <= _DISCORD_MAX_MESSAGE_LEN for chunk in chunks) + assert "".join(chunks) == text + + def test_split_text_preserves_empty_and_short_messages(self): + from app.channels.discord import DiscordChannel + + assert DiscordChannel._split_text("") == [""] + assert DiscordChannel._split_text("hello\n\nworld") == ["hello\n\nworld"] + def test_stop_prevents_queued_typing_starter_from_creating_task(self): from app.channels.discord import DiscordChannel