Session-Binding kanalunabhängiger Plan

Überblick

Dieses Dokument definiert das langfristige kanalunabhängige Session-Binding-Modell und den konkreten Umfang für die nächste Implementierungsiteration.

Ziel:

  • Subagent-gebundenes Session-Routing zu einer Kernfähigkeit machen
  • Kanalspezifisches Verhalten in Adaptern halten
  • Regressionen im normalen Discord-Verhalten vermeiden

Warum das existiert

Das aktuelle Verhalten vermischt:

  • Completion-Content-Policy
  • Ziel-Routing-Policy
  • Discord-spezifische Details

Dies verursachte Randfälle wie:

  • Doppelte Main- und Thread-Zustellung bei gleichzeitigen Runs
  • Veraltete Token-Nutzung bei wiederverwendeten Binding-Managern
  • Fehlende Activity-Accounting für Webhook-Sends

Iteration 1 Umfang

Diese Iteration ist bewusst begrenzt.

1. Kanalunabhängige Core-Interfaces hinzufügen

Core-Typen und Service-Interfaces für Bindings und Routing hinzufügen.

Vorgeschlagene Core-Typen:

export type BindingTargetKind = "subagent" | "session";
export type BindingStatus = "active" | "ending" | "ended";

export type ConversationRef = {
  channel: string;
  accountId: string;
  conversationId: string;
  parentConversationId?: string;
};

export type SessionBindingRecord = {
  bindingId: string;
  targetSessionKey: string;
  targetKind: BindingTargetKind;
  conversation: ConversationRef;
  status: BindingStatus;
  boundAt: number;
  expiresAt?: number;
  metadata?: Record<string, unknown>;
};

Core-Service-Vertrag:

export interface SessionBindingService {
  bind(input: {
    targetSessionKey: string;
    targetKind: BindingTargetKind;
    conversation: ConversationRef;
    metadata?: Record<string, unknown>;
    ttlMs?: number;
  }): Promise<SessionBindingRecord>;

  listBySession(targetSessionKey: string): SessionBindingRecord[];
  resolveByConversation(ref: ConversationRef): SessionBindingRecord | null;
  touch(bindingId: string, at?: number): void;
  unbind(input: {
    bindingId?: string;
    targetSessionKey?: string;
    reason: string;
  }): Promise<SessionBindingRecord[]>;
}

2. Einen Core-Delivery-Router für Subagent-Completions hinzufügen

Einen einzelnen Ziel-Auflösungspfad für Completion-Events hinzufügen.

Router-Vertrag:

export interface BoundDeliveryRouter {
  resolveDestination(input: {
    eventKind: "task_completion";
    targetSessionKey: string;
    requester?: ConversationRef;
    failClosed: boolean;
  }): {
    binding: SessionBindingRecord | null;
    mode: "bound" | "fallback";
    reason: string;
  };
}

Für diese Iteration:

  • Nur task_completion wird über diesen neuen Pfad geroutet
  • Bestehende Pfade für andere Event-Arten bleiben unverändert

3. Discord als Adapter beibehalten

Discord bleibt die erste Adapter-Implementierung.

Adapter-Verantwortlichkeiten:

  • Thread-Konversationen erstellen/wiederverwenden
  • Gebundene Nachrichten per Webhook oder Channel-Send senden
  • Thread-Status validieren (archiviert/gelöscht)
  • Adapter-Metadaten zuordnen (Webhook-Identität, Thread-IDs)

4. Aktuell bekannte Korrektheitsprobleme beheben

In dieser Iteration erforderlich:

  • Token-Nutzung bei Wiederverwendung eines bestehenden Thread-Binding-Managers auffrischen
  • Ausgehende Aktivität für Webhook-basierte Discord-Sends aufzeichnen
  • Impliziten Main-Channel-Fallback stoppen wenn ein gebundenes Thread-Ziel für die Session-Modus-Completion ausgewählt ist

5. Aktuelle Runtime-Sicherheitsstandards beibehalten

Kein Verhaltensänderung für Benutzer mit deaktiviertem threadgebundenen Spawn.

Standards bleiben:

  • channels.discord.threadBindings.spawnSubagentSessions = false

Ergebnis:

  • Normale Discord-Benutzer bleiben beim aktuellen Verhalten
  • Der neue Core-Pfad betrifft nur gebundenes Session-Completion-Routing wo aktiviert

Nicht in Iteration 1

Explizit aufgeschoben:

  • ACP-Binding-Ziele (targetKind: "acp")
  • Neue Kanaladapter jenseits von Discord
  • Globaler Ersatz aller Zustellungspfade (spawn_ack, zukünftige subagent_message)
  • Protokollebenen-Änderungen
  • Store-Migration/Versioning-Redesign für alle Binding-Persistenz

Hinweise zu ACP:

  • Interface-Design behält Platz für ACP
  • ACP-Implementierung wird in dieser Iteration nicht begonnen

Routing-Invarianten

Diese Invarianten sind für Iteration 1 verbindlich.

  • Zielauswahl und Content-Generierung sind separate Schritte
  • Wenn Session-Modus-Completion zu einem aktiven gebundenen Ziel auflöst, muss die Zustellung dieses Ziel ansteuern
  • Kein verstecktes Umrouten von gebundenem Ziel zum Main-Channel
  • Fallback-Verhalten muss explizit und beobachtbar sein

Kompatibilität und Rollout

Kompatibilitätsziel:

  • Keine Regression für Benutzer mit deaktiviertem threadgebundenen Spawning
  • Keine Änderung für Nicht-Discord-Kanäle in dieser Iteration

Rollout:

  1. Interfaces und Router hinter aktuellen Feature-Gates landen.
  2. Discord-Completion-Modus-gebundene Zustellungen über Router routen.
  3. Legacy-Pfad für ungebundene Flows beibehalten.
  4. Mit gezielten Tests und Canary-Runtime-Logs verifizieren.

In Iteration 1 erforderliche Tests

Unit- und Integrations-Coverage erforderlich:

  • Manager-Token-Rotation nutzt neuesten Token nach Manager-Wiederverwendung
  • Webhook-Sends aktualisieren Channel-Activity-Timestamps
  • Zwei aktive gebundene Sessions im selben Requester-Channel duplizieren nicht zum Main-Channel
  • Completion für gebundenen Session-Modus-Run löst nur zum Thread-Ziel auf
  • Deaktiviertes Spawn-Flag behält Legacy-Verhalten unverändert bei

Vorgeschlagene Implementierungsdateien

Core:

  • src/infra/outbound/session-binding-service.ts (neu)
  • src/infra/outbound/bound-delivery-router.ts (neu)
  • src/agents/subagent-announce.ts (Completion-Zielauflösungs-Integration)

Discord-Adapter und Runtime:

  • src/discord/monitor/thread-bindings.manager.ts
  • src/discord/monitor/reply-delivery.ts
  • src/discord/send.outbound.ts

Tests:

  • src/discord/monitor/provider*.test.ts
  • src/discord/monitor/reply-delivery.test.ts
  • src/agents/subagent-announce.format.test.ts

Done-Kriterien für Iteration 1

  • Core-Interfaces existieren und sind für Completion-Routing verdrahtet
  • Oben genannte Korrektheitsfixes sind mit Tests gemergt
  • Keine Main- und Thread-doppelte-Completion-Zustellung in Session-Modus-gebundenen Runs
  • Kein Verhaltensänderung für Deployments mit deaktiviertem Bound-Spawn
  • ACP bleibt explizit aufgeschoben