diff --git a/gateway/config.py b/gateway/config.py index 0f8afc22a4..5efd36729d 100644 --- a/gateway/config.py +++ b/gateway/config.py @@ -638,6 +638,8 @@ def load_gateway_config() -> GatewayConfig: os.environ["TELEGRAM_IGNORED_THREADS"] = str(ignored_threads) if "reactions" in telegram_cfg and not os.getenv("TELEGRAM_REACTIONS"): os.environ["TELEGRAM_REACTIONS"] = str(telegram_cfg["reactions"]).lower() + if "proxy_url" in telegram_cfg and not os.getenv("TELEGRAM_PROXY"): + os.environ["TELEGRAM_PROXY"] = str(telegram_cfg["proxy_url"]).strip() if "disable_link_previews" in telegram_cfg: plat_data = platforms_data.setdefault(Platform.TELEGRAM.value, {}) if not isinstance(plat_data, dict): diff --git a/gateway/platforms/telegram.py b/gateway/platforms/telegram.py index 54e79b3951..19eb72e2ec 100644 --- a/gateway/platforms/telegram.py +++ b/gateway/platforms/telegram.py @@ -575,7 +575,7 @@ class TelegramAdapter(BasePlatformAdapter): "write_timeout": _env_float("HERMES_TELEGRAM_HTTP_WRITE_TIMEOUT", 20.0), } - proxy_url = resolve_proxy_url() + proxy_url = resolve_proxy_url("TELEGRAM_PROXY") disable_fallback = (os.getenv("HERMES_TELEGRAM_DISABLE_FALLBACK_IPS", "").strip().lower() in ("1", "true", "yes", "on")) fallback_ips = self._fallback_ips() if not fallback_ips: diff --git a/gateway/platforms/telegram_network.py b/gateway/platforms/telegram_network.py index 4fca934ef8..ed2d60d797 100644 --- a/gateway/platforms/telegram_network.py +++ b/gateway/platforms/telegram_network.py @@ -46,7 +46,7 @@ _SEED_FALLBACK_IPS: list[str] = ["149.154.167.220"] def _resolve_proxy_url() -> str | None: # Delegate to shared implementation (env vars + macOS system proxy detection) from gateway.platforms.base import resolve_proxy_url - return resolve_proxy_url() + return resolve_proxy_url("TELEGRAM_PROXY") class TelegramFallbackTransport(httpx.AsyncBaseTransport): diff --git a/hermes_cli/config.py b/hermes_cli/config.py index ee66d51a7e..6a646d0df5 100644 --- a/hermes_cli/config.py +++ b/hermes_cli/config.py @@ -1252,6 +1252,12 @@ OPTIONAL_ENV_VARS = { "password": False, "category": "messaging", }, + "TELEGRAM_PROXY": { + "description": "Proxy URL for Telegram connections (overrides HTTPS_PROXY). Supports http://, https://, socks5://", + "prompt": "Telegram proxy URL (optional)", + "password": False, + "category": "messaging", + }, "DISCORD_BOT_TOKEN": { "description": "Discord bot token from Developer Portal", "prompt": "Discord bot token", diff --git a/tests/gateway/test_config.py b/tests/gateway/test_config.py index 1b5a2c530a..e60bf1e92c 100644 --- a/tests/gateway/test_config.py +++ b/tests/gateway/test_config.py @@ -300,6 +300,42 @@ class TestLoadGatewayConfig: assert config.platforms[Platform.TELEGRAM].extra["disable_link_previews"] is True + def test_bridges_telegram_proxy_url_from_config_yaml(self, tmp_path, monkeypatch): + hermes_home = tmp_path / ".hermes" + hermes_home.mkdir() + config_path = hermes_home / "config.yaml" + config_path.write_text( + "telegram:\n" + " proxy_url: socks5://127.0.0.1:1080\n", + encoding="utf-8", + ) + + monkeypatch.setenv("HERMES_HOME", str(hermes_home)) + monkeypatch.delenv("TELEGRAM_PROXY", raising=False) + + load_gateway_config() + + import os + assert os.environ.get("TELEGRAM_PROXY") == "socks5://127.0.0.1:1080" + + def test_telegram_proxy_env_takes_precedence_over_config(self, tmp_path, monkeypatch): + hermes_home = tmp_path / ".hermes" + hermes_home.mkdir() + config_path = hermes_home / "config.yaml" + config_path.write_text( + "telegram:\n" + " proxy_url: http://from-config:8080\n", + encoding="utf-8", + ) + + monkeypatch.setenv("HERMES_HOME", str(hermes_home)) + monkeypatch.setenv("TELEGRAM_PROXY", "socks5://from-env:1080") + + load_gateway_config() + + import os + assert os.environ.get("TELEGRAM_PROXY") == "socks5://from-env:1080" + class TestHomeChannelEnvOverrides: """Home channel env vars should apply even when the platform was already diff --git a/website/docs/reference/environment-variables.md b/website/docs/reference/environment-variables.md index bf6022bd87..aa0acd8c7a 100644 --- a/website/docs/reference/environment-variables.md +++ b/website/docs/reference/environment-variables.md @@ -170,6 +170,7 @@ For cloud sandbox backends, persistence is filesystem-oriented. `TERMINAL_LIFETI | `TELEGRAM_WEBHOOK_SECRET` | Secret token for verifying updates come from Telegram | | `TELEGRAM_REACTIONS` | Enable emoji reactions on messages during processing (default: `false`) | | `TELEGRAM_IGNORED_THREADS` | Comma-separated Telegram forum topic/thread IDs where the bot never responds | +| `TELEGRAM_PROXY` | Proxy URL for Telegram connections — overrides `HTTPS_PROXY`. Supports `http://`, `https://`, `socks5://` | | `DISCORD_BOT_TOKEN` | Discord bot token | | `DISCORD_ALLOWED_USERS` | Comma-separated Discord user IDs allowed to use the bot | | `DISCORD_HOME_CHANNEL` | Default Discord channel for cron delivery | diff --git a/website/docs/user-guide/messaging/telegram.md b/website/docs/user-guide/messaging/telegram.md index 4292ae4f6e..0fa2e830b9 100644 --- a/website/docs/user-guide/messaging/telegram.md +++ b/website/docs/user-guide/messaging/telegram.md @@ -172,6 +172,27 @@ fly deploy The gateway log should show: `[telegram] Connected to Telegram (webhook mode)`. +## Proxy Support + +If Telegram's API is blocked or you need to route traffic through a proxy, set a Telegram-specific proxy URL. This takes priority over the generic `HTTPS_PROXY` / `HTTP_PROXY` env vars. + +**Option 1: config.yaml (recommended)** + +```yaml +telegram: + proxy_url: "socks5://127.0.0.1:1080" +``` + +**Option 2: environment variable** + +```bash +TELEGRAM_PROXY=socks5://127.0.0.1:1080 +``` + +Supported schemes: `http://`, `https://`, `socks5://`. + +The proxy applies to both the main Telegram connection and the fallback IP transport. If no Telegram-specific proxy is set, the gateway falls back to `HTTPS_PROXY` / `HTTP_PROXY` / `ALL_PROXY` (or macOS system proxy auto-detection). + ## Home Channel Use the `/sethome` command in any Telegram chat (DM or group) to designate it as the **home channel**. Scheduled tasks (cron jobs) deliver their results to this channel.