mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-24 05:41:40 +00:00
fix(send_message): map Telegram General topic id to None for forum groups (#22423)
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 has a `_message_thread_id_for_send` helper that maps
"1" to None for that reason; the standalone `_send_telegram` helper
used by the `send_message` tool never got the same mapping, so any
`send_message` call to a Topics-enabled group's General topic
(target shape `telegram:<chat_id>:1`) failed with "Message thread
not found."
Reuse the adapter's helper when available, with an explicit fallback
to the same mapping for environments where the adapter import path
fails (e.g. python-telegram-bot missing in this venv).
Fixes #22267
This commit is contained in:
parent
8fb3e2d63a
commit
ae005ec588
2 changed files with 79 additions and 1 deletions
|
|
@ -742,6 +742,64 @@ class TestSendTelegramHtmlDetection:
|
||||||
sleep_mock.assert_awaited_once()
|
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
|
# Tests for Discord thread_id support
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -710,7 +710,27 @@ async def _send_telegram(token, chat_id, message, media_files=None, thread_id=No
|
||||||
media_files = media_files or []
|
media_files = media_files or []
|
||||||
thread_kwargs = {}
|
thread_kwargs = {}
|
||||||
if thread_id is not None:
|
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:
|
if disable_link_previews:
|
||||||
thread_kwargs["disable_web_page_preview"] = True
|
thread_kwargs["disable_web_page_preview"] = True
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue