Skip to main content

Telegram

agent-telegram is a polling bridge that converts Telegram updates ↔ Redis Streams. No webhook, no domain, no SSL needed for the bridge itself.

Architecture

Telegram API ←─┐
│ long-polling

agent-telegram (Python)

│ XADD events:incoming

agent-redis (Streams)

│ XREADGROUP

agent-core (handlers)

│ XADD events:outgoing

agent-redis (Streams)

│ XREADGROUP

agent-telegram (Python)

│ Telegram API (sendMessage / editMessage)

User receives reply

Configuration

TELEGRAM_BOT_TOKEN=123456789:ABCdefGHI...
TELEGRAM_ALLOWED_USERS=12345678 # comma-separated numeric user IDs
SCHEDULER_NOTIFY_CHAT_ID=12345678 # where the agent sends proactive alerts

Fail-closed. If TELEGRAM_BOT_TOKEN is set but TELEGRAM_ALLOWED_USERS is empty, the bridge refuses to start with an error message — there is no public-bot mode and no escape hatch. The onboarding wizard enforces this by requiring a numeric Telegram ID (5–15 digits) and replicating it to both env vars.

Only Telegram user IDs in the allowlist can interact. Other senders receive an "Unauthorized" reply.

Input types

InputHandling
TextFull pipeline
PhotoVision-capable model receives the image bytes
DocumentTreated as file; can be referenced in subsequent messages
Voice noteTranscribed via OpenAI Whisper, then passed through the text pipeline
Video / video noteFirst frame extracted with ffmpeg (added to the agent-core Dockerfile), then vision pipeline

The bridge writes uploads to /data/shared/uploads/<uuid>.{jpg,mp4,...} so handlers can reference them.

Built-in commands

CommandEffect
/startConcise welcome with capability summary (multi-language: EN/ES/PT/FR)
/helpFull command reference
/pingQuick reachability check
/statusSystem status
/memoryMemory subsystem info
/snapshotSave current state to a memory snapshot
/modelShow active model + provider
/skillsList registered skills
/skill <name> <args>Invoke a skill directly
/scheduleShow scheduled tasks
/introspectCapability + health snapshot
/monitor <url>Watch a URL for changes
/brokerIntegrations management
/api set <provider> <key>Persist a model API key
/openclaw <action>Manage dynamic skills from the ClawHub registry

Live progress

While the agent is working, it publishes TELEGRAM_PROGRESS events. The bridge edits a single status message in place:

🔧 Working...
└─ Step 1: web_search
└─ Step 2: render_report

Only one progress message per turn. On edit failure (Telegram rate limit or message-too-old), the bridge silently drops the update — it never sends a fallback message.

When the final response arrives, the bridge edits the status message into the final content, or replaces it with the final message and deletes the status.

Boot sequence

The first message after a fresh start triggers a special boot sequence (_run_boot_sequence):

🚀 WASP starting up...
✓ Telegram connectivity
✓ Model live (anthropic claude-sonnet-4-6)
✓ Knowledge graph ready
✓ Browser session ready
✓ Memory subsystem ready

If any check fails, the corresponding line shows ✗ with a hint. When the boot sequence runs after a Panic Reset, an additional message warns that all cognitive memory has been cleared.

Output sanitization

Before sending, every response passes through _clean_telegram_output():

  • Strips markdown image syntax ![...](...) (file paths must not appear in user output)
  • Collapses [text](url) to text (url)
  • Strips bold/italic/inline-code markers
  • Strips header # prefixes
  • Removes horizontal rules
  • Strips internal paths and prompt-leak fragments
  • Strips system prefixes like [TAREA PROGRAMADA:], EJECUTA AHORA, etc.

The result is plain text that renders cleanly in Telegram without raw markdown leaking.

Voice notes

Voice notes are downloaded by the bridge to /data/shared/uploads/voice_<uuid>.ogg. The handler invokes OpenAI Whisper API for transcription (requires OPENAI_API_KEY). The transcribed text replaces the original audio and goes through the full pipeline.

Video / video notes

filters.VIDEO | filters.VIDEO_NOTE handler in the bridge downloads videos to /data/shared/uploads/video_<uuid>.mp4. The handler uses ffmpeg to extract the first frame:

ffmpeg -i video.mp4 -vf "select=eq(n\,0)" -frames:v 1 -q:v 2 frame.jpg

The frame is then treated as an image (vision pipeline).

Bridge restart safety

On bridge restart, Redis Streams + consumer groups guarantee at-least-once delivery. PEL zombie recovery (xautoclaim at startup, idle > 5 min) recovers messages from a previously-crashed consumer.

See also