Telegram (Bot API)

Status: Produktionsreif für Bot-DMs und Gruppen via grammY. Standardmäßig Long-Polling; Webhook optional.

Schnellstart (Einsteiger)

  1. Erstelle einen Bot mit @BotFather (Direktlink). Bestätige, dass der Handle exakt @BotFather ist, und kopiere dann den Token.
  2. Setze den Token:
    • Umgebungsvariable: TELEGRAM_BOT_TOKEN=...
    • Oder Config: channels.telegram.botToken: "...".
    • Wenn beides gesetzt ist, hat die Config Vorrang (Umgebungsvariable gilt nur für den Standard-Account).
  3. Starte den Gateway.
  4. DM-Zugriff nutzt standardmäßig Pairing; genehmige den Pairing-Code beim ersten Kontakt.

Minimale Config:

{
  channels: {
    telegram: {
      enabled: true,
      botToken: "123:abc",
      dmPolicy: "pairing",
    },
  },
}

Was ist das

  • Ein Telegram Bot API Channel, der vom Gateway verwaltet wird.
  • Deterministisches Routing: Antworten gehen zurück zu Telegram; das Modell wählt nie selbst Channels aus.
  • DMs teilen sich die Haupt-Session des Agents; Gruppen bleiben isoliert (agent:<agentId>:telegram:group:<chatId>).

Setup (schneller Weg)

1) Bot-Token erstellen (BotFather)

  1. Öffne Telegram und chatte mit @BotFather (Direktlink). Bestätige, dass der Handle exakt @BotFather ist.
  2. Führe /newbot aus und folge den Anweisungen (Name + Username, der auf bot endet).
  3. Kopiere den Token und bewahre ihn sicher auf.

Optionale BotFather-Einstellungen:

  • /setjoingroups — erlaube/verbiete das Hinzufügen des Bots zu Gruppen.
  • /setprivacy — steuere, ob der Bot alle Gruppennachrichten sieht.

2) Token konfigurieren (Umgebungsvariable oder Config)

Beispiel:

{
  channels: {
    telegram: {
      enabled: true,
      botToken: "123:abc",
      dmPolicy: "pairing",
      groups: { "*": { requireMention: true } },
    },
  },
}

Umgebungsvariable: TELEGRAM_BOT_TOKEN=... (funktioniert für den Standard-Account). Wenn sowohl Umgebungsvariable als auch Config gesetzt sind, hat die Config Vorrang.

Multi-Account-Unterstützung: Nutze channels.telegram.accounts mit Token pro Account und optionalem name. Siehe gateway/configuration für das gemeinsame Muster.

  1. Starte den Gateway. Telegram startet, wenn ein Token aufgelöst wird (Config zuerst, Umgebungsvariable als Fallback).
  2. DM-Zugriff nutzt standardmäßig Pairing. Genehmige den Code, wenn der Bot zum ersten Mal kontaktiert wird.
  3. Für Gruppen: Füge den Bot hinzu, entscheide über Privacy/Admin-Verhalten (siehe unten), und setze dann channels.telegram.groups, um Mention-Gating und Allowlists zu steuern.

Token + Privacy + Berechtigungen (Telegram-Seite)

Token-Erstellung (BotFather)

  • /newbot erstellt den Bot und gibt den Token zurück (halte ihn geheim).
  • Wenn ein Token geleakt ist, widerrufe/regeneriere ihn über @BotFather und aktualisiere deine Config.

Gruppennachrichten-Sichtbarkeit (Privacy Mode)

Telegram-Bots nutzen standardmäßig den Privacy Mode, der einschränkt, welche Gruppennachrichten sie empfangen. Wenn dein Bot alle Gruppennachrichten sehen muss, hast du zwei Optionen:

  • Deaktiviere den Privacy Mode mit /setprivacy oder
  • Füge den Bot als Gruppen-Admin hinzu (Admin-Bots empfangen alle Nachrichten).

Hinweis: Wenn du den Privacy Mode umschaltest, verlangt Telegram, dass du den Bot aus jeder Gruppe entfernst und wieder hinzufügst, damit die Änderung wirksam wird.

Gruppenberechtigungen (Admin-Rechte)

Der Admin-Status wird innerhalb der Gruppe gesetzt (Telegram UI). Admin-Bots empfangen immer alle Gruppennachrichten, also nutze Admin, wenn du volle Sichtbarkeit brauchst.

