fix(telegram): preserve thread_id=1 for forum General typing indicator (#21390)

The May 5 refactor in d5357f816 made _message_thread_id_for_typing()
symmetric with _message_thread_id_for_send() by mapping the General
topic (thread id "1") to None upfront for both. That's correct for
sendMessage — Telegram rejects message_thread_id=1 on sends and the
topic must be omitted — but it's wrong for sendChatAction.

Observed behavior (confirmed via before/after Telegram wire traces):
  Before d5357f816: thread_id=1 → message_thread_id=1 → bubble visible in General
  After  d5357f816: thread_id=1 → message_thread_id=None → no visible typing

Omitting message_thread_id on sendChatAction does NOT fall back to
the General topic's view in a forum-enabled supergroup; the bubble
ends up hidden from the client's General-topic pane entirely. For
any user on a forum-group, the typing indicator stopped appearing.

Fix: drop the symmetric "1 → None" mapping from the typing resolver.
sendMessage still maps 1 → None via _message_thread_id_for_send (that
side was never broken). The asymmetry is real and required by
Telegram's API — document it in the resolver docstring.

Partial revert of d5357f816; restores the behavior from 0cf7d570e
("fix(telegram): restore typing indicator and thread routing for
forum General topic"). Does not re-introduce the retry-without-thread
fallback that 41545f7ec scoped down for DM topics — with the resolver
fixed, the first call already hits the right wire shape.

Test updated from test_send_typing_general_topic_uses_none_thread_id
(which encoded the broken contract) to
test_send_typing_preserves_general_topic_thread_id, asserting the
single correct call with message_thread_id=1. 10 other tests in the
file untouched and passing.
This commit is contained in:
Teknium 2026-05-07 08:39:21 -07:00 committed by GitHub
parent 812ce0b987
commit 2564132a1f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 19 additions and 10 deletions

View file

@ -159,12 +159,17 @@ async def test_send_omits_general_topic_thread_id():
@pytest.mark.asyncio
async def test_send_typing_general_topic_uses_none_thread_id():
"""Typing for forum General should hit the API with message_thread_id=None directly.
async def test_send_typing_preserves_general_topic_thread_id():
"""Typing for forum General must send message_thread_id=1, not None.
_message_thread_id_for_typing() maps the General topic (thread id "1") to None
the same way _message_thread_id_for_send() does, so there's no retry path — the
first call is already correct.
Asymmetric with _message_thread_id_for_send: sendMessage rejects
message_thread_id=1, but sendChatAction needs it to scope the typing
bubble to the General topic. Omitting it (message_thread_id=None) hides
the bubble from the General-topic view entirely.
Regression guard for the d5357f816 refactor that mapped "1" None in
the typing resolver and silently killed typing indicators in every
forum-group General topic.
"""
adapter = _make_adapter()
call_log = []
@ -177,7 +182,7 @@ async def test_send_typing_general_topic_uses_none_thread_id():
await adapter.send_typing("-100123", metadata={"thread_id": "1"})
assert call_log == [
{"chat_id": -100123, "action": "typing", "message_thread_id": None},
{"chat_id": -100123, "action": "typing", "message_thread_id": 1},
]