diff --git a/plugins/platforms/telegram/adapter.py b/plugins/platforms/telegram/adapter.py index 1642ee039e..464ee389fc 100644 --- a/plugins/platforms/telegram/adapter.py +++ b/plugins/platforms/telegram/adapter.py @@ -2363,15 +2363,10 @@ class TelegramAdapter(BasePlatformAdapter): "message_id": int(message_id), "rich_message": self._rich_message_payload(content), } - thread_id = self._metadata_thread_id(metadata) - thread_kwargs = self._thread_kwargs_for_send( - chat_id, - thread_id, - metadata, - reply_to_message_id=None, - reply_to_mode=self._reply_to_mode, - ) - payload.update({k: v for k, v in thread_kwargs.items() if v is not None}) + # Edits target an existing message by chat_id + message_id. Topic + # routing belongs only on send endpoints; forwarding message_thread_id + # or direct_messages_topic_id makes Telegram reject this rich edit and + # sends the caller through the legacy table-to-bullets fallback. if getattr(self, "_disable_link_previews", False): payload["link_preview_options"] = {"is_disabled": True} try: diff --git a/tests/gateway/test_telegram_rich_messages.py b/tests/gateway/test_telegram_rich_messages.py index 1e895eee69..932bce1827 100644 --- a/tests/gateway/test_telegram_rich_messages.py +++ b/tests/gateway/test_telegram_rich_messages.py @@ -677,6 +677,41 @@ async def test_finalize_edit_uses_rich_for_table_content(): adapter._bot.delete_message.assert_not_called() +@pytest.mark.asyncio +async def test_finalize_edit_dm_topic_omits_send_only_routing_fields(): + """DM-topic metadata must not make a rich edit look like a new send. + + Telegram identifies an edit by chat_id + message_id. Passing topic-routing + fields on editMessageText rejects the rich request, after which the legacy + formatter permanently rewrites the table into bullet groups. + """ + adapter = _make_adapter() + + async def _api(endpoint, api_kwargs=None, **kwargs): + assert endpoint == "editMessageText" + has_send_routing = ( + "message_thread_id" in api_kwargs + or "direct_messages_topic_id" in api_kwargs + ) + if has_send_routing: + raise BadRequest("unexpected topic routing on editMessageText") + return True + + adapter._bot.do_api_request = AsyncMock(side_effect=_api) + + result = await adapter.edit_message( + "12345", "555", TOPIC_TABLE, finalize=True, metadata=TOPIC_METADATA, + ) + + assert result.success is True + api_kwargs = _rich_edit_kwargs(adapter) + assert api_kwargs["message_id"] == 555 + assert "message_thread_id" not in api_kwargs + assert "direct_messages_topic_id" not in api_kwargs + assert "| F1 |" in api_kwargs["rich_message"]["markdown"] + adapter._bot.edit_message_text.assert_not_called() + + @pytest.mark.asyncio async def test_legacy_edit_error_logs_redacted_bot_token_without_traceback(monkeypatch, caplog): import agent.redact as redact