Get started
Plan zur Refaktorierung der Kanaldarstellung
Status
Implementiert für die Oberflächen des gemeinsamen Agents, der CLI, der Plugin-Fähigkeiten und der ausgehenden Zustellung:
ReplyPayload.presentationtransportiert semantische Nachrichten-UI.ReplyPayload.delivery.pintransportiert Anforderungen zum Anheften gesendeter Nachrichten.- Gemeinsame Nachrichtenaktionen legen
presentation,deliveryundpinoffen statt Provider-nativercomponents,blocks,buttonsodercard. - Der Core rendert oder reduziert Presentation automatisch anhand der vom Plugin deklarierten ausgehenden Fähigkeiten.
- Renderer für Discord, Slack, Telegram, Mattermost, MS Teams und Feishu nutzen den generischen Vertrag.
- Der Control-Plane-Code des Discord-Kanals importiert keine Carbon-gestützten UI-Container mehr.
Die kanonischen Docs befinden sich jetzt in Nachrichten-Presentation. Behalten Sie diesen Plan als historischen Implementierungskontext bei; aktualisieren Sie den kanonischen Leitfaden bei Änderungen am Vertrag, Renderer- oder Fallback-Verhalten.
Problem
Kanal-UI ist derzeit auf mehrere inkompatible Oberflächen verteilt:
- Der Core besitzt über
buildCrossContextComponentseinen Discord-förmigen Renderer-Hook für kontextübergreifende Nutzung. - Discord
channel.tskann native Carbon-UI überDiscordUiContainerimportieren, wodurch UI-Laufzeitabhängigkeiten in die Control Plane des Kanal-Plugins gezogen werden. - Agent und CLI legen native Payload-Ausweichmechanismen offen, etwa Discord
components, Slackblocks, Telegram- oder Mattermost-buttonssowie Teams- oder Feishu-card. ReplyPayload.channelDatatransportiert sowohl Transporthinweise als auch native UI-Umschläge.- Das generische
interactive-Modell existiert, ist aber enger als die reicheren Layouts, die bereits von Discord, Slack, Teams, Feishu, LINE, Telegram und Mattermost verwendet werden.
Dadurch kennt der Core native UI-Formen, die Laufzeit-Laziness von Plugins wird geschwächt, und Agents erhalten zu viele Provider-spezifische Wege, dieselbe Nachrichtenabsicht auszudrücken.
Ziele
- Der Core entscheidet anhand deklarierter Fähigkeiten über die beste semantische Presentation für eine Nachricht.
- Erweiterungen deklarieren Fähigkeiten und rendern semantische Presentation in native Transport-Payloads.
- Die Web-Control-UI bleibt von nativer Chat-UI getrennt.
- Native Kanal-Payloads werden nicht über die gemeinsame Nachrichtenoberfläche von Agent oder CLI offengelegt.
- Nicht unterstützte Presentation-Funktionen werden automatisch auf die beste Textdarstellung reduziert.
- Zustellverhalten wie das Anheften einer gesendeten Nachricht ist generische Zustellmetadaten, nicht Presentation.
Nichtziele
- Kein Abwärtskompatibilitäts-Shim für
buildCrossContextComponents. - Keine öffentlichen nativen Ausweichmechanismen für
components,blocks,buttonsodercard. - Keine Core-Importe von kanalnativen UI-Bibliotheken.
- Keine Provider-spezifischen SDK-Schnittstellen für gebündelte Kanäle.
Zielmodell
Fügen Sie ReplyPayload ein Core-eigenes Feld presentation hinzu.
type MessagePresentationTone = "neutral" | "info" | "success" | "warning" | "danger";
type MessagePresentation = {
tone?: MessagePresentationTone;
title?: string;
blocks: MessagePresentationBlock[];
};
type MessagePresentationBlock =
| { type: "text"; text: string }
| { type: "context"; text: string }
| { type: "divider" }
| { type: "buttons"; buttons: MessagePresentationButton[] }
| { type: "select"; placeholder?: string; options: MessagePresentationOption[] };
type MessagePresentationButton = {
label: string;
value?: string;
url?: string;
style?: "primary" | "secondary" | "success" | "danger";
};
type MessagePresentationOption = {
label: string;
value: string;
};
interactive wird während der Migration zu einer Teilmenge von presentation:
- Der
interactive-Textblock wird aufpresentation.blocks[].type = "text"abgebildet. - Der
interactive-Button-Block wird aufpresentation.blocks[].type = "buttons"abgebildet. - Der
interactive-Select-Block wird aufpresentation.blocks[].type = "select"abgebildet.
Die externen Agent- und CLI-Schemas verwenden jetzt presentation; interactive bleibt ein interner Legacy-Parser- und Rendering-Helfer für bestehende Antwort-Produzenten.
Zustellmetadaten
Fügen Sie ein Core-eigenes Feld delivery für Sendeverhalten hinzu, das keine UI ist.
type ReplyPayloadDelivery = {
pin?:
| boolean
| {
enabled: boolean;
notify?: boolean;
required?: boolean;
};
};
Semantik:
delivery.pin = truebedeutet, die erste erfolgreich zugestellte Nachricht anzuheften.notifyist standardmäßigfalse.requiredist standardmäßigfalse; nicht unterstützte Kanäle oder fehlgeschlagenes Anheften werden automatisch reduziert, indem die Zustellung fortgesetzt wird.- Manuelle Nachrichtenaktionen
pin,unpinundlist-pinsbleiben für bestehende Nachrichten erhalten.
Die aktuelle Telegram-ACP-Themenbindung sollte von channelData.telegram.pin = true zu delivery.pin = true verschoben werden.
Laufzeit-Fähigkeitsvertrag
Fügen Sie Presentation- und Zustell-Render-Hooks zum ausgehenden Laufzeitadapter hinzu, nicht zum Control-Plane-Kanal-Plugin.
type ChannelPresentationCapabilities = {
supported: boolean;
buttons?: boolean;
selects?: boolean;
context?: boolean;
divider?: boolean;
tones?: MessagePresentationTone[];
};
type ChannelDeliveryCapabilities = {
pinSentMessage?: boolean;
};
type ChannelOutboundAdapter = {
presentationCapabilities?: ChannelPresentationCapabilities;
renderPresentation?: (params: {
payload: ReplyPayload;
presentation: MessagePresentation;
ctx: ChannelOutboundSendContext;
}) => ReplyPayload | null;
deliveryCapabilities?: ChannelDeliveryCapabilities;
pinDeliveredMessage?: (params: {
cfg: OpenClawConfig;
accountId?: string | null;
to: string;
threadId?: string | number | null;
messageId: string;
notify: boolean;
}) => Promise<void>;
};
Core-Verhalten:
- Zielkanal und Laufzeitadapter auflösen.
- Presentation-Fähigkeiten abfragen.
- Nicht unterstützte Blöcke vor dem Rendering reduzieren.
renderPresentationaufrufen.- Wenn kein Renderer vorhanden ist, Presentation in einen Text-Fallback umwandeln.
- Nach erfolgreichem Senden
pinDeliveredMessageaufrufen, wenndelivery.pinangefordert und unterstützt wird.
Kanalzuordnung
Discord:
presentationin Runtime-only-Modulen zu Komponenten v2 und Carbon-Containern rendern.- Akzentfarben-Helfer in leichten Modulen behalten.
DiscordUiContainer-Importe aus dem Control-Plane-Code des Kanal-Plugins entfernen.
Slack:
presentationzu Block Kit rendern.- Agent- und CLI-
blocks-Eingabe entfernen.
Telegram:
- Text, Kontext und Trenner als Text rendern.
- Aktionen und Select als Inline-Keyboards rendern, wenn sie konfiguriert und für die Zieloberfläche erlaubt sind.
- Text-Fallback verwenden, wenn Inline-Buttons deaktiviert sind.
- ACP-Themen-Anheftung zu
delivery.pinverschieben.
Mattermost:
- Aktionen als interaktive Buttons rendern, sofern konfiguriert.
- Andere Blöcke als Text-Fallback rendern.
MS Teams:
presentationzu Adaptive Cards rendern.- Manuelle Aktionen zum Anheften, Lösen und Auflisten angehefteter Nachrichten behalten.
- Optional
pinDeliveredMessageimplementieren, wenn Graph-Unterstützung für die Zielunterhaltung zuverlässig ist.
Feishu:
presentationzu interaktiven Karten rendern.- Manuelle Aktionen zum Anheften, Lösen und Auflisten angehefteter Nachrichten behalten.
- Optional
pinDeliveredMessagefür das Anheften gesendeter Nachrichten implementieren, wenn das API-Verhalten zuverlässig ist.
LINE:
presentationnach Möglichkeit zu Flex- oder Vorlagennachrichten rendern.- Für nicht unterstützte Blöcke auf Text zurückfallen.
- LINE-UI-Payloads aus
channelDataentfernen.
Einfache oder eingeschränkte Kanäle:
- Presentation mit konservativer Formatierung in Text umwandeln.
Refaktorierungsschritte
- Den Discord-Release-Fix erneut anwenden, der
ui-colors.tsvon Carbon-gestützter UI trennt undDiscordUiContainerausextensions/discord/src/channel.tsentfernt. presentationunddeliveryzuReplyPayload, ausgehender Payload-Normalisierung, Zustellzusammenfassungen und Hook-Payloads hinzufügen.MessagePresentation-Schema und Parser-Helfer in einem schmalen SDK-/Runtime-Unterpfad hinzufügen.- Nachrichtenfähigkeiten
buttons,cards,componentsundblocksdurch semantische Presentation-Fähigkeiten ersetzen. - Hooks für ausgehende Runtime-Adapter für Presentation-Rendering und Zustell-Anheftung hinzufügen.
- Kontexübergreifende Komponentenkonstruktion durch
buildCrossContextPresentationersetzen. src/infra/outbound/channel-adapters.tslöschen undbuildCrossContextComponentsaus Kanal-Plugin-Typen entfernen.maybeApplyCrossContextMarkerso ändern, dasspresentationstatt nativer Parameter angehängt wird.- Sendepfade von Plugin-Dispatch aktualisieren, sodass sie nur semantische Presentation und Zustellmetadaten verwenden.
- Native Payload-Parameter aus Agent und CLI entfernen:
components,blocks,buttonsundcard. - SDK-Helfer entfernen, die native Nachrichtenwerkzeug-Schemas erstellen, und durch Presentation-Schema-Helfer ersetzen.
- UI-/native Umschläge aus
channelDataentfernen; nur Transportmetadaten behalten, bis jedes verbleibende Feld überprüft wurde. - Renderer für Discord, Slack, Telegram, Mattermost, MS Teams, Feishu und LINE migrieren.
- Docs für Nachrichten-CLI, Kanalseiten, Plugin-SDK und Fähigkeiten-Cookbook aktualisieren.
- Import-Fanout-Profiling für Discord und betroffene Kanal-Einstiegspunkte ausführen.
Schritte 1-11 und 13-14 sind in dieser Refaktorierung für den gemeinsamen Agent, die CLI, Plugin-Fähigkeiten und ausgehende Adapterverträge implementiert. Schritt 12 bleibt ein tiefergehender interner Cleanup-Durchlauf für Provider-private channelData-Transportumschläge. Schritt 15 bleibt eine Folgevalidierung, falls wir quantifizierte Import-Fanout-Zahlen über das Typ-/Test-Gate hinaus wünschen.
Tests
Hinzufügen oder aktualisieren:
- Presentation-Normalisierungstests.
- Presentation-Tests für automatische Reduktion nicht unterstützter Blöcke.
- Kontexübergreifende Marker-Tests für Plugin-Dispatch- und Core-Zustellpfade.
- Kanal-Render-Matrix-Tests für Discord, Slack, Telegram, Mattermost, MS Teams, Feishu, LINE und Text-Fallback.
- Nachrichtenwerkzeug-Schematests, die belegen, dass native Felder entfernt sind.
- CLI-Tests, die belegen, dass native Flags entfernt sind.
- Discord-Einstiegspunkt-Regressionsabdeckung für Import-Laziness mit Carbon.
- Zustell-Anheftungstests für Telegram und generischen Fallback.
Offene Fragen
- Soll
delivery.pinim ersten Durchlauf für Discord, Slack, MS Teams und Feishu implementiert werden, oder zunächst nur für Telegram? - Soll
deliverykünftig bestehende Felder wiereplyToId,replyToCurrent,silentundaudioAsVoiceaufnehmen, oder auf Verhalten nach dem Senden fokussiert bleiben? - Soll Presentation Bilder oder Dateireferenzen direkt unterstützen, oder sollen Medien vorerst getrennt vom UI-Layout bleiben?