Wie es funktioniert (Verhalten)

  • Eingehende Nachrichten werden in den gemeinsamen Channel-Envelope normalisiert, mit Antwort-Kontext und Media-Platzhaltern.
  • Gruppenantworten erfordern standardmäßig eine Erwähnung (natives @mention oder agents.list[].groupChat.mentionPatterns / messages.groupChat.mentionPatterns).
  • Multi-Agent-Override: Setze Agent-spezifische Patterns auf agents.list[].groupChat.mentionPatterns.
  • Antworten werden immer zurück zum selben Telegram-Chat geroutet.
  • Long-Polling nutzt grammY Runner mit Chat-spezifischer Sequenzierung; die Gesamt-Concurrency ist durch agents.defaults.maxConcurrent begrenzt.
  • Die Telegram Bot API unterstützt keine Lesebestätigungen; es gibt keine sendReadReceipts-Option.

Draft Streaming

OpenClaw kann partielle Antworten in Telegram-DMs streamen, indem es sendMessageDraft nutzt.

Voraussetzungen:

  • Threaded Mode für den Bot in @BotFather aktiviert (Forum-Topic-Modus).
  • Nur private Chat-Threads (Telegram fügt message_thread_id zu eingehenden Nachrichten hinzu).
  • channels.telegram.streamMode nicht auf "off" gesetzt (Standard: "partial", "block" aktiviert chunked Draft-Updates).

Draft Streaming funktioniert nur in DMs; Telegram unterstützt es nicht in Gruppen oder Channels.

Formatierung (Telegram HTML)

  • Ausgehender Telegram-Text nutzt parse_mode: "HTML" (Telegrams unterstützte Tag-Teilmenge).
  • Markdown-ähnliche Eingabe wird in Telegram-sicheres HTML gerendert (fett/kursiv/durchgestrichen/code/links); Block-Elemente werden zu Text mit Zeilenumbrüchen/Bullets geflacht.
  • Rohes HTML von Modellen wird escaped, um Telegram-Parse-Fehler zu vermeiden.
  • Wenn Telegram die HTML-Payload ablehnt, versucht OpenClaw die gleiche Nachricht als Plain Text erneut.

Befehle (native + custom)

OpenClaw registriert native Befehle (wie /status, /reset, /model) beim Start im Telegram-Bot-Menü. Du kannst custom Befehle über die Config zum Menü hinzufügen:

{
  channels: {
    telegram: {
      customCommands: [
        { command: "backup", description: "Git backup" },
        { command: "generate", description: "Create an image" },
      ],
    },
  },
}

Troubleshooting

  • setMyCommands failed in den Logs bedeutet normalerweise, dass ausgehende HTTPS/DNS zu api.telegram.org blockiert ist.
  • Wenn du sendMessage- oder sendChatAction-Fehler siehst, prüfe IPv6-Routing und DNS.

Mehr Hilfe: Channel Troubleshooting.

Hinweise:

  • Custom Befehle sind nur Menü-Einträge; OpenClaw implementiert sie nicht, außer du behandelst sie anderswo.
  • Befehlsnamen werden normalisiert (führendes / entfernt, kleingeschrieben) und müssen a-z, 0-9, _ entsprechen (1–32 Zeichen).
  • Custom Befehle können native Befehle nicht überschreiben. Konflikte werden ignoriert und geloggt.
  • Wenn commands.native deaktiviert ist, werden nur custom Befehle registriert (oder gelöscht, wenn keine vorhanden sind).

Limits

  • Ausgehender Text wird in Chunks von channels.telegram.textChunkLimit aufgeteilt (Standard 4000).
  • Optionales Newline-Chunking: Setze channels.telegram.chunkMode="newline", um bei Leerzeilen (Absatzgrenzen) zu splitten, bevor nach Länge gechunkt wird.
  • Media-Downloads/-Uploads sind durch channels.telegram.mediaMaxMb begrenzt (Standard 5).
  • Telegram Bot API Requests haben ein Timeout nach channels.telegram.timeoutSeconds (Standard 500 via grammY). Setze einen niedrigeren Wert, um lange Hänger zu vermeiden.
  • Gruppen-History-Context nutzt channels.telegram.historyLimit (oder channels.telegram.accounts.*.historyLimit), mit Fallback auf messages.groupChat.historyLimit. Setze 0 zum Deaktivieren (Standard 50).
  • DM-History kann mit channels.telegram.dmHistoryLimit (User-Turns) begrenzt werden. Pro-User-Overrides: channels.telegram.dms["<user_id>"].historyLimit.

Gruppen-Aktivierungsmodi

Standardmäßig antwortet der Bot nur auf Erwähnungen in Gruppen (@botname oder Patterns in agents.list[].groupChat.mentionPatterns). Um dieses Verhalten zu ändern:

Via Config (empfohlen)

{
  channels: {
    telegram: {
      groups: {
        "-1001234567890": { requireMention: false }, // immer antworten in dieser Gruppe
      },
    },
  },
}

