feat(telegram): telegram bot host with connection recovery
This commit is contained in:
75
docs/telegram-bot.md
Normal file
75
docs/telegram-bot.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Telegram bot
|
||||
|
||||
`hosts/Volcanic.AgenticCore.Telegram` lets you chat with the agent from Telegram. It uses long polling (no public
|
||||
URL, no webhook), gives every private chat its own agent session and workspace, and runs the model through the
|
||||
Claude Code provider (`claude-code/claude-opus-5-5`) on your Claude subscription.
|
||||
|
||||
## Setup
|
||||
|
||||
1. Create a bot with [@BotFather](https://t.me/BotFather) (`/newbot`) and copy the token.
|
||||
2. Find your numeric Telegram user id, for example by messaging [@userinfobot](https://t.me/userinfobot).
|
||||
3. Install Claude Code on the machine that runs the bot and log in (`claude`, then `/login`). Check with
|
||||
`claude --version`; see [claude-code-provider.md](claude-code-provider.md).
|
||||
4. Run:
|
||||
|
||||
```bash
|
||||
TELEGRAM_BOT_TOKEN=123456:ABC... \
|
||||
TELEGRAM_ALLOWED_USER_IDS=111111111 \
|
||||
dotnet run --project hosts/Volcanic.AgenticCore.Telegram
|
||||
```
|
||||
|
||||
Open the bot in Telegram and say hello.
|
||||
|
||||
## Configuration
|
||||
|
||||
Environment variables, or the `Telegram` section of `appsettings.json` (`Telegram__Name` in the environment):
|
||||
|
||||
| Setting | Default | Notes |
|
||||
|---|---|---|
|
||||
| `TELEGRAM_BOT_TOKEN` / `Telegram:BotToken` | — | Required |
|
||||
| `TELEGRAM_ALLOWED_USER_IDS` / `Telegram:AllowedUserIds` | — | Required, comma separated. The bot refuses to start without it |
|
||||
| `Telegram:WorkspaceRoot` | `~/.volcanic/telegram-workspaces` | Chat `<id>` works in `<root>/<id>` |
|
||||
| `Telegram:Model` | `claude-code/claude-opus-5-5` | Any `provider/model` the Claude Code provider serves |
|
||||
| `Telegram:EditInterval` | `00:00:01.5` | Minimum time between edits of a streaming reply |
|
||||
| `Telegram:ReconnectInitialDelay` / `ReconnectMaxDelay` | `1 s` / `60 s` | Backoff after lost connection |
|
||||
|
||||
Sessions are stored as usual under `~/.volcanic/agent/sessions/telegram-<chatId>/`; after a restart each chat resumes
|
||||
its most recent conversation.
|
||||
|
||||
## Using it
|
||||
|
||||
Write normally. The reply streams into one message (split into several past Telegram's 4096 character limit);
|
||||
each tool call shows as a line, `▶ bash: ls -la` becoming `✓ bash` or `✗ bash` with an excerpt of the error.
|
||||
A message sent while the agent works steers the current run. Photos (with or without a caption) are passed to the model.
|
||||
|
||||
| Command | |
|
||||
|---|---|
|
||||
| `/new` | Start a new conversation |
|
||||
| `/stop` | Stop the current run |
|
||||
| `/status` | Model, thinking level, session, context usage, workspace |
|
||||
| `/sessions`, `/resume <id>` | List and resume earlier conversations (an id prefix is enough) |
|
||||
| `/compact` | Summarise the conversation to free context |
|
||||
| `/thinking [level]` | Show or set the thinking level (Claude Code `--effort`) |
|
||||
| `/help` | Short help |
|
||||
|
||||
Any other `/command` is passed to the session, so extension commands such as `/claude-code-doctor` work.
|
||||
When an extension asks something, the question appears with buttons (or as a reply prompt for free text).
|
||||
|
||||
## Security
|
||||
|
||||
The agent has the built-in tools, including `bash`, and runs them as the bot's OS user. Only allow-listed user ids
|
||||
are served (everyone else is ignored and logged), and only in private chats. Run the bot as a dedicated user or in a
|
||||
container, and treat the workspace root as writable by anyone on the allow-list.
|
||||
|
||||
## Connection loss
|
||||
|
||||
Polling uses Telegram.Bot's built-in loop with a hardened error handler:
|
||||
|
||||
- a failed `getUpdates` waits 1 s, 2 s, 4 s … up to 60 s (±20 % jitter) before the next attempt, instead of retrying
|
||||
in a tight loop; the first successful poll resets the delay and logs `Telegram connection restored`;
|
||||
- the update offset only moves past updates that were handed on, so reconnecting neither loses nor repeats messages;
|
||||
- if the loop itself ever ends while the host runs, it is restarted from the last offset;
|
||||
- a `401` (revoked or wrong token) is the one error it does not retry: the host logs it and exits with code 1.
|
||||
|
||||
Replies that fail to send (Telegram unreachable mid-run) are logged; the render loop keeps going and later edits
|
||||
catch the message up.
|
||||
Reference in New Issue
Block a user