Skip to content

Kanäle-Übersicht

Ongrid spricht mit Menschen über Kanäle. Ein Kanal ist entweder:

  • ein Benachrichtigungskanal — Ongrid pusht Alarme an eine Chat-Oberfläche; der Mensch liest, aber der Kanal selbst trägt nie eine Antwort zurück zum Agenten. Das sind notify_channels in der DB und die internal/pkg/notify/webhook.go-Sender.
  • ein IM-Kanal — Ongrid sitzt als Bot auf der Chat-Oberfläche eines Workspaces, liest eingehende Nachrichten und führt dieselbe Agent-Logik aus, die die Web-UI ausführt, und streamt die Antwort als Edits einer Platzhalter-Nachricht zurück. Das sind im_apps in der DB und internal/manager/biz/imbridge/provider/*.

Die beiden sind unabhängig. Telegram-Alarme zu verdrahten (sendMessage out) lässt Benutzer nicht mit dem Agenten auf Telegram chatten, und umgekehrt.

Andere Tabelle, andere Credentials, gleiche UI

Beide Oberflächen werden in Settings → Channels in der Web-UI konfiguriert. Benachrichtigungskanäle gehen in den Notify-Tab; IM-Kanäle in den IM bridge-Tab.

Welchen will ich?

ZielVerwendenDatei
Gefeuerte Alarme an einen Slack-Channel pushenSlack-Incoming-Webhook (Notify)internal/pkg/notify/webhook.go NewSlackSender
Gefeuerte Alarme an Feishu/Lark-Gruppe pushenFeishu Custom Bot (Notify)NewFeishuSender
Gefeuerte Alarme an DingTalk-Gruppe pushenDingTalk Custom Bot (Notify)NewDingTalkSender
Gefeuerte Alarme an WeCom-Gruppe pushenWeCom Group Bot (Notify)NewWeComSender
Generisches JSON-POST an eigenen DienstWebhook (Notify)NewGenericWebhookSender
Telegram-Alarme (einseitig)Telegram-Bot sendMessage (Notify)NewTelegramSender
Mit dem Agenten von Slack aus als Bot redenSlack Socket Mode App (IM bridge)imbridge/provider/slack/
Mit dem Agenten von Telegram aus redenTelegram-Bot getUpdates (IM bridge)imbridge/provider/telegram/
Mit dem Agenten von Feishu/Larksuite aus redenFeishu Long-Connection (IM bridge)imbridge/provider/feishu/

Ein Workspace kann beides betreiben: z. B. einen Slack-Incoming-Webhook für Alarme plus eine separate Slack Socket Mode App für Konversation. Sie teilen keinen Zustand.

Benachrichtigungskanäle

Ein Benachrichtigungskanal ist ein zustandsloser Send(ctx, Message)-Sender. Er wird von der Alarmpipeline aufgerufen, wann immer ein Alarm feuert (oder sich erholt, oder das Dämpfungsfenster abläuft). Alle Kanaltypen rendern dieselbe kanonische notify.Message-Form; nur das Payload-Format und das Signaturprotokoll unterscheiden sich pro Provider.

Gemeinsame Felder, die ein Sender erhält

go
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
}

Der Slack-Sender rendert dies in das Attachments-Format mit einer severity-getönten Farbschiene, strukturierten Feldern (Severity, Source, Rule, Incident, Device, Dedupe) und einem ts-Footer. Die Feishu- / DingTalk- / WeCom-Sender flachen es zu einem [SEV] subject\nbody\nsource:…\ndedupe:… Textpayload, weil ihre Bot-APIs in v1 nur reinen Text liefern.

Signaturmodelle auf einen Blick

ProviderWie er authentifiziert
SlackDie Webhook-URL selbst ist das Secret. Keine weitere Signatur.
FeishuHMAC-SHA256(ts\nsecret), platziert im JSON-Body als sign.
DingTalkHMAC-SHA256(ts\nsecret), platziert im URL-Query als sign.
WeComBot-Key im URL-Query. Keine weitere Signatur.
TelegramBot-Token im Pfad (/bot<TOKEN>/sendMessage).
WebhookOptionaler X-Ongrid-Signature: sha256=<HMAC> über den Body.

Die exakten Implementierungen leben in internal/pkg/notify/webhook.go: signFeishu, signDingTalkURL, signGenericWebhook.

Slack droppt das secret-Feld stillschweigend

Die Slack-Incoming-Webhook-URL ist selbst die Credential. Wenn Sie das Secret-Feld für einen Slack-Kanal ausfüllen, droppt der Channel-Builder es, bevor er den Sender konstruiert. Das ist beabsichtigt — Slacks Protokoll hat keine separate Signaturoberfläche für Incoming Webhooks.

IM-Kanäle

Ein IM-Kanal ist eine langlaufende Goroutine, die:

  1. Ausgehend zum Provider verbindet (WebSocket für Feishu/Slack, Long-Poll für Telegram). Keine eingehenden Ports werden auf dem Manager geöffnet.
  2. Eingehende Benutzernachrichten empfängt, durch allow_from filtert und den Text an bizbridge.Bridge.HandleInbound übergibt.
  3. HandleInbound postet eine Platzhalter-Antwort, führt den vollen Agent-Graphen aus (denselben, den die Web-UI verwendet) und streamt Edits zurück an die Platzhalter-Nachricht-ID.

Derselbe Agent-Kernel, dieselben Skills und dieselbe Persona-Registry treiben sowohl die Web-UI als auch die IM-Kanäle an. Es gibt keinen „IM-spezifischen Agenten" — der coordinator ist derselbe, den Sie auf /chat sehen.

Eingehend ist provider-spezifisch, ausgehend ist einheitlich

Provider-Unterschiede (Slack envelope_id ack, Telegram update offset, Feishu encrypt_key) leben in imbridge/provider/*/stream.go. Sobald eine Nachricht in bizbridge.HandleInbound ist, ist alles Downstream provider-agnostisch.