Wichtig: Das Setzen von channels.telegram.groups erstellt eine Allowlist - nur gelistete Gruppen (oder "*") werden akzeptiert. Forum-Topics erben die Config ihrer Parent-Gruppe (allowFrom, requireMention, skills, prompts), außer du fügst Topic-spezifische Overrides unter channels.telegram.groups.<groupId>.topics.<topicId> hinzu.

Um alle Gruppen mit Always-Respond zu erlauben:

{
  channels: {
    telegram: {
      groups: {
        "*": { requireMention: false }, // alle Gruppen, immer antworten
      },
    },
  },
}

Um Mention-Only für alle Gruppen beizubehalten (Standardverhalten):

{
  channels: {
    telegram: {
      groups: {
        "*": { requireMention: true }, // oder groups komplett weglassen
      },
    },
  },
}

Via Befehl (Session-Level)

Sende in der Gruppe:

  • /activation always - auf alle Nachrichten antworten
  • /activation mention - Erwähnungen erforderlich (Standard)

Hinweis: Befehle aktualisieren nur den Session-State. Für persistentes Verhalten über Neustarts hinweg nutze die Config.

Gruppen-Chat-ID herausfinden

Leite eine beliebige Nachricht aus der Gruppe an @userinfobot oder @getidsbot auf Telegram weiter, um die Chat-ID zu sehen (negative Zahl wie -1001234567890).

Tipp: Für deine eigene User-ID schreibe dem Bot eine DM und er antwortet mit deiner User-ID (Pairing-Nachricht), oder nutze /whoami, sobald Befehle aktiviert sind.

Privacy-Hinweis: @userinfobot ist ein Drittanbieter-Bot. Wenn du das bevorzugst, füge den Bot zur Gruppe hinzu, sende eine Nachricht und nutze openclaw logs --follow, um chat.id zu lesen, oder verwende die Bot API getUpdates.

Config Writes

Standardmäßig darf Telegram Config-Updates schreiben, die durch Channel-Events oder /config set|unset ausgelöst werden.

Das passiert, wenn:

  • Eine Gruppe zu einer Supergroup aufgewertet wird und Telegram migrate_to_chat_id sendet (Chat-ID ändert sich). OpenClaw kann channels.telegram.groups automatisch migrieren.
  • Du /config set oder /config unset in einem Telegram-Chat ausführst (erfordert commands.config: true).

Deaktivieren mit:

{
  channels: { telegram: { configWrites: false } },
}

Topics (Forum-Supergroups)

Telegram-Forum-Topics enthalten eine message_thread_id pro Nachricht. OpenClaw:

  • Hängt :topic:<threadId> an den Telegram-Gruppen-Session-Key an, sodass jedes Topic isoliert ist.
  • Sendet Typing-Indikatoren und Antworten mit message_thread_id, sodass Antworten im Topic bleiben.
  • General Topic (Thread-ID 1) ist speziell: Nachrichten werden ohne message_thread_id gesendet (Telegram lehnt es ab), aber Typing-Indikatoren enthalten es trotzdem.
  • Stellt MessageThreadId + IsForum im Template-Context für Routing/Templating bereit.
  • Topic-spezifische Konfiguration ist verfügbar unter channels.telegram.groups.<chatId>.topics.<threadId> (skills, allowlists, auto-reply, system prompts, disable).
  • Topic-Configs erben Gruppen-Einstellungen (requireMention, allowlists, skills, prompts, enabled), außer sie werden pro Topic überschrieben.

Private Chats können in einigen Edge Cases message_thread_id enthalten. OpenClaw behält den DM-Session-Key unverändert, nutzt aber trotzdem die Thread-ID für Antworten/Draft-Streaming, wenn sie vorhanden ist.

Inline Buttons

Telegram unterstützt Inline-Keyboards mit Callback-Buttons.

{
  channels: {
    telegram: {
      capabilities: {
        inlineButtons: "allowlist",
      },
    },
  },
}

Für Account-spezifische Konfiguration:

{
  channels: {
    telegram: {
      accounts: {
        main: {
          capabilities: {
            inlineButtons: "allowlist",
          },
        },
      },
    },
  },
}

Scopes:

  • off — Inline-Buttons deaktiviert
  • dm — nur DMs (Gruppen-Targets blockiert)
  • group — nur Gruppen (DM-Targets blockiert)
  • all — DMs + Gruppen
  • allowlist — DMs + Gruppen, aber nur Sender, die durch allowFrom/groupAllowFrom erlaubt sind (gleiche Regeln wie Control-Befehle)

Standard: allowlist. Legacy: capabilities: ["inlineButtons"] = inlineButtons: "all".

Buttons senden

