Get started
Plan zur Umstrukturierung der Kanalpräsentation
Status
Implementiert für den gemeinsamen Agent, die CLI, Plugin-Fähigkeiten und Oberflächen für ausgehende Zustellung:
ReplyPayload.presentationträgt semantische Nachrichten-UI.ReplyPayload.delivery.pinträgt Anforderungen zum Anheften gesendeter Nachrichten.- Gemeinsame Nachrichtenaktionen stellen
presentation,deliveryundpinbereit statt Provider-nativencomponents,blocks,buttonsodercard. - Der Kern rendert Präsentation oder stuft sie automatisch über von Plugins deklarierte ausgehende Fähigkeiten herab.
- Discord-, Slack-, Telegram-, Mattermost-, MS Teams- und Feishu-Renderer verwenden den generischen Vertrag.
- Code der Discord-Kanal-Steuerungsebene importiert keine Carbon-basierten UI-Container mehr.
Kanonische Dokumentation befindet sich jetzt in Nachrichtenpräsentation. Bewahren Sie diesen Plan als historischen Implementierungskontext auf; 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 Kern besitzt über
buildCrossContextComponentseinen Discord-förmigen Renderer-Hook für kontextübergreifende Nutzung. - Discord
channel.tskann native Carbon-UI überDiscordUiContainerimportieren, wodurch Laufzeit-UI-Abhängigkeiten in die Steuerungsebene des Kanal-Plugins gezogen werden. - Der Agent und die CLI stellen native Payload-Ausweichpfade wie Discord
components, Slackblocks, Telegram- oder Mattermost-buttonssowie Teams- oder Feishu-cardbereit. ReplyPayload.channelDataträgt sowohl Transporthinweise als auch native UI-Umschläge.- Das generische
interactive-Modell existiert, ist aber schmaler als die reicheren Layouts, die bereits von Discord, Slack, Teams, Feishu, LINE, Telegram und Mattermost verwendet werden.
Dadurch kennt der Kern native UI-Formen, die träge Plugin-Laufzeit wird geschwächt, und Agents erhalten zu viele Provider-spezifische Möglichkeiten, dieselbe Nachrichtenabsicht auszudrücken.
Ziele
- Der Kern entscheidet anhand deklarierter Fähigkeiten über die beste semantische Präsentation für eine Nachricht.
- Erweiterungen deklarieren Fähigkeiten und rendern semantische Präsentation in native Transport-Payloads.
- 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 Präsentationsfunktionen werden automatisch zur besten Textdarstellung herabgestuft.
- Zustellverhalten wie das Anheften einer gesendeten Nachricht ist generische Zustellmetadaten, keine Präsentation.
Nicht-Ziele
- Kein Abwärtskompatibilitäts-Shim für
buildCrossContextComponents. - Keine öffentlichen nativen Ausweichpfade für
components,blocks,buttonsodercard. - Keine Kernimporte von kanalnativen UI-Bibliotheken.
- Keine Provider-spezifischen SDK-Schnittstellen für gebündelte Kanäle.
Zielmodell
Fügen Sie ein kernverwaltetes Feld presentation zu ReplyPayload 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:
interactive-Textblock wird aufpresentation.blocks[].type = "text"abgebildet.interactive-Buttonblock wird aufpresentation.blocks[].type = "buttons"abgebildet.interactive-Selectblock wird aufpresentation.blocks[].type = "select"abgebildet.
Die externen Agent- und CLI-Schemas verwenden jetzt presentation; interactive bleibt ein interner Legacy-Parser-/Rendering-Helfer für bestehende Antwortproduzenten.
Die öffentliche, produzentenorientierte API behandelt interactive als veraltet. Laufzeitunterstützung
bleibt erhalten, damit bestehende Genehmigungshelfer und ältere Plugins weiter
funktionieren, während neuer Code presentation ausgibt.
Zustellmetadaten
Fügen Sie ein kernverwaltetes 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 herabgestuft, 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 wechseln.
Laufzeit-Fähigkeitsvertrag
Fügen Sie Präsentations- und Zustell-Renderer-Hooks zum ausgehenden Laufzeitadapter hinzu, nicht zum Kanal-Plugin der Steuerungsebene.
type ChannelPresentationCapabilities = { supported: boolean; buttons?: boolean; selects?: boolean; context?: boolean; divider?: boolean; tones?: MessagePresentationTone[]; limits?: { actions?: { maxActions?: number; maxActionsPerRow?: number; maxRows?: number; maxLabelLength?: number; maxValueBytes?: number; supportsStyles?: boolean; supportsDisabled?: boolean; supportsLayoutHints?: boolean; }; selects?: { maxOptions?: number; maxLabelLength?: number; maxValueBytes?: number; }; text?: { maxLength?: number; encoding?: "characters" | "utf8-bytes" | "utf16-units"; markdownDialect?: "plain" | "markdown" | "html" | "slack-mrkdwn" | "discord-markdown"; supportsEdit?: boolean; }; };}; 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>;};Kernverhalten:
- Zielkanal und Laufzeitadapter auflösen.
- Präsentationsfähigkeiten abfragen.
- Nicht unterstützte Blöcke herabstufen und generische Fähigkeitsgrenzen vor dem Rendering anwenden.
renderPresentationaufrufen.- Wenn kein Renderer existiert, Präsentation in Text-Fallback umwandeln.
- Nach erfolgreichem Senden
pinDeliveredMessageaufrufen, wenndelivery.pinangefordert und unterstützt wird.
Kanalzuordnung
Discord:
presentationin Komponenten v2 und Carbon-Container in Nur-Laufzeit-Modulen rendern.- Akzentfarben-Helfer in leichten Modulen behalten.
DiscordUiContainer-Importe aus Code der Kanal-Plugin-Steuerungsebene entfernen.
Slack:
presentationin Block Kit rendern.- Agent- und CLI-
blocks-Eingabe entfernen.
Telegram:
- Text, Kontext und Trenner als Text rendern.
- Aktionen und Select als Inline-Tastaturen rendern, wenn sie für die Zieloberfläche konfiguriert und erlaubt sind.
- Text-Fallback verwenden, wenn Inline-Buttons deaktiviert sind.
- ACP-Themenanheftung zu
delivery.pinverschieben.
Mattermost:
- Aktionen als interaktive Buttons rendern, sofern konfiguriert.
- Andere Blöcke als Text-Fallback rendern.
MS Teams:
presentationin Adaptive Cards rendern.- Manuelle Aktionen zum Anheften, Lösen und Auflisten von Pins behalten.
- Optional
pinDeliveredMessageimplementieren, wenn Graph-Unterstützung für die Zielunterhaltung zuverlässig ist.
Feishu:
presentationin interaktive Karten rendern.- Manuelle Aktionen zum Anheften, Lösen und Auflisten von Pins behalten.
- Optional
pinDeliveredMessagefür das Anheften gesendeter Nachrichten implementieren, wenn das API-Verhalten zuverlässig ist.
LINE:
presentationnach Möglichkeit in 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:
- Präsentation mit konservativer Formatierung in Text umwandeln.
Refaktorierungsschritte
- Wenden Sie den Discord-Release-Fix erneut an, der
ui-colors.tsvon Carbon-basierter UI trennt undDiscordUiContainerausextensions/discord/src/channel.tsentfernt. - Fügen Sie
presentationunddeliveryzuReplyPayload, der Normalisierung ausgehender Payloads, Zustellzusammenfassungen und Hook-Payloads hinzu. - Fügen Sie
MessagePresentation-Schema und Parser-Helfer in einem schmalen SDK-/Laufzeit-Unterpfad hinzu. - Ersetzen Sie Nachrichtenfähigkeiten
buttons,cards,componentsundblocksdurch semantische Präsentationsfähigkeiten. - Fügen Sie Hooks für Präsentations-Rendering und Zustellungsanheftung zum ausgehenden Laufzeitadapter hinzu.
- Ersetzen Sie die kontextübergreifende Komponentenerstellung durch
buildCrossContextPresentation. - Löschen Sie
src/infra/outbound/channel-adapters.tsund entfernen SiebuildCrossContextComponentsaus Kanal-Plugin-Typen. - Ändern Sie
maybeApplyCrossContextMarker, sodasspresentationstatt nativer Parameter angehängt wird. - Aktualisieren Sie Plugin-Dispatch-Sendepfade so, dass sie nur semantische Präsentation und Zustellmetadaten verwenden.
- Entfernen Sie native Payload-Parameter von Agent und CLI:
components,blocks,buttonsundcard. - Entfernen Sie SDK-Helfer, die native Nachrichtenwerkzeug-Schemas erstellen, und ersetzen Sie sie durch Präsentationsschema-Helfer.
- Entfernen Sie UI-/native Umschläge aus
channelData; behalten Sie nur Transportmetadaten, bis jedes verbleibende Feld geprüft wurde. - Migrieren Sie Discord-, Slack-, Telegram-, Mattermost-, MS Teams-, Feishu- und LINE-Renderer.
- Aktualisieren Sie Dokumentation für Nachrichten-CLI, Kanalseiten, Plugin-SDK und Fähigkeits-Cookbook.
- Führen Sie Import-Fanout-Profiling für Discord und betroffene Kanal-Einstiegspunkte aus.
Schritte 1-11 und 13-14 sind in dieser Refaktorierung für die Verträge des gemeinsamen Agent, der CLI, der Plugin-Fähigkeiten und des ausgehenden Adapters implementiert. Schritt 12 bleibt ein tieferer interner Bereinigungsdurchgang für Provider-private channelData-Transportumschläge. Schritt 15 bleibt Folgevalidierung, falls wir quantifizierte Import-Fanout-Zahlen über das Typ-/Test-Gate hinaus wünschen.
Tests
Hinzufügen oder aktualisieren:
- Tests für Präsentationsnormalisierung.
- Tests für automatische Herabstufung der Präsentation bei nicht unterstützten Blöcken.
- Tests für kontextübergreifende Marker für Plugin-Dispatch und Kernzustellungspfade.
- Kanal-Rendering-Matrixtests 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-Regression für träge Importe mit Carbon-Abdeckung.
- Tests für Zustellungsanheftung mit Telegram und generischem Fallback.
Offene Fragen
- Sollte
delivery.pinim ersten Durchgang für Discord, Slack, MS Teams und Feishu implementiert werden oder zunächst nur für Telegram? - Sollte
deliverylangfristig bestehende Felder wiereplyToId,replyToCurrent,silentundaudioAsVoiceaufnehmen oder auf Verhalten nach dem Senden fokussiert bleiben? - Sollte Präsentation Bilder oder Dateireferenzen direkt unterstützen, oder sollten Medien vorerst getrennt vom UI-Layout bleiben?