ACP-threadgebundene Agents

Überblick

Dieser Plan definiert, wie OpenClaw ACP-Coding-Agents in threadfähigen Kanälen (Discord zuerst) mit produktionsreifem Lifecycle und Recovery unterstützen soll.

Verwandtes Dokument:

Angestrebte Benutzererfahrung:

  • Ein Benutzer spawnt oder fokussiert eine ACP-Session in einem Thread
  • Benutzernachrichten in diesem Thread werden an die gebundene ACP-Session geroutet
  • Agent-Output wird in derselben Thread-Persona zurückgestreamt
  • Die Session kann persistent oder einmalig sein, mit expliziten Cleanup-Steuerungen

Entscheidungszusammenfassung

Langfristige Empfehlung ist eine hybride Architektur:

  • OpenClaw-Kern steuert ACP-Steuerungsebenen-Belange
    • Session-Identität und Metadaten
    • Thread-Binding und Routing-Entscheidungen
    • Zustellungsinvarianten und Duplikat-Unterdrückung
    • Lifecycle-Bereinigung und Recovery-Semantik
  • ACP-Laufzeit-Backend ist austauschbar
    • Erstes Backend ist ein acpx-gestützter Plugin-Service
    • Runtime erledigt ACP-Transport, Queuing, Abbruch, Reconnect

OpenClaw sollte ACP-Transport-Interna nicht im Kern nachimplementieren. OpenClaw sollte sich für Routing nicht auf einen reinen Plugin-only-Interception-Pfad verlassen.

Zielarchitektur (Holy Grail)

ACP als erstklassige Steuerungsebene in OpenClaw behandeln, mit austauschbaren Laufzeit-Adaptern.

Unverrückbare Invarianten:

  • Jedes ACP-Thread-Binding referenziert einen gültigen ACP-Session-Datensatz
  • Jede ACP-Session hat einen expliziten Lifecycle-Status (creating, idle, running, cancelling, closed, error)
  • Jeder ACP-Run hat einen expliziten Run-Status (queued, running, completed, failed, cancelled)
  • Spawn, Bind und initiales Enqueue sind atomar
  • Befehlswiederholungen sind idempotent (keine doppelten Runs oder Discord-Ausgaben)
  • Threadgebundene Kanalausgabe ist eine Projektion von ACP-Run-Events, niemals Ad-hoc-Seiteneffekte

Langfristiges Ownership-Modell:

  • AcpSessionManager ist der einzige ACP-Writer und Orchestrator
  • Manager lebt zunächst im Gateway-Prozess; kann später hinter derselben Schnittstelle in einen dedizierten Sidecar verschoben werden
  • Pro ACP-Session-Key besitzt der Manager einen In-Memory-Actor (serialisierte Befehlsausführung)
  • Adapter (acpx, zukünftige Backends) sind nur Transport-/Runtime-Implementierungen

Langfristiges Persistenzmodell:

  • ACP-Steuerungsebenen-Zustand in eine dedizierte SQLite-Datenbank (WAL-Modus) unter dem OpenClaw-State-Verzeichnis verschieben
  • SessionEntry.acp als Kompatibilitätsprojektion während der Migration beibehalten, nicht als Source of Truth
  • ACP-Events append-only speichern, um Replay, Crash-Recovery und deterministische Zustellung zu unterstützen

Zustellungsstrategie (Brücke zum Holy Grail)

  • Kurzfristige Brücke
    • Aktuelle Thread-Binding-Mechaniken und bestehende ACP-Konfigurationsoberfläche beibehalten
    • Metadaten-Lücken-Bugs beheben und ACP-Turns durch einen einzigen Core-ACP-Zweig leiten
    • Idempotenz-Schlüssel und Fail-Closed-Routing-Prüfungen sofort hinzufügen
  • Langfristiger Umstieg
    • ACP-Source-of-Truth in Steuerungsebenen-DB + Actors verschieben
    • Threadgebundene Zustellung rein auf Event-Projektion basieren lassen
    • Legacy-Fallback-Verhalten entfernen, das auf opportunistische Session-Entry-Metadaten angewiesen ist

Warum nicht rein Plugin-only

Aktuelle Plugin-Hooks reichen nicht für durchgehendes ACP-Session-Routing ohne Kernänderungen.

  • Eingehendes Routing aus Thread-Binding löst zuerst im Core-Dispatch zu einem Session-Key auf
  • Message-Hooks sind fire-and-forget und können den Haupt-Reply-Pfad nicht kurzschließen
  • Plugin-Befehle sind gut für Steuerungsoperationen, aber nicht zum Ersetzen des Core-Per-Turn-Dispatch-Flows

Ergebnis:

  • ACP-Runtime kann als Plugin implementiert werden
  • ACP-Routing-Zweig muss im Kern existieren

Bestehende Grundlagen zur Wiederverwendung

