Skip to content

fix(send_message): map Telegram General topic id to None for forum groups#22423

Merged
kshitijk4poor merged 1 commit into
NousResearch:mainfrom
kshitijk4poor:fix/send-message-telegram-general-topic-22267
May 9, 2026
Merged

fix(send_message): map Telegram General topic id to None for forum groups#22423
kshitijk4poor merged 1 commit into
NousResearch:mainfrom
kshitijk4poor:fix/send-message-telegram-general-topic-22267

Conversation

@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Summary

Fixes #22267send_message tool 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 with message_thread_id=1 ("Bad Request: Message thread not found"). The gateway adapter has had a _message_thread_id_for_send helper that maps "1" to None for this reason, but the standalone _send_telegram helper in tools/send_message_tool.py (used by the agent-facing send_message tool) never got the same mapping.

So any send_message call to a forum group's General topic — i.e. target shape telegram:<chat_id>:1 — failed with the error from the issue.

Fix

Reuse the gateway adapter's _message_thread_id_for_send classmethod from inside _send_telegram. Since the adapter is also imported a few lines above for format_message, a fresh import here is essentially free. Includes an explicit fallback that does the same "1" → None mapping inline, in case the adapter import fails (e.g. python-telegram-bot missing in this venv during a stripped-down install).

Verification

$ scripts/run_tests.sh tests/tools/test_send_message_tool.py
99 passed in 3.98s

Includes 4 new regression tests in TestSendTelegramThreadIdMapping:

  • test_general_topic_thread_id_omittedthread_id="1" → no message_thread_id kwarg
  • test_non_general_topic_thread_id_preserved — real topic ids (e.g. 17585) still pass through
  • test_no_thread_id_no_kwarg — no thread_id stays absent
  • test_general_topic_thread_id_int_input_also_droppedthread_id=1 (int) handled too

E2E 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:

thread_id="1" (General): message_thread_id absent ✓
thread_id="17585": message_thread_id=17585 ✓
no thread_id: message_thread_id absent ✓

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_picker path by #22410 (salvage of #22053). These five PRs were all targeting the same _message_thread_id_for_send mapping in send_model_picker and are now redundant; will close with credit pointing here:

This PR completes the fix for the parallel code path (the send_message tool's standalone _send_telegram helper), which #22410 didn't touch.

…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
@kshitijk4poor kshitijk4poor merged commit ae005ec into NousResearch:main May 9, 2026
9 of 11 checks passed
@kshitijk4poor kshitijk4poor deleted the fix/send-message-telegram-general-topic-22267 branch May 9, 2026 08:59
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery platform/telegram Telegram bot adapter comp/tools Tool registry, model_tools, toolsets labels 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery comp/tools Tool registry, model_tools, toolsets P2 Medium — degraded but workaround exists platform/telegram Telegram bot adapter type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Telegram Send Failed: "Message thread not found" when sending to Groups with Topics enabled

2 participants