fix(telegram): make Bot API 10.1 rich messages opt-in (default off)

Rich messages are not ready for primetime: current Telegram clients can
render Bot API 10.1 rich messages as blank/unsupported bubbles and make
them hard to copy as plain text, which is worse than the legacy
MarkdownV2 path for command snippets and mobile handoffs. Default the
rich_messages toggle to False so replies stay on the copyable legacy
path; users opt in per bot via platforms.telegram.extra.rich_messages:
true. Updates adapter, gateway config default, example config, English +
zh-Hans docs, and the default/opt-in tests.
This commit is contained in:
kn8-codes 2026-06-21 11:37:44 -07:00 committed by Teknium
parent 3b56d3a29a
commit 6183e8ce1b
7 changed files with 44 additions and 17 deletions

View file

@ -881,7 +881,7 @@ class TestLoadGatewayConfig:
assert config.platforms[Platform.TELEGRAM].extra["rich_messages"] is False
def test_load_config_default_enables_telegram_rich_messages(self, tmp_path, monkeypatch):
def test_load_config_default_keeps_telegram_rich_messages_opt_in(self, tmp_path, monkeypatch):
hermes_home = tmp_path / ".hermes"
hermes_home.mkdir()
@ -891,7 +891,7 @@ class TestLoadGatewayConfig:
config = load_config()
assert config["telegram"]["extra"]["rich_messages"] is True
assert config["telegram"]["extra"]["rich_messages"] is False
def test_bridges_telegram_extra_base_url_from_config_yaml(self, tmp_path, monkeypatch):
hermes_home = tmp_path / ".hermes"

View file

@ -210,10 +210,10 @@ async def test_rich_messages_opt_out_accepts_string_false():
@pytest.mark.asyncio
async def test_rich_messages_default_is_enabled():
"""Rich messages are on by default (Bot API 10.1); rich-eligible content
(tables/task lists/details/math) goes through sendRichMessage without the
user having to opt in."""
async def test_rich_messages_default_is_legacy_copyable_path():
"""Rich messages stay opt-in because current Telegram clients can make
Bot API rich messages hard to copy as plain text. Rich-eligible content
defaults to the legacy MarkdownV2 path unless the user opts in."""
config = PlatformConfig(enabled=True, token="fake-token")
adapter = TelegramAdapter(config)
bot = MagicMock()
@ -224,6 +224,29 @@ async def test_rich_messages_default_is_enabled():
result = await adapter.send("12345", RICH_CONTENT)
assert result.success is True
bot = adapter._bot
assert bot is not None
bot.do_api_request.assert_not_called()
bot.send_message.assert_awaited()
@pytest.mark.asyncio
async def test_rich_messages_can_be_opted_in():
"""Setting platforms.telegram.extra.rich_messages: true enables native
Bot API rich rendering for tables/task lists/details/math."""
config = PlatformConfig(
enabled=True, token="fake-token", extra={"rich_messages": True}
)
adapter = TelegramAdapter(config)
bot = MagicMock()
bot.do_api_request = AsyncMock(return_value=SimpleNamespace(message_id=123))
bot.send_message = AsyncMock(return_value=MagicMock(message_id=1))
bot.send_chat_action = AsyncMock()
adapter._bot = bot
result = await adapter.send("12345", RICH_CONTENT)
assert result.success is True
bot = adapter._bot
assert bot is not None