fix(send_message): map Telegram General topic id to None for forum groups#22423
Merged
kshitijk4poor merged 1 commit intoMay 9, 2026
Conversation
…oups
Telegram forum supergroups address the General topic as
`message_thread_id="1"` on incoming updates, but the Bot API rejects
sends with `message_thread_id=1` ("Message thread not found"). The
gateway adapter has a `_message_thread_id_for_send` helper that maps
"1" to None for that reason; the standalone `_send_telegram` helper
used by the `send_message` tool never got the same mapping, so any
`send_message` call to a Topics-enabled group's General topic
(target shape `telegram:<chat_id>:1`) failed with "Message thread
not found."
Reuse the adapter's helper when available, with an explicit fallback
to the same mapping for environments where the adapter import path
fails (e.g. python-telegram-bot missing in this venv).
Fixes NousResearch#22267
This was referenced May 9, 2026
teknium1
pushed a commit
that referenced
this pull request
May 11, 2026
Cherry-picked from PR #10371. Two-layer defense for the spurious-thread_id issue (#3206): 1. _build_message_event filters DM thread_ids: only preserve thread_id for real topic messages (is_topic_message=True). Telegram puts message_thread_id on every DM that is a reply, but reply-chain ids route to nonexistent threads on send. 2. _send_message_with_thread_fallback helper: control sends (send_update_prompt, send_exec_approval / send_slash_confirm, send_model_picker) retry once without message_thread_id when Telegram returns BadRequest 'Message thread not found'. Mirrors the pattern PR #3390 added for the streaming send path. Salvage notes: - Conflict 1 (line ~4099): merged the contributor's DM is_topic_message filter with the existing forum General-topic default from #22423, preserving both behaviors. - Conflict 2 (line ~1664 / 1690): kept main's delete_message (PR #23416) alongside the new helper. Tightened the helper's exception catch from bare 'Exception' to use the existing _is_bad_request_error + _is_thread_not_found_error helpers (line 484-496) for consistency with the streaming send path. - Widened the fix to send_update_prompt (was bare self._bot.send_message, same bug class). Authored by rahimsais via PR #10371 (re-attributed from donrhmexe@ local commit author).
JZKK720
pushed a commit
to JZKK720/hermes-agent
that referenced
this pull request
May 11, 2026
…oups (NousResearch#22423) Telegram forum supergroups address the General topic as `message_thread_id="1"` on incoming updates, but the Bot API rejects sends with `message_thread_id=1` ("Message thread not found"). The gateway adapter has a `_message_thread_id_for_send` helper that maps "1" to None for that reason; the standalone `_send_telegram` helper used by the `send_message` tool never got the same mapping, so any `send_message` call to a Topics-enabled group's General topic (target shape `telegram:<chat_id>:1`) failed with "Message thread not found." Reuse the adapter's helper when available, with an explicit fallback to the same mapping for environments where the adapter import path fails (e.g. python-telegram-bot missing in this venv). Fixes NousResearch#22267
JZKK720
pushed a commit
to JZKK720/hermes-agent
that referenced
this pull request
May 11, 2026
Cherry-picked from PR NousResearch#10371. Two-layer defense for the spurious-thread_id issue (NousResearch#3206): 1. _build_message_event filters DM thread_ids: only preserve thread_id for real topic messages (is_topic_message=True). Telegram puts message_thread_id on every DM that is a reply, but reply-chain ids route to nonexistent threads on send. 2. _send_message_with_thread_fallback helper: control sends (send_update_prompt, send_exec_approval / send_slash_confirm, send_model_picker) retry once without message_thread_id when Telegram returns BadRequest 'Message thread not found'. Mirrors the pattern PR NousResearch#3390 added for the streaming send path. Salvage notes: - Conflict 1 (line ~4099): merged the contributor's DM is_topic_message filter with the existing forum General-topic default from NousResearch#22423, preserving both behaviors. - Conflict 2 (line ~1664 / 1690): kept main's delete_message (PR NousResearch#23416) alongside the new helper. Tightened the helper's exception catch from bare 'Exception' to use the existing _is_bad_request_error + _is_thread_not_found_error helpers (line 484-496) for consistency with the streaming send path. - Widened the fix to send_update_prompt (was bare self._bot.send_message, same bug class). Authored by rahimsais via PR NousResearch#10371 (re-attributed from donrhmexe@ local commit author).
rmulligan
pushed a commit
to rmulligan/hermes-agent
that referenced
this pull request
May 11, 2026
…oups (NousResearch#22423) Telegram forum supergroups address the General topic as `message_thread_id="1"` on incoming updates, but the Bot API rejects sends with `message_thread_id=1` ("Message thread not found"). The gateway adapter has a `_message_thread_id_for_send` helper that maps "1" to None for that reason; the standalone `_send_telegram` helper used by the `send_message` tool never got the same mapping, so any `send_message` call to a Topics-enabled group's General topic (target shape `telegram:<chat_id>:1`) failed with "Message thread not found." Reuse the adapter's helper when available, with an explicit fallback to the same mapping for environments where the adapter import path fails (e.g. python-telegram-bot missing in this venv). Fixes NousResearch#22267
rmulligan
pushed a commit
to rmulligan/hermes-agent
that referenced
this pull request
May 11, 2026
Cherry-picked from PR NousResearch#10371. Two-layer defense for the spurious-thread_id issue (NousResearch#3206): 1. _build_message_event filters DM thread_ids: only preserve thread_id for real topic messages (is_topic_message=True). Telegram puts message_thread_id on every DM that is a reply, but reply-chain ids route to nonexistent threads on send. 2. _send_message_with_thread_fallback helper: control sends (send_update_prompt, send_exec_approval / send_slash_confirm, send_model_picker) retry once without message_thread_id when Telegram returns BadRequest 'Message thread not found'. Mirrors the pattern PR NousResearch#3390 added for the streaming send path. Salvage notes: - Conflict 1 (line ~4099): merged the contributor's DM is_topic_message filter with the existing forum General-topic default from NousResearch#22423, preserving both behaviors. - Conflict 2 (line ~1664 / 1690): kept main's delete_message (PR NousResearch#23416) alongside the new helper. Tightened the helper's exception catch from bare 'Exception' to use the existing _is_bad_request_error + _is_thread_not_found_error helpers (line 484-496) for consistency with the streaming send path. - Widened the fix to send_update_prompt (was bare self._bot.send_message, same bug class). Authored by rahimsais via PR NousResearch#10371 (re-attributed from donrhmexe@ local commit author).
JinyuID
pushed a commit
to JinyuID/hermes-agent
that referenced
this pull request
May 11, 2026
…oups (NousResearch#22423) Telegram forum supergroups address the General topic as `message_thread_id="1"` on incoming updates, but the Bot API rejects sends with `message_thread_id=1` ("Message thread not found"). The gateway adapter has a `_message_thread_id_for_send` helper that maps "1" to None for that reason; the standalone `_send_telegram` helper used by the `send_message` tool never got the same mapping, so any `send_message` call to a Topics-enabled group's General topic (target shape `telegram:<chat_id>:1`) failed with "Message thread not found." Reuse the adapter's helper when available, with an explicit fallback to the same mapping for environments where the adapter import path fails (e.g. python-telegram-bot missing in this venv). Fixes NousResearch#22267
JinyuID
pushed a commit
to JinyuID/hermes-agent
that referenced
this pull request
May 11, 2026
Cherry-picked from PR NousResearch#10371. Two-layer defense for the spurious-thread_id issue (NousResearch#3206): 1. _build_message_event filters DM thread_ids: only preserve thread_id for real topic messages (is_topic_message=True). Telegram puts message_thread_id on every DM that is a reply, but reply-chain ids route to nonexistent threads on send. 2. _send_message_with_thread_fallback helper: control sends (send_update_prompt, send_exec_approval / send_slash_confirm, send_model_picker) retry once without message_thread_id when Telegram returns BadRequest 'Message thread not found'. Mirrors the pattern PR NousResearch#3390 added for the streaming send path. Salvage notes: - Conflict 1 (line ~4099): merged the contributor's DM is_topic_message filter with the existing forum General-topic default from NousResearch#22423, preserving both behaviors. - Conflict 2 (line ~1664 / 1690): kept main's delete_message (PR NousResearch#23416) alongside the new helper. Tightened the helper's exception catch from bare 'Exception' to use the existing _is_bad_request_error + _is_thread_not_found_error helpers (line 484-496) for consistency with the streaming send path. - Widened the fix to send_update_prompt (was bare self._bot.send_message, same bug class). Authored by rahimsais via PR NousResearch#10371 (re-attributed from donrhmexe@ local commit author).
02356abc
pushed a commit
to 02356abc/hermes-agent
that referenced
this pull request
May 14, 2026
Cherry-picked from PR NousResearch#10371. Two-layer defense for the spurious-thread_id issue (NousResearch#3206): 1. _build_message_event filters DM thread_ids: only preserve thread_id for real topic messages (is_topic_message=True). Telegram puts message_thread_id on every DM that is a reply, but reply-chain ids route to nonexistent threads on send. 2. _send_message_with_thread_fallback helper: control sends (send_update_prompt, send_exec_approval / send_slash_confirm, send_model_picker) retry once without message_thread_id when Telegram returns BadRequest 'Message thread not found'. Mirrors the pattern PR NousResearch#3390 added for the streaming send path. Salvage notes: - Conflict 1 (line ~4099): merged the contributor's DM is_topic_message filter with the existing forum General-topic default from NousResearch#22423, preserving both behaviors. - Conflict 2 (line ~1664 / 1690): kept main's delete_message (PR NousResearch#23416) alongside the new helper. Tightened the helper's exception catch from bare 'Exception' to use the existing _is_bad_request_error + _is_thread_not_found_error helpers (line 484-496) for consistency with the streaming send path. - Widened the fix to send_update_prompt (was bare self._bot.send_message, same bug class). Authored by rahimsais via PR NousResearch#10371 (re-attributed from donrhmexe@ local commit author).
jsboige
pushed a commit
to jsboige/hermes-agent
that referenced
this pull request
May 14, 2026
…oups (NousResearch#22423) Telegram forum supergroups address the General topic as `message_thread_id="1"` on incoming updates, but the Bot API rejects sends with `message_thread_id=1` ("Message thread not found"). The gateway adapter has a `_message_thread_id_for_send` helper that maps "1" to None for that reason; the standalone `_send_telegram` helper used by the `send_message` tool never got the same mapping, so any `send_message` call to a Topics-enabled group's General topic (target shape `telegram:<chat_id>:1`) failed with "Message thread not found." Reuse the adapter's helper when available, with an explicit fallback to the same mapping for environments where the adapter import path fails (e.g. python-telegram-bot missing in this venv). Fixes NousResearch#22267
jsboige
pushed a commit
to jsboige/hermes-agent
that referenced
this pull request
May 14, 2026
Cherry-picked from PR NousResearch#10371. Two-layer defense for the spurious-thread_id issue (NousResearch#3206): 1. _build_message_event filters DM thread_ids: only preserve thread_id for real topic messages (is_topic_message=True). Telegram puts message_thread_id on every DM that is a reply, but reply-chain ids route to nonexistent threads on send. 2. _send_message_with_thread_fallback helper: control sends (send_update_prompt, send_exec_approval / send_slash_confirm, send_model_picker) retry once without message_thread_id when Telegram returns BadRequest 'Message thread not found'. Mirrors the pattern PR NousResearch#3390 added for the streaming send path. Salvage notes: - Conflict 1 (line ~4099): merged the contributor's DM is_topic_message filter with the existing forum General-topic default from NousResearch#22423, preserving both behaviors. - Conflict 2 (line ~1664 / 1690): kept main's delete_message (PR NousResearch#23416) alongside the new helper. Tightened the helper's exception catch from bare 'Exception' to use the existing _is_bad_request_error + _is_thread_not_found_error helpers (line 484-496) for consistency with the streaming send path. - Widened the fix to send_update_prompt (was bare self._bot.send_message, same bug class). Authored by rahimsais via PR NousResearch#10371 (re-attributed from donrhmexe@ local commit author).
AlexFoxD
pushed a commit
to AlexFoxD/hermes-agent
that referenced
this pull request
May 21, 2026
Cherry-picked from PR NousResearch#10371. Two-layer defense for the spurious-thread_id issue (NousResearch#3206): 1. _build_message_event filters DM thread_ids: only preserve thread_id for real topic messages (is_topic_message=True). Telegram puts message_thread_id on every DM that is a reply, but reply-chain ids route to nonexistent threads on send. 2. _send_message_with_thread_fallback helper: control sends (send_update_prompt, send_exec_approval / send_slash_confirm, send_model_picker) retry once without message_thread_id when Telegram returns BadRequest 'Message thread not found'. Mirrors the pattern PR NousResearch#3390 added for the streaming send path. Salvage notes: - Conflict 1 (line ~4099): merged the contributor's DM is_topic_message filter with the existing forum General-topic default from NousResearch#22423, preserving both behaviors. - Conflict 2 (line ~1664 / 1690): kept main's delete_message (PR NousResearch#23416) alongside the new helper. Tightened the helper's exception catch from bare 'Exception' to use the existing _is_bad_request_error + _is_thread_not_found_error helpers (line 484-496) for consistency with the streaming send path. - Widened the fix to send_update_prompt (was bare self._bot.send_message, same bug class). Authored by rahimsais via PR NousResearch#10371 (re-attributed from donrhmexe@ local commit author).
Egavasyug
pushed a commit
to Egavasyug/hermes-agent
that referenced
this pull request
May 25, 2026
…oups (NousResearch#22423) Telegram forum supergroups address the General topic as `message_thread_id="1"` on incoming updates, but the Bot API rejects sends with `message_thread_id=1` ("Message thread not found"). The gateway adapter has a `_message_thread_id_for_send` helper that maps "1" to None for that reason; the standalone `_send_telegram` helper used by the `send_message` tool never got the same mapping, so any `send_message` call to a Topics-enabled group's General topic (target shape `telegram:<chat_id>:1`) failed with "Message thread not found." Reuse the adapter's helper when available, with an explicit fallback to the same mapping for environments where the adapter import path fails (e.g. python-telegram-bot missing in this venv). Fixes NousResearch#22267
gweeteve
pushed a commit
to gweeteve/hermes-agent
that referenced
this pull request
Jun 2, 2026
…oups (NousResearch#22423) Telegram forum supergroups address the General topic as `message_thread_id="1"` on incoming updates, but the Bot API rejects sends with `message_thread_id=1` ("Message thread not found"). The gateway adapter has a `_message_thread_id_for_send` helper that maps "1" to None for that reason; the standalone `_send_telegram` helper used by the `send_message` tool never got the same mapping, so any `send_message` call to a Topics-enabled group's General topic (target shape `telegram:<chat_id>:1`) failed with "Message thread not found." Reuse the adapter's helper when available, with an explicit fallback to the same mapping for environments where the adapter import path fails (e.g. python-telegram-bot missing in this venv). Fixes NousResearch#22267
gweeteve
pushed a commit
to gweeteve/hermes-agent
that referenced
this pull request
Jun 2, 2026
Cherry-picked from PR NousResearch#10371. Two-layer defense for the spurious-thread_id issue (NousResearch#3206): 1. _build_message_event filters DM thread_ids: only preserve thread_id for real topic messages (is_topic_message=True). Telegram puts message_thread_id on every DM that is a reply, but reply-chain ids route to nonexistent threads on send. 2. _send_message_with_thread_fallback helper: control sends (send_update_prompt, send_exec_approval / send_slash_confirm, send_model_picker) retry once without message_thread_id when Telegram returns BadRequest 'Message thread not found'. Mirrors the pattern PR NousResearch#3390 added for the streaming send path. Salvage notes: - Conflict 1 (line ~4099): merged the contributor's DM is_topic_message filter with the existing forum General-topic default from NousResearch#22423, preserving both behaviors. - Conflict 2 (line ~1664 / 1690): kept main's delete_message (PR NousResearch#23416) alongside the new helper. Tightened the helper's exception catch from bare 'Exception' to use the existing _is_bad_request_error + _is_thread_not_found_error helpers (line 484-496) for consistency with the streaming send path. - Widened the fix to send_update_prompt (was bare self._bot.send_message, same bug class). Authored by rahimsais via PR NousResearch#10371 (re-attributed from donrhmexe@ local commit author).
Egavasyug
pushed a commit
to Egavasyug/hermes-agent
that referenced
this pull request
Jun 10, 2026
…oups (NousResearch#22423) Telegram forum supergroups address the General topic as `message_thread_id="1"` on incoming updates, but the Bot API rejects sends with `message_thread_id=1` ("Message thread not found"). The gateway adapter has a `_message_thread_id_for_send` helper that maps "1" to None for that reason; the standalone `_send_telegram` helper used by the `send_message` tool never got the same mapping, so any `send_message` call to a Topics-enabled group's General topic (target shape `telegram:<chat_id>:1`) failed with "Message thread not found." Reuse the adapter's helper when available, with an explicit fallback to the same mapping for environments where the adapter import path fails (e.g. python-telegram-bot missing in this venv). Fixes NousResearch#22267
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #22267 —
send_messagetool fails on Topics-enabled Telegram groups with "Message thread not found" when targeting the General topic.Root cause
Telegram forum supergroups address the General topic as
message_thread_id="1"on incoming updates, but the Bot API rejects sends withmessage_thread_id=1("Bad Request: Message thread not found"). The gateway adapter has had a_message_thread_id_for_sendhelper that maps"1"toNonefor this reason, but the standalone_send_telegramhelper intools/send_message_tool.py(used by the agent-facingsend_messagetool) never got the same mapping.So any
send_messagecall to a forum group's General topic — i.e. target shapetelegram:<chat_id>:1— failed with the error from the issue.Fix
Reuse the gateway adapter's
_message_thread_id_for_sendclassmethod from inside_send_telegram. Since the adapter is also imported a few lines above forformat_message, a fresh import here is essentially free. Includes an explicit fallback that does the same"1" → Nonemapping inline, in case the adapter import fails (e.g. python-telegram-bot missing in this venv during a stripped-down install).Verification
Includes 4 new regression tests in
TestSendTelegramThreadIdMapping:test_general_topic_thread_id_omitted—thread_id="1"→ nomessage_thread_idkwargtest_non_general_topic_thread_id_preserved— real topic ids (e.g. 17585) still pass throughtest_no_thread_id_no_kwarg— no thread_id stays absenttest_general_topic_thread_id_int_input_also_dropped—thread_id=1(int) handled tooE2E test in an isolated env confirms both the primary path (via adapter helper) and the fallback path (explicit
"1"check when adapter import fails) work correctly:Lint diff: 0 new ruff issues.
Closes / supersedes
Related (already fixed, closing with credit)
The same General-topic mapping was incidentally fixed for the gateway adapter's
send_model_pickerpath by #22410 (salvage of #22053). These five PRs were all targeting the same_message_thread_id_for_sendmapping insend_model_pickerand are now redundant; will close with credit pointing here:This PR completes the fix for the parallel code path (the
send_messagetool's standalone_send_telegramhelper), which #22410 didn't touch.