Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions tests/tools/test_send_message_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,64 @@ def test_transient_bad_gateway_retries_text_send(self, monkeypatch):
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
# ---------------------------------------------------------------------------
Expand Down
22 changes: 21 additions & 1 deletion tools/send_message_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading