Skip to content

fix(send_message): wire Telegram fallback transport into one-shot sends#20924

Open
SandroHub013 wants to merge 1 commit into
NousResearch:mainfrom
SandroHub013:fix/send-message-telegram-fallback-transport
Open

fix(send_message): wire Telegram fallback transport into one-shot sends#20924
SandroHub013 wants to merge 1 commit into
NousResearch:mainfrom
SandroHub013:fix/send-message-telegram-fallback-transport

Conversation

@SandroHub013

Copy link
Copy Markdown

Closes #20915.

What

tools/send_message_tool.py::_send_telegram was instantiating a plain telegram.Bot with the default HTTPXRequest, bypassing the TelegramFallbackTransport that the gateway adapter (gateway/platforms/telegram.py) configures. On networks where the system DNS resolves api.telegram.org to a blocked IP, the gateway adapter still works but the send_message tool — and every cron job built on it — silently times out.

Fix

Factored the gateway's network setup into a new async helper:

# gateway/platforms/telegram_network.py
async def create_bot_with_fallback(token: str) -> Bot

_send_telegram now calls it instead of constructing Bot(token=token) directly.

The helper honors the same env vars as the gateway adapter:

  • HERMES_TELEGRAM_DISABLE_FALLBACK_IPS=1 — skip fallback entirely
  • HERMES_TELEGRAM_FALLBACK_IPS=ip1,ip2 — explicit fallback IPs
  • TELEGRAM_PROXY (and standard HTTPS_PROXY / HTTP_PROXY) — proxy precedence

When no env IPs are configured, the helper auto-discovers via discover_fallback_ips() (DNS-over-HTTPS through Google + Cloudflare). If discovery fails or returns nothing, the helper degrades to a plain Bot — identical to the prior behaviour, so users on healthy networks see no change.

Why factor a helper instead of duplicating?

The gateway adapter (TelegramAdapter.start) has a config-object-driven IP list, two separate request pools (one for polling, one for bot ops), and platform-specific timeout overrides. The send_message tool runs without a config object and only needs one request pool. Putting both behind one helper would either bloat the helper or duplicate the gateway's complexity in _send_telegram. The helper covers the 80% case (single pool, env-driven config) that the one-shot tool path needs; the gateway keeps its bespoke setup.

Out of scope (intentional)

  • The gateway adapter (gateway/platforms/telegram.py) is not migrated to use the new helper. Its setup needs the config-object pathway and twin request pools; refactoring that is a separate cleanup.
  • No changes to cron/ — cron jobs that send Telegram messages go through send_message_tool, so they pick up this fix automatically.

Tests

$ pytest tests/gateway/test_telegram_network_create_bot.py -q
6 passed in 13.82s

$ pytest tests/gateway/test_telegram_network.py \
         tests/gateway/test_telegram_network_reconnect.py \
         tests/gateway/test_telegram_network_create_bot.py -q
67 passed in 21.66s

$ pytest tests/tools/test_send_message_tool.py -q
95 passed in 126.27s

$ ruff check gateway/platforms/telegram_network.py \
             tools/send_message_tool.py \
             tests/gateway/test_telegram_network_create_bot.py
All checks passed!

The 6 new tests cover: disabled-via-env, explicit-env-IPs, discovery-success, discovery-empty, discovery-raises, and proxy-takes-precedence-over-fallback.

Closes NousResearch#20915.

`tools/send_message_tool.py::_send_telegram` was instantiating a plain
`telegram.Bot` with the default `HTTPXRequest`, bypassing the
`TelegramFallbackTransport` that the gateway adapter
(`gateway/platforms/telegram.py`) sets up.  On networks where the
system DNS resolves `api.telegram.org` to a blocked IP (a common
condition in some regions), the gateway adapter still works but the
`send_message` tool — and any cron job built on it — silently times
out.

Fix: factor the gateway's network setup into a new helper
`gateway.platforms.telegram_network.create_bot_with_fallback(token)`
and call it from `_send_telegram`.  The helper honors the same env
vars as the gateway adapter:

- `HERMES_TELEGRAM_DISABLE_FALLBACK_IPS=1` to skip fallback
- `HERMES_TELEGRAM_FALLBACK_IPS=ip1,ip2` for explicit IPs
- `TELEGRAM_PROXY` (and standard `HTTPS_PROXY` etc.) for proxy use

The one-shot path doesn't have access to the gateway's per-platform
config object, so the helper falls back on env-var configuration plus
DoH auto-discovery via `discover_fallback_ips()`.

The send_message-tool change is wrapped in a defensive try/except so
that import errors (e.g. minimal test environments) degrade gracefully
to the previous `Bot(token=token)` behaviour.

Tests: 6 new in `tests/gateway/test_telegram_network_create_bot.py`
covering disabled / explicit-env-IPs / discovery-success /
discovery-empty / discovery-raises / proxy-precedence.  Existing 67
telegram_network tests + 95 send_message_tool tests stay green.
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists platform/telegram Telegram bot adapter comp/tools Tool registry, model_tools, toolsets labels May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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.

send_message_tool._send_telegram doesn't use TelegramFallbackTransport, causing delivery failures on blocked networks

2 participants