Telegram
Telegram fonctionne dans les deux modes :
| Mode | Ce que ça fait |
|---|---|
| Notification | sendMessage à direction unique depuis le pipeline d'alerte. |
| Pont IM | Chat bidirectionnel avec l'agent via long-poll getUpdates. |
Le même token de bot (8…:AA…, de @BotFather) pilote les deux — Telegram authentifie par token-dans-le-path. Il n'y a pas de schéma de signature séparé.
Conçu pour les utilisateurs hors territoire Feishu / DingTalk
Telegram est le canal IM qu'Ongrid recommande pour les équipes hors Chine et pour les déploiements hybrides où les opérateurs vivent sur Telegram. Le provider a été ajouté dans ADR-031.
Mode notification
Un notify.Sender POST {chat_id, text} à https://api.telegram.org/bot<TOKEN>/sendMessage. Le credential est le token de bot (dans le path) ; le chat_id (numérique) est le chat de destination.
// internal/pkg/notify/webhook.go
NewTelegramSender(name, endpoint, chatID, client)Où endpoint est l'URL littérale …/bot<TOKEN>/sendMessage et chatID est le chat cible (l'ID numérique d'un utilisateur pour un DM, ou le nombre négatif que Telegram vous donne pour un groupe).
Setup :
- DM
@BotFather→/newbot→ choisissez un username → copiez le token. - Ajoutez le bot au chat cible (groupe / canal) ou DM-le une fois pour qu'il vous connaisse.
- Récupérez le chat ID. Le moyen le plus rapide : envoyez n'importe quel message dans le chat, puis
curl https://api.telegram.org/bot<TOKEN>/getUpdateset lisezresult[0].message.chat.id. - Dans Ongrid : Settings → Channels → New → Provider =
telegram→ Endpoint =https://api.telegram.org/bot<TOKEN>/sendMessage, chat_id = le nombre de l'étape 3.
Mode pont IM (bidirectionnel)
L'entrant est long-pollé depuis la connexion HTTPS sortante du manager. Comme l'appel est sortant, Telegram fonctionne derrière NAT, firewalls et proxies HTTPS. setWebhook (l'alternative) nécessiterait que Telegram atteigne le manager — c'est incompatible avec la plupart des déploiements en cloud privé et non fiable depuis la Chine continentale.
stream est le seul mode
Le validateur rejette tout le reste :
telegram only supports stream mode
Le mode webhook n'est pas exposé dans l'UI pour Telegram.
Mapping des credentials
La ligne im_apps réutilise des colonnes existantes — pas de changement de schéma :
Colonne im_apps | Signification Telegram |
|---|---|
provider | "telegram" |
mode | "stream" (le validateur épingle ceci) |
app_id | Username du bot (par ex. ongridbot). Affichage + dédoublonnage. |
app_secret | Token BotFather (8…:AA…). Chiffré au repos. |
allow_from | Requis liste séparée par virgules d'IDs utilisateur numériques. |
verify_token | Inutilisé. |
encrypt_key | Inutilisé. |
allow_from
Une liste non vide d'IDs utilisateur Telegram numériques qui peuvent converser avec le bot. Le validateur drop les tokens non-numériques (pour qu'un alice avec typo atterrisse comme erreur required propre, pas comme une allowlist silencieusement vide) et rejette les tokens négatifs (ce sont des IDs de chat de groupe / supergroupe et n'ont rien à faire dans une allowlist d'expéditeur).
telegram requires allow_from — at least one numeric Telegram user ID (the bot is publicly reachable; an empty allowlist would let anyone command the agent)
Comment trouver un ID utilisateur numérique :
- DM
@userinfobotet il répond avec votre ID numérique. - Ou envoyez un message dans le chat après enregistrement, exécutez
curl https://api.telegram.org/bot<TOKEN>/getUpdates, et lisezresult[0].message.from.id.
Les préfixes telegram: / tg: sont retirés silencieusement (compat OpenClaw), donc telegram:123456789 et 123456789 sont la même entrée.
Drop silencieux en miss
Les expéditeurs non-allowlistés sont droppés avec un log WARN :
telegram inbound from non-allowlisted sender — ignored
user_id=42 user_name=alice chat_id=42Il n'y a pas de réponse. Il n'y a pas de placeholder. Le bot ne confirme même pas qu'il existe. Cela mirror allowFrom d'OpenClaw — une réponse fuirait qu'un bot adossé à un agent vit sur ce username et tenterait les gens de le sonder.
Setup
- DM
@BotFather→/newbot→ choisissez un nom et un username unique se terminant parbot. Copiez le token. - (Optionnel)
@BotFather → /setprivacy → Disablesi vous voulez que le bot voie les messages dans les groupes (défaut est mention-only). - Trouvez votre ID utilisateur numérique via
@userinfobot. - Dans Ongrid : Settings → IM bridge → New → Provider =
telegram→ Mode =stream→ App ID = l'username du bot → App secret = le token BotFather →allow_from= votre ID numérique (et ceux de coéquipiers). Save et Enable. - DM le bot depuis un compte allowlisté. Le bot répond avec un placeholder, puis l'édite en place à mesure que l'agent raisonne.
L'histoire du proxy
L'host de l'API Telegram (api.telegram.org) est joignable sur la plupart des réseaux mais bloqué depuis la Chine continentale. Le provider utilise un http.Client à valeur zéro pour qu'il honore HTTPS_PROXY / HTTP_PROXY / NO_PROXY depuis l'environnement du manager — le même proxy qui porte getUpdates porte sendMessage.
Dans les déploiements docker-compose, persistez le proxy dans docker-compose.override.yml :
services:
manager:
environment:
HTTPS_PROXY: http://your-proxy:8080
NO_PROXY: localhost,127.0.0.1,manager,mysql,prometheus,loki,tempo,grafana,qdrantNe mettez pas le proxy dans le docker-compose.yml principal
Le docker-compose.yml principal est livré avec chaque release. Un fichier override est par-environnement et survit aux re-runs de make package / script d'install.
Particularités à connaître
message is not modified est inoffensif
Telegram renvoie HTTP 400 (message is not modified) quand un payload editMessageText matche exactement le texte du message courant. Le streaming progressif peut répéter le même chunk sur un tick throttlé ou sur le flush final. Le client avale exactement cette chaîne d'erreur et renvoie nil — tout le reste (400, 403, 5xx) propage encore. Voir EditMessageText.
Un seul poller par bot
Telegram rejette les appels getUpdates concurrents. Le StreamSupervisor impose un client par ligne im_app. Si vous dupliquez une ligne d'app Telegram, seule une pollera avec succès — l'autre verra 409 Conflict et se reculera.
Retries de rate-limit
429 Too Many Requests est retenté jusqu'à 3 fois. L'attente honore le parameters.retry_after de Telegram, plafonné à 60s. Les erreurs 5xx retentent avec un backoff 1s / 2s / 4s. Les 4xx dures (400/401/403) ne retentent pas — elles bouillonnent vers le superviseur et indiquent probablement un problème de token / chat-id. Voir maxCallRetries.
Timeout du long-poll
Le long poll côté serveur attend 25s (pollTimeoutSec) avec un buffer de 10s côté client. Les réseaux lents voient juste des cycles de poll plus longs ; le superviseur ne fait pas de busy-wait reconnects.
Texte seulement
Les stickers, photos, notes vocales et fichiers sont droppés silencieusement. Seuls les événements message.text pilotent un tour d'agent. Le pont est intentionnellement S1 (texte in / texte out) ; les médias riches sont une expansion future.