default_locale

Sowohl IM- als auch Notify-Zeilen tragen ein optionales default_locale. Der Validator akzeptiert den leeren String (auto), en oder zh nur — en-US / zh-CN werden zu ihrem primären Subtag gefaltet, und EN-us / ein vertipptes Locale wird vorne in AppInput.validate abgelehnt.

WertVerhalten
"" (auto)Keine Direktive. Das LLM spiegelt die Sprache des Benutzers. Legacy-Default.
enFügt eine Respond in English-Direktive zum System-Prompt hinzu.
zhFügt eine 「请用中文回复」-Direktive zum System-Prompt hinzu.

Das ist unabhängig vom UI-Locale (ONGRID_DEFAULT_LOCALE-Umgebungsvariable oder Browser-Sprache). Ein IM-Kanal gewinnt immer für Nachrichten, die durch ihn empfangen werden. Siehe das AI-Output-Locale-Feedback für die Auto-Trigger-Fallback-Regel auf manager-initiierten Ausgaben.

allow_from

Die Sender-Allowlist. Erforderlich für Telegram und Slack; optional für Feishu/DingTalk. Sie wird genau einmal von ParseAllowFrom geparst, geteilt zwischen Validator und jeder Provider-Poll/Stream-Loop, sodass die Parse-Regel eine einzige Definition hat.

Syntax. Komma, Leerzeichen, Newline, Tab, Semikolon — jede Kombination trennt Tokens. Reihenfolge bleibt erhalten, Duplikate werden gedroppt. Die telegram:- und tg:-Präfixe werden stillschweigend entfernt (OpenClaw-Kompatibilität).

Per-Provider-Format.

  • Telegram. Nur numerische User-IDs. Nicht-numerische Tokens und negative Werte (Gruppen-Chat-IDs) werden zur Validierungszeit gedroppt. Mindestens eine ID ist erforderlich — der Bot ist öffentlich per Benutzername auffindbar, sodass eine leere Allowlist es jedem Telegram-Benutzer erlauben würde, einen tool-ausgestatteten Agenten zu kommandieren. Siehe ADR-031.
  • Slack. User-IDs, die mit U beginnen (oder W für Enterprise-Gäste). Mindestens eine ist erforderlich. Finden Sie Ihre eigene, indem Sie auf Ihr Workspace-Profil klicken → Copy member ID.
  • Feishu / DingTalk. Optional. Diese Plattformen sind durch Enterprise-Tenant-Mitgliedschaft gegated; nur Org-Mitglieder können den Bot erreichen.

Leere Allowlist für Telegram oder Slack wird abgelehnt

Der Validator gibt telegram requires allow_from / slack requires allow_from zurück, wenn die geparste Liste leer ist. Es gibt keinen „Deny by default, aber Setup später erlauben"-Modus. Der Bot ist öffentlich erreichbar; der Operator muss die Tür bewusst öffnen.

Failure-Mode ist stilles Droppen. Eine Nachricht von einem nicht in der Allowlist befindlichen Sender wird auf WARN mit der user_id des Senders geloggt, dann gedroppt. Keine Antwort, kein Platzhalter, kein Agent-Lauf. Der Bot bestätigt nicht einmal, dass er existiert — gleiche Form wie OpenClaw dmPolicy: allowFrom.

Wie eine gefeuerte Alarm-Zustellung aussieht

text
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

Für tieferes Detail siehe die Per-Kanal-Seiten: