refactor(telegram): make typing thread-id resolver symmetric with send

Mirror _message_thread_id_for_typing() with _message_thread_id_for_send():
both now map the General forum topic (thread id "1") to None upfront.

That removes the need for the retry-without-thread fallback in send_typing()
entirely — if _message_thread_id_for_typing() returns a non-None value, it's
a real user-created topic and falling back to the root chat is never correct.
If Telegram rejects the typing action (e.g. topic deleted mid-session), we
swallow it at debug level instead of bleeding the indicator into All Messages.

Updates the General-topic typing regression test to assert the new single-call
contract.
This commit is contained in:
Teknium 2026-05-05 13:27:27 -07:00
parent 41545f7ec5
commit d5357f816d
2 changed files with 21 additions and 22 deletions

View file

@ -159,22 +159,24 @@ async def test_send_omits_general_topic_thread_id():
@pytest.mark.asyncio
async def test_send_typing_retries_without_general_thread_when_not_found():
"""Typing for forum General should fall back if Telegram rejects thread 1."""
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.
_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.
"""
adapter = _make_adapter()
call_log = []
async def mock_send_chat_action(**kwargs):
call_log.append(dict(kwargs))
if kwargs.get("message_thread_id") == 1:
raise FakeBadRequest("Message thread not found")
adapter._bot = SimpleNamespace(send_chat_action=mock_send_chat_action)
await adapter.send_typing("-100123", metadata={"thread_id": "1"})
assert call_log == [
{"chat_id": -100123, "action": "typing", "message_thread_id": 1},
{"chat_id": -100123, "action": "typing", "message_thread_id": None},
]