mirror of
https://github.com/harivansh-afk/pi-telegram-webhook.git
synced 2026-04-15 03:00:47 +00:00
- 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
162 lines
5 KiB
Markdown
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
|