From 06bd7852c8919a26fc789f0f70f4730b012d8b4d Mon Sep 17 00:00:00 2001 From: 1cbyc Date: Fri, 25 Sep 2026 20:32:25 +0000 Subject: [PATCH] fix: send long Discord replies in chunks Co-authored-by: insisong --- taskuary/outbound.py | 6 +++++- tests/test_reply_channels.py | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/taskuary/outbound.py b/taskuary/outbound.py index 8d0b7821..a4132b26 100644 --- a/taskuary/outbound.py +++ b/taskuary/outbound.py @@ -604,11 +604,15 @@ def reply_to_message(store, msg: dict, body: str, to: list = None, cc: list = No connector_id = _source_connector_id(store, 'imessage', chat) return send_text(store, chat, body, connector_id) if connector_id else send_text(store, chat, body) if ch == 'discord': + from . import chatformat from .devtools import discord_send chat = str(msg.get('ConversationId') or '').split(':', 1)[-1] # 'discord:' if not chat: raise RuntimeError('this chat message has no channel id to answer in') connector_id = _source_connector_id(store, 'discord', chat) - return discord_send(store, chat, body, connector_id) if connector_id else discord_send(store, chat, body) + pieces = chatformat.split(body, 1900) + sent = [discord_send(store, chat, piece, connector_id) if connector_id else + discord_send(store, chat, piece) for piece in pieces] + return sent[0] if ch in CHAT_SERVERS: from . import chatservers chat = str(msg.get('ConversationId') or '').split(':', 1)[-1] # ':' diff --git a/tests/test_reply_channels.py b/tests/test_reply_channels.py index 6a462113..3b9ce21c 100644 --- a/tests/test_reply_channels.py +++ b/tests/test_reply_channels.py @@ -48,6 +48,30 @@ def test_case_and_blank_are_handled(self): self.assertFalse(outbound.can_reply(s, None)) +class DiscordReplyTests(unittest.TestCase): + def test_long_reply_is_sent_in_order_without_loss(self): + s = MemoryStore() + body = 'x' * 5000 + msg = {'Channel': 'discord', 'ConversationId': 'discord:555', 'ExternalId': 'discord:1'} + + with mock.patch('taskuary.devtools.discord_send', return_value={'channel': 'discord'}) as send: + outbound.reply_to_message(s, msg, body) + + pieces = [call.args[2] for call in send.call_args_list] + self.assertEqual(len(pieces), 3) + self.assertTrue(all(len(piece) <= 2000 for piece in pieces)) + self.assertEqual(''.join(pieces), body) + + def test_short_reply_is_sent_once_unchanged(self): + s = MemoryStore() + msg = {'Channel': 'discord', 'ConversationId': 'discord:555', 'ExternalId': 'discord:1'} + + with mock.patch('taskuary.devtools.discord_send', return_value={'channel': 'discord'}) as send: + outbound.reply_to_message(s, msg, 'On it.') + + send.assert_called_once_with(s, '555', 'On it.') + + class FinishTests(unittest.TestCase): """coder.finish is the truth, and the UI promises exactly what it did: a channel that cannot carry the reply still gets its draft (the always-draft rule, PW-237) - Send is hidden and the reason said."""