fix(gateway): route forum supergroup General topic messages by including 'supergroup' chat type (#13607)

Forum supergroups always have chat.type == SUPERGROUP in the Telegram API,
but the General topic fallback in _build_message_event() only checked for
chat_type == "group". While the current mapping happens to map SUPERGROUP
to "group", this is fragile — other methods (e.g. _is_group_chat) already
distinguish the two types, and any refactor to the mapping would silently
break General topic routing.

Extend the check to accept both "group" and "supergroup", and add a debug
log when the fallback fires to aid future diagnosis.
This commit is contained in:
Tranquil-Flow 2026-04-25 08:49:47 +10:00
parent 00c3d848d8
commit 027e054a17
2 changed files with 85 additions and 1 deletions

View file

@ -2989,8 +2989,12 @@ class TelegramAdapter(BasePlatformAdapter):
# Resolve DM topic name and skill binding
thread_id_raw = message.message_thread_id
thread_id_str = str(thread_id_raw) if thread_id_raw is not None else None
if chat_type == "group" and thread_id_str is None and getattr(chat, "is_forum", False):
if chat_type in ("group", "supergroup") and thread_id_str is None and getattr(chat, "is_forum", False):
thread_id_str = self._GENERAL_TOPIC_THREAD_ID
logger.debug(
"Forum %s message without thread_id — routing to General topic (thread=%s)",
chat_type, thread_id_str,
)
chat_topic = None
topic_skill = None

View file

@ -132,6 +132,86 @@ def test_forum_general_topic_without_message_thread_id_keeps_thread_context():
assert event.source.thread_id == "1"
def test_forum_group_general_topic_fallback():
"""Forum GROUP chat without thread_id should also fall back to General topic."""
from gateway.platforms import telegram as telegram_mod
adapter = _make_adapter()
message = SimpleNamespace(
text="hello from group forum General",
caption=None,
chat=SimpleNamespace(
id=-100999,
type=telegram_mod.ChatType.GROUP,
is_forum=True,
title="Group forum",
),
from_user=SimpleNamespace(id=789, full_name="Bob"),
message_thread_id=None,
reply_to_message=None,
message_id=20,
date=None,
)
event = adapter._build_message_event(message, msg_type=SimpleNamespace(value="text"))
assert event.source.chat_id == "-100999"
assert event.source.chat_type == "group"
assert event.source.thread_id == "1"
def test_forum_supergroup_with_thread_id_preserves_it():
"""Forum supergroup messages WITH a thread_id should keep the original value."""
from gateway.platforms import telegram as telegram_mod
adapter = _make_adapter()
message = SimpleNamespace(
text="hello from a named topic",
caption=None,
chat=SimpleNamespace(
id=-100123,
type=telegram_mod.ChatType.SUPERGROUP,
is_forum=True,
title="Forum group",
),
from_user=SimpleNamespace(id=456, full_name="Alice"),
message_thread_id=42,
reply_to_message=None,
message_id=30,
date=None,
)
event = adapter._build_message_event(message, msg_type=SimpleNamespace(value="text"))
assert event.source.thread_id == "42"
def test_non_forum_supergroup_without_thread_id_stays_none():
"""Non-forum supergroup messages without thread_id should NOT get General topic."""
from gateway.platforms import telegram as telegram_mod
adapter = _make_adapter()
message = SimpleNamespace(
text="hello from a regular supergroup",
caption=None,
chat=SimpleNamespace(
id=-100555,
type=telegram_mod.ChatType.SUPERGROUP,
is_forum=False,
title="Regular supergroup",
),
from_user=SimpleNamespace(id=456, full_name="Alice"),
message_thread_id=None,
reply_to_message=None,
message_id=40,
date=None,
)
event = adapter._build_message_event(message, msg_type=SimpleNamespace(value="text"))
assert event.source.thread_id is None
@pytest.mark.asyncio
async def test_send_omits_general_topic_thread_id():
"""Telegram sends to forum General should omit message_thread_id=1."""