Bereits implementiert und kanonisch:

  • Thread-Binding-Ziel unterstützt subagent und acp
  • Eingehendes Thread-Routing-Override wird vor normalem Dispatch per Binding aufgelöst
  • Ausgehende Thread-Identität über Webhook in der Reply-Zustellung
  • /focus- und /unfocus-Flow mit ACP-Ziel-Kompatibilität
  • Persistenter Binding-Store mit Wiederherstellung beim Start
  • Unbind-Lifecycle bei Archivierung, Löschung, Unfocus, Reset und Delete

Dieser Plan erweitert diese Grundlage, anstatt sie zu ersetzen.

Architektur

Grenzmodell

Kern (muss im OpenClaw-Kern sein):

  • ACP-Session-Modus-Dispatch-Zweig in der Reply-Pipeline
  • Zustellungs-Arbitrierung, um Duplikate zwischen Parent und Thread zu vermeiden
  • ACP-Steuerungsebenen-Persistenz (mit SessionEntry.acp-Kompatibilitätsprojektion während der Migration)
  • Lifecycle-Unbind und Runtime-Detach-Semantik gekoppelt an Session-Reset/-Delete

Plugin-Backend (acpx-Implementierung):

  • ACP-Runtime-Worker-Supervision
  • acpx-Prozessaufruf und Event-Parsing
  • ACP-Befehlshandler (/acp ...) und Operator-UX
  • Backend-spezifische Konfigurationsstandards und Diagnose

Runtime-Ownership-Modell

  • Ein Gateway-Prozess besitzt den ACP-Orchestrierungszustand
  • ACP-Ausführung läuft in überwachten Kindprozessen über das acpx-Backend
  • Prozessstrategie ist langlebig pro aktivem ACP-Session-Key, nicht pro Nachricht

Dies vermeidet Startup-Kosten bei jeder Eingabe und hält Cancel- und Reconnect-Semantik zuverlässig.

Core-Runtime-Vertrag

Einen Core-ACP-Runtime-Vertrag hinzufügen, damit Routing-Code nicht von CLI-Details abhängt und Backends ohne Dispatch-Logik-Änderungen wechseln kann:

export type AcpRuntimePromptMode = "prompt" | "steer";

export type AcpRuntimeHandle = {
  sessionKey: string;
  backend: string;
  runtimeSessionName: string;
};

export type AcpRuntimeEvent =
  | { type: "text_delta"; stream: "output" | "thought"; text: string }
  | { type: "tool_call"; name: string; argumentsText: string }
  | { type: "done"; usage?: Record<string, number> }
  | { type: "error"; code: string; message: string; retryable?: boolean };

export interface AcpRuntime {
  ensureSession(input: {
    sessionKey: string;
    agent: string;
    mode: "persistent" | "oneshot";
    cwd?: string;
    env?: Record<string, string>;
    idempotencyKey: string;
  }): Promise<AcpRuntimeHandle>;

  submit(input: {
    handle: AcpRuntimeHandle;
    text: string;
    mode: AcpRuntimePromptMode;
    idempotencyKey: string;
  }): Promise<{ runtimeRunId: string }>;

  stream(input: {
    handle: AcpRuntimeHandle;
    runtimeRunId: string;
    onEvent: (event: AcpRuntimeEvent) => Promise<void> | void;
    signal?: AbortSignal;
  }): Promise<void>;

  cancel(input: {
    handle: AcpRuntimeHandle;
    runtimeRunId?: string;
    reason?: string;
    idempotencyKey: string;
  }): Promise<void>;

  close(input: { handle: AcpRuntimeHandle; reason: string; idempotencyKey: string }): Promise<void>;

  health?(): Promise<{ ok: boolean; details?: string }>;
}

Implementierungsdetail:

  • Erstes Backend: AcpxRuntime, ausgeliefert als Plugin-Service
  • Kern löst Runtime über Registry auf und schlägt mit explizitem Operator-Fehler fehl, wenn kein ACP-Runtime-Backend verfügbar ist

Steuerungsebenen-Datenmodell und Persistenz

Langfristige Source of Truth ist eine dedizierte ACP-SQLite-Datenbank (WAL-Modus) für transaktionale Updates und crashsichere Recovery:

  • acp_sessions
    • session_key (pk), backend, agent, mode, cwd, state, created_at, updated_at, last_error
  • acp_runs
    • run_id (pk), session_key (fk), state, requester_message_id, idempotency_key, started_at, ended_at, error_code, error_message
  • acp_bindings
    • binding_key (pk), thread_id, channel_id, account_id, session_key (fk), expires_at, bound_at
  • acp_events
    • event_id (pk), run_id (fk), seq, kind, payload_json, created_at
  • acp_delivery_checkpoint
    • run_id (pk/fk), last_event_seq, last_discord_message_id, updated_at
  • acp_idempotency
    • scope, idempotency_key, result_json, created_at, unique (scope, idempotency_key)
export type AcpSessionMeta = {
  backend: string;
  agent: string;
  runtimeSessionName: string;
  mode: "persistent" | "oneshot";
  cwd?: string;
  state: "idle" | "running" | "error";
  lastActivityAt: number;
  lastError?: string;
};

