Get started
Plan de refactorisation de la présentation des canaux
État
Implémenté pour l’agent partagé, la CLI, les capacités des plugins et les surfaces d’envoi sortant :
ReplyPayload.presentationtransporte une interface de message sémantique.ReplyPayload.delivery.pintransporte les demandes d’épinglage des messages envoyés.- Les actions de message partagées exposent
presentation,deliveryetpinau lieu des éléments natifs du fournisseurcomponents,blocks,buttonsoucard. - Le cœur effectue le rendu de la présentation ou la dégrade automatiquement selon les capacités d’envoi sortant déclarées par le plugin.
- Les moteurs de rendu de Discord, Slack, Telegram, Mattermost, MS Teams et Feishu utilisent le contrat générique.
- Le code du plan de contrôle du canal Discord n’importe plus de conteneurs d’interface reposant sur Carbon.
La documentation canonique se trouve désormais dans Présentation des messages. Conservez ce plan comme contexte historique de l’implémentation ; mettez à jour le guide canonique pour toute modification du contrat, du moteur de rendu ou du comportement de repli.
Problème
L’interface des canaux est actuellement répartie entre plusieurs surfaces incompatibles :
- Le cœur possède un hook de rendu intercontexte conçu selon le modèle de Discord via
buildCrossContextComponents. - Le fichier
channel.tsde Discord peut importer l’interface native Carbon viaDiscordUiContainer, ce qui introduit des dépendances d’interface d’exécution dans le plan de contrôle du plugin de canal. - L’agent et la CLI exposent des échappatoires de charges utiles natives telles que
componentspour Discord,blockspour Slack,buttonspour Telegram ou Mattermost, etcardpour Teams ou Feishu. ReplyPayload.channelDatatransporte à la fois des indications de transport et des enveloppes d’interface natives.- Le modèle générique
interactiveexiste, mais il est plus limité que les mises en page enrichies déjà utilisées par Discord, Slack, Teams, Feishu, LINE, Telegram et Mattermost.
Cela rend le cœur dépendant des structures d’interface natives, affaiblit le chargement différé de l’exécution des plugins et offre aux agents trop de moyens propres aux fournisseurs pour exprimer la même intention de message.
Objectifs
- Le cœur détermine la meilleure présentation sémantique d’un message à partir des capacités déclarées.
- Les extensions déclarent leurs capacités et transforment la présentation sémantique en charges utiles de transport natives.
- L’interface Web Control UI reste distincte de l’interface native des discussions.
- Les charges utiles natives des canaux ne sont pas exposées par la surface de messagerie partagée de l’agent ou de la CLI.
- Les fonctionnalités de présentation non prises en charge sont automatiquement dégradées vers la meilleure représentation textuelle.
- Le comportement d’envoi, tel que l’épinglage d’un message envoyé, relève de métadonnées génériques d’envoi et non de la présentation.
Hors objectifs
- Aucun adaptateur de rétrocompatibilité pour
buildCrossContextComponents. - Aucune échappatoire native publique pour
components,blocks,buttonsoucard. - Aucune importation, par le cœur, de bibliothèques d’interface natives des canaux.
- Aucune surface du SDK propre à un fournisseur pour les canaux intégrés.
Modèle cible
Ajouter à ReplyPayload un champ presentation appartenant au cœur.
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;};Pendant la migration, interactive devient un sous-ensemble de presentation :
- Le bloc de texte
interactivecorrespond àpresentation.blocks[].type = "text". - Le bloc de boutons
interactivecorrespond àpresentation.blocks[].type = "buttons". - Le bloc de sélection
interactivecorrespond àpresentation.blocks[].type = "select".
Les schémas externes de l’agent et de la CLI utilisent désormais presentation ; interactive reste un ancien utilitaire interne d’analyse et de rendu pour les producteurs de réponses existants.
L’API publique destinée aux producteurs considère interactive comme obsolète. Sa prise en charge à l’exécution
est conservée afin que les utilitaires d’approbation existants et les anciens plugins continuent de
fonctionner, tandis que le nouveau code émet presentation.
Métadonnées d’envoi
Ajouter un champ delivery appartenant au cœur pour le comportement d’envoi qui ne relève pas de l’interface.
type ReplyPayloadDelivery = { pin?: | boolean | { enabled: boolean; notify?: boolean; required?: boolean; };};Sémantique :
delivery.pin = truesignifie épingler le premier message envoyé avec succès.- La valeur par défaut de
notifyestfalse. - La valeur par défaut de
requiredestfalse; les canaux non pris en charge ou les échecs d’épinglage sont automatiquement dégradés en poursuivant l’envoi. - Les actions de message manuelles
pin,unpinetlist-pinsrestent disponibles pour les messages existants.
L’association actuelle des sujets ACP de Telegram doit passer de channelData.telegram.pin = true à delivery.pin = true.
Contrat de capacités d’exécution
Ajouter les hooks de rendu de présentation et d’envoi à l’adaptateur d’envoi sortant d’exécution, et non au plugin de canal du plan de contrôle.
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>;};Comportement du cœur :
- Résoudre le canal cible et l’adaptateur d’exécution.
- Demander les capacités de présentation.
- Dégrader les blocs non pris en charge et appliquer les limites génériques des capacités avant le rendu.
- Appeler
renderPresentation. - Si aucun moteur de rendu n’existe, convertir la présentation en représentation textuelle de repli.
- Après un envoi réussi, appeler
pinDeliveredMessagelorsquedelivery.pinest demandé et pris en charge.
Correspondance des canaux
Discord :
- Transformer
presentationen composants v2 et en conteneurs Carbon dans des modules réservés à l’exécution. - Conserver les utilitaires de couleur d’accentuation dans des modules légers.
- Supprimer les importations de
DiscordUiContainerdu code du plan de contrôle du plugin de canal.
Slack :
- Transformer
presentationen Block Kit. - Supprimer l’entrée
blocksde l’agent et de la CLI.
Telegram :
- Afficher le texte, le contexte et les séparateurs sous forme de texte.
- Afficher les actions et la sélection sous forme de claviers intégrés lorsqu’ils sont configurés et autorisés pour la surface cible.
- Utiliser la représentation textuelle de repli lorsque les boutons intégrés sont désactivés.
- Déplacer l’épinglage des sujets ACP vers
delivery.pin.
Mattermost :
- Afficher les actions sous forme de boutons interactifs lorsqu’ils sont configurés.
- Afficher les autres blocs sous forme de représentation textuelle de repli.
MS Teams :
- Transformer
presentationen Adaptive Cards. - Conserver les actions manuelles d’épinglage, de désépinglage et de liste des éléments épinglés.
- Implémenter éventuellement
pinDeliveredMessagesi la prise en charge de Graph est fiable pour la conversation cible.
Feishu :
- Transformer
presentationen cartes interactives. - Conserver les actions manuelles d’épinglage, de désépinglage et de liste des éléments épinglés.
- Implémenter éventuellement
pinDeliveredMessagepour épingler les messages envoyés si le comportement de l’API est fiable.
LINE :
- Transformer
presentationen messages Flex ou en modèles de messages lorsque cela est possible. - Revenir au texte pour les blocs non pris en charge.
- Supprimer les charges utiles d’interface de LINE de
channelData.
Canaux simples ou limités :
- Convertir la présentation en texte avec un formatage prudent.
Étapes de refactorisation
- Réappliquer le correctif de version de Discord qui sépare
ui-colors.tsde l’interface reposant sur Carbon et supprimeDiscordUiContainerdeextensions/discord/src/channel.ts. - Ajouter
presentationetdeliveryàReplyPayload, à la normalisation des charges utiles sortantes, aux résumés d’envoi et aux charges utiles des hooks. - Ajouter le schéma
MessagePresentationet les utilitaires d’analyse dans un sous-chemin étroit du SDK ou de l’exécution. - Remplacer les capacités de message
buttons,cards,componentsetblockspar des capacités de présentation sémantiques. - Ajouter aux adaptateurs d’envoi sortant d’exécution des hooks pour le rendu de la présentation et l’épinglage après envoi.
- Remplacer la construction de composants intercontextes par
buildCrossContextPresentation. - Supprimer
src/infra/outbound/channel-adapters.tset retirerbuildCrossContextComponentsdes types des plugins de canal. - Modifier
maybeApplyCrossContextMarkerafin qu’il ajoutepresentationau lieu de paramètres natifs. - Mettre à jour les chemins d’envoi de la répartition des plugins afin qu’ils n’utilisent que la présentation sémantique et les métadonnées d’envoi.
- Supprimer les paramètres de charges utiles natives de l’agent et de la CLI :
components,blocks,buttonsetcard. - Supprimer les utilitaires du SDK qui créent des schémas natifs d’outils de messagerie et les remplacer par des utilitaires de schéma de présentation.
- Supprimer les enveloppes d’interface natives de
channelData; ne conserver que les métadonnées de transport jusqu’à l’examen de chaque champ restant. - Migrer les moteurs de rendu de Discord, Slack, Telegram, Mattermost, MS Teams, Feishu et LINE.
- Mettre à jour la documentation de la CLI de messagerie, des pages des canaux, du SDK de plugins et du guide pratique des capacités.
- Exécuter un profilage de la propagation des importations pour Discord et les points d’entrée des canaux concernés.
Les étapes 1 à 11 et 13 à 14 sont implémentées dans cette refactorisation pour l’agent partagé, la CLI, les capacités des plugins et les contrats des adaptateurs d’envoi sortant. L’étape 12 reste une passe de nettoyage interne plus approfondie concernant les enveloppes de transport channelData privées des fournisseurs. L’étape 15 reste une validation ultérieure si nous souhaitons obtenir des mesures quantifiées de propagation des importations au-delà des contrôles de types et des tests.
Tests
Ajouter ou mettre à jour :
- Les tests de normalisation de la présentation.
- Les tests de dégradation automatique de la présentation pour les blocs non pris en charge.
- Les tests des marqueurs intercontextes pour la répartition des plugins et les chemins d’envoi du cœur.
- Les tests matriciels du rendu des canaux pour Discord, Slack, Telegram, Mattermost, MS Teams, Feishu, LINE et la représentation textuelle de repli.
- Les tests du schéma des outils de messagerie prouvant que les champs natifs ont été supprimés.
- Les tests de la CLI prouvant que les options natives ont été supprimées.
- Le test de non-régression du chargement différé des importations du point d’entrée Discord couvrant Carbon.
- Les tests d’épinglage après envoi couvrant Telegram et le repli générique.
Questions ouvertes
delivery.pindoit-il être implémenté dès la première passe pour Discord, Slack, MS Teams et Feishu, ou uniquement pour Telegram dans un premier temps ?deliverydoit-il finalement intégrer des champs existants tels quereplyToId,replyToCurrent,silentetaudioAsVoice, ou rester centré sur les comportements postérieurs à l’envoi ?- La présentation doit-elle prendre directement en charge les images ou les références de fichiers, ou les médias doivent-ils rester séparés de la mise en page de l’interface pour le moment ?