Files
hub/docs/telegram.md
T

92 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Telegram Channel
Connect a Telegram bot to an agent so the agent can read incoming messages and
reply. Telegram is the only channel implemented today; the machinery lives in
`backend/src/app_mixins/channel.py` (logic) and `backend/src/server/telegram.py`
(webhook route).
An agent that owns a `channel`/`telegram` resource *is* the agent that answers.
You can bind the same bot token to several agents, and one agent can be bound to
several bots.
## 1. Create a bot
Talk to [@BotFather](https://t.me/BotFather), create a bot, and copy its token
(looks like `123456:ABC-DEF...`). Treat the token as a secret.
## 2. Choose a delivery mode
Telegram can push updates to a webhook, or the hub can pull them with long
polling. The choice is driven entirely by the `HUB_HOST` environment variable:
- **Webhook** — set `HUB_HOST` to a publicly reachable host. Telegram requires
HTTPS on ports 443, 80, 88 or 8443, so the hub must be reachable there.
- **Long polling** — leave `HUB_HOST` unset. The hub prints a warning and polls
`getUpdates` instead. No public endpoint or TLS certificate is needed.
The `POST /channel/telegram/<agent_id>` route is always served regardless of
mode; in polling mode it simply never receives traffic.
Webhooks and polling are mutually exclusive. A webhook is never registered when
`HUB_HOST` is unset, and the poller clears any existing webhook (`deleteWebhook`)
before it starts.
## 3. Bind the bot to an agent
Add a resource to the responding agent (via the resources UI or the
`save-agent-resource` action):
```
kind = "channel"
key = "telegram"
value = {"token": "<bot token>", "secret": "<random webhook secret>", "name": "<display>"}
```
- `token` — the BotFather token. Required.
- `secret` — a random string of `A-Z a-z 0-9 _ -`, 1–256 characters. Optional,
and only meaningful in webhook mode. When present, Telegram sends it back on
every request in the `X-Telegram-Bot-Api-Secret-Token` header and the route
rejects mismatches with `403`.
- `name` — a display label. Optional.
This is the only state the channel persists. Conversations are **not** stored —
no `Chat`, `Thread` or `Message` rows are created. The rolling transcript is
held in memory on the hub and discarded when the process exits.
## 4. Restart the hub
On startup the hub queries all `channel`/`telegram` resources and reconciles the
provider:
- **Webhook mode**: it calls `getWebhookInfo` for each binding and, when the
registered URL does not match `https://<HUB_HOST>/channel/telegram/<agent_id>`,
calls `setWebhook` with that URL, the `secret_token`, and
`allowed_updates=["message"]`. Verify with `getWebhookInfo`.
- **Polling mode**: it starts one background task per binding. Confirm the bot is
reachable with `getMe`, then send a test message.
## 5. Talk to the bot
Message the bot. On each text message the hub:
1. Appends the message to the conversation's in-memory transcript.
2. Runs the agent with a flattened input — an instruction, a status message
(channel, chat id/title/type, current time, sender), and the rendered
conversation.
3. The agent replies by calling the `send_message` tool, which issues a
`sendMessage` call to Telegram.
Non-text updates (edited messages, media, callbacks) are ignored. Messages
authored by other bots are ignored.
## 6. Troubleshooting
| Symptom | Cause |
|---|---|
| Webhook not set | `HUB_HOST` unset, or the host is not reachable over HTTPS. Check the startup log. |
| Polling active when you expected a webhook | `HUB_HOST` is unset. |
| `403` from the webhook route | `X-Telegram-Bot-Api-Secret-Token` does not match the resource's `secret`. |
| `404` from the webhook route | No `channel`/`telegram` resource on that agent. |
| No reply | The agent has no model/tool configuration, or the run errored — check the hub log for `[channel]` lines. |
| `Conflict: can't use getUpdates method while webhook is active` | A stale webhook from a previous deployment. Remove it (`deleteWebhook`) or set `HUB_HOST` so webhook mode takes over. |