Speicherregeln:

  • SessionEntry.acp als Kompatibilitätsprojektion während der Migration beibehalten
  • Prozess-IDs und Sockets bleiben nur im Speicher
  • Dauerhafter Lifecycle- und Run-Status lebt in der ACP-DB, nicht im generischen Session-JSON
  • Wenn der Runtime-Owner stirbt, rehydriert das Gateway aus der ACP-DB und setzt ab Checkpoints fort

Routing und Zustellung

Eingehend:

  • Aktuelles Thread-Binding-Lookup als ersten Routing-Schritt beibehalten
  • Wenn gebundenes Ziel eine ACP-Session ist, zum ACP-Runtime-Zweig routen statt zu getReplyFromConfig
  • Expliziter /acp steer-Befehl nutzt mode: "steer"

Ausgehend:

  • ACP-Event-Stream wird in OpenClaw-Reply-Chunks normalisiert
  • Zustellungsziel wird über den bestehenden gebundenen Zielpfad aufgelöst
  • Wenn ein gebundener Thread für diesen Session-Turn aktiv ist, wird die Parent-Kanal-Vervollständigung unterdrückt

Streaming-Policy:

  • Teilausgabe mit Koaleszenzfenster streamen
  • Konfigurierbares Mindestintervall und maximale Chunk-Bytes, um unter Discord-Ratenlimits zu bleiben
  • Abschlussnachricht wird immer bei Vervollständigung oder Fehler gesendet

Zustandsmaschinen und Transaktionsgrenzen

Session-Zustandsmaschine:

  • creating -> idle -> running -> idle
  • running -> cancelling -> idle | error
  • idle -> closed
  • error -> idle | closed

Run-Zustandsmaschine:

  • queued -> running -> completed
  • running -> failed | cancelled
  • queued -> cancelled

Erforderliche Transaktionsgrenzen:

  • Spawn-Transaktion
    • ACP-Session-Zeile erstellen
    • ACP-Thread-Binding-Zeile erstellen/aktualisieren
    • Initialen Run-Eintrag enqueuen
  • Close-Transaktion
    • Session als geschlossen markieren
    • Binding-Zeilen löschen/ablaufen lassen
    • Finales Close-Event schreiben
  • Cancel-Transaktion
    • Ziel-Run als cancelling/cancelled mit Idempotenz-Schlüssel markieren

Kein partieller Erfolg ist über diese Grenzen hinweg erlaubt.

Per-Session-Actor-Modell

AcpSessionManager betreibt einen Actor pro ACP-Session-Key:

  • Actor-Mailbox serialisiert submit-, cancel-, close- und stream-Seiteneffekte
  • Actor besitzt Runtime-Handle-Hydratisierung und Runtime-Adapter-Prozess-Lifecycle für diese Session
  • Actor schreibt Run-Events in Reihenfolge (seq) vor jeder Discord-Zustellung
  • Actor aktualisiert Zustellungs-Checkpoints nach erfolgreichem ausgehendem Senden

Dies beseitigt Turn-übergreifende Races und verhindert doppelte oder ungeordnete Thread-Ausgaben.

Idempotenz und Zustellungsprojektion

Alle externen ACP-Aktionen müssen Idempotenz-Schlüssel tragen:

  • Spawn-Idempotenz-Schlüssel
  • Prompt/Steer-Idempotenz-Schlüssel
  • Cancel-Idempotenz-Schlüssel
  • Close-Idempotenz-Schlüssel

Zustellungsregeln:

  • Discord-Nachrichten werden aus acp_events plus acp_delivery_checkpoint abgeleitet
  • Wiederholungen setzen ab Checkpoint fort, ohne bereits zugestellte Chunks erneut zu senden
  • Finale Reply-Emission ist exactly-once pro Run durch Projektionslogik

Recovery und Selbstheilung

Beim Gateway-Start:

  • Nicht-terminale ACP-Sessions laden (creating, idle, running, cancelling, error)
  • Actors lazy beim ersten eingehenden Event oder eager unter konfiguriertem Limit neu erstellen
  • Alle running-Runs ohne Heartbeat abgleichen und als failed markieren oder über Adapter recovern

Bei eingehender Discord-Thread-Nachricht:

  • Wenn Binding existiert, aber ACP-Session fehlt: geschlossen fehlschlagen mit expliziter Stale-Binding-Nachricht
  • Optional Stale-Binding nach operator-sicherer Validierung automatisch lösen
  • Stale ACP-Bindings niemals stillschweigend zum normalen LLM-Pfad routen

Lifecycle und Sicherheit

Unterstützte Operationen:

  • Aktuellen Run abbrechen: /acp cancel
  • Thread-Binding lösen: /unfocus
  • ACP-Session schließen: /acp close
  • Idle-Sessions per effektiver TTL automatisch schließen

TTL-Policy:

  • Effektive TTL ist das Minimum aus
    • globaler/Session-TTL
    • Discord-Thread-Binding-TTL
    • ACP-Runtime-Owner-TTL

