pi-telegram-webhook/README.md
Harivansh Rathi ce9abc2a8e initial: webhook telegram adapter for pi with streaming replies
- webhook server with secret validation, rate limiting, body guards
- streaming replies via sendMessage + editMessageText throttled loop
- RPC session management for persistent conversations
- 15/15 tests passing
2026-04-03 05:30:05 +00:00

162 lines
5 KiB
Markdown

# pi-telegram-webhook
Webhook-based Telegram adapter for [pi](https://github.com/badlogic/pi-mono) with streaming replies and persistent RPC sessions.
## Features
- **Webhook ingress** (vs polling) — lower latency, better for production
- **Security hardened**:
- Constant-time secret validation (timing attack resistant)
- Fixed-window rate limiter per IP
- 1MB body size limit
- 30s read timeout
- Trusted proxy X-Forwarded-For support
- **Streaming replies** — throttled `editMessageText` for live updates (default 1s, 4096 char limit)
- **Persistent RPC sessions** — `pi --mode rpc` subprocess per sender, context preserved across messages
- **Generation tracking** — prevents new messages from clobbering old edits
- **FIFO queues** — per-sender serialization, configurable concurrency
- **Bot commands**: `/start`, `/help`, `/new`, `/abort`, `/clear`
## Installation
```bash
npm install pi-telegram-webhook
```
## Configuration
Add to `.pi/settings.json`:
```json
{
"pi-telegram-webhook": {
"botToken": "your-telegram-bot-token",
"webhookUrl": "https://your-domain.com/telegram-webhook",
"webhookPort": 2470,
"webhookHost": "127.0.0.1",
"webhookPath": "/telegram-webhook",
"webhookSecret": "random-secret-token",
"allowedChatIds": ["123456789"],
"streamingThrottleMs": 1000,
"minInitialChars": 50,
"trustedProxies": ["127.0.0.1", "10.0.0.0/8"],
"maxConcurrent": 2,
"timeoutMs": 300000,
"idleTimeoutMinutes": 30,
"model": "anthropic/claude-sonnet-4",
"extensions": ["pi-channels"]
}
}
```
### Config Reference
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `botToken` | `string` | *required* | Telegram Bot API token |
| `webhookUrl` | `string` | *required* | Public webhook URL (must be HTTPS in production) |
| `webhookSecret` | `string` | *required* | Secret token for webhook validation |
| `webhookPort` | `number` | `2470` | Local server port |
| `webhookHost` | `string` | `127.0.0.1` | Local server bind address |
| `webhookPath` | `string` | `/telegram-webhook` | Webhook endpoint path |
| `allowedChatIds` | `string[]` | `undefined` | Whitelist of allowed chat IDs (optional) |
| `streamingThrottleMs` | `number` | `1000` | Throttle interval for streaming edits |
| `minInitialChars` | `number` | `50` | Min chars before sending first message (debounce) |
| `trustedProxies` | `string[]` | `["127.0.0.1"]` | Trusted proxy IPs/CIDRs for X-Forwarded-For |
| `maxConcurrent` | `number` | `2` | Max concurrent prompts across all senders |
| `timeoutMs` | `number` | `300000` | Prompt timeout (5 min) |
| `idleTimeoutMinutes` | `number` | `30` | RPC session idle timeout |
| `model` | `string` | `undefined` | Override model for RPC sessions |
| `extensions` | `string[]` | `[]` | Additional pi extensions to load |
## Deployment
### Reverse Proxy (nginx)
```nginx
location /telegram-webhook {
proxy_pass http://127.0.0.1:2470;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
proxy_read_timeout 35s;
client_max_body_size 2M;
}
```
### Systemd Service
```ini
[Unit]
Description=pi Telegram webhook
After=network.target
[Service]
Type=simple
User=youruser
WorkingDirectory=/path/to/your/project
ExecStart=/usr/bin/pi --no-tui
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
```
### Webhook Setup
The extension automatically calls `setWebhook` on startup. To manually test:
```bash
curl -X POST "https://api.telegram.org/bot<YOUR_TOKEN>/setWebhook" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-domain.com/telegram-webhook",
"secret_token": "your-secret"
}'
```
## Bot Commands
- `/start`, `/help` — Show welcome message
- `/new` — Start a new conversation (clear context)
- `/abort` — Abort the current task
- `/clear` — Clear the message queue
## Architecture
```
Telegram → HTTPS webhook → nginx → pi-telegram-webhook
├─ webhook-server (security, rate limiting)
├─ bridge (FIFO queues, concurrency)
└─ RPC sessions (streaming replies)
```
### Flow
1. Incoming webhook → secret validation → rate limit check → body parsing
2. Message enqueued in per-sender FIFO queue
3. Bridge spawns/reuses `pi --mode rpc` subprocess for sender
4. Prompt sent to RPC session, streaming deltas received
5. StreamingReply sends initial message, then throttled edits
6. Generation tracking prevents race conditions
## Development
```bash
npm install
npm run build
npm test
```
## Security Notes
- **Secret validation** uses constant-time comparison (timing attack resistant)
- **Rate limiting** applied *before* secret check (prevents brute-force)
- **Body size limit** prevents memory exhaustion
- **Read timeout** prevents slowloris attacks
- **Trusted proxies** must be explicitly configured for X-Forwarded-For
## License
MIT