Skip to content

Telegram

Telegram funktioniert in beiden Modi:

ModusWas er tut
NotificationEinseitiges sendMessage von der Alarmpipeline.
IM bridgeZweiseitiger Chat mit dem Agenten via getUpdates-Long-Poll.

Dasselbe Bot-Token (8…:AA…, von @BotFather) treibt beide an — Telegram authentifiziert per Token-im-Pfad. Es gibt kein separates Signaturschema.

Entworfen für Benutzer außerhalb des Feishu- / DingTalk-Gebiets

Telegram ist der IM-Kanal, den Ongrid für Nicht-China-Teams und für hybride Bereitstellungen empfiehlt, wo die Operatoren zufällig auf Telegram leben. Der Provider wurde in ADR-031 hinzugefügt.

Notification-Modus

Ein notify.Sender POSTet {chat_id, text} an https://api.telegram.org/bot<TOKEN>/sendMessage. Die Credential ist das Bot-Token (im Pfad); die chat_id (numerisch) ist der Ziel-Chat.

go
// internal/pkg/notify/webhook.go
NewTelegramSender(name, endpoint, chatID, client)

Wo endpoint die wörtliche …/bot<TOKEN>/sendMessage-URL ist und chatID der Ziel-Chat (eine numerische User-ID für eine DM, oder die negative Zahl, die Telegram für eine Gruppe gibt).

Setup:

  1. DM @BotFather/newbot → Username auswählen → Token kopieren.
  2. Bot zum Ziel-Chat (Gruppe / Channel) hinzufügen oder einmal DMen, damit er von Ihnen weiß.
  3. Die Chat-ID greifen. Der schnellste Weg: irgendeine Nachricht im Chat senden, dann curl https://api.telegram.org/bot<TOKEN>/getUpdates und result[0].message.chat.id lesen.
  4. In Ongrid: Settings → Channels → New → Provider = telegram → Endpoint = https://api.telegram.org/bot<TOKEN>/sendMessage, chat_id = die Zahl aus Schritt 3.

IM-Bridge-Modus (zweiseitig)

Eingehend wird vom ausgehenden HTTPS-Connection des Managers long-gepollt. Weil der Aufruf ausgehend ist, funktioniert Telegram hinter NAT, Firewalls und HTTPS-Proxies. setWebhook (die Alternative) würde erfordern, dass Telegram den Manager erreicht — das ist inkompatibel mit den meisten privaten Cloud-Bereitstellungen und unzuverlässig vom Festland China aus.

stream ist der einzige Modus

Der Validator lehnt alles andere ab:

telegram only supports stream mode

Webhook-Modus ist in der UI für Telegram nicht exponiert.

Credential-Mapping

Die im_apps-Zeile verwendet bestehende Spalten wieder — keine Schema-Änderungen:

im_apps-SpalteTelegram-Bedeutung
provider"telegram"
mode"stream" (Validator pinnt das)
app_idBot-Username (z. B. ongridbot). Display + Dedupe.
app_secretBotFather-Token (8…:AA…). Verschlüsselt at rest.
allow_fromErforderlich komma-getrennte numerische User-IDs.
verify_tokenUnbenutzt.
encrypt_keyUnbenutzt.

allow_from

Eine nicht-leere Liste numerischer Telegram-User-IDs, die mit dem Bot konversieren dürfen. Der Validator droppt nicht-numerische Tokens (sodass ein vertipptes alice als sauberer Required-Error landet, nicht als stillschweigend leere Allowlist) und lehnt negative Tokens ab (das sind Gruppen-/Supergruppen-Chat-IDs und gehören nicht in eine Sender-Allowlist).

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)

Wie man eine numerische User-ID findet:

  • DM @userinfobot und es antwortet mit Ihrer numerischen ID.
  • Oder eine Nachricht im Chat nach der Registrierung senden, curl https://api.telegram.org/bot<TOKEN>/getUpdates ausführen und result[0].message.from.id lesen.

telegram:- / tg:-Präfixe werden stillschweigend entfernt (OpenClaw-Kompatibilität), sodass telegram:123456789 und 123456789 derselbe Eintrag sind.

Stilles Droppen bei Miss

Nicht in der Allowlist befindliche Sender werden mit einem WARN-Log gedroppt:

text
telegram inbound from non-allowlisted sender — ignored
  user_id=42  user_name=alice  chat_id=42

Es gibt keine Antwort. Es gibt keinen Platzhalter. Der Bot bestätigt nicht einmal, dass er existiert. Das spiegelt OpenClaw allowFrom — eine Antwort würde leaken, dass ein agent-gestützter Bot unter diesem Username lebt und Menschen versuchen lassen, ihn zu sondieren.

Setup

  1. DM @BotFather/newbot → einen Namen und einen einzigartigen Username, der auf bot endet, wählen. Token kopieren.
  2. (Optional) @BotFather → /setprivacy → Disable, wenn Sie möchten, dass der Bot Nachrichten in Gruppen sieht (Default ist nur-Mention).
  3. Ihre numerische User-ID via @userinfobot finden.
  4. In Ongrid: Settings → IM bridge → New → Provider = telegram → Mode = stream → App ID = der Bot-Username → App secret = das BotFather-Token → allow_from = Ihre numerische ID (und die Ihrer Teamkollegen). Save und Enable.
  5. Den Bot von einem in der Allowlist befindlichen Account DMen. Der Bot antwortet mit einem Platzhalter und editiert ihn dann in place, während der Agent argumentiert.

Die Proxy-Story

Der Telegram-API-Host (api.telegram.org) ist auf den meisten Netzwerken erreichbar, aber vom Festland China aus blockiert. Der Provider verwendet einen Zero-Value http.Client, sodass er HTTPS_PROXY / HTTP_PROXY / NO_PROXY aus der Umgebung des Managers ehrt — derselbe Proxy, der getUpdates trägt, trägt sendMessage.

In docker-compose-Bereitstellungen persistieren Sie den Proxy in docker-compose.override.yml:

yaml
services:
  manager:
    environment:
      HTTPS_PROXY: http://your-proxy:8080
      NO_PROXY: localhost,127.0.0.1,manager,mysql,prometheus,loki,tempo,grafana,qdrant

Den Proxy nicht in die Haupt-docker-compose.yml setzen

Die Haupt-docker-compose.yml wird mit jedem Release ausgeliefert. Eine Override-Datei ist per-Umgebung und überlebt make package / Install-Skript-Reruns.

Eigenheiten, die zu kennen sich lohnt

message is not modified ist harmlos

Telegram gibt HTTP 400 (message is not modified) zurück, wenn ein editMessageText-Payload exakt mit dem aktuellen Nachrichtentext übereinstimmt. Progressives Streaming kann denselben Chunk auf einem gedrosselten Tick oder auf dem finalen Flush wiederholen. Der Client schluckt genau diese Fehlerzeichenkette und gibt nil zurück — alles andere (400, 403, 5xx) propagiert weiter. Siehe EditMessageText.

Nur ein Poller pro Bot

Telegram lehnt parallele getUpdates-Aufrufe ab. Der StreamSupervisor erzwingt einen Client pro im_app-Zeile. Wenn Sie eine Telegram-App-Zeile duplizieren, wird nur eine erfolgreich pollen — die andere wird 409 Conflict sehen und zurückfallen.

Rate-Limit-Retries

429 Too Many Requests wird bis zu 3-mal wiederholt. Das Warten ehrt Telegrams parameters.retry_after, gecappt auf 60s. 5xx-Fehler wiederholen mit 1s / 2s / 4s Backoff. Hartes 4xx (400/401/403) wiederholt nicht — es blubbert zum Supervisor und deutet wahrscheinlich auf ein Token-/Chat-ID-Problem hin. Siehe maxCallRetries.

Long-Poll-Timeout

Der serverseitige Long-Poll wartet 25s (pollTimeoutSec) mit einem 10s-Buffer auf der Client-Seite. Langsame Netzwerke sehen einfach längere Poll-Zyklen; der Supervisor macht keine Busy-Wait-Reconnects.

Nur Text

Sticker, Fotos, Sprachnachrichten und Dateien werden stillschweigend gedroppt. Nur message.text-Events treiben einen Agent-Turn. Der Bridge ist absichtlich S1 (Text rein / Text raus); rich media ist eine zukünftige Erweiterung.