fix(send_message_tool): add sendRichMessage fast-path for Telegram - #46118
fix(send_message_tool): add sendRichMessage fast-path for Telegram#46118michaeltanyk wants to merge 2 commits into
Conversation
…ch sends The _send_telegram function bypasses the gateway's rich message path entirely by creating a raw Bot and calling sendMessage with MarkdownV2. Tables, task lists, math, and other rich constructs always degrade to bulleted lists when sent via the send_message tool. This adds a sendRichMessage fast-path via bot.do_api_request before the MarkdownV2 fallback. On any failure the existing MarkdownV2 path runs as before — purely additive. The _RichMsg helper class wraps the message_id from sendRichMessage responses so the rest of the return-value pipeline works unchanged. Related: NousResearch#45741 (original rich message implementation)
|
**Performance: Version: ImageMagick 7.1.2-8 Q16-HDRI aarch64 23412 https://imagemagick.org Image Settings: Image Operators: Miscellaneous Options: By default, 'file' is written in the MIFF image format. To The rich-path guard does Move it to the top of the file: import inspect # module-levelThen the hot-path check becomes just: if inspect.iscoroutinefunction(getattr(bot, "do_api_request", None)):Everything else looks solid — clean fallback to legacy MarkdownV2 on any failure, correct scoping inside |
Per PR review — the inline inside _send_telegram hits the import lock and sys.modules walk on every message send. Move to module-level import.
|
Good catch — moved |
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved
Adds sendRichMessage fast-path for Telegram in send_message_tool, avoiding the generic JSON path.
Looks Good
- Clean targeted optimization for Telegram platform.
- No impact on other platforms.
Reviewed by Hermes Agent
teknium1
left a comment
There was a problem hiding this comment.
Thanks for identifying a real standalone-send gap. Current main still routes Telegram send_message through tools/send_message_tool.py:849-859 and _send_telegram, whose text loop uses bot.send_message at tools/send_message_tool.py:1228-1246.
Problems
- The proposed fast path sends every non-HTML body as rich. Current adapter policy intentionally limits rich delivery to qualifying constructs and skips known unsafe shapes in
plugins/platforms/telegram/adapter.py:1393-1462. - The proposed catch-all fallback can duplicate delivery after a timeout or other transient failure. The current rich path specifically returns such failures without a legacy resend in
plugins/platforms/telegram/adapter.py:1545-1691. - The raw payload omits the current line-break normalization and successful-send reply index used by
plugins/platforms/telegram/adapter.py:1506-1521and:1700-1707.
Suggested changes
- Share or extract the adapter's eligibility, payload, error-classification, and rich-send recording behavior for the standalone sender.
- Add standalone-path coverage for successful rich delivery, permanent fallback, transient no-resend, and the configured safety gates.
Automated hermes-sweeper review.
| # sendRichMessage preserves tables, task lists, math, etc. | ||
| # Falls through to legacy MarkdownV2 on any failure. | ||
| _rich_ok = False | ||
| if not _has_html and message.strip() and len(message) <= 32768: |
There was a problem hiding this comment.
Please do not route every non-HTML body through rich delivery. Current Telegram policy only selects qualifying rich constructs and also skips known unsafe details+math/CJK shapes (plugins/platforms/telegram/adapter.py:1393-1462); this standalone path needs to preserve those gates and the rich_messages configuration.
| if rich_msg_id is not None: | ||
| last_msg = _RichMsg(rich_msg_id) | ||
| _rich_ok = True | ||
| except Exception: |
There was a problem hiding this comment.
This catch-all fallback can duplicate a message when the rich request times out after Telegram accepted it. The adapter only falls back for permanent/capability failures and returns transient failures without a legacy resend (plugins/platforms/telegram/adapter.py:1545-1691). Please share that classification here.
|
Thanks for the review. I worked with my AI agent on the initial PR, but the plugin migration changes you've outlined are beyond me — I'm not familiar with that part of the codebase. I'm currently in a country with internet restrictions and fighting infrastructure fires just to stay connected, so I don't have the bandwidth to dig in properly, and I won't let my agent touch the code without me reviewing it. I'm respectfully recusing myself from this PR. Please take the idea and run with it, or close if it's not worth the team's time. Apologies for the noise, and thanks for the thoughtful review. |
Problem
The
send_messagetool's_send_telegramfunction creates a rawBotobject and callsbot.sendMessage(parse_mode=MarkdownV2). It bypasses the gateway's rich message path entirely. Tables, task lists, math, and other rich constructs always degrade to bulleted lists when sent via thesend_messagetool.Agent streaming responses work fine (they go through the gateway adapter's rich path), but any explicit
send_messagecall — notifications, cron outputs, cross-channel messages — gets MarkdownV2 degradation.Fix
Two additions to
tools/send_message_tool.py:_RichMsghelper class — wraps themessage_idfromsendRichMessageresponses so the return-value pipeline (which expects a message object) works unchanged.Rich fast-path in
_send_telegram— before the existing MarkdownV2 path, triesbot.do_api_request("sendRichMessage", ...)withrich_message: {markdown: ...}. On any failure, falls through to the existing MarkdownV2 path — purely additive, zero regression risk.Verification
Tested on a Hermes instance with Telegram PTB 22.6+:
Tables, task lists, blockquotes, and math expressions now render natively when sent via the
send_messagetool.Related
send_messagetool path.