320 lines
15 KiB
Markdown
320 lines
15 KiB
Markdown
---
|
|
name: hermes-telegram
|
|
description: Configure, troubleshoot, and manage Telegram integration for Hermes Agent — bot setup, .env configuration, gateway restart, and common failure modes.
|
|
version: 1.0.0
|
|
author: Hermes Agent
|
|
license: MIT
|
|
platforms: [linux, macos]
|
|
metadata:
|
|
hermes:
|
|
tags: [hermes, telegram, messaging, gateway, bot]
|
|
related_skills: [hermes-agent]
|
|
related_skills: [hermes-agent]
|
|
---
|
|
|
|
# Hermes Telegram Integration
|
|
|
|
Configure the Hermes Agent gateway to send and receive messages on Telegram. Covers bot creation, .env setup, allowed users, home channel, gateway restart, and troubleshooting.
|
|
|
|
## Prerequisites
|
|
|
|
- Hermes Agent gateway installed and running (`hermes gateway status` or `ps aux | grep 'hermes gateway run'`)
|
|
- A Telegram account to create and manage the bot
|
|
|
|
## Setup Steps
|
|
|
|
### 1. Create a Bot on Telegram
|
|
|
|
Message [@BotFather](https://t.me/BotFather) on Telegram:
|
|
|
|
```
|
|
/newbot
|
|
```
|
|
|
|
Follow the prompts to choose a name and username. BotFather will return a bot token like:
|
|
```
|
|
8971430276:AAFu...Amq4
|
|
```
|
|
|
|
Save this token — you'll need it in the next step.
|
|
|
|
### 2. Find Your Numeric IDs
|
|
|
|
You need numeric Telegram IDs, not usernames. Message [@userinfobot](https://t.me/userinfobot) on Telegram — it will reply with:
|
|
|
|
- **Your user ID** (a number like `123456789`) — used for `TELEGRAM_ALLOWED_USERS`
|
|
- For groups/channels: add the bot to the group, send a message, then use @userinfobot in the group to get the **chat ID**
|
|
|
|
Note: `TELEGRAM_ALLOWED_USERS` and `TELEGRAM_HOME_CHANNEL` require **numeric IDs**, not `@username` strings.
|
|
|
|
### 3. Configure .env
|
|
|
|
Edit the `.env` file. The default template has all Telegram variables **commented out** — you must uncomment and fill them in:
|
|
|
|
```bash
|
|
hermes config env-path # prints the path (typically ~/.hermes/.env)
|
|
```
|
|
|
|
The relevant lines (find them under the `# TELEGRAM INTEGRATION` section):
|
|
|
|
```env
|
|
TELEGRAM_BOT_TOKEN=your_bot_token_here
|
|
TELEGRAM_ALLOWED_USERS=123456789 # Comma-separated numeric user IDs
|
|
TELEGRAM_HOME_CHANNEL=123456789 # Numeric chat ID for cron deliveries
|
|
TELEGRAM_HOME_CHANNEL_NAME=@yourusername # Display name (optional, username is fine here)
|
|
```
|
|
|
|
**Important:** The default template uses a combined single-line format:
|
|
```
|
|
# TELEGRAM_BOT_TOKEN=*** TELEGRAM_ALLOWED_USERS=
|
|
```
|
|
When uncommenting, split this into **separate lines** as shown above — one variable per line. Use your editor or `sed` to do it cleanly.
|
|
|
|
For the `HOME_CHANNEL`, if you only want DM delivery (bot messages you directly), set it to your own user ID — same as `ALLOWED_USERS`.
|
|
|
|
### 4. Restart the Gateway
|
|
|
|
Configuration changes in `.env` are read at startup. Restart the gateway to pick them up:
|
|
|
|
```bash
|
|
hermes gateway restart
|
|
```
|
|
|
|
Or if running as a systemd user service:
|
|
```bash
|
|
systemctl --user restart hermes-gateway
|
|
```
|
|
|
|
#### Manual Restart (no systemd service)
|
|
|
|
If `systemctl --user list-units --type=service --all | grep hermes` returns nothing, the gateway was started manually. Kill and restart it:
|
|
|
|
```bash
|
|
# Find the gateway PID
|
|
ps aux | grep 'hermes gateway run'
|
|
|
|
# Kill it (use -9 if plain kill won't work)
|
|
kill -9 <PID>
|
|
|
|
# Wait for it to die
|
|
sleep 2
|
|
|
|
# Start fresh — MUST use background=true (nohup/disown is blocked by tool policy)
|
|
# In the Hermes CLI session:
|
|
# terminal(background=true, notify_on_complete=true, command="hermes gateway run")
|
|
```
|
|
|
|
**Important:** Do not use `nohup`, `disown`, or trailing `&` in a foreground terminal() call — the tool policy blocks shell-level background wrappers. Always use `terminal(background=true)` so Hermes tracks the process.
|
|
|
|
### 5. Verify It's Working
|
|
|
|
Send a message to your bot on Telegram. It should respond. Check the gateway logs for confirmation:
|
|
|
|
```bash
|
|
grep -i telegram ~/.hermes/logs/gateway.log | tail -20
|
|
```
|
|
|
|
Look for these lines to confirm a successful connection:
|
|
|
|
```
|
|
Connecting to telegram...
|
|
[Telegram] Auto-discovered Telegram fallback IPs: 149.154.166.110
|
|
[Telegram] set_my_commands OK for scope BotCommandScopeDefault (30 cmds)
|
|
[Telegram] Connected to Telegram (polling mode)
|
|
✓ telegram connected
|
|
```
|
|
|
|
If you see `Connected to Telegram (polling mode)` and `✓ telegram connected`, the bot is live.
|
|
|
|
For a full reference of restart commands, log signatures, curl test-message patterns, and sed snippets, see [`references/gateway-restart-and-test.md`](references/gateway-restart-and-test.md).
|
|
|
|
#### Sending a Test Message from the CLI
|
|
|
|
The Hermes `send_message` tool only works in sessions initiated from a messaging platform (Telegram, Discord, etc.). In a CLI session, it returns `"No messaging platforms connected"` even when the gateway has Telegram active.
|
|
|
|
**Workaround — use the Telegram Bot API directly via curl:**
|
|
|
|
```bash
|
|
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
|
|
-d "chat_id=${CHAT_ID}" \
|
|
-d "text=Hello from Hermes! 👋"
|
|
```
|
|
|
|
The `${TELEGRAM_BOT_TOKEN}` is the value set in `.env` and `${CHAT_ID}` is the numeric user/chat ID. This sends a message bypassing the Hermes gateway — useful for testing or one-off notifications from the CLI.
|
|
|
|
## Gateway Check
|
|
|
|
To see if the gateway is running before troubleshooting:
|
|
|
|
```bash
|
|
ps aux | grep 'hermes gateway run'
|
|
```
|
|
|
|
## Key Configuration Variables
|
|
|
|
| Variable | Required | Description |
|
|
|----------|----------|-------------|
|
|
| `TELEGRAM_BOT_TOKEN` | Yes | Bot token from @BotFather |
|
|
| `TELEGRAM_ALLOWED_USERS` | Recommended | Comma-separated numeric user IDs allowed to chat. **Leave empty to allow anyone** (not recommended for production). |
|
|
| `TELEGRAM_HOME_CHANNEL` | For cron | Default chat ID for cron job deliveries |
|
|
| `TELEGRAM_HOME_CHANNEL_NAME` | No | Display name for the home channel |
|
|
| `TELEGRAM_CRON_THREAD_ID` | No | Forum topic ID for cron deliveries in topic-mode groups |
|
|
|
|
## Long-Running Tasks & Blocking Behavior
|
|
|
|
The gateway processes **one turn at a time per session**. While the agent is inside a turn (thinking, running tools, waiting for a terminal command), it cannot receive or process new messages from you. Telegram shows "typing..." the entire time.
|
|
|
|
### Why the bot blocks
|
|
|
|
| Phase | What's happening | Can you message? |
|
|
|-------|-----------------|-----------------|
|
|
| 🔄 Agent calls a tool (e.g. `terminal()`) | Blocks waiting for result | ❌ Queued |
|
|
| 🤖 Agent calls the LLM again with tool output | Generating next action | ❌ Queued |
|
|
| 📨 Agent sends you a progress update | Brief mid-turn message | ❌ Still in same turn |
|
|
| ✅ Agent sends final response and ends turn | **Done** | ✅ Next message processed |
|
|
|
|
### "Typing..." = active LLM calls = cost
|
|
|
|
Every iteration of the agent loop makes a new API call to your LLM provider. While the bot shows "typing...", it is actively making LLM calls — you are being charged for input + output tokens each round. Input tokens grow each iteration as tool results are appended to the conversation context.
|
|
|
|
### How to avoid blocking the bot
|
|
|
|
Three approaches, in order of preference:
|
|
|
|
| Approach | How | Best for |
|
|
|----------|-----|----------|
|
|
| ⏰ **Cron job** | `cronjob(action='create', schedule='...', prompt='run my script', no_agent=True)` — script runs independently, stdout delivered verbatim to Telegram | Standalone scripts that run on a schedule or fire-and-forget |
|
|
| 🏃 **Background terminal** | `terminal(command='python long_script.py', background=true, notify_on_complete=true)` — agent returns immediately, pings you when done | One-off long scripts the user triggers |
|
|
| 📋 **/queue** | In CLI: `/queue <prompt>` — queues work for after current turn ends | Quick follow-ups during an active session |
|
|
|
|
The cron approach is cleanest: the bot never blocks, and `no_agent=True` means zero LLM calls during execution — the script's stdout is delivered verbatim.
|
|
|
|
### Verifying the bot is stuck mid-turn
|
|
|
|
Check the gateway logs for the last activity:
|
|
```bash
|
|
tail -20 ~/.hermes/logs/gateway.log
|
|
```
|
|
|
|
Look for:
|
|
- `inbound message: ... msg='your prompt'` — last message received
|
|
- `Flushing text batch ... (N chars)` — last update sent (but turn not over)
|
|
- No new `inbound message` entries — session is blocked, new messages are queued
|
|
|
|
## Pitfalls
|
|
|
|
- **Usernames are not IDs.** `TELEGRAM_ALLOWED_USERS` and `TELEGRAM_HOME_CHANNEL` need **numeric** Telegram IDs, not `@username` strings. Use @userinfobot to get them.
|
|
- **All vars start commented out.** The `.env` template ships with `#` prefix on every Telegram line. You must uncomment them.
|
|
- **Multi-variable line trap.** The default `.env` template writes `TELEGRAM_BOT_TOKEN` and `TELEGRAM_ALLOWED_USERS` on the same line: `# TELEGRAM_BOT_TOKEN=*** TELEGRAM_ALLOWED_USERS=`. This is NOT valid env format with the token value — split into two separate lines when configuring.
|
|
- **Gateway restart required.** `.env` is read at process startup. Simply running `hermes` in a new CLI session does not reload the gateway's env vars. Use `hermes gateway restart` (or `systemctl --user restart hermes-gateway`) every time you change `TELEGRAM_*` variables.
|
|
- **Config schema warnings can block clean startup.** If gateway status/logs show `custom_providers is a dict — it must be a YAML list`, fix it in `~/.hermes/config.yaml` by making `custom_providers` a list (or clear it with `hermes config set custom_providers "[]"`), then restart the gateway.
|
|
- **Token secrecy.** The bot token is a secret — anyone with it can control your bot. Keep it out of version control and shell history.
|
|
- **Gateway API server must be running.** The gateway also starts the API server (typically port 8642). If tools or web UI can't reach the agent, the root cause is often a stopped gateway, not Telegram itself.
|
|
- **send_message tool is CLI-blind to Telegram.** From a CLI session, `send_message(action=list)` returns `No messaging platforms connected` even when the gateway has Telegram active. This is by design — the tool only routes through gateway-originated sessions. Use the Telegram Bot API directly via curl to send messages from CLI sessions (see the Verification section for the exact curl command).
|
|
|
|
### Bot Commands: Registration & Limits
|
|
|
|
The gateway auto-registers bot commands from `hermes_cli.commands.telegram_bot_commands()` on startup. Commands come from three sources: built-in CommandDef entries, plugin slash commands, and skill entries. Gateway caps the command list at `MAX_COMMANDS_PER_SCOPE = 30` (telegram.py:108) to stay under Telegram's undocumented ~4KB payload limit.
|
|
|
|
**Adding a custom command persistently:**
|
|
|
|
1. Edit `~/.hermes/hermes-agent/hermes_cli/commands.py` -- add your (name, description) pair at the end of `telegram_bot_commands()`:
|
|
```python
|
|
result.append(("imagine", "Generate an image from a text prompt"))
|
|
```
|
|
2. Add the command to `_TELEGRAM_MENU_PRIORITY` if the cap is tight -- commands outside the priority list get trimmed first.
|
|
3. If you go over 30 commands, raise `MAX_COMMANDS_PER_SCOPE` in `telegram.py`.
|
|
4. Restart the gateway to pick up changes.
|
|
|
|
Without these three changes, custom commands get overwritten on gateway restart or silently truncated at the 30-command cap.
|
|
|
|
## Troubleshooting
|
|
|
|
### Diagnostic Flow: Bot Not Responding
|
|
|
|
Start with a **status check first** — it's the fastest way to narrow the cause.
|
|
|
|
```
|
|
hermes gateway status # Primary check
|
|
```
|
|
|
|
If that's unavailable, fall back to:
|
|
```
|
|
ps aux | grep 'hermes gateway run' # Second — gateway process exists?
|
|
systemctl --user status hermes-gateway 2>/dev/null # Third — systemd service?
|
|
```
|
|
|
|
#### Branch A: Gateway is not running
|
|
The most common cause of "stopped working" is the gateway having been shut down. Check the logs to find out why:
|
|
|
|
```
|
|
grep -i "telegram\|error\|fail\|warn\|sigterm\|sigkill\|oom" ~/.hermes/logs/gateway.log | tail -20
|
|
```
|
|
|
|
Common shutdown signatures in the logs:
|
|
|
|
| Log pattern | Likely cause | Action |
|
|
|-------------|-------------|--------|
|
|
| `WARNING ... Shutdown context: signal=SIGTERM under_systemd=yes parent_pid=1` | systemd sent SIGTERM (user logout, reboot, service stop) | Restart gateway or install as permanent service |
|
|
| `ERROR ... signal=SIGKILL` | OOM killer or forced kill | Check memory pressure, `dmesg | grep -i oom` |
|
|
| `ERROR ... Traceback (most recent call last)` | Crash / unhandled exception | Read the traceback, fix the root cause |
|
|
| Logs end abruptly with no shutdown message | Process was killed externally (shell session closed, SSH disconnect) | Restart gateway |
|
|
| No Telegram-related log entries at all | Telegram may not be configured or enabled in config | Check `.env` for `TELEGRAM_*` vars, check `config.yaml` → `telegram` section |
|
|
|
|
If the log shows the gateway was working fine then received SIGTERM, the fix is straightforward — restart it:
|
|
|
|
```bash
|
|
hermes gateway run # foreground (session-dependent)
|
|
hermes gateway install # as permanent systemd user service (auto-restarts)
|
|
```
|
|
|
|
If no systemd service exists (`systemctl --user list-units --type=service --all | grep hermes` returns empty), the gateway was started manually and won't survive a logout/reboot without the service.
|
|
|
|
#### Branch B: Gateway is running but not responding
|
|
|
|
```
|
|
grep -i telegram ~/.hermes/logs/gateway.log | tail -30
|
|
```
|
|
|
|
Look for:
|
|
|
|
- `[Telegram] Connected to Telegram (polling mode)` — connection was established
|
|
- `inbound message: platform=telegram user=...` — messages are being received
|
|
- `Sending response (... chars) to 1498679692` — responses are being sent
|
|
- `ERROR` or `WARNING` entries — something went wrong
|
|
|
|
If messages arrive but responses fail, check:
|
|
1. `TELEGRAM_BOT_TOKEN` is correct and uncommented in `.env`
|
|
2. The bot hasn't been blocked by Telegram (try sending a test from a different bot)
|
|
3. Network/firewall: Telegram polling needs outbound connectivity to `api.telegram.org`
|
|
|
|
#### Branch C: Never worked (first-time setup)
|
|
|
|
If the user says the bot never responded:
|
|
1. Follow the full Setup Steps section above
|
|
2. Check that `TELEGRAM_BOT_TOKEN` is on its own line (not merged with another var)
|
|
3. Verify with `curl` directly: `curl -s "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getMe"` — should return `{"ok":true,"result":{"id":...,"is_bot":true,"first_name":"...","username":"..."}}`
|
|
4. Check `TELEGRAM_ALLOWED_USERS` — without it, the bot defaults to allowing everyone; if it's set to the wrong numeric ID, the bot ignores your messages
|
|
5. After fixing, restart the gateway
|
|
6. Wait 5-10 seconds, then send a message to the bot on Telegram
|
|
|
|
### Symptom: "Bot responds to everyone / ignores me"
|
|
Check `TELEGRAM_ALLOWED_USERS` is set to your numeric user ID. Without this, the bot is open to anyone who finds it.
|
|
|
|
### Symptom: "Cron messages don't arrive on Telegram"
|
|
1. Ensure `TELEGRAM_HOME_CHANNEL` is set to the correct numeric chat ID
|
|
2. The home channel is where cron delivers by default — if you DM'd the bot manually but set the home channel to a group, cron goes to the group, not your DMs
|
|
|
|
### Symptom: "send_message tool says 'No messaging platforms connected' from CLI"
|
|
This is expected behavior — the `send_message` tool only routes through a session that was initiated from that platform. From a CLI session, it cannot discover Telegram even if the gateway has it connected.
|
|
|
|
**Workaround:** Call the Telegram Bot API directly:
|
|
```bash
|
|
curl -s -X POST "https://api.telegram.org/bot${TOKEN}/sendMessage" \
|
|
-d "chat_id=${CHAT_ID}" \
|
|
-d "text=Your message"
|
|
```
|
|
|
|
### Symptom: "Can't restart — no systemd service found"
|
|
If `systemctl --user list-units` shows no hermes service, the gateway was started manually (e.g., via `hermes gateway run` in a background terminal). See the **Manual Restart (no systemd service)** section in step 4 above.
|