Telegram
Telegram は 両方 のモードで動作します:
| モード | 内容 |
|---|---|
| 通知 | アラートパイプラインからの単方向 sendMessage。 |
| IM bridge | getUpdates 長ポーリングによるエージェントとの双方向チャット。 |
同じ 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(数値)は宛先チャットです。
// internal/pkg/notify/webhook.go
NewTelegramSender(name, endpoint, chatID, client)endpoint は literal な …/bot<TOKEN>/sendMessage URL、chatID はターゲットチャット (DM ならユーザーの数値 ID、グループなら Telegram から渡される負の番号)。
セットアップ:
@BotFatherに DM →/newbot→ username を選択 → token をコピー。- ターゲットチャット(グループ / チャンネル)に bot を追加するか、一度 DM して bot が自分を認識するように。
- chat ID を取得。最速:チャットでメッセージ送信、
curl https://api.telegram.org/bot<TOKEN>/getUpdates、result[0].message.chat.idを読む。 - 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_id | bot username(例 ongridbot)。表示 + 重複排除。 |
app_secret | BotFather token(8…: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>/getUpdates、result[0].message.from.idを読む。
telegram: / tg: プレフィックスは静かに剥がされ(OpenClaw 互換)、telegram:123456789 と 123456789 は同じエントリです。
ミスでサイレントドロップ
非許可リスト送信者は WARN ログでドロップ:
telegram inbound from non-allowlisted sender — ignored
user_id=42 user_name=alice chat_id=42返信なし。プレースホルダーなし。bot は存在を確認すらしません。これは OpenClaw allowFrom をミラー —— 返信するとエージェント装備の bot がこの username にいることを漏らし、人々の探りを誘うからです。
セットアップ
@BotFatherに DM →/newbot→ 名前とbotで終わるユニーク username を選択。token をコピー。- (任意)
@BotFather → /setprivacy → Disable—— bot がグループ内のメッセージを見たい場合 (デフォルトは mention のみ)。 @userinfobotで数値ユーザー ID を見つける。- Ongrid で:Settings → IM bridge → New → Provider =
telegram→ Mode =stream→ App ID = bot username → App secret = BotFather token →allow_from= 自分の数値 ID(とチームメイトの)。保存して Enable。 - 許可リストアカウントから 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 にプロキシを永続化:
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 呼び出しを拒否。StreamSupervisor は im_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)—— リッチメディアは将来の拡張です。