Nutze das Message-Tool mit dem buttons-Parameter:

{
  action: "send",
  channel: "telegram",
  to: "123456789",
  message: "Choose an option:",
  buttons: [
    [
      { text: "Yes", callback_data: "yes" },
      { text: "No", callback_data: "no" },
    ],
    [{ text: "Cancel", callback_data: "cancel" }],
  ],
}

Wenn ein User einen Button klickt, werden die Callback-Daten als Nachricht an den Agent zurückgesendet, im Format: callback_data: value

Konfigurationsoptionen

Telegram-Capabilities können auf zwei Ebenen konfiguriert werden (Objekt-Form oben gezeigt; Legacy-String-Arrays werden noch unterstützt):

  • channels.telegram.capabilities: Globale Standard-Capability-Config, die auf alle Telegram-Accounts angewendet wird, außer sie wird überschrieben.
  • channels.telegram.accounts.<account>.capabilities: Account-spezifische Capabilities, die die globalen Standards für diesen Account überschreiben.

Nutze die globale Einstellung, wenn alle Telegram-Bots/Accounts sich gleich verhalten sollen. Nutze Account-spezifische Konfiguration, wenn verschiedene Bots unterschiedliches Verhalten brauchen (z.B. ein Account behandelt nur DMs, während ein anderer in Gruppen erlaubt ist).

Zugriffskontrolle (DMs + Gruppen)

DM-Zugriff

  • Standard: channels.telegram.dmPolicy = "pairing". Unbekannte Sender erhalten einen Pairing-Code; Nachrichten werden ignoriert, bis sie genehmigt sind (Codes laufen nach 1 Stunde ab).
  • Genehmigen via:
    • openclaw pairing list telegram
    • openclaw pairing approve telegram <CODE>
  • Pairing ist der Standard-Token-Austausch für Telegram-DMs. Details: Pairing
  • channels.telegram.allowFrom akzeptiert numerische User-IDs (empfohlen) oder @username-Einträge. Es ist nicht der Bot-Username; nutze die ID des menschlichen Senders. Der Wizard akzeptiert @username und löst es zur numerischen ID auf, wenn möglich.

Deine Telegram-User-ID herausfinden

Sicherer (kein Drittanbieter-Bot):

  1. Starte den Gateway und schreibe deinem Bot eine DM.
  2. Führe openclaw logs --follow aus und suche nach from.id.

Alternative (offizielle Bot API):

  1. Schreibe deinem Bot eine DM.
  2. Hole Updates mit deinem Bot-Token und lies message.from.id:
    curl "https://api.telegram.org/bot<bot_token>/getUpdates"

Drittanbieter (weniger privat):

  • Schreibe @userinfobot oder @getidsbot eine DM und nutze die zurückgegebene User-ID.

Gruppen-Zugriff

Zwei unabhängige Kontrollen:

1. Welche Gruppen erlaubt sind (Gruppen-Allowlist via channels.telegram.groups):

  • Keine groups-Config = alle Gruppen erlaubt
  • Mit groups-Config = nur gelistete Gruppen oder "*" sind erlaubt
  • Beispiel: "groups": { "-1001234567890": {}, "*": {} } erlaubt alle Gruppen

2. Welche Sender erlaubt sind (Sender-Filterung via channels.telegram.groupPolicy):

  • "open" = alle Sender in erlaubten Gruppen können Nachrichten senden
  • "allowlist" = nur Sender in channels.telegram.groupAllowFrom können Nachrichten senden
  • "disabled" = keine Gruppennachrichten werden akzeptiert Standard ist groupPolicy: "allowlist" (blockiert, außer du fügst groupAllowFrom hinzu).

Die meisten User wollen: groupPolicy: "allowlist" + groupAllowFrom + spezifische Gruppen in channels.telegram.groups gelistet

Long-Polling vs Webhook

  • Standard: Long-Polling (keine öffentliche URL erforderlich).
  • Webhook-Modus: Setze channels.telegram.webhookUrl und channels.telegram.webhookSecret (optional channels.telegram.webhookPath).
    • Der lokale Listener bindet an 0.0.0.0:8787 und bedient POST /telegram-webhook standardmäßig.
    • Wenn deine öffentliche URL anders ist, nutze einen Reverse Proxy und zeige channels.telegram.webhookUrl auf den öffentlichen Endpoint.

Reply Threading

Telegram unterstützt optionale Thread-Antworten via Tags:

  • [[reply_to_current]] — antworte auf die auslösende Nachricht.
  • [[reply_to:<id>]] — antworte auf eine spezifische Nachrichten-ID.

Gesteuert durch channels.telegram.replyToMode:

  • first (Standard), all, off.

Audio-Nachrichten (Voice vs File)

Telegram unterscheidet Voice Notes (runde Blase) von Audio-Dateien (Metadaten-Karte). OpenClaw nutzt standardmäßig Audio-Dateien für Rückwärtskompatibilität.

Um eine Voice-Note-Blase in Agent-Antworten zu erzwingen, füge dieses Tag irgendwo in die Antwort ein:

  • [[audio_as_voice]] — sende Audio als Voice Note statt als Datei.

Das Tag wird aus dem gelieferten Text entfernt. Andere Channels ignorieren dieses Tag.

Für Message-Tool-Sends setze asVoice: true mit einer Voice-kompatiblen Audio-media-URL (message ist optional, wenn Media vorhanden ist):

{
  action: "send",
  channel: "telegram",
  to: "123456789",
  media: "https://example.com/voice.ogg",
  asVoice: true,
}

Stickers

OpenClaw unterstützt das Empfangen und Senden von Telegram-Stickern mit intelligentem Caching.

Sticker empfangen

Wenn ein User einen Sticker sendet, behandelt OpenClaw ihn basierend auf dem Sticker-Typ:

  • Statische Sticker (WEBP): Heruntergeladen und durch Vision verarbeitet. Der Sticker erscheint als <media:sticker>-Platzhalter im Nachrichteninhalt.
  • Animierte Sticker (TGS): Übersprungen (Lottie-Format wird nicht für die Verarbeitung unterstützt).
  • Video-Sticker (WEBM): Übersprungen (Video-Format wird nicht für die Verarbeitung unterstützt).

Template-Context-Feld verfügbar beim Empfangen von Stickern:

  • Sticker — Objekt mit:
    • emoji — Emoji, das mit dem Sticker assoziiert ist
    • setName — Name des Sticker-Sets
    • fileId — Telegram-File-ID (sende den gleichen Sticker zurück)
    • fileUniqueId — stabile ID für Cache-Lookup
    • cachedDescription — gecachte Vision-Beschreibung, wenn verfügbar

Sticker-Cache

Sticker werden durch die Vision-Fähigkeiten der AI verarbeitet, um Beschreibungen zu generieren. Da die gleichen Sticker oft wiederholt gesendet werden, cached OpenClaw diese Beschreibungen, um redundante API-Calls zu vermeiden.

Wie es funktioniert:

  1. Erste Begegnung: Das Sticker-Bild wird zur Vision-Analyse an die AI gesendet. Die AI generiert eine Beschreibung (z.B. “Eine Cartoon-Katze, die enthusiastisch winkt”).
  2. Cache-Speicherung: Die Beschreibung wird zusammen mit der File-ID, dem Emoji und dem Set-Namen des Stickers gespeichert.
  3. Nachfolgende Begegnungen: Wenn der gleiche Sticker wieder gesehen wird, wird die gecachte Beschreibung direkt genutzt. Das Bild wird nicht an die AI gesendet.

Cache-Speicherort: ~/.openclaw/telegram/sticker-cache.json

Cache-Entry-Format:

{
  "fileId": "CAACAgIAAxkBAAI...",
  "fileUniqueId": "AgADBAADb6cxG2Y",
  "emoji": "👋",
  "setName": "CoolCats",
  "description": "A cartoon cat waving enthusiastically",
  "cachedAt": "2026-01-15T10:30:00.000Z"
}

Vorteile:

  • Reduziert API-Kosten durch Vermeidung wiederholter Vision-Calls für den gleichen Sticker
  • Schnellere Antwortzeiten für gecachte Sticker (keine Vision-Verarbeitungsverzögerung)
  • Ermöglicht Sticker-Suchfunktionalität basierend auf gecachten Beschreibungen

Der Cache wird automatisch gefüllt, wenn Sticker empfangen werden. Es ist kein manuelles Cache-Management erforderlich.

Sticker senden

Der Agent kann Sticker senden und suchen, indem er die sticker- und sticker-search-Actions nutzt. Diese sind standardmäßig deaktiviert und müssen in der Config aktiviert werden:

{
  channels: {
    telegram: {
      actions: {
        sticker: true,
      },
    },
  },
}

Einen Sticker senden:

{
  action: "sticker",
  channel: "telegram",
  to: "123456789",
  fileId: "CAACAgIAAxkBAAI...",
}

Parameter:

  • fileId (erforderlich) — die Telegram-File-ID des Stickers. Erhalte diese von Sticker.fileId beim Empfangen eines Stickers oder von einem sticker-search-Ergebnis.
  • replyTo (optional) — Nachrichten-ID, auf die geantwortet werden soll.
  • threadId (optional) — Message-Thread-ID für Forum-Topics.

