チャネル概要
Ongrid は チャネル を通じて人間と対話します。チャネルは以下のいずれかです:
- 通知チャネル —— Ongrid がチャット面にアラートを push。人間は読みますが、 チャネル自身は返信をエージェントに運びません。DB 上は
notify_channels、internal/pkg/notify/webhook.goの Sender 群がこれにあたります。 - IM チャネル —— Ongrid がワークスペースのチャット面に bot として常駐し、 受信メッセージを読み、Web UI が動かすのと同じエージェント推論を実行、 プレースホルダーメッセージへの編集として回答をストリーミングして返します。 DB 上は
im_apps、internal/manager/biz/imbridge/provider/*です。
両者は 独立 です。Telegram アラート(sendMessage 送出)を配線しても、 ユーザーが Telegram 上でエージェントとチャットできるようにはなりませんし、逆もまた然り。
別テーブル、別認証情報、同じ UI
両面とも Web UI の Settings → Channels で設定します。通知チャネルは Notify タブ、IM チャネルは IM bridge タブです。
どれが欲しい?
| ゴール | 使うもの | ファイル |
|---|---|---|
| 発火アラートを Slack チャネルに push | Slack incoming webhook (Notify) | internal/pkg/notify/webhook.go NewSlackSender |
| 発火アラートを Feishu/Lark グループに push | Feishu カスタム bot (Notify) | NewFeishuSender |
| 発火アラートを DingTalk グループに push | DingTalk カスタム bot (Notify) | NewDingTalkSender |
| 発火アラートを WeCom グループに push | WeCom グループ bot (Notify) | NewWeComSender |
| 自社サービスへの汎用 JSON POST | Webhook (Notify) | NewGenericWebhookSender |
| Telegram アラート(片方向) | Telegram bot sendMessage (Notify) | NewTelegramSender |
| Slack で bot としてエージェントと対話 | Slack Socket Mode アプリ (IM bridge) | imbridge/provider/slack/ |
| Telegram でエージェントと対話 | Telegram bot getUpdates (IM bridge) | imbridge/provider/telegram/ |
| Feishu/Larksuite でエージェントと対話 | Feishu 長接続 (IM bridge) | imbridge/provider/feishu/ |
ワークスペースは 両方 を運用できます:例:アラート用 Slack incoming webhook プラス会話用の独立した Slack Socket Mode アプリ。両者は状態を共有しません。
通知チャネル
通知チャネルはステートレスな Send(ctx, Message) Sender です。アラートが発火 (または回復、ダンプニングウィンドウ満了)するたびにアラートパイプラインから呼ばれます。 全チャネルタイプが同じ canonical な notify.Message 形を描画 —— プロバイダーごとに異なるのは ペイロード形式 と 署名プロトコル だけです。
Sender が受け取る共通フィールド
type Message struct {
Severity Severity // critical | warning | info
Subject string // alert rule name + target
Body string // human-readable detail
Source string // "alert" | "test" | ...
Labels map[string]string // rule, incident_id, device_id, ...
DedupeKey string // pipeline:rule:label-set
OccurredAt time.Time
}Slack sender はこれを attachments 形式に描画し、severity 色のサイドレール、 構造化フィールド(Severity、Source、Rule、Incident、Device、Dedupe)、 ts フッターを付けます。Feishu / DingTalk / WeCom sender は [SEV] subject\nbody\nsource:…\ndedupe:… テキストペイロードに平坦化します —— これらの bot API は v1 で平文のみだからです。
署名モデルの概観
| プロバイダー | 認証方法 |
|---|---|
| Slack | webhook URL 自体がシークレット。追加の署名なし。 |
| Feishu | HMAC-SHA256(ts\nsecret)、JSON ボディの sign に配置。 |
| DingTalk | HMAC-SHA256(ts\nsecret)、URL クエリの sign に配置。 |
| WeCom | URL クエリの bot key。追加の署名なし。 |
| Telegram | path に bot token(/bot<TOKEN>/sendMessage)。 |
| Webhook | ボディ上の任意の X-Ongrid-Signature: sha256=<HMAC>。 |
正確な実装は internal/pkg/notify/webhook.go にあります: signFeishu、 signDingTalkURL、 signGenericWebhook。
Slack は secret フィールドを静かに落とす
Slack incoming webhook URL 自体が認証情報です。Slack チャネルの Secret 欄を 埋めると、チャネルビルダーは Sender 構築前にそれを落とします。これは意図的 —— Slack のプロトコルには incoming webhook 用の独立した署名面がありません。
IM チャネル
IM チャネルは長期実行 goroutine で、以下を行います:
- プロバイダーへアウトバウンド接続(Feishu/Slack は WebSocket、Telegram は long poll)。manager に インバウンドポートは開きません。
- 受信ユーザーメッセージを受け、
allow_fromでフィルタし、 テキストをbizbridge.Bridge.HandleInboundに渡す。 HandleInboundがプレースホルダー返信を投稿、完全なエージェントグラフ (Web UI と同じもの)を実行、プレースホルダーメッセージ id に 編集を逆ストリーミング。
同じエージェントカーネル、スキル、persona レジストリが Web UI と IM チャネルの両方を駆動。 「IM 専用エージェント」はありません —— coordinator は /chat で見るのと同じです。
受信はプロバイダー固有、送信は均一
プロバイダーの違い(Slack envelope_id ack、Telegram update offset、Feishu encrypt_key)は imbridge/provider/*/stream.go にあります。メッセージが bizbridge.HandleInbound 内に入った後、下流のすべてはプロバイダー非依存です。
default_locale
IM と Notify 両方の行が任意の default_locale を持ちます。バリデーターは 空文字(auto)、en、zh のみ受け入れ —— en-US / zh-CN は primary subtag に折り畳まれ、EN-us やタイポされたロケールは AppInput.validate で 事前に拒否されます。
| 値 | 振る舞い |
|---|---|
""(auto) | ディレクティブなし。LLM がユーザーの言語をミラー。レガシーデフォルト。 |
en | システムプロンプトに Respond in English ディレクティブを追加。 |
zh | システムプロンプトに 「请用中文回复」 ディレクティブを追加。 |
これは UI ロケール(ONGRID_DEFAULT_LOCALE 環境変数またはブラウザ言語)と独立です。 IM チャネルを通じて受信したメッセージは常に IM 側が勝ちます。manager 起動の出力に対する auto-trigger フォールバックルールは AI output locale feedback を参照。
allow_from
送信者許可リスト。Telegram と Slack で必須、Feishu/DingTalk で任意。 ParseAllowFrom で 一度だけ解析され、バリデーターと各プロバイダーの poll/stream ループで 共有されるので、解析ルールは単一の定義を持ちます。
構文。 カンマ、スペース、改行、タブ、セミコロン —— 任意の組み合わせがトークンを分けます。 順序は保たれ、重複は捨てられます。telegram: と tg: プレフィックスは静かに剥がされます(OpenClaw 互換)。
プロバイダー別フォーマット。
- Telegram。 数値ユーザー ID のみ。非数値トークンと負の値(グループ chat ID)は検証時に落とされます。 少なくとも 1 つの ID が必須 —— bot は username で公開発見可能なので、空の許可リストは ツール装備のエージェントを誰でも操作できる状態になります。ADR-031 を参照。
- Slack。
Uで始まるユーザー ID(または Enterprise ゲスト用のW)。少なくとも 1 つ必須。 自分の ID はワークスペースプロフィール →⋯→ Copy member ID で見つかります。 - Feishu / DingTalk。 任意。これらのプラットフォームは企業テナントメンバーシップでゲートされ、 組織メンバーだけが bot に到達できます。
Telegram または Slack の空許可リストは拒否
解析リストが空のとき、バリデーターは telegram requires allow_from / slack requires allow_from を返します。「デフォルト拒否、後でセットアップで許可」モードはありません。 bot は公開到達可能なので、オペレーターは意識的にドアを開く必要があります。
失敗モードはサイレントドロップ。 非許可リスト送信者からのメッセージは送信者の user_id 付きで WARN ログされ、ドロップされます。返信なし、プレースホルダーなし、エージェント実行なし。 bot は存在を確認すらしません —— OpenClaw の dmPolicy: allowFrom と同形です。
発火アラート配信の見え方
alert evaluator → produces notify.Message
↓
notify.Sender (per channel) ↓ buildBody(msg) → JSON payload
↓ signTarget(endpoint, secret, body) → headers / URL params
↓ POST endpoint
↓ resp.StatusCode in [200, 299] → success
↓
chat surface詳細は各チャネルページを参照: