diff --git a/tests/tools/test_send_message_tool.py b/tests/tools/test_send_message_tool.py index 3b2c0899158..48003f410a8 100644 --- a/tests/tools/test_send_message_tool.py +++ b/tests/tools/test_send_message_tool.py @@ -742,6 +742,64 @@ class TestSendTelegramHtmlDetection: sleep_mock.assert_awaited_once() +class TestSendTelegramThreadIdMapping: + """General-topic mapping in _send_telegram (issue #22267). + + Telegram forum supergroups address the General topic as + ``message_thread_id="1"`` on incoming updates, but the Bot API rejects + sends with ``message_thread_id=1`` ("Message thread not found"). The + gateway adapter's ``_message_thread_id_for_send`` helper maps "1" to + ``None`` for that reason; the standalone ``_send_telegram`` helper used + by the ``send_message`` tool needs the same mapping. + """ + + def _make_bot(self): + bot = MagicMock() + bot.send_message = AsyncMock(return_value=SimpleNamespace(message_id=1)) + return bot + + def test_general_topic_thread_id_omitted(self, monkeypatch): + """thread_id="1" must be dropped before calling the Bot API.""" + bot = self._make_bot() + _install_telegram_mock(monkeypatch, bot) + + asyncio.run(_send_telegram("tok", "-1001234567890", "hello", thread_id="1")) + + bot.send_message.assert_awaited_once() + kwargs = bot.send_message.await_args.kwargs + assert "message_thread_id" not in kwargs + + def test_non_general_topic_thread_id_preserved(self, monkeypatch): + """Real forum-topic thread ids (>1) still pass through as ints.""" + bot = self._make_bot() + _install_telegram_mock(monkeypatch, bot) + + asyncio.run(_send_telegram("tok", "-1001234567890", "hello", thread_id="17585")) + + kwargs = bot.send_message.await_args.kwargs + assert kwargs["message_thread_id"] == 17585 + + def test_no_thread_id_no_kwarg(self, monkeypatch): + """With no thread_id, message_thread_id must not appear in kwargs.""" + bot = self._make_bot() + _install_telegram_mock(monkeypatch, bot) + + asyncio.run(_send_telegram("tok", "-1001234567890", "hello")) + + kwargs = bot.send_message.await_args.kwargs + assert "message_thread_id" not in kwargs + + def test_general_topic_thread_id_int_input_also_dropped(self, monkeypatch): + """thread_id passed as the int 1 (not str) must still be dropped.""" + bot = self._make_bot() + _install_telegram_mock(monkeypatch, bot) + + asyncio.run(_send_telegram("tok", "-1001234567890", "hello", thread_id=1)) + + kwargs = bot.send_message.await_args.kwargs + assert "message_thread_id" not in kwargs + + # --------------------------------------------------------------------------- # Tests for Discord thread_id support # --------------------------------------------------------------------------- diff --git a/tools/send_message_tool.py b/tools/send_message_tool.py index 380208d429e..5199bca67a0 100644 --- a/tools/send_message_tool.py +++ b/tools/send_message_tool.py @@ -710,7 +710,27 @@ async def _send_telegram(token, chat_id, message, media_files=None, thread_id=No media_files = media_files or [] thread_kwargs = {} if thread_id is not None: - thread_kwargs["message_thread_id"] = int(thread_id) + # Reuse the gateway adapter's General-topic mapping: in Telegram + # forum supergroups, the General topic is addressed as + # message_thread_id="1" on incoming updates, but Bot API + # sendMessage rejects message_thread_id=1 with "Message thread + # not found". The adapter's helper maps "1" to None for that + # reason; the send_message tool needs the same mapping or a + # send to a forum group's General topic always errors out + # (see issue #22267). + try: + from gateway.platforms.telegram import TelegramAdapter + effective_thread_id = TelegramAdapter._message_thread_id_for_send( + str(thread_id) + ) + except Exception: + # Fallback: explicit mapping in case the adapter import + # fails (e.g. python-telegram-bot missing in this venv). + effective_thread_id = ( + None if str(thread_id) == "1" else int(thread_id) + ) + if effective_thread_id is not None: + thread_kwargs["message_thread_id"] = effective_thread_id if disable_link_previews: thread_kwargs["disable_web_page_preview"] = True