Sicherheitskontrollen:

  • ACP-Agents per Name auf Allowlist setzen
  • Workspace-Roots für ACP-Sessions einschränken
  • Env-Allowlist-Passthrough
  • Maximale gleichzeitige ACP-Sessions pro Account und global
  • Begrenzter Restart-Backoff bei Runtime-Crashs

Konfigurationsoberfläche

Kern-Schlüssel:

  • acp.enabled
  • acp.dispatch.enabled (unabhängiger ACP-Routing-Kill-Switch)
  • acp.backend (Standard acpx)
  • acp.defaultAgent
  • acp.allowedAgents[]
  • acp.maxConcurrentSessions
  • acp.stream.coalesceIdleMs
  • acp.stream.maxChunkChars
  • acp.runtime.ttlMinutes
  • acp.controlPlane.store (Standard sqlite)
  • acp.controlPlane.storePath
  • acp.controlPlane.recovery.eagerActors
  • acp.controlPlane.recovery.reconcileRunningAfterMs
  • acp.controlPlane.checkpoint.flushEveryEvents
  • acp.controlPlane.checkpoint.flushEveryMs
  • acp.idempotency.ttlHours
  • channels.discord.threadBindings.spawnAcpSessions

Plugin-/Backend-Schlüssel (acpx-Plugin-Bereich):

  • Backend-Command/Path-Overrides
  • Backend-Env-Allowlist
  • Backend-per-Agent-Presets
  • Backend-Startup/Stop-Timeouts
  • Backend max inflight Runs pro Session

Implementierungsspezifikation

Steuerungsebenen-Module (neu)

Dedizierte ACP-Steuerungsebenen-Module im Kern hinzufügen:

  • src/acp/control-plane/manager.ts
    • besitzt ACP-Actors, Lifecycle-Übergänge, Befehls-Serialisierung
  • src/acp/control-plane/store.ts
    • SQLite-Schemaverwaltung, Transaktionen, Abfrage-Helper
  • src/acp/control-plane/events.ts
    • typisierte ACP-Event-Definitionen und Serialisierung
  • src/acp/control-plane/checkpoint.ts
    • dauerhafte Zustellungs-Checkpoints und Replay-Cursors
  • src/acp/control-plane/idempotency.ts
    • Idempotenz-Schlüssel-Reservierung und Response-Replay
  • src/acp/control-plane/recovery.ts
    • Boot-Zeit-Abgleich und Actor-Rehydrate-Plan

Kompatibilitäts-Brücken-Module:

  • src/acp/runtime/session-meta.ts
    • bleibt temporär für Projektion in SessionEntry.acp
    • darf nach Migrations-Umstellung nicht mehr Source of Truth sein

Erforderliche Invarianten (müssen im Code erzwungen werden)

  • ACP-Session-Erstellung und Thread-Bind sind atomar (einzelne Transaktion)
  • Pro ACP-Session-Actor ist höchstens ein aktiver Run gleichzeitig
  • Event-seq ist streng steigend pro Run
  • Zustellungs-Checkpoint rückt nie über das letzte committete Event hinaus vor
  • Idempotenz-Replay gibt vorherige Erfolgs-Payload für doppelte Befehlsschlüssel zurück
  • Fehlende/veraltete ACP-Metadaten können nicht zum normalen Nicht-ACP-Reply-Pfad routen

Core-Berührungspunkte

