Skip to content

Telegram

Telegram は 両方 のモードで動作します:

モード内容
通知アラートパイプラインからの単方向 sendMessage
IM bridgegetUpdates 長ポーリングによるエージェントとの双方向チャット。

同じ bot token(@BotFather からの 8…:AA…)が両方を駆動 —— Telegram は path 内 token で認証します。独立した署名スキームはありません。

Feishu / DingTalk 圏外のユーザー向けに設計

Telegram は Ongrid が非中国チームと、オペレーターが Telegram にいるハイブリッド デプロイに推奨する IM チャネルです。プロバイダーは ADR-031 で追加されました。

通知モード

notify.Sender{chat_id, text}https://api.telegram.org/bot<TOKEN>/sendMessage に POST。認証情報は bot token(path 内)、 chat_id(数値)は宛先チャットです。

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

endpoint は literal な …/bot<TOKEN>/sendMessage URL、chatID はターゲットチャット (DM ならユーザーの数値 ID、グループなら Telegram から渡される負の番号)。

セットアップ:

  1. @BotFather に DM → /newbot → username を選択 → token をコピー。
  2. ターゲットチャット(グループ / チャンネル)に bot を追加するか、一度 DM して bot が自分を認識するように。
  3. chat ID を取得。最速:チャットでメッセージ送信、curl https://api.telegram.org/bot<TOKEN>/getUpdatesresult[0].message.chat.id を読む。
  4. Ongrid で:Settings → Channels → New → Provider = telegram → Endpoint = https://api.telegram.org/bot<TOKEN>/sendMessage、 chat_id = ステップ 3 の番号。

IM bridge モード(双方向)

受信は manager のアウトバウンド HTTPS 接続から長ポーリング。呼び出しが アウトバウンド なので、 Telegram は NAT、ファイアウォール、HTTPS プロキシ背後で動作します。setWebhook(代替)は Telegram が manager に到達する必要があり —— ほとんどのプライベートクラウドデプロイと両立せず、 中国本土から不安定です。

stream のみがモード

バリデーターは他のすべてを拒否:

telegram only supports stream mode

webhook モードは Telegram の UI に公開されていません。

認証情報マッピング

im_apps 行は既存のカラムを再利用 —— スキーマ変更なし:

im_apps カラムTelegram の意味
provider"telegram"
mode"stream"(バリデーターがピン)
app_idbot username(例 ongridbot)。表示 + 重複排除。
app_secretBotFather token8…:AA…)。保存時暗号化。
allow_from必須 カンマ区切り数値ユーザー ID。
verify_token未使用。
encrypt_key未使用。

allow_from

bot と会話できる数値 Telegram ユーザー ID の非空リスト。バリデーターは非数値トークンを落とし (タイポの alice は静かに空の許可リストではなくクリーンな required-error になる)、 負のトークン(グループ / supergroup chat ID)を拒否(送信者許可リストに属さないから)。

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)

数値ユーザー ID を見つける方法:

  • @userinfobot に DM するとあなたの数値 ID を返します。
  • または登録後にチャットでメッセージ送信、curl https://api.telegram.org/bot<TOKEN>/getUpdatesresult[0].message.from.id を読む。

telegram: / tg: プレフィックスは静かに剥がされ(OpenClaw 互換)、telegram:123456789123456789 は同じエントリです。

ミスでサイレントドロップ

非許可リスト送信者は WARN ログでドロップ:

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

返信なし。プレースホルダーなし。bot は存在を確認すらしません。これは OpenClaw allowFrom をミラー —— 返信するとエージェント装備の bot がこの username にいることを漏らし、人々の探りを誘うからです。

セットアップ

  1. @BotFather に DM → /newbot → 名前と bot で終わるユニーク username を選択。token をコピー。
  2. (任意)@BotFather → /setprivacy → Disable —— bot がグループ内のメッセージを見たい場合 (デフォルトは mention のみ)。
  3. @userinfobot で数値ユーザー ID を見つける。
  4. Ongrid で:Settings → IM bridge → New → Provider = telegram → Mode = stream → App ID = bot username → App secret = BotFather token → allow_from = 自分の数値 ID(とチームメイトの)。保存して Enable
  5. 許可リストアカウントから bot に DM。bot はプレースホルダーで返信し、エージェントが推論する間に編集します。

プロキシ事情

Telegram API ホスト(api.telegram.org)は多くのネットワークで到達可能ですが、中国本土からブロックされています。 プロバイダーはゼロ値の http.Client を使うので manager 環境の HTTPS_PROXY / HTTP_PROXY / NO_PROXY を尊重 —— getUpdates を運ぶプロキシが sendMessage も運びます。

docker-compose デプロイでは 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

メインの docker-compose.yml にプロキシを入れない

メインの docker-compose.yml は各リリースで同梱されます。override ファイルは 環境別で make package / インストールスクリプト再実行を生き残ります。

知っておく価値のある癖

message is not modified は無害

Telegram は editMessageText ペイロードが現在のメッセージテキストに完全一致するとき HTTP 400(message is not modified)を返します。プログレッシブストリーミングは スロットルされた tick や最終フラッシュで同じチャンクを繰り返すことがあります。 クライアントはこのエラー文字列だけを吞み込み nil を返す —— それ以外(400、403、5xx)は伝播します。 EditMessageText を参照。

bot ごとに 1 つの poller

Telegram は並行 getUpdates 呼び出しを拒否。StreamSupervisorim_app 行ごとに 1 クライアントを強制。 Telegram アプリ行を重複させると、ポーリング成功は 1 つだけ —— もう一つは 409 Conflict を見てバックオフします。

レート制限リトライ

429 Too Many Requests は最大 3 回リトライ。待機は Telegram の parameters.retry_after を尊重し、60 秒で上限。 5xx エラーは 1s / 2s / 4s バックオフでリトライ。ハード 4xx(400/401/403)は リトライしません —— スーパーバイザーにバブルアップし、おそらく token / chat-id 問題を示します。 maxCallRetries を参照。

長ポーリングタイムアウト

サーバー側の長ポーリングは 25 秒待ち (pollTimeoutSec)、 クライアント側に 10 秒バッファ。遅いネットワークは単に長いポーリングサイクルを見るだけで、 スーパーバイザーは busy-wait 再接続をしません。

テキストのみ

ステッカー、写真、ボイスノート、ファイルは静かにドロップ。message.text イベントだけが エージェントターンを駆動します。ブリッジは意図的に S1(テキスト in / テキスト out)—— リッチメディアは将来の拡張です。