Persistente ACP-Bindings für Discord-Kanäle und Telegram-Topics
Status: Entwurf
Zusammenfassung
Einführung persistenter ACP-Bindings, die folgende Zuordnungen abbilden:
- Discord-Kanäle (und ggf. bestehende Threads) sowie
- Telegram-Forum-Topics in Gruppen/Supergruppen (
chatId:topic:topicId)
auf langlebige ACP-Sessions. Der Binding-Zustand wird in Top-Level-bindings[]-Einträgen mit expliziten Binding-Typen gespeichert.
Damit wird die ACP-Nutzung in stark frequentierten Messaging-Kanälen vorhersagbar und dauerhaft, sodass Benutzer dedizierte Kanäle/Topics wie codex, claude-1 oder claude-myrepo erstellen können.
Warum
Das aktuelle threadgebundene ACP-Verhalten ist auf kurzlebige Discord-Thread-Workflows optimiert. Telegram hat kein vergleichbares Thread-Modell; es verwendet Forum-Topics in Gruppen/Supergruppen. Benutzer wünschen sich stabile, dauerhaft aktive ACP-„Workspaces” in Chat-Oberflächen, nicht nur temporäre Thread-Sessions.
Ziele
- Dauerhafte ACP-Bindings unterstützen für:
- Discord-Kanäle/-Threads
- Telegram-Forum-Topics (Gruppen/Supergruppen)
- Binding als konfigurationsgesteuerte Single Source of Truth.
/acp,/new,/reset,/focusund Zustellungsverhalten konsistent über Discord und Telegram halten.- Bestehende temporäre Binding-Flows für Ad-hoc-Nutzung beibehalten.
Nicht-Ziele
- Vollständiger Umbau der ACP-Runtime/Session-Interna.
- Entfernung bestehender kurzlebiger Binding-Flows.
- Erweiterung auf alle Kanäle in der ersten Iteration.
- Implementierung von Telegram-Kanal-Direktnachrichten-Topics (
direct_messages_topic_id) in dieser Phase. - Implementierung von Telegram-Privatchat-Topic-Varianten in dieser Phase.
UX-Richtung
1) Zwei Binding-Typen
- Persistentes Binding: in der Konfiguration gespeichert, beim Start abgeglichen, gedacht für „benannte Workspace”-Kanäle/Topics.
- Temporäres Binding: nur zur Laufzeit, läuft nach Idle-/Max-Age-Policy ab.
2) Befehlsverhalten
/acp spawn ... --thread here|auto|offbleibt verfügbar.- Explizite Binding-Lifecycle-Steuerungen ergänzen:
/acp bind [session|agent] [--persist]/acp unbind [--persist]/acp statuszeigt an, ob das Bindingpersistentodertemporaryist.
- In gebundenen Konversationen setzen
/newund/resetdie gebundene ACP-Session vor Ort zurück und behalten das Binding bei.
3) Konversationsidentität
- Kanonische Konversations-IDs verwenden:
- Discord: Kanal-/Thread-ID.
- Telegram-Topic:
chatId:topic:topicId.
- Telegram-Bindings niemals nur über die nackte Topic-ID keyen.
Konfigurationsmodell (Vorschlag)
Routing und persistente ACP-Binding-Konfiguration in Top-Level-bindings[] mit explizitem type-Discriminator vereinheitlichen:
{
"agents": {
"list": [
{
"id": "main",
"default": true,
"workspace": "~/.openclaw/workspace-main",
"runtime": { "type": "embedded" },
},
{
"id": "codex",
"workspace": "~/.openclaw/workspace-codex",
"runtime": {
"type": "acp",
"acp": {
"agent": "codex",
"backend": "acpx",
"mode": "persistent",
"cwd": "/workspace/repo-a",
},
},
},
{
"id": "claude",
"workspace": "~/.openclaw/workspace-claude",
"runtime": {
"type": "acp",
"acp": {
"agent": "claude",
"backend": "acpx",
"mode": "persistent",
"cwd": "/workspace/repo-b",
},
},
},
],
},
"acp": {
"enabled": true,
"backend": "acpx",
"allowedAgents": ["codex", "claude"],
},
"bindings": [
// Route-Bindings (bestehendes Verhalten)
{
"type": "route",
"agentId": "main",
"match": { "channel": "discord", "accountId": "default" },
},
{
"type": "route",
"agentId": "main",
"match": { "channel": "telegram", "accountId": "default" },
},
// Persistente ACP-Konversations-Bindings
{
"type": "acp",
"agentId": "codex",
"match": {
"channel": "discord",
"accountId": "default",
"peer": { "kind": "channel", "id": "222222222222222222" },
},
"acp": {
"label": "codex-main",
"mode": "persistent",
"cwd": "/workspace/repo-a",
"backend": "acpx",
},
},
{
"type": "acp",
"agentId": "claude",
"match": {
"channel": "discord",
"accountId": "default",
"peer": { "kind": "channel", "id": "333333333333333333" },
},
"acp": {
"label": "claude-repo-b",
"mode": "persistent",
"cwd": "/workspace/repo-b",
},
},
{
"type": "acp",
"agentId": "codex",
"match": {
"channel": "telegram",
"accountId": "default",
"peer": { "kind": "group", "id": "-1001234567890:topic:42" },
},
"acp": {
"label": "tg-codex-42",
"mode": "persistent",
},
},
],
"channels": {
"discord": {
"guilds": {
"111111111111111111": {
"channels": {
"222222222222222222": {
"enabled": true,
"requireMention": false,
},
"333333333333333333": {
"enabled": true,
"requireMention": false,
},
},
},
},
},
"telegram": {
"groups": {
"-1001234567890": {
"topics": {
"42": {
"requireMention": false,
},
},
},
},
},
},
}
Minimales Beispiel (ohne Binding-spezifische ACP-Overrides)
{
"agents": {
"list": [
{ "id": "main", "default": true, "runtime": { "type": "embedded" } },
{
"id": "codex",
"runtime": {
"type": "acp",
"acp": { "agent": "codex", "backend": "acpx", "mode": "persistent" },
},
},
{
"id": "claude",
"runtime": {
"type": "acp",
"acp": { "agent": "claude", "backend": "acpx", "mode": "persistent" },
},
},
],
},
"acp": { "enabled": true, "backend": "acpx" },
"bindings": [
{
"type": "route",
"agentId": "main",
"match": { "channel": "discord", "accountId": "default" },
},
{
"type": "route",
"agentId": "main",
"match": { "channel": "telegram", "accountId": "default" },
},
{
"type": "acp",
"agentId": "codex",
"match": {
"channel": "discord",
"accountId": "default",
"peer": { "kind": "channel", "id": "222222222222222222" },
},
},
{
"type": "acp",
"agentId": "claude",
"match": {
"channel": "discord",
"accountId": "default",
"peer": { "kind": "channel", "id": "333333333333333333" },
},
},
{
"type": "acp",
"agentId": "codex",
"match": {
"channel": "telegram",
"accountId": "default",
"peer": { "kind": "group", "id": "-1009876543210:topic:5" },
},
},
],
}
Anmerkungen:
bindings[].typeist explizit:route: normales Agent-Routing.acp: persistentes ACP-Harness-Binding für eine zugeordnete Konversation.
- Bei
type: "acp"istmatch.peer.idder kanonische Konversationsschlüssel:- Discord-Kanal/-Thread: rohe Kanal-/Thread-ID.
- Telegram-Topic:
chatId:topic:topicId.
bindings[].acp.backendist optional. Backend-Fallback-Reihenfolge:bindings[].acp.backendagents.list[].runtime.acp.backend- globales
acp.backend
mode,cwdundlabelfolgen demselben Override-Muster (Binding-Override -> Agent-Runtime-Default -> globales/Standard-Verhalten).- Bestehende
session.threadBindings.*undchannels.discord.threadBindings.*für temporäre Binding-Policies beibehalten. - Persistente Einträge deklarieren den gewünschten Zustand; die Laufzeit gleicht mit den tatsächlichen ACP-Sessions/Bindings ab.
- Pro Konversationsknoten ist genau ein aktives ACP-Binding vorgesehen.
- Abwärtskompatibilität: fehlender
typewird alsroutefür Legacy-Einträge interpretiert.
Backend-Auswahl
- Die ACP-Session-Initialisierung nutzt bereits die konfigurierte Backend-Auswahl beim Spawn (
acp.backendheute). - Dieser Vorschlag erweitert die Spawn-/Abgleichlogik um typisierte ACP-Binding-Overrides:
bindings[].acp.backendfür konversationslokale Overrides.agents.list[].runtime.acp.backendfür Agent-spezifische Defaults.
- Wenn kein Override existiert, wird das aktuelle Verhalten beibehalten (
acp.backend-Standard).
Architekturpassung im aktuellen System
Bestehende Komponenten wiederverwenden
SessionBindingServiceunterstützt bereits kanalunabhängige Konversationsreferenzen.- ACP-Spawn-/Bind-Flows unterstützen bereits Binding über Service-APIs.
- Telegram transportiert bereits Topic-/Thread-Kontext über
MessageThreadIdundchatId.
Neue/erweiterte Komponenten
- Telegram-Binding-Adapter (parallel zum Discord-Adapter):
- Adapter pro Telegram-Account registrieren,
- Auflösen/Auflisten/Binden/Lösen/Touch per kanonischer Konversations-ID.
- Typisierter Binding-Resolver/-Index:
bindings[]inroute- undacp-Ansichten aufteilen,resolveAgentRoutenur aufroute-Bindings anwenden,- persistente ACP-Absicht nur aus
acp-Bindings auflösen.
- Eingehende Binding-Auflösung für Telegram:
- Gebundene Session vor der Route-Finalisierung auflösen (Discord macht das bereits).
- Persistenter Binding-Abgleicher:
- Beim Start: konfigurierte Top-Level-
type: "acp"-Bindings laden, sicherstellen dass ACP-Sessions existieren, sicherstellen dass Bindings existieren. - Bei Konfigurationsänderung: Deltas sicher anwenden.
- Beim Start: konfigurierte Top-Level-
- Umstellungsmodell:
- Kein kanalspezifischer ACP-Binding-Fallback wird gelesen,
- persistente ACP-Bindings werden ausschließlich aus Top-Level-
bindings[].type="acp"-Einträgen bezogen.
Schrittweise Auslieferung
Phase 1: Typisierte Binding-Schema-Grundlage
- Konfigurationsschema um
bindings[].type-Discriminator erweitern:route,acpmit optionalemacp-Override-Objekt (mode,backend,cwd,label).
- Agent-Schema um Runtime-Deskriptor erweitern, um ACP-native Agents zu kennzeichnen (
agents.list[].runtime.type). - Parser-/Indexer-Aufteilung für Route- vs. ACP-Bindings hinzufügen.
Phase 2: Laufzeit-Auflösung + Discord/Telegram-Parität
- Persistente ACP-Bindings aus Top-Level-
type: "acp"-Einträgen auflösen für:- Discord-Kanäle/-Threads,
- Telegram-Forum-Topics (
chatId:topic:topicIdkanonische IDs).
- Telegram-Binding-Adapter und eingehende gebundene-Session-Override-Parität mit Discord implementieren.
- Telegram-Direkt-/Privat-Topic-Varianten nicht in dieser Phase einschließen.
Phase 3: Befehlsparität und Resets
/acp,/new,/resetund/focus-Verhalten in gebundenen Telegram-/Discord-Konversationen angleichen.- Sicherstellen, dass Bindings Reset-Flows wie konfiguriert überleben.
Phase 4: Härtung
- Bessere Diagnose (
/acp status, Abgleich-Logs beim Start). - Konfliktbehandlung und Health-Checks.
Leitplanken und Richtlinien
- ACP-Aktivierung und Sandbox-Einschränkungen exakt wie heute respektieren.
- Explizites Account-Scoping (
accountId) beibehalten, um Account-übergreifende Vermischung zu vermeiden. - Bei mehrdeutigem Routing: geschlossen fehlschlagen.
- Mention-/Zugangsrichtlinien-Verhalten je Kanalkonfiguration explizit halten.
Testplan
- Unit:
- Konversations-ID-Normalisierung (insbesondere Telegram-Topic-IDs),
- Abgleicher-Create/Update/Delete-Pfade,
/acp bind --persist- und Unbind-Flows.
- Integration:
- Eingehendes Telegram-Topic -> gebundene ACP-Session-Auflösung,
- Eingehender Discord-Kanal/-Thread -> persistentes Binding-Vorrang.
- Regression:
- Temporäre Bindings funktionieren weiterhin,
- Ungebundene Kanäle/Topics behalten das aktuelle Routing-Verhalten bei.
Offene Fragen
- Sollte
/acp spawn --thread autoim Telegram-Topic standardmäßighereverwenden? - Sollten persistente Bindings immer Mention-Gating in gebundenen Konversationen umgehen oder explizites
requireMention=falseerfordern? - Sollte
/focusein--persistals Alias für/acp bind --persisterhalten?
Rollout
- Als Opt-in pro Konversation ausliefern (
bindings[].type="acp"-Eintrag vorhanden). - Zunächst nur Discord + Telegram.
- Dokumentation mit Beispielen hinzufügen für:
- „ein Kanal/Topic pro Agent”
- „mehrere Kanäle/Topics pro Agent mit unterschiedlichem
cwd” - „Team-Benennungsmuster (
codex-1,claude-repo-x)”.