elton 831c2a953f Direktnachrichten kommen doch sofort an -- das Gespraech ist Echtzeit
Andreas: "dann durchsuch noch mal die foren, das kann doch nicht sein
das das niemand da draussen hat das problem." Hatte jemand, und der
entscheidende Satz stand in einem Bugreport eines anderen Projekts:
"DMs work fine."

Nachgemessen, und es stimmt:

  Direktnachricht            -> posted kommt SOFORT
  eigener Kanalbeitrag       -> posted kommt
  Kanalbeitrag eines anderen -> kommt nie

Damit ist die Lage eine voellig andere als gedacht. Mit einem Agenten zu
reden -- der Anwendungsfall, um den es Andreas ging -- laeuft in Echtzeit
ueber eine DM. Der Boden deckt nur noch Erwaehnungen in Kanaelen ab, und
das ist der Fall, bei dem 15 Sekunden niemanden stoeren.

Dabei ausserdem einen eigenen Fehler korrigiert: Ich hatte den Test
"direkt am Container, ohne Caddy" als erledigt dargestellt, obwohl das
sed dafuer fehlgeschlagen war und gegen den Proxy gemessen wurde.
Nachgeholt: ws://192.168.1.142:8065 direkt verhaelt sich genauso. Der
Proxy ist jetzt wirklich ausgeschlossen.
2026-09-01 20:54:02 +02:00

mmnotify

Hört am Mattermost-Websocket und weckt einen Agenten, wenn er gemeint ist.

Gegenstück zu goimapnotify für Mail: ein kleiner Prozess, der lauscht und bei einem Ereignis einen Befehl ausführt. Der Agent liest und antwortet danach mit seinen eigenen Werkzeugen — mmnotify schreibt nie in einen Kanal, es klopft nur an.

mmnotify -conf /etc/mmnotify.json

Konfiguration

{
  "url": "https://team.42i.org",
  "token": "<persönliches Zugriffstoken des Agenten>",
  "on_mention": "/root/run-agent.sh team",
  "on_direct": "",
  "debounce_seconds": 5,
  "floor_seconds": 60,
  "ignore_users": []
}

Die Datei enthält ein Token und gehört mit 0600 dem Dienstbenutzer.

Feld Bedeutung
on_mention Befehl bei Erwähnung (@name) im Kanal
on_direct Befehl bei Direktnachricht; leer = on_mention
debounce_seconds Mindestabstand zwischen zwei Läufen (Standard 5)
floor_seconds Nachsehen auch ohne Ereignis (Standard 15, 0 schaltet ab)
ignore_users Absender, die nie wecken
away_after_seconds Wann der grüne Punkt auf abwesend zurückfällt (Standard 120)

Der Befehl bekommt die Ereignisdaten über die Umgebung: MM_TRIGGER (event oder floor), MM_CHANNEL, MM_CHANNEL_NAME, MM_CHANNEL_TYPE, MM_SENDER, MM_POST_ID, MM_ROOT_ID, MM_MESSAGE.

Zwei Wege, und der Boden ist der tragende

Der Websocket ist der Beschleuniger; darunter läuft ein Boden, der ohnehin nachsieht. Die Aufteilung stammt aus hive (hive_runtime/channels/team.py) und ist dort begründet: „A stream that dies quietly must make us LATE, never blind."

Hier ist der Boden nicht nur Vorsicht. Gemessen am 2026-09-01 gegen Mattermost 11.7.10:

Direktnachricht posted kommt sofort an
eigener Kanalbeitrag posted kommt an
Kanalbeitrag eines anderen Kontos kommt nie an

Das Gespräch mit einem Agenten läuft damit in Echtzeit. Eine DM weckt ihn ohne Verzögerung; nur Erwähnungen in Kanälen gehen über den Boden. Dieselbe Trennung ist für andere Mattermost-Integrationen dokumentiert: „DMs work fine" — Kanal-Ereignisse fehlen, DMs kommen durch.

Die Verbindung ist also voll funktionsfähig und hat die Kanal-Abos — es fehlen ausschließlich die Ereignisse fremder Konten. Ausgeschlossen wurden: authentication_challenge, Token im Authorization-Header beim Handshake, ein echter Bot-Account statt eines Nutzers mit Token, und das Sitzungs-Cookie MMAUTHTOKEN wie im Browser. Alle vier verhalten sich gleich.

Das Verhalten ist im Mattermost-Forum beschrieben und tritt dort auch mit einem System-Admin-Token auf; eine Lösung steht nicht dabei.

Deshalb ist floor_seconds der Weg und nicht der Notnagel, und der Standard ist kurz: 15 Sekunden. Ein Durchgang kostet einen API-Aufruf — billig genug, um es oft zu tun. Wer den Stream repariert bekommt, kann ihn hochsetzen.

Daraus folgt die zweite Entscheidung: mmnotify liest den Beitrag nicht aus dem Ereignis. Es klopft an; was zu tun ist, entscheidet der Agent, wenn er nachsieht. Zwei Leser wären zwei Antworten.

Anwesenheit

Solange mmnotify verbunden ist, zeigt der Punkt neben dem Namen, woran man ist:

  • abwesend, sobald die Verbindung steht — da, aber untätig
  • grün, während der Befehl wegen einer Erwähnung läuft
  • abwesend wieder, wenn es away_after_seconds still war
  • offline beim Beenden, statt einen grünen Punkt zurückzulassen, hinter dem niemand mehr sitzt

Das routinemäßige Nachsehen des Bodens macht ausdrücklich nicht grün. Läuft der Boden häufiger als die Away-Frist, leuchtete der Agent sonst rund um die Uhr — und ein Punkt, der immer grün ist, sagt genauso wenig wie gar keiner. (Beim Testen genau so passiert: Boden alle 20 s, Frist 25 s, nie abwesend.)

Ein Status ist eine Höflichkeit gegenüber dem, der in die Seitenleiste schaut. Weigert sich der Server, wird das protokolliert und weitergearbeitet: Ein Agent, der aufhört zu antworten, weil er einen Punkt nicht einfärben konnte, wäre absurd.

Robustheit

  • Wiederaufbau mit wachsendem Abstand (1 s bis 60 s). Ein Server, der neu startet, wird nicht von einem Client bestürmt, der im Sekundentakt anklopft.
  • Herzschlag alle 30 s, Lesefrist 90 s. Eine halboffene Verbindung liest sich sonst für immer wie Stille.
  • Höchstens ein Lauf gleichzeitig; wer währenddessen schreibt, wird vom laufenden Durchgang mitgenommen. Ohne das lösen fünf Beiträge in einer Minute fünf Agentenläufe aus, die sich gegenseitig überholen.
  • Eigene Beiträge und system_*-Ereignisse wecken nie — sonst antwortet ein Agent auf sich selbst.
  • SIGTERM beendet sofort und sauber.

Bauen

go build -o mmnotify .

Ein statisches Binary ohne Laufzeitabhängigkeiten — gedacht zum Einbacken in das Agenten-Image, neben goimapnotify.

S
Description
Hoert am Mattermost-Websocket und weckt einen Agenten, wenn er gemeint ist — Gegenstueck zu goimapnotify fuer Mail
Readme
67 KiB
Languages
Go 100%