Nach Stickern suchen:

Der Agent kann gecachte Sticker nach Beschreibung, Emoji oder Set-Namen durchsuchen:

{
  action: "sticker-search",
  channel: "telegram",
  query: "cat waving",
  limit: 5,
}

Gibt passende Sticker aus dem Cache zurück:

{
  ok: true,
  count: 2,
  stickers: [
    {
      fileId: "CAACAgIAAxkBAAI...",
      emoji: "👋",
      description: "A cartoon cat waving enthusiastically",
      setName: "CoolCats",
    },
  ],
}

Die Suche nutzt Fuzzy-Matching über Beschreibungstext, Emoji-Zeichen und Set-Namen.

Beispiel mit Threading:

{
  action: "sticker",
  channel: "telegram",
  to: "-1001234567890",
  fileId: "CAACAgIAAxkBAAI...",
  replyTo: 42,
  threadId: 123,
}

Streaming (Drafts)

Telegram kann Draft-Bubbles streamen, während der Agent eine Antwort generiert. OpenClaw nutzt Bot API sendMessageDraft (keine echten Nachrichten) und sendet dann die finale Antwort als normale Nachricht.

Voraussetzungen (Telegram Bot API 9.3+):

  • Private Chats mit aktivierten Topics (Forum-Topic-Modus für den Bot).
  • Eingehende Nachrichten müssen message_thread_id enthalten (privater Topic-Thread).
  • Streaming wird für Gruppen/Supergroups/Channels ignoriert.

Config:

  • channels.telegram.streamMode: "off" | "partial" | "block" (Standard: partial)
    • partial: aktualisiere die Draft-Bubble mit dem neuesten Streaming-Text.
    • block: aktualisiere die Draft-Bubble in größeren Blöcken (gechunkt).
    • off: deaktiviere Draft-Streaming.
  • Optional (nur für streamMode: "block"):
    • channels.telegram.draftChunk: { minChars?, maxChars?, breakPreference? }
      • Standards: minChars: 200, maxChars: 800, breakPreference: "paragraph" (begrenzt auf channels.telegram.textChunkLimit).

Hinweis: Draft-Streaming ist getrennt von Block-Streaming (Channel-Nachrichten). Block-Streaming ist standardmäßig aus und erfordert channels.telegram.blockStreaming: true, wenn du frühe Telegram-Nachrichten statt Draft-Updates willst.

Reasoning Stream (nur Telegram):

  • /reasoning stream streamt Reasoning in die Draft-Bubble, während die Antwort generiert wird, und sendet dann die finale Antwort ohne Reasoning.
  • Wenn channels.telegram.streamMode auf off ist, ist Reasoning Stream deaktiviert. Mehr Kontext: Streaming + chunking.

Retry Policy

Ausgehende Telegram API Calls werden bei transienten Netzwerk-/429-Fehlern mit exponentiellem Backoff und Jitter wiederholt. Konfiguriere via channels.telegram.retry. Siehe Retry Policy.

Agent Tool (Nachrichten + Reaktionen)

  • Tool: telegram mit sendMessage-Action (to, content, optional mediaUrl, replyToMessageId, messageThreadId).
  • Tool: telegram mit react-Action (chatId, messageId, emoji).
  • Tool: telegram mit deleteMessage-Action (chatId, messageId).
  • Reaktions-Entfernungs-Semantik: siehe /tools/reactions.
  • Tool-Gating: channels.telegram.actions.reactions, channels.telegram.actions.sendMessage, channels.telegram.actions.deleteMessage (Standard: aktiviert), und channels.telegram.actions.sticker (Standard: deaktiviert).

Reaktions-Benachrichtigungen

Wie Reaktionen funktionieren: Telegram-Reaktionen kommen als separate message_reaction-Events, nicht als Properties in Nachrichten-Payloads. Wenn ein User eine Reaktion hinzufügt, macht OpenClaw Folgendes:

  1. Empfängt das message_reaction-Update von der Telegram API
  2. Konvertiert es zu einem System-Event mit Format: "Telegram reaction added: {emoji} by {user} on msg {id}"
  3. Reiht das System-Event mit dem gleichen Session-Key wie reguläre Nachrichten ein
  4. Wenn die nächste Nachricht in dieser Konversation ankommt, werden System-Events geleert und dem Context des Agents vorangestellt

Der Agent sieht Reaktionen als System-Benachrichtigungen in der Konversations-History, nicht als Nachrichten-Metadaten.

Konfiguration:

  • channels.telegram.reactionNotifications: Steuert, welche Reaktionen Benachrichtigungen auslösen

    • "off" — ignoriere alle Reaktionen
    • "own" — benachrichtige, wenn User auf Bot-Nachrichten reagieren (Best-Effort; in-memory) (Standard)
    • "all" — benachrichtige für alle Reaktionen
  • channels.telegram.reactionLevel: Steuert die Reaktions-Fähigkeit des Agents

    • "off" — Agent kann nicht auf Nachrichten reagieren
    • "ack" — Bot sendet Bestätigungs-Reaktionen (👀 während der Verarbeitung) (Standard)
    • "minimal" — Agent kann sparsam reagieren (Richtlinie: 1 pro 5-10 Austausche)
    • "extensive" — Agent kann liberal reagieren, wenn angemessen

Forum-Gruppen: Reaktionen in Forum-Gruppen enthalten message_thread_id und nutzen Session-Keys wie agent:main:telegram:group:{chatId}:topic:{threadId}. Das stellt sicher, dass Reaktionen und Nachrichten im gleichen Topic zusammenbleiben.

Beispiel-Config:

{
  channels: {
    telegram: {
      reactionNotifications: "all", // Alle Reaktionen sehen
      reactionLevel: "minimal", // Agent kann sparsam reagieren
    },
  },
}

Voraussetzungen:

  • Telegram-Bots müssen explizit message_reaction in allowed_updates anfordern (wird automatisch von OpenClaw konfiguriert)
  • Für Webhook-Modus sind Reaktionen in den Webhook-allowed_updates enthalten
  • Für Polling-Modus sind Reaktionen in den getUpdates-allowed_updates enthalten

Delivery Targets (CLI/Cron)

  • Nutze eine Chat-ID (123456789) oder einen Username (@name) als Target.
  • Beispiel: openclaw message send --channel telegram --target 123456789 --message "hi".

Troubleshooting

Bot antwortet nicht auf Nicht-Erwähnungs-Nachrichten in einer Gruppe:

  • Wenn du channels.telegram.groups.*.requireMention=false setzt, muss der Privacy Mode der Telegram Bot API deaktiviert sein.
    • BotFather: /setprivacyDisable (dann entferne den Bot aus der Gruppe und füge ihn wieder hinzu)
  • openclaw channels status zeigt eine Warnung, wenn die Config unerwähnte Gruppennachrichten erwartet.
  • openclaw channels status --probe kann zusätzlich die Mitgliedschaft für explizite numerische Gruppen-IDs prüfen (es kann keine Wildcard-"*"-Regeln prüfen).
  • Schnelltest: /activation always (nur Session; nutze Config für Persistenz)

Bot sieht überhaupt keine Gruppennachrichten:

  • Wenn channels.telegram.groups gesetzt ist, muss die Gruppe gelistet sein oder "*" nutzen
  • Prüfe Privacy-Einstellungen in @BotFather → “Group Privacy” sollte OFF sein
  • Verifiziere, dass der Bot tatsächlich Mitglied ist (nicht nur Admin ohne Lesezugriff)
  • Prüfe Gateway-Logs: openclaw logs --follow (suche nach “skipping group message”)

Bot antwortet auf Erwähnungen, aber nicht auf /activation always:

  • Der /activation-Befehl aktualisiert den Session-State, persistiert aber nicht in die Config
  • Für persistentes Verhalten füge die Gruppe zu channels.telegram.groups mit requireMention: false hinzu

Befehle wie /status funktionieren nicht:

  • Stelle sicher, dass deine Telegram-User-ID autorisiert ist (via Pairing oder channels.telegram.allowFrom)
  • Befehle erfordern Autorisierung, auch in Gruppen mit groupPolicy: "open"

Long-Polling bricht sofort ab auf Node 22+ (oft mit Proxies/custom fetch):

  • Node 22+ ist strenger bei AbortSignal-Instanzen; fremde Signals können fetch-Calls sofort abbrechen.
  • Upgrade auf einen OpenClaw-Build, der Abort-Signals normalisiert, oder führe den Gateway auf Node 20 aus, bis du upgraden kannst.

Bot startet, hört dann still auf zu antworten (oder loggt HttpError: Network request ... failed):

  • Einige Hosts lösen api.telegram.org zuerst zu IPv6 auf. Wenn dein Server keinen funktionierenden IPv6-Egress hat, kann grammY bei IPv6-only-Requests hängen bleiben.
  • Behebe das, indem du IPv6-Egress aktivierst oder IPv4-Auflösung für api.telegram.org erzwingst (z.B. füge einen /etc/hosts-Eintrag mit dem IPv4-A-Record hinzu, oder bevorzuge IPv4 in deinem OS-DNS-Stack), dann starte den Gateway neu.
  • Schnellcheck: dig +short api.telegram.org A und dig +short api.telegram.org AAAA, um zu bestätigen, was DNS zurückgibt.

Konfigurationsreferenz (Telegram)

Vollständige Konfiguration: Configuration

Provider-Optionen:

  • channels.telegram.enabled: Channel-Start aktivieren/deaktivieren.
  • channels.telegram.botToken: Bot-Token (BotFather).
  • channels.telegram.tokenFile: Token aus Dateipfad lesen.
  • channels.telegram.dmPolicy: pairing | allowlist | open | disabled (Standard: pairing).
  • channels.telegram.allowFrom: DM-Allowlist (IDs/Usernames). open erfordert "*".
  • channels.telegram.groupPolicy: open | allowlist | disabled (Standard: allowlist).
  • channels.telegram.groupAllowFrom: Gruppen-Sender-Allowlist (IDs/Usernames).
  • channels.telegram.groups: Pro-Gruppen-Standards + Allowlist (nutze "*" für globale Standards).
    • channels.telegram.groups.<id>.requireMention: Mention-Gating-Standard.
    • channels.telegram.groups.<id>.skills: Skill-Filter (weglassen = alle Skills, leer = keine).
    • channels.telegram.groups.<id>.allowFrom: Pro-Gruppen-Sender-Allowlist-Override.
    • channels.telegram.groups.<id>.systemPrompt: Extra-System-Prompt für die Gruppe.
    • channels.telegram.groups.<id>.enabled: Gruppe deaktivieren, wenn false.
    • channels.telegram.groups.<id>.topics.<threadId>.*: Pro-Topic-Overrides (gleiche Felder wie Gruppe).
    • channels.telegram.groups.<id>.topics.<threadId>.requireMention: Pro-Topic-Mention-Gating-Override.
  • channels.telegram.capabilities.inlineButtons: off | dm | group | all | allowlist (Standard: allowlist).
  • channels.telegram.accounts.<account>.capabilities.inlineButtons: Pro-Account-Override.
  • channels.telegram.replyToMode: off | first | all (Standard: first).
  • channels.telegram.textChunkLimit: Ausgehende Chunk-Größe (Zeichen).
  • channels.telegram.chunkMode: length (Standard) oder newline, um bei Leerzeilen (Absatzgrenzen) zu splitten, bevor nach Länge gechunkt wird.
  • channels.telegram.linkPreview: Link-Vorschauen für ausgehende Nachrichten umschalten (Standard: true).
  • channels.telegram.streamMode: off | partial | block (Draft-Streaming).
  • channels.telegram.mediaMaxMb: Eingehende/ausgehende Media-Begrenzung (MB).
  • channels.telegram.retry: Retry-Policy für ausgehende Telegram API Calls (attempts, minDelayMs, maxDelayMs, jitter).
  • channels.telegram.network.autoSelectFamily: Node autoSelectFamily überschreiben (true=aktivieren, false=deaktivieren). Standardmäßig deaktiviert auf Node 22, um Happy-Eyeballs-Timeouts zu vermeiden.
  • channels.telegram.proxy: Proxy-URL für Bot API Calls (SOCKS/HTTP).
  • channels.telegram.webhookUrl: Webhook-Modus aktivieren (erfordert channels.telegram.webhookSecret).
  • channels.telegram.webhookSecret: Webhook-Secret (erforderlich, wenn webhookUrl gesetzt ist).
  • channels.telegram.webhookPath: Lokaler Webhook-Pfad (Standard /telegram-webhook).
  • channels.telegram.actions.reactions: Telegram-Tool-Reaktionen gaten.
  • channels.telegram.actions.sendMessage: Telegram-Tool-Nachrichten-Sends gaten.
  • channels.telegram.actions.deleteMessage: Telegram-Tool-Nachrichten-Deletes gaten.
  • channels.telegram.actions.sticker: Telegram-Sticker-Actions gaten — senden und suchen (Standard: false).
  • channels.telegram.reactionNotifications: off | own | all — steuere, welche Reaktionen System-Events auslösen (Standard: own, wenn nicht gesetzt).
  • channels.telegram.reactionLevel: off | ack | minimal | extensive — steuere die Reaktions-Fähigkeit des Agents (Standard: minimal, wenn nicht gesetzt).

Verwandte globale Optionen:

  • agents.list[].groupChat.mentionPatterns (Mention-Gating-Patterns).
  • messages.groupChat.mentionPatterns (globaler Fallback).
  • commands.native (Standard: "auto" → on für Telegram/Discord, off für Slack), commands.text, commands.useAccessGroups (Befehls-Verhalten). Override mit channels.telegram.commands.native.
  • messages.responsePrefix, messages.ackReaction, messages.ackReactionScope, messages.removeAckAfterReply.