Zu ändernde Core-Dateien:

  • src/auto-reply/reply/dispatch-from-config.ts
    • ACP-Zweig ruft AcpSessionManager.submit und Event-Projektions-Zustellung auf
    • Direkten ACP-Fallback entfernen, der Steuerungsebenen-Invarianten umgeht
  • src/auto-reply/reply/inbound-context.ts (oder nächste normalisierte Kontextgrenze)
    • Normalisierte Routing-Schlüssel und Idempotenz-Seeds für die ACP-Steuerungsebene bereitstellen
  • src/config/sessions/types.ts
    • SessionEntry.acp als Projections-only-Kompatibilitätsfeld beibehalten
  • src/gateway/server-methods/sessions.ts
    • Reset/Delete/Archivierung muss ACP-Manager-Close/Unbind-Transaktionspfad aufrufen
  • src/infra/outbound/bound-delivery-router.ts
    • Fail-Closed-Zielverhalten für ACP-gebundene Session-Turns erzwingen
  • src/discord/monitor/thread-bindings.ts
    • ACP-Stale-Binding-Validierungs-Helper hinzufügen, verbunden mit Steuerungsebenen-Lookups
  • src/auto-reply/reply/commands-acp.ts
    • Spawn/Cancel/Close/Steer über ACP-Manager-APIs routen
  • src/agents/acp-spawn.ts
    • Ad-hoc-Metadaten-Schreibvorgänge stoppen; ACP-Manager-Spawn-Transaktion aufrufen
  • src/plugin-sdk/** und Plugin-Runtime-Brücke
    • ACP-Backend-Registrierung und Health-Semantik sauber bereitstellen

Core-Dateien, die explizit nicht ersetzt werden:

  • src/discord/monitor/message-handler.preflight.ts
    • Thread-Binding-Override-Verhalten als kanonischer Session-Key-Resolver beibehalten

ACP-Runtime-Registry-API

Core-Registry-Modul hinzufügen:

  • src/acp/runtime/registry.ts

Erforderliche API:

export type AcpRuntimeBackend = {
  id: string;
  runtime: AcpRuntime;
  healthy?: () => boolean;
};

export function registerAcpRuntimeBackend(backend: AcpRuntimeBackend): void;
export function unregisterAcpRuntimeBackend(id: string): void;
export function getAcpRuntimeBackend(id?: string): AcpRuntimeBackend | null;
export function requireAcpRuntimeBackend(id?: string): AcpRuntimeBackend;

Verhalten:

  • requireAcpRuntimeBackend wirft einen typisierten ACP-Backend-Missing-Error, wenn nicht verfügbar
  • Plugin-Service registriert Backend bei start und deregistriert bei stop
  • Runtime-Lookups sind read-only und prozesslokal

acpx-Runtime-Plugin-Vertrag (Implementierungsdetail)

Für das erste Produktions-Backend (extensions/acpx) sind OpenClaw und acpx über einen strikten Befehlsvertrag verbunden:

  • Backend-ID: acpx
  • Plugin-Service-ID: acpx-runtime
  • Runtime-Handle-Kodierung: runtimeSessionName = acpx:v1:<base64url(json)>
  • Kodierte Payload-Felder:
    • name (acpx-benannte Session; nutzt OpenClaws sessionKey)
    • agent (acpx-Agent-Befehl)
    • cwd (Session-Workspace-Root)
    • mode (persistent | oneshot)

Befehlszuordnung:

  • Session sicherstellen:
    • acpx --format json --json-strict --cwd <cwd> <agent> sessions ensure --name <name>
  • Prompt-Turn:
    • acpx --format json --json-strict --cwd <cwd> <agent> prompt --session <name> --file -
  • Abbrechen:
    • acpx --format json --json-strict --cwd <cwd> <agent> cancel --session <name>
  • Schließen:
    • acpx --format json --json-strict --cwd <cwd> <agent> sessions close <name>

Streaming:

  • OpenClaw konsumiert ndjson-Events aus acpx --format json --json-strict
  • text => text_delta/output
  • thought => text_delta/thought
  • tool_call => tool_call
  • done => done
  • error => error

Session-Schema-Patch

SessionEntry in src/config/sessions/types.ts patchen:

type SessionAcpMeta = {
  backend: string;
  agent: string;
  runtimeSessionName: string;
  mode: "persistent" | "oneshot";
  cwd?: string;
  state: "idle" | "running" | "error";
  lastActivityAt: number;
  lastError?: string;
};

Persistiertes Feld:

  • SessionEntry.acp?: SessionAcpMeta

Migrationsregeln:

  • Phase A: Dual-Write (acp-Projektion + ACP-SQLite-Source-of-Truth)
  • Phase B: Read-Primary aus ACP-SQLite, Fallback-Read aus Legacy-SessionEntry.acp
  • Phase C: Migrationsbefehl füllt fehlende ACP-Zeilen aus gültigen Legacy-Einträgen nach
  • Phase D: Fallback-Read entfernen und Projektion optional nur für UX behalten
  • Legacy-Felder (cliSessionIds, claudeCliSessionId) bleiben unverändert

Fehlervertrag

Stabile ACP-Fehlercodes und benutzerseitige Meldungen ergänzen:

  • ACP_BACKEND_MISSING
    • Meldung: ACP runtime backend is not configured. Install and enable the acpx runtime plugin.
  • ACP_BACKEND_UNAVAILABLE
    • Meldung: ACP runtime backend is currently unavailable. Try again in a moment.
  • ACP_SESSION_INIT_FAILED
    • Meldung: Could not initialize ACP session runtime.
  • ACP_TURN_FAILED
    • Meldung: ACP turn failed before completion.

Regeln:

  • Handlungsfähige, benutzersichere Meldung im Thread zurückgeben
  • Detaillierte Backend-/Systemfehler nur in Runtime-Logs protokollieren
  • Niemals stillschweigend zum normalen LLM-Pfad zurückfallen, wenn ACP-Routing explizit ausgewählt wurde

Duplikat-Zustellungs-Arbitrierung

Einzelne Routing-Regel für ACP-gebundene Turns:

  • Wenn ein aktives Thread-Binding für die Ziel-ACP-Session und den Anforderungskontext existiert, nur an diesen gebundenen Thread zustellen
  • Nicht zusätzlich für denselben Turn an den Parent-Kanal senden
  • Wenn die gebundene Zielauswahl mehrdeutig ist, geschlossen mit explizitem Fehler fehlschlagen (kein impliziter Parent-Fallback)
  • Wenn kein aktives Binding existiert, normales Session-Zielverhalten verwenden

Beobachtbarkeit und Betriebsbereitschaft

Erforderliche Metriken:

  • ACP-Spawn-Erfolg/Fehler-Anzahl nach Backend und Fehlercode
  • ACP-Run-Latenz-Perzentile (Queue-Wartezeit, Runtime-Turn-Zeit, Zustellungs-Projektionszeit)
  • ACP-Actor-Restart-Anzahl und Restart-Grund
  • Stale-Binding-Erkennungsanzahl
  • Idempotenz-Replay-Trefferrate
  • Discord-Zustellungs-Retry- und Ratenlimit-Zähler

Erforderliche Logs:

  • Strukturierte Logs mit sessionKey, runId, backend, threadId, idempotencyKey
  • Explizite Zustandsübergangs-Logs für Session- und Run-Zustandsmaschinen
  • Adapter-Befehlslogs mit maskierungssicheren Argumenten und Exit-Zusammenfassung

Erforderliche Diagnose:

  • /acp sessions enthält Status, aktiven Run, letzten Fehler und Binding-Status
  • /acp doctor (oder Äquivalent) validiert Backend-Registrierung, Store-Health und Stale-Bindings

Konfigurationsvorrang und effektive Werte

ACP-Aktivierungsvorrang:

  • Account-Override: channels.discord.accounts.<id>.threadBindings.spawnAcpSessions
  • Kanal-Override: channels.discord.threadBindings.spawnAcpSessions
  • Globales ACP-Gate: acp.enabled
  • Dispatch-Gate: acp.dispatch.enabled
  • Backend-Verfügbarkeit: registriertes Backend für acp.backend

Auto-Enable-Verhalten:

  • Wenn ACP konfiguriert ist (acp.enabled=true, acp.dispatch.enabled=true oder acp.backend=acpx), markiert Plugin-Auto-Enable plugins.entries.acpx.enabled=true, sofern nicht auf der Denylist oder explizit deaktiviert

Effektiver TTL-Wert:

  • min(Session-TTL, Discord-Thread-Binding-TTL, ACP-Runtime-TTL)

Testplan

Unit-Tests:

  • src/acp/runtime/registry.test.ts (neu)
  • src/auto-reply/reply/dispatch-from-config.acp.test.ts (neu)
  • src/infra/outbound/bound-delivery-router.test.ts (ACP-Fail-Closed-Fälle erweitern)
  • src/config/sessions/types.test.ts oder nächste Session-Store-Tests (ACP-Metadaten-Persistenz)

Integrationstests:

  • src/discord/monitor/reply-delivery.test.ts (gebundenes ACP-Zustellungsziel-Verhalten)
  • src/discord/monitor/message-handler.preflight*.test.ts (gebundene ACP-Session-Key-Routing-Kontinuität)
  • acpx-Plugin-Runtime-Tests im Backend-Paket (Service-Register/Start/Stop + Event-Normalisierung)

Gateway-E2E-Tests:

  • src/gateway/server.sessions.gateway-server-sessions-a.e2e.test.ts (ACP-Reset/Delete-Lifecycle-Abdeckung erweitern)
  • ACP-Thread-Turn-Roundtrip-E2E für Spawn, Nachricht, Stream, Cancel, Unfocus, Restart-Recovery

Rollout-Schutz

Unabhängigen ACP-Dispatch-Kill-Switch hinzufügen:

  • acp.dispatch.enabled Standard false für das erste Release
  • Wenn deaktiviert:
    • ACP-Spawn/Focus-Steuerungsbefehle können weiterhin Sessions binden
    • ACP-Dispatch-Pfad aktiviert sich nicht
    • Benutzer erhält explizite Meldung, dass ACP-Dispatch per Policy deaktiviert ist
  • Nach Canary-Validierung kann der Standard in einem späteren Release auf true umgestellt werden

Befehls- und UX-Plan

Neue Befehle

  • /acp spawn <agent-id> [--mode persistent|oneshot] [--thread auto|here|off]
  • /acp cancel [session]
  • /acp steer <instruction>
  • /acp close [session]
  • /acp sessions

Bestehende Befehlskompatibilität

  • /focus <sessionKey> unterstützt weiterhin ACP-Ziele
  • /unfocus behält aktuelle Semantik
  • /session idle und /session max-age ersetzen den alten TTL-Override

Schrittweiser Rollout

Phase 0: ADR und Schema-Freeze

  • ADR für ACP-Steuerungsebenen-Ownership und Adapter-Grenzen ausliefern
  • DB-Schema einfrieren (acp_sessions, acp_runs, acp_bindings, acp_events, acp_delivery_checkpoint, acp_idempotency)
  • Stabile ACP-Fehlercodes, Event-Vertrag und Zustandsübergangs-Guards definieren

Phase 1: Steuerungsebenen-Grundlage im Kern

  • AcpSessionManager und Per-Session-Actor-Runtime implementieren
  • ACP-SQLite-Store und Transaktions-Helper implementieren
  • Idempotenz-Store und Replay-Helper implementieren
  • Event-Append + Zustellungs-Checkpoint-Module implementieren
  • Spawn/Cancel/Close-APIs mit transaktionalen Garantien an den Manager anbinden

Phase 2: Core-Routing und Lifecycle-Integration

  • Threadgebundene ACP-Turns aus der Dispatch-Pipeline in den ACP-Manager routen
  • Fail-Closed-Routing erzwingen, wenn ACP-Binding/Session-Invarianten scheitern
  • Reset/Delete/Archiv/Unfocus-Lifecycle mit ACP-Close/Unbind-Transaktionen integrieren
  • Stale-Binding-Erkennung und optionale Auto-Unbind-Policy hinzufügen

Phase 3: acpx-Backend-Adapter/Plugin

  • acpx-Adapter gegen Runtime-Vertrag implementieren (ensureSession, submit, stream, cancel, close)
  • Backend-Health-Checks und Startup/Teardown-Registrierung hinzufügen
  • acpx-ndjson-Events in ACP-Runtime-Events normalisieren
  • Backend-Timeouts, Prozess-Supervision und Restart/Backoff-Policy erzwingen

Phase 4: Zustellungsprojektion und Kanal-UX (Discord zuerst)

  • Event-gesteuerte Kanalprojektion mit Checkpoint-Resume implementieren (Discord zuerst)
  • Streaming-Chunks mit ratenlimitbewusster Flush-Policy zusammenführen
  • Exactly-Once finale Abschlussnachricht pro Run garantieren
  • /acp spawn, /acp cancel, /acp steer, /acp close, /acp sessions ausliefern

Phase 5: Migration und Umstellung

  • Dual-Write zu SessionEntry.acp-Projektion plus ACP-SQLite-Source-of-Truth einführen
  • Migrationstool für Legacy-ACP-Metadatenzeilen hinzufügen
  • Lesepfad auf ACP-SQLite-Primary umstellen
  • Legacy-Fallback-Routing entfernen, das von fehlendem SessionEntry.acp abhängt

Phase 6: Härtung, SLOs und Skalierungslimits

  • Gleichzeitigkeitslimits (global/Account/Session), Queue-Policies und Timeout-Budgets erzwingen
  • Vollständige Telemetrie, Dashboards und Schwellenwert-Alerts hinzufügen
  • Chaos-Test für Crash-Recovery und Duplikat-Zustellungs-Unterdrückung
  • Runbook für Backend-Ausfall, DB-Korruption und Stale-Binding-Behebung veröffentlichen

Vollständige Implementierungs-Checkliste

  • Core-Steuerungsebenen-Module und Tests
  • DB-Migrationen und Rollback-Plan
  • ACP-Manager-API-Integration über Dispatch und Befehle
  • Adapter-Registrierungsschnittstelle in Plugin-Runtime-Brücke
  • acpx-Adapter-Implementierung und Tests
  • Threadfähige Kanal-Zustellungs-Projektionslogik mit Checkpoint-Replay (Discord zuerst)
  • Lifecycle-Hooks für Reset/Delete/Archiv/Unfocus
  • Stale-Binding-Detektor und operator-seitige Diagnose
  • Konfigurationsvalidierung und Vorrangtests für alle neuen ACP-Schlüssel
  • Betriebsdokumentation und Troubleshooting-Runbook

Testplan

Unit-Tests:

  • ACP-DB-Transaktionsgrenzen (Spawn/Bind/Enqueue-Atomarität, Cancel, Close)
  • ACP-Zustandsmaschinen-Übergangs-Guards für Sessions und Runs
  • Idempotenz-Reservierung/Replay-Semantik über alle ACP-Befehle
  • Per-Session-Actor-Serialisierung und Queue-Reihenfolge
  • acpx-Event-Parser und Chunk-Koaleszierer
  • Runtime-Supervisor-Restart und Backoff-Policy
  • Konfigurationsvorrang und effektive TTL-Berechnung
  • Core-ACP-Routing-Zweigauswahl und Fail-Closed-Verhalten bei ungültigem Backend/Session

Integrationstests:

  • Fake-ACP-Adapter-Prozess für deterministisches Streaming- und Cancel-Verhalten
  • ACP-Manager + Dispatch-Integration mit transaktionaler Persistenz
  • Threadgebundenes eingehendes Routing zu ACP-Session-Key
  • Threadgebundene ausgehende Zustellung unterdrückt Parent-Kanal-Duplikation
  • Checkpoint-Replay erholt sich nach Zustellungsfehler und setzt vom letzten Event fort
  • Plugin-Service-Registrierung und Teardown des ACP-Runtime-Backends

Gateway-E2E-Tests:

  • ACP mit Thread spawnen, Multi-Turn-Prompts austauschen, unfocusen
  • Gateway-Neustart mit persistierter ACP-DB und Bindings, dann dieselbe Session fortsetzen
  • Gleichzeitige ACP-Sessions in verschiedenen Threads haben kein Crosstalk
  • Doppelte Befehlswiederholungen (gleicher Idempotenz-Schlüssel) erzeugen keine doppelten Runs oder Replies
  • Stale-Binding-Szenario liefert expliziten Fehler und optionales Auto-Clean-Verhalten

Risiken und Gegenmaßnahmen

  • Doppelte Zustellungen während der Umstellung
    • Gegenmaßnahme: einzelner Ziel-Resolver und idempotenter Event-Checkpoint
  • Runtime-Prozess-Churn unter Last
    • Gegenmaßnahme: langlebige Per-Session-Owners + Gleichzeitigkeitslimits + Backoff
  • Plugin fehlt oder ist falsch konfiguriert
    • Gegenmaßnahme: expliziter Operator-Fehler und Fail-Closed-ACP-Routing (kein impliziter Fallback zum normalen Session-Pfad)
  • Konfigurationsverwirrung zwischen Subagent- und ACP-Gates
    • Gegenmaßnahme: explizite ACP-Schlüssel und Befehls-Feedback mit effektiver Policy-Quelle
  • Steuerungsebenen-Store-Korruption oder Migrationsbugs
    • Gegenmaßnahme: WAL-Modus, Backup/Restore-Hooks, Migrations-Smoke-Tests und Read-Only-Fallback-Diagnose
  • Actor-Deadlocks oder Mailbox-Aushungerung
    • Gegenmaßnahme: Watchdog-Timer, Actor-Health-Probes und begrenzte Mailbox-Tiefe mit Ablehnungs-Telemetrie

Akzeptanz-Checkliste

  • ACP-Session-Spawn kann einen Thread in einem unterstützten Kanal-Adapter erstellen oder binden (derzeit Discord)
  • Alle Thread-Nachrichten routen nur zur gebundenen ACP-Session
  • ACP-Ausgaben erscheinen in derselben Thread-Identität mit Streaming oder Batches
  • Keine doppelte Ausgabe im Parent-Kanal für gebundene Turns
  • Spawn+Bind+initiales Enqueue sind atomar im persistenten Store
  • ACP-Befehlswiederholungen sind idempotent und erzeugen keine doppelten Runs oder Ausgaben
  • Cancel, Close, Unfocus, Archiv, Reset und Delete führen deterministisches Cleanup durch
  • Crash-Restart bewahrt Zuordnung und setzt Multi-Turn-Kontinuität fort
  • Gleichzeitige threadgebundene ACP-Sessions arbeiten unabhängig
  • Fehlender ACP-Backend-Zustand erzeugt klaren, handlungsfähigen Fehler
  • Stale-Bindings werden erkannt und explizit angezeigt (mit optionalem sicheren Auto-Clean)
  • Steuerungsebenen-Metriken und Diagnose stehen Operatoren zur Verfügung
  • Neue Unit-, Integrations- und E2E-Abdeckung besteht

Anhang: Gezielte Refactorings für die aktuelle Implementierung (Status)

Dies sind nicht-blockierende Follow-ups, um den ACP-Pfad nach dem Landen des aktuellen Funktionsumfangs wartbar zu halten.

1) ACP-Dispatch-Policy-Auswertung zentralisieren (abgeschlossen)

  • Implementiert über gemeinsame ACP-Policy-Helper in src/acp/policy.ts
  • Dispatch, ACP-Befehl-Lifecycle-Handler und ACP-Spawn-Pfad nutzen jetzt gemeinsame Policy-Logik

2) ACP-Befehlshandler nach Subbefehlsdomäne aufteilen (abgeschlossen)

  • src/auto-reply/reply/commands-acp.ts ist jetzt ein dünner Router
  • Subbefehlsverhalten ist aufgeteilt in:
    • src/auto-reply/reply/commands-acp/lifecycle.ts
    • src/auto-reply/reply/commands-acp/runtime-options.ts
    • src/auto-reply/reply/commands-acp/diagnostics.ts
    • gemeinsame Helper in src/auto-reply/reply/commands-acp/shared.ts

3) ACP-Session-Manager nach Verantwortung aufteilen (abgeschlossen)

  • Manager ist aufgeteilt in:
    • src/acp/control-plane/manager.ts (öffentliche Fassade + Singleton)
    • src/acp/control-plane/manager.core.ts (Manager-Implementierung)
    • src/acp/control-plane/manager.types.ts (Manager-Typen/Abhängigkeiten)
    • src/acp/control-plane/manager.utils.ts (Normalisierung + Helper-Funktionen)

4) Optionaler acpx-Runtime-Adapter-Cleanup

  • extensions/acpx/src/runtime.ts kann aufgeteilt werden in:
  • Prozessausführung/-supervision
  • ndjson-Event-Parsing/-Normalisierung
  • Runtime-API-Oberfläche (submit, cancel, close, etc.)
  • Verbessert die Testbarkeit und macht Backend-Verhalten leichter auditierbar