- Die Kernprimitive sollten Empfangen und Senden sein, nicht Antworten.
- Eine Antwort ist nur eine Relation auf einer ausgehenden Nachricht.
- Ein Turn ist eine Komfortfunktion für die Verarbeitung eingehender Nachrichten, nicht der Besitzer der Zustellung.
- Senden muss kontextbasiert sein:
begin, rendern, Preview oder Stream, final senden, committen, fehlschlagen. - Empfangen muss ebenfalls kontextbasiert sein: normalisieren, deduplizieren, routen, aufzeichnen, dispatchen, Plattform-Ack, fehlschlagen.
- Das öffentliche Plugin-SDK sollte auf eine kleine Channel-Outbound-Oberfläche reduziert werden.
Probleme
Der aktuelle Channel-Stack ist aus mehreren berechtigten lokalen Anforderungen gewachsen:- Einfache Inbound-Adapter verwenden
runtime.channel.inbound.run. - Umfangreiche Adapter verwenden
runtime.channel.inbound.runPreparedReply. - Legacy-Hilfsfunktionen verwenden
dispatchInboundReplyWithBase,recordInboundSessionAndDispatchReply, Reply-Payload-Hilfsfunktionen, Reply-Chunking, Reply-Referenzen und Outbound-Runtime-Hilfsfunktionen. - Preview-Streaming lebt in Channel-spezifischen Dispatchern.
- Dauerhaftigkeit für finale Zustellung wird um bestehende Reply-Payload-Pfade herum ergänzt.
Ziele
- Ein Kernlebenszyklus für alle Receive- und Send-Pfade von Channel-Nachrichten.
- Dauerhafte finale Sends standardmäßig im neuen Nachrichtenlebenszyklus, nachdem ein Adapter replay-sicheres Verhalten deklariert.
- Gemeinsame Semantik für Preview, Edit, Stream, Finalisierung, Retry, Wiederherstellung und Quittung.
- Eine kleine Plugin-SDK-Oberfläche, die Drittanbieter-Plugins lernen und pflegen können.
- Kompatibilität für bestehende Inbound-Reply-Kompatibilitätsaufrufer während der Migration.
- Klare Erweiterungspunkte für neue Channel-Fähigkeiten.
- Keine plattformspezifischen Branches im Kern.
- Keine Token-Delta-Channel-Nachrichten. Channel-Streaming bleibt Nachrichten-Preview, Edit, Append oder Zustellung abgeschlossener Blöcke.
- Strukturierte OpenClaw-Origin-Metadaten für operative/Systemausgaben, damit sichtbare Gateway-Fehler nicht als neue Prompts wieder in gemeinsame Bot-aktivierte Räume eintreten.
Nicht-Ziele
- Nicht jeden bestehenden Channel in der ersten Phase zu dauerhafter Nachrichtenzustellung zwingen.
- Nicht jeden Channel in dasselbe native Transportverhalten zwingen.
- Dem Kern keine Telegram-Topics, nativen Slack-Streams, Matrix-Redactions, Feishu-Karten, QQ-Voice oder Teams-Aktivitäten beibringen.
- Nicht alle internen Migrationshilfsfunktionen als stabile SDK-API veröffentlichen.
- Retrys sollen abgeschlossene nicht idempotente Plattformoperationen nicht erneut abspielen.
Referenzmodell
Vercel Chat hat ein gutes öffentliches mentales Modell:ChatThreadChannelMessage- Adaptermethoden wie
postMessage,editMessage,deleteMessage,stream,startTypingund History-Fetches - ein State-Adapter für Deduplizierung, Sperren, Queues und Persistenz
- Dauerhafte Outbound-Sendeabsichten vor direkten Transportaufrufen.
- Explizite Sendekontexte mit Begin, Commit und Fail.
- Receive-Kontexte, die die Plattform-Ack-Richtlinie kennen.
- Quittungen, die einen Neustart überleben und Edits, Deletes, Wiederherstellung und Unterdrückung von Duplikaten steuern können.
- Ein kleineres öffentliches SDK. Gebündelte Plugins können interne Runtime-Hilfsfunktionen verwenden, aber Drittanbieter-Plugins sollten eine kohärente Nachrichten-API sehen.
- Agent-spezifisches Verhalten: Sessions, Transkripte, Block-Streaming, Tool-Fortschritt, Freigaben, Medienanweisungen, stille Antworten und Verlauf von Gruppenerwähnungen.
thread.post() reichen für OpenClaw nicht aus. Sie verbergen die Transaktionsgrenze, die entscheidet, ob ein Send wiederherstellbar ist.
Kernmodell
Die neue Domain sollte unter einem internen Kern-Namespace wiesrc/channels/message/* leben.
Sie hat vier Konzepte:
receive besitzt den Inbound-Lebenszyklus.
send besitzt den Outbound-Lebenszyklus.
live besitzt Preview-, Edit-, Fortschritts- und Stream-State.
state besitzt dauerhafte Intent-Speicherung, Quittungen, Idempotenz, Wiederherstellung, Sperren und Deduplizierung.
Nachrichtenbegriffe
Nachricht
Eine normalisierte Nachricht ist plattformneutral:Ziel
Das Ziel beschreibt, wo die Nachricht lebt:Relation
Antwort ist eine Relation, kein API-Root:Origin
Origin beschreibt, wer eine Nachricht erzeugt hat und wie OpenClaw Echos dieser Nachricht behandeln sollte. Sie ist von der Relation getrennt: Eine Nachricht kann eine Antwort an einen Benutzer sein und trotzdem von OpenClaw stammende operative Ausgabe sein.allowBots aktiviert ist.
Quittung
Quittungen sind First-Class:Receive-Kontext
Empfangen sollte kein bloßer Hilfsfunktionsaufruf sein. Der Kern benötigt einen Kontext, der Deduplizierung, Routing, Session-Aufzeichnung und Plattform-Ack-Richtlinie kennt.- Transport-Ack: teilt dem Plattform-Webhook oder Socket mit, dass OpenClaw den Ereignisumschlag akzeptiert hat. Einige Plattformen verlangen dies vor dem Dispatch.
- Polling-Offset-Ack: schiebt einen Cursor vor, damit dasselbe Ereignis nicht erneut abgerufen wird. Dies darf nicht über Arbeit hinaus fortschreiten, die nicht wiederhergestellt werden kann.
- Inbound-Record-Ack: bestätigt, dass OpenClaw genug Inbound-Metadaten persistiert hat, um eine erneute Zustellung zu deduplizieren und zu routen.
- Benutzersichtbare Quittung: optionales Lese-/Status-/Typing-Verhalten; niemals eine Dauerhaftigkeitsgrenze.
ReceiveAckPolicy steuert nur Transport- oder Polling-Bestätigung. Sie darf nicht für Lesebestätigungen oder Statusreaktionen wiederverwendet werden.
Vor der Bot-Autorisierung muss Receive die gemeinsame OpenClaw-Echo-Richtlinie anwenden, wenn der Channel Nachrichten-Origin-Metadaten decodieren kann:
allowBots-Autorisierung.
Ack-Richtlinie ist explizit:
getUpdates-Fetch-Offset wird weiterhin von der Polling-Bibliothek gesteuert; der verbleibende tiefere Eingriff ist daher eine vollständig dauerhafte Polling-Quelle, falls wir plattformseitige erneute Zustellung über OpenClaws Neustart-Watermark hinaus benötigen. Webhook-Plattformen benötigen möglicherweise einen sofortigen HTTP-Ack, brauchen aber weiterhin Inbound-Deduplizierung und dauerhafte Outbound-Sendeabsichten, weil Webhooks erneut zustellen können.
Send-Kontext
Senden ist ebenfalls kontextbasiert:unknown_after_send fortgesetzt
werden, nicht blind erneut abgespielt werden. Kanäle ohne Abgleich dürfen
At-least-once-Replay nur wählen, wenn doppelte sichtbare Nachrichten ein akzeptabler,
dokumentierter Kompromiss für diesen Kanal und diese Beziehung sind. Die aktuelle
SDK-Abgleichsbrücke verlangt, dass der Adapter reconcileUnknownSend deklariert,
und fordert dann durableFinal.reconcileUnknownSend auf, einen unbekannten Eintrag
als sent, not_sent oder unresolved zu klassifizieren; nur not_sent erlaubt
Replay, und ungelöste Einträge bleiben terminal oder wiederholen nur die
Abgleichsprüfung.
Die Durability-Richtlinie muss explizit sein:
required bedeutet, dass Core fail-closed handeln muss, wenn der Durable Intent
nicht geschrieben werden kann. best_effort kann fortfahren, wenn Persistenz nicht
verfügbar ist. disabled behält das alte direkte Sendeverhalten bei. Während der
Migration verwenden Legacy-Wrapper und öffentliche Kompatibilitäts-Helper standardmäßig
disabled; sie dürfen required nicht daraus ableiten, dass ein Kanal einen
generischen ausgehenden Adapter hat.
Sendekontexte besitzen auch kanal-lokale Effekte nach dem Senden. Eine Migration ist
nicht sicher, wenn Durable Delivery lokales Verhalten umgeht, das zuvor an den direkten
Sendepfad des Kanals gebunden war. Beispiele sind Caches zur Unterdrückung von
Self-Echos, Thread-Teilnahmemarker, native Edit-Anker, Modell-Signatur-Rendering
und plattformspezifische Duplikat-Schutzmechanismen. Diese Effekte müssen entweder
in den Sendeadapter, den Render-Adapter oder einen benannten Sendekontext-Hook
verschoben werden, bevor dieser Kanal Durable Generic Final Delivery aktivieren kann.
Sende-Helper müssen Receipts vollständig an ihren Aufrufer zurückgeben. Durable
Wrapper dürfen Nachrichten-IDs nicht verschlucken oder ein Kanalzustellungsergebnis
durch undefined ersetzen; gepufferte Dispatcher verwenden diese IDs für
Thread-Anker, spätere Bearbeitungen, Preview-Finalisierung und Duplikatunterdrückung.
Fallback-Sends arbeiten mit Batches, nicht mit einzelnen Payloads. Silent-Reply-Rewrites,
Medien-Fallback, Card-Fallback und Chunk-Projektion können alle mehr als eine
zustellbare Nachricht erzeugen, daher muss ein Sendekontext entweder den gesamten
projizierten Batch zustellen oder explizit dokumentieren, warum nur ein Payload gültig ist.
unknown_after_send markieren, bis der Adapter ihn abgleicht.
Live-Kontext
Preview-, Edit-, Fortschritts- und Stream-Verhalten sollte ein Opt-in-Lifecycle sein.- Telegram-Send plus Edit-Preview, mit frischem Final nach veraltetem Preview-Alter.
- Discord-Send plus Edit-Preview, Abbruch bei Medien/Fehler/expliziter Antwort.
- Slack-nativer Stream oder Draft-Preview abhängig von der Thread-Form.
- Mattermost-Draft-Post-Finalisierung.
- Matrix-Draft-Event-Finalisierung oder Redaction bei Abweichung.
- Teams-nativer Fortschrittsstream.
- QQ-Bot-Stream oder angesammelter Fallback.
Adapter-Oberfläche
Das öffentliche SDK-Ziel sollte ein Subpath sein:origin.decode OpenClaw-Origin-Metadaten zurückgibt. Der Empfangsadapter
liefert Plattformfakten wie Bot-Autor und Raumform; Core besitzt die Drop-Entscheidung
und Reihenfolge, damit Kanäle keine Textfilter erneut implementieren.
Origin-Adapter:
MessageOrigin. Kanäle übersetzen es nur zu und aus nativen
Transportmetadaten. Slack mappt dies auf chat.postMessage({ metadata }) und
eingehendes message.metadata; Matrix kann es auf zusätzliche Event-Inhalte mappen;
Kanäle ohne native Metadaten können eine Receipt-/Outbound-Registry verwenden, wenn
das die beste verfügbare Annäherung ist.
Capabilities:
Reduktion des öffentlichen SDK
Die neue öffentliche Oberfläche sollte diese konzeptionellen Bereiche aufnehmen oder als veraltet markieren:reply-runtimereply-dispatch-runtimereply-referencereply-chunkingreply-payloadinbound-reply-dispatchchannel-reply-pipeline- die meisten öffentlichen Verwendungen von
outbound-runtime - Ad-hoc-Helper für den Draft-Stream-Lifecycle
plugin-sdk/channel-outbound führen, sobald es existiert.
Beziehung zu Channel Inbound
runtime.channel.inbound.* ist während der Migration die Runtime-Brücke.
Es sollte zu einem Kompatibilitätsadapter werden:
channel.inbound.runPreparedReply sollte anfänglich ebenfalls bestehen bleiben:
channel.turn-Runtime-Oberfläche wurde entfernt. Runtime-Aufrufer verwenden
channel.inbound.*; Kanaldokumentation und SDK-Subpaths verwenden Inbound-/Message-Nomen.
Kompatibilitätsleitplanken
Während der Migration ist generische Durable Delivery Opt-in für jeden Kanal, dessen bestehender Delivery-Callback Nebeneffekte über „diesen Payload senden“ hinaus hat. Legacy-Einstiegspunkte sind standardmäßig nicht durable:channel.inbound.rununddispatchChannelInboundReplyverwenden den Delivery-Callback des Kanals, sofern dieser Kanal nicht explizit ein auditiertes Durable-Policy-/Optionsobjekt bereitstellt.channel.inbound.runPreparedReplybleibt kanalgeführt, bis der vorbereitete Dispatcher explizit den Sendekontext aufruft.- Öffentliche Kompatibilitäts-Helper wie
recordInboundSessionAndDispatchReply,dispatchInboundReplyWithBaseund Direct-DM-Helper injizieren niemals generische Durable Delivery vor dem vom Aufrufer bereitgestelltendeliver- oderreply-Callback.
durable: undefined „nicht durable“. Der
Durable-Pfad wird nur durch einen expliziten Policy-/Optionswert aktiviert. durable: false kann als Kompatibilitätsschreibweise bestehen bleiben, aber die Implementierung
sollte nicht verlangen, dass jeder nicht migrierte Kanal sie hinzufügt.
Aktueller Bridge-Code muss die Durability-Entscheidung explizit halten:
- Dauerhafte finale Zustellung gibt einen diskriminierten Status zurück.
handled_visibleundhandled_no_sendsind terminal;unsupportedundnot_applicablekönnen auf kanalverwaltete Zustellung zurückfallen;failedgibt den Sendefehler weiter. - Generische dauerhafte finale Zustellung wird durch Adapterfähigkeiten wie stille Zustellung, Erhaltung des Antwortziels, Erhaltung nativer Zitate und Hooks zum Senden von Nachrichten abgesichert. Fehlende Parität sollte kanalverwaltete Zustellung wählen, nicht einen generischen Versand, der für Benutzer sichtbares Verhalten ändert.
- Warteschlangenbasierte dauerhafte Sends stellen eine Referenz auf die Zustellabsicht bereit. Bestehende
pendingFinalDelivery*-Sitzungsfelder können während des Übergangs die Intent-ID tragen; der Endzustand ist einMessageSendIntent-Speicher statt eingefrorenem Antworttext plus Ad-hoc-Kontextfeldern.
- Der generische Send-Adapter führt dasselbe Rendering- und Transportverhalten aus wie der alte direkte Pfad.
- Lokale Nebeneffekte nach dem Senden bleiben über den Send-Kontext erhalten.
- Der Adapter gibt Empfangsbestätigungen oder Zustellergebnisse mit allen Plattform-Nachrichten-IDs zurück.
- Vorbereitete Dispatcher-Pfade rufen entweder den neuen Send-Kontext auf oder bleiben dokumentiert als außerhalb der dauerhaften Garantie.
- Fallback-Zustellung verarbeitet jede projizierte Payload, nicht nur die erste.
- Dauerhafte Fallback-Zustellung zeichnet das gesamte Array projizierter Payloads als eine wiederholbare Absicht oder einen Batch-Plan auf.
- iMessage-Monitor-Zustellung zeichnet gesendete Nachrichten nach einem erfolgreichen Versand in einem Echo-Cache auf. Dauerhafte finale Sends müssen diesen Cache weiterhin füllen, andernfalls kann OpenClaw seine eigenen finalen Antworten erneut als eingehende Benutzernachrichten aufnehmen.
- Tlon hängt optional eine Modellsignatur an und zeichnet teilgenommene Threads nach Gruppenantworten auf. Generische dauerhafte Zustellung darf diese Effekte nicht umgehen; verschieben Sie sie entweder in Tlon-Render-/Send-/Finalize-Adapter oder belassen Sie Tlon auf dem kanalverwalteten Pfad.
- Discord und andere vorbereitete Dispatcher besitzen bereits direkte Zustellung und Vorschauverhalten. Sie sind nicht von einer dauerhaften Garantie für zusammengesetzte Turns abgedeckt, bis ihre vorbereiteten Dispatcher finale Antworten ausdrücklich durch den Send-Kontext leiten.
- Telegram-Fallback-Zustellung im stillen Modus muss das vollständige Array projizierter Payloads zustellen. Eine Abkürzung mit nur einer Payload kann zusätzliche Fallback-Payloads nach der Projektion verwerfen.
- LINE, Zalo, Nostr und andere bestehende zusammengesetzte/Helfer-Pfade können Reply-Token-Behandlung, Medien-Proxying, Caches für gesendete Nachrichten, Bereinigung von Lade-/Statusanzeigen oder reine Callback-Ziele haben. Sie bleiben auf kanalverwalteter Zustellung, bis diese Semantik durch den Send-Adapter dargestellt und durch Tests verifiziert ist.
- Direct-DM-Helfer können einen Antwort-Callback haben, der das einzige korrekte Transportziel
ist. Generischer ausgehender Versand darf nicht aus
OriginatingTooderToraten und diesen Callback überspringen. - OpenClaw-Gateway-Fehlerausgabe muss für Menschen sichtbar bleiben, aber markierte
botverfasste Raum-Echos müssen vor der
allowBots-Autorisierung verworfen werden. Kanäle dürfen dies nicht mit sichtbaren Textpräfixfiltern implementieren, außer als kurzer Notfall-Stopgap; der dauerhafte Vertrag ist strukturierte Ursprungsmetadaten.
Interner Speicher
Die dauerhafte Warteschlange sollte Nachrichtensendeabsichten speichern, keine Antwort-Payloads.Fehlerklassen
Kanaladapter klassifizieren Transportfehler in geschlossene Kategorien:transientundrate_limiterneut versuchen.invalid_payloadnicht erneut versuchen, außer es gibt einen Rendering-Fallback.authoderpermissionnicht erneut versuchen, bis sich die Konfiguration ändert.- Bei
not_founddarf Live-Finalisierung von Bearbeitung auf frischen Versand zurückfallen, wenn der Kanal dies als sicher deklariert. - Bei
conflictEmpfangsbestätigungs-/Idempotenzregeln verwenden, um zu entscheiden, ob die Nachricht bereits existiert. - Jeder Fehler, nachdem der Adapter möglicherweise Plattform-I/O abgeschlossen hat, aber vor dem Commit
der Empfangsbestätigung, wird zu
unknown_after_send, außer der Adapter kann beweisen, dass die Plattformoperation nicht stattgefunden hat.
Kanalzuordnung
| Channel | Zielmigration |
|---|---|
| Telegram | Empfängt Bestätigungsrichtlinie plus persistente finale Sendungen. Live-Adapter besitzt Senden plus Vorschau-Bearbeitung, finalen Versand veralteter Vorschau, Themen, Überspringen der Zitat-Antwort-Vorschau, Medien-Fallback und Retry-after-Behandlung. |
| Discord | Sendeadapter umschließt vorhandene persistente Payload-Zustellung. Live-Adapter besitzt Entwurfsbearbeitung, Fortschrittsentwurf, Abbruch von Medien-/Fehlervorschau, Beibehaltung des Antwortziels und Nachrichten-ID-Empfangsbestätigungen. Prüfen Sie bot-erstellte Gateway-Fehler-Echos in gemeinsamen Räumen; verwenden Sie eine Ausgangsregistrierung oder ein anderes natives Äquivalent, wenn Discord Herkunftsmetadaten bei normalen Nachrichten nicht übertragen kann. |
| Slack | Sendeadapter verarbeitet normale Chat-Beiträge. Live-Adapter wählt nativen Stream, wenn die Thread-Form dies unterstützt, andernfalls Entwurfsvorschau. Empfangsbestätigungen bewahren Thread-Zeitstempel. Ursprungsadapter ordnet OpenClaw-Gateway-Fehler Slack-chat.postMessage.metadata zu und verwirft markierte Bot-Raum-Echos vor der allowBots-Autorisierung. |
| Sendeadapter besitzt Text-/Medienversand mit persistenten finalen Intents. Empfangsadapter verarbeitet Gruppenerwähnung und Senderidentität. Live kann fehlen, bis WhatsApp einen bearbeitbaren Transport hat. | |
| Matrix | Live-Adapter besitzt Entwurfsereignis-Bearbeitungen, Finalisierung, Schwärzung, Einschränkungen für verschlüsselte Medien und Fallback bei Antwortziel-Abweichung. Empfangsadapter besitzt Hydration und Deduplizierung verschlüsselter Ereignisse. Ursprungsadapter sollte den Ursprung von OpenClaw-Gateway-Fehlern in Matrix-Ereignisinhalte codieren und konfigurierte Bot-Raum-Echos vor der allowBots-Behandlung verwerfen. |
| Mattermost | Live-Adapter besitzt einen Entwurfsbeitrag, Fortschritts-/Tool-Faltung, Finalisierung vor Ort und Fresh-Send-Fallback. |
| Microsoft Teams | Live-Adapter besitzt natives Fortschritts- und Block-Stream-Verhalten. Sendeadapter besitzt Aktivitäten und Empfangsbestätigungen für Anhänge/Karten. |
| Feishu | Render-Adapter besitzt Text-/Karten-/Roh-Rendering. Live-Adapter besitzt Streaming-Karten und Unterdrückung doppelter Finalnachrichten. Sendeadapter besitzt Kommentare, Themensitzungen, Medien und Sprachunterdrückung. |
| QQ Bot | Live-Adapter besitzt C2C-Streaming, Akkumulator-Timeout und finalen Fallback-Versand. Render-Adapter besitzt Medien-Tags und Text-als-Sprache. |
| Signal | Einfacher Empfang plus Sendeadapter. Kein Live-Adapter, sofern signal-cli keine zuverlässige Bearbeitungsunterstützung hinzufügt. |
| iMessage | Einfacher Empfang plus Sendeadapter. iMessage-Versand muss die Befüllung des Monitor-Echo-Cache beibehalten, bevor persistente finale Sendungen die Monitor-Zustellung umgehen können. |
| Google Chat | Einfacher Empfang plus Sendeadapter mit Thread-Beziehung, die Spaces und Thread-IDs zugeordnet ist. Prüfen Sie das Raumverhalten bei allowBots=true auf markierte OpenClaw-Gateway-Fehler-Echos. |
| LINE | Einfacher Empfang plus Sendeadapter mit Antwort-Token-Einschränkungen, modelliert als Ziel-/Beziehungsfähigkeit. |
| Nextcloud Talk | SDK-Empfangsbrücke plus Sendeadapter. |
| IRC | Einfacher Empfang plus Sendeadapter, keine persistenten Bearbeitungsbestätigungen. |
| Nostr | Empfang plus Sendeadapter für verschlüsselte DMs; Empfangsbestätigungen sind Ereignis-IDs. |
| QA Channel | Vertragstest-Adapter für Empfangs-, Sende-, Live-, Retry- und Wiederherstellungsverhalten. |
| Synology Chat | Einfacher Empfang plus Sendeadapter. |
| Tlon | Sendeadapter muss Modell-Signatur-Rendering und Nachverfolgung beteiligter Threads beibehalten, bevor generische persistente finale Zustellung aktiviert wird. |
| Twitch | Einfacher Empfang plus Sendeadapter mit Rate-Limit-Klassifizierung. |
| Zalo | Einfacher Empfang plus Sendeadapter. |
| Zalo Personal | Einfacher Empfang plus Sendeadapter. |
Migrationsplan
Phase 1: Interne Nachrichtendomäne
- Fügen Sie
src/channels/message/*-Typen für Nachrichten, Ziele, Beziehungen, Ursprünge, Empfangsbestätigungen, Fähigkeiten, persistente Intents, Empfangskontext, Sendekontext, Live-Kontext und Fehlerklassen hinzu. - Fügen Sie
origin?: MessageOriginzum Payload-Typ der Migrationsbrücke hinzu, der von der aktuellen Antwortzustellung verwendet wird, und verschieben Sie dieses Feld dann nachChannelMessageund in gerenderte Nachrichtentypen, während das Refactoring Antwort-Payloads ersetzt. - Halten Sie dies intern, bis Adapter und Tests die Form nachweisen.
- Fügen Sie reine Unit-Tests für Zustandsübergänge und Serialisierung hinzu.
Phase 2: Persistenter Sendekern
- Verschieben Sie die vorhandene Ausgangswarteschlange von Antwort-Payload-Persistenz zu persistenten Nachrichtensende-Intents.
- Lassen Sie einen persistenten Sende-Intent ein projiziertes Payload-Array oder einen Batch-Plan tragen, nicht nur einen Antwort-Payload.
- Behalten Sie das aktuelle Warteschlangen-Wiederherstellungsverhalten durch Kompatibilitätskonvertierung bei.
- Lassen Sie
deliverOutboundPayloadsmessages.sendaufrufen. - Machen Sie persistente finale Sendungen zum Standard und schlagen Sie geschlossen fehl, wenn der persistente Intent im neuen Nachrichtenlebenszyklus nicht geschrieben werden kann, nachdem der Adapter Replay-Sicherheit deklariert. Vorhandene eingehende Runner- und SDK-Kompatibilitätspfade bleiben in dieser Phase standardmäßig Direktversand.
- Zeichnen Sie Empfangsbestätigungen konsistent auf.
- Geben Sie Empfangsbestätigungen und Zustellungsergebnisse an den ursprünglichen Dispatcher-Aufrufer zurück, statt persistenten Versand als terminalen Nebeneffekt zu behandeln.
- Persistieren Sie den Nachrichtenursprung über persistente Sende-Intents, damit Wiederherstellung, Replay und segmentierte Sendungen die operative OpenClaw-Provenienz beibehalten.
Phase 3: Channel-Eingangsbrücke
- Implementieren Sie
channel.inbound.rununddispatchChannelInboundReplyauf Basis vonmessages.receiveundmessages.sendneu. - Halten Sie aktuelle Faktentypen stabil.
- Behalten Sie Legacy-Verhalten standardmäßig bei. Ein Channel mit zusammengesetztem Turn wird nur persistent, wenn sein Adapter sich ausdrücklich mit einer replay-sicheren Persistenzrichtlinie dafür entscheidet.
- Behalten Sie
durable: falseals Kompatibilitätsausweg für Pfade bei, die native Bearbeitungen finalisieren und noch nicht sicher wiedergegeben werden können, verlassen Sie sich jedoch nicht auffalse-Marker, um nicht migrierte Channels zu schützen. - Aktivieren Sie Standardpersistenz für zusammengesetzte Turns nur im neuen Nachrichtenlebenszyklus, nachdem die Channel-Zuordnung nachweist, dass der generische Sendepfad die alte Channel- Zustellungssemantik beibehält.
Phase 4: Vorbereitete Dispatcher-Brücke
- Ersetzen Sie
deliverDurableInboundReplyPayloaddurch eine Send-Kontext-Bridge. - Behalten Sie den alten Helper als Wrapper bei.
- Migrieren Sie zuerst Telegram, WhatsApp, Slack, Signal, iMessage und Discord, weil sie bereits Durable-Final-Arbeit oder einfachere Sendepfade haben.
- Behandeln Sie jeden vorbereiteten Dispatcher als nicht abgedeckt, bis er sich explizit für den Send-Kontext entscheidet. Dokumentation und Changelog-Einträge müssen „zusammengesetzte Channel-Turns“ sagen oder die migrierten Channel-Pfade benennen, statt alle automatischen finalen Antworten zu beanspruchen.
- Halten Sie
recordInboundSessionAndDispatchReply, Direct-DM-Helper und ähnliche öffentliche Kompatibilitäts-Helper verhaltenserhaltend. Sie können später ein explizites Send-Kontext-Opt-in anbieten, dürfen aber nicht automatisch eine generische Durable-Zustellung vor dem caller-eigenen Zustellungs-Callback versuchen.
Phase 5: Vereinheitlichter Live-Lebenszyklus
- Erstellen Sie
messages.livemit zwei Proof-Adaptern:- Telegram für Senden plus Bearbeiten plus veraltetes finales Senden.
- Matrix für Entwurfsfinalisierung plus Redaction-Fallback.
- Migrieren Sie danach Discord, Slack, Mattermost, Teams, QQ Bot und Feishu.
- Löschen Sie duplizierten Code für die Preview-Finalisierung erst, nachdem jeder Channel Paritätstests hat.
Phase 6: Öffentliches SDK
- Fügen Sie
openclaw/plugin-sdk/channel-outboundhinzu. - Dokumentieren Sie es als bevorzugte Channel-Plugin-API.
- Aktualisieren Sie Package-Exports, Entrypoint-Inventar, generierte API-Baselines und Plugin-SDK-Dokumentation.
- Nehmen Sie
MessageOrigin, Origin-Encode/Decode-Hooks und das gemeinsameshouldDropOpenClawEcho-Prädikat in die channel-outbound-SDK-Oberfläche auf. - Behalten Sie Kompatibilitäts-Wrapper für alte Unterpfade bei.
- Markieren Sie antwortbenannte SDK-Helper in der Dokumentation als veraltet, nachdem gebündelte Plugins migriert wurden.
Phase 7: Alle Sender
Verschieben Sie alle Nicht-Antwort-Outbound-Produzenten aufmessages.send:
- cron- und Heartbeat-Benachrichtigungen
- Aufgabenabschlüsse
- Hook-Ergebnisse
- Genehmigungsaufforderungen und Genehmigungsergebnisse
- Message-Tool-Sends
- Abschlussankündigungen von Subagents
- explizite CLI- oder Control-UI-Sends
- Automatisierungs-/Broadcast-Pfade
Phase 8: Turn-benannte Kompatibilität entfernen
- Behalten Sie inbound-/message-benannte Wrapper als Kompatibilitätsfenster bei.
- Veröffentlichen Sie Migrationshinweise.
- Führen Sie Plugin-SDK-Kompatibilitätstests gegen alte Importe aus.
- Entfernen oder verbergen Sie alte interne Helper erst, nachdem kein gebündeltes Plugin sie mehr benötigt und Drittanbieter-Verträge einen stabilen Ersatz haben.
Testplan
Unit-Tests:- Durable-Send-Intent-Serialisierung und Wiederherstellung.
- Wiederverwendung von Idempotenzschlüsseln und Duplikatunterdrückung.
- Receipt-Commit und Replay-Überspringen.
unknown_after_send-Wiederherstellung, die vor dem Replay abgleicht, wenn ein Adapter Abgleich unterstützt.- Richtlinie zur Fehlerklassifizierung.
- Sequenzierung der Receive-Ack-Richtlinie.
- Relationsmapping für Antwort-, Follow-up-, System- und Broadcast-Sends.
- Gateway-Fehler-Origin-Factory und
shouldDropOpenClawEcho-Prädikat. - Origin-Erhaltung durch Payload-Normalisierung, Chunking, Durable-Queue-Serialisierung und Wiederherstellung.
- Einfacher
channel.inbound.run-Adapter zeichnet weiterhin auf und sendet. - Legacy-Zustellung zusammengesetzter Events wird nicht Durable, es sei denn, der Channel entscheidet sich explizit dafür.
channel.inbound.runPreparedReply-Bridge zeichnet weiterhin auf und finalisiert.- Öffentliche Kompatibilitäts-Helper rufen standardmäßig caller-eigene Zustellungs-Callbacks auf und senden nicht generisch vor diesen Callbacks.
- Durable-Fallback-Zustellung spielt nach einem Neustart das gesamte projizierte Payload-Array erneut ab und kann die späteren Payloads nach einem frühen Absturz nicht unaufgezeichnet lassen.
- Durable-Zustellung zusammengesetzter Events gibt Plattform-Nachrichten-IDs an den gepufferten Dispatcher zurück.
- Benutzerdefinierte Zustellungs-Hooks geben weiterhin Plattform-Nachrichten-IDs zurück, wenn Durable-Zustellung deaktiviert oder nicht verfügbar ist.
- Finale Antwort übersteht Neustart zwischen Assistant-Abschluss und Plattform-Send.
- Preview-Entwurf wird, wenn erlaubt, an Ort und Stelle finalisiert.
- Preview-Entwurf wird abgebrochen oder redigiert, wenn Medien-/Fehler-/Antwortziel-Mismatch normale Zustellung erfordert.
- Block-Streaming und Preview-Streaming liefern nicht beide denselben Text aus.
- Früh gestreamte Medien werden in der finalen Zustellung nicht dupliziert.
- Telegram-Topic-Antwort mit Polling-Ack, verzögert bis zur Safe-Completed-Watermark des Receive-Kontexts.
- Telegram-Polling-Wiederherstellung für akzeptierte, aber nicht zugestellte Updates, abgedeckt durch das persistierte Safe-Completed-Offset-Modell.
- Veraltete Telegram-Preview sendet frisches Final und räumt die Preview auf.
- Telegram-Silent-Fallback sendet jede projizierte Fallback-Payload.
- Telegram-Silent-Fallback-Durability zeichnet das gesamte projizierte Fallback-Array atomar auf, nicht einen einzelnen Single-Payload-Durable-Intent pro Schleifeniteration.
- Discord-Preview-Abbruch bei Medien/Fehler/expliziter Antwort.
- Finale Nachrichten des vorbereiteten Discord-Dispatchers laufen durch den Send-Kontext, bevor Dokumentation oder Changelog Discord-Final-Reply-Durability beanspruchen.
- Durable iMessage-Final-Sends befüllen den Monitor-Echo-Cache für gesendete Nachrichten.
- Legacy-Zustellungspfade von LINE, Zalo und Nostr werden nicht durch generischen Durable-Send umgangen, bis ihre Adapter-Paritätstests existieren.
- Direct-DM-/Nostr-Callback-Zustellung bleibt maßgeblich, sofern sie nicht explizit auf ein vollständiges Message-Target und einen replay-sicheren Send-Adapter migriert wurde.
- Getaggte OpenClaw-Gateway-Fehlermeldungen in Slack bleiben outbound sichtbar, getaggte
Bot-Room-Echos werden vor
allowBotsverworfen, und ungetaggte Bot-Nachrichten mit demselben sichtbaren Text folgen weiterhin der normalen Bot-Autorisierung. - Slack-Native-Stream-Fallback auf Draft-Preview in Top-Level-DMs.
- Matrix-Preview-Finalisierung und Redaction-Fallback.
- Getaggte OpenClaw-Gateway-Fehler-Room-Echos in Matrix von konfigurierten Bot-
Konten werden vor der
allowBots-Behandlung verworfen. - Gateway-Fehler-Kaskaden-Audits für geteilte Räume in Discord und Google Chat decken allowBots-Modi ab, bevor dort generischer Schutz beansprucht wird.
- Mattermost-Entwurfsfinalisierung und Fresh-Send-Fallback.
- Native Teams-Fortschrittsfinalisierung.
- Feishu-Duplikatunterdrückung für finale Nachrichten.
- QQ Bot Accumulator-Timeout-Fallback.
- Durable Tlon-Final-Sends bewahren Model-Signature-Rendering und Tracking beteiligter Threads.
- Einfache Durable-Final-Sends für WhatsApp, Signal, iMessage, Google Chat, LINE, IRC, Nostr, Nextcloud Talk, Synology Chat, Tlon, Twitch, Zalo und Zalo Personal.
- Gezielte Vitest-Dateien während der Entwicklung.
pnpm check:changedin Testbox für die gesamte geänderte Oberfläche.- Breiteres
pnpm checkin Testbox vor dem Landen des vollständigen Refactors oder nach öffentlichen SDK-/Export-Änderungen. - Live- oder qa-channel-Smoke für mindestens einen bearbeitungsfähigen Channel und einen einfachen Send-only-Channel, bevor Kompatibilitäts-Wrapper entfernt werden.
Offene Fragen
- Ob Telegram die grammY-Runner-Quelle irgendwann durch eine vollständig Durable-Polling-Quelle ersetzen sollte, die plattformseitige erneute Zustellung kontrollieren kann, nicht nur die persistierte Neustart-Watermark von OpenClaw.
- Ob Durable-Live-Preview-State im selben Queue-Record wie der finale Send-Intent oder in einem benachbarten Live-State-Store gespeichert werden sollte.
- Wie lange Kompatibilitäts-Wrapper dokumentiert bleiben, nachdem
plugin-sdk/channel-outboundausgeliefert wurde. - Ob Drittanbieter-Plugins Receive-Adapter direkt implementieren oder nur
Normalize-/Send-/Live-Hooks über
defineChannelMessageAdapterbereitstellen sollten. - Welche Receipt-Felder sicher im öffentlichen SDK statt im internen Runtime- State offengelegt werden können.
- Ob Side Effects wie Self-Echo-Caches und Marker für beteiligte Threads als Send-Kontext-Hooks, adaptereigene Finalize-Schritte oder Receipt-Subscriber modelliert werden sollten.
- Welche Channels native Origin-Metadaten haben, welche persistierte Outbound- Registries benötigen und welche keine zuverlässige Cross-Bot-Echo-Unterdrückung bieten können.
Akzeptanzkriterien
- Jeder gebündelte Message-Channel sendet finale sichtbare Ausgabe über
messages.send. - Jeder inbound Message-Channel tritt über
messages.receiveoder einen dokumentierten Kompatibilitäts-Wrapper ein. - Jeder Preview-/Edit-/Stream-Channel verwendet
messages.livefür Entwurfs-State und Finalisierung. channel.inboundist nur ein Wrapper.- Antwortbenannte SDK-Helper sind Kompatibilitäts-Exports, nicht der empfohlene Pfad.
- Durable-Wiederherstellung kann ausstehende Final-Sends nach einem Neustart erneut abspielen, ohne die finale Antwort zu verlieren oder bereits committete Sends zu duplizieren; Sends, deren Plattform-Ergebnis unbekannt ist, werden vor dem Replay abgeglichen oder für diesen Adapter als at-least-once dokumentiert.
- Durable-Final-Sends fail closed, wenn der Durable-Intent nicht geschrieben werden kann, sofern ein Caller nicht explizit einen dokumentierten nicht-Durable-Modus ausgewählt hat.
- Legacy-SDK-Kompatibilitäts-Helper verwenden standardmäßig direkte channel-eigene Zustellung; generischer Durable-Send ist nur explizites Opt-in.
- Receipts bewahren alle Plattform-Nachrichten-IDs für mehrteilige Zustellungen und eine primäre ID für Threading-/Edit-Komfort.
- Durable-Wrapper bewahren channel-lokale Side Effects, bevor direkte Zustellungs-Callbacks ersetzt werden.
- Vorbereitete Dispatcher werden nicht als Durable gezählt, bis ihr finaler Zustellungspfad explizit den Send-Kontext verwendet.
- Fallback-Zustellung verarbeitet jede projizierte Payload.
- Durable-Fallback-Zustellung zeichnet jede projizierte Payload in einem replaybaren Intent oder Batch-Plan auf.
- Von OpenClaw stammende Gateway-Fehlerausgabe ist für Menschen sichtbar, aber getaggte bot-verfasste Room-Echos werden vor der Bot-Autorisierung auf Channels verworfen, die Unterstützung für den Origin-Vertrag deklarieren.
- Die Dokumentation erklärt Send, Receive, Live, State, Receipts, Relations, Fehler- Richtlinie, Migration und Testabdeckung.