Get started
Piano di refactoring della presentazione del canale
Stato
Implementato per l’agente condiviso, la CLI, le capacità dei plugin e le superfici di recapito in uscita:
ReplyPayload.presentationtrasporta l’interfaccia semantica dei messaggi.ReplyPayload.delivery.pintrasporta le richieste di fissaggio dei messaggi inviati.- Le azioni di messaggistica condivise espongono
presentation,deliveryepininvece dicomponents,blocks,buttonsocardnativi del provider. - Il core renderizza o degrada automaticamente la presentazione tramite le capacità in uscita dichiarate dal plugin.
- I renderer di Discord, Slack, Telegram, Mattermost, MS Teams e Feishu consumano il contratto generico.
- Il codice del control plane del canale Discord non importa più contenitori UI basati su Carbon.
La documentazione canonica ora si trova in Presentazione dei messaggi. Mantieni questo piano come contesto storico dell’implementazione; aggiorna la guida canonica per modifiche al contratto, al renderer o al comportamento di fallback.
Problema
L’interfaccia dei canali è attualmente divisa tra diverse superfici incompatibili:
- Il core possiede un hook di rendering cross-context modellato su Discord tramite
buildCrossContextComponents. channel.tsdi Discord può importare l’interfaccia nativa Carbon tramiteDiscordUiContainer, che porta dipendenze UI runtime nel control plane del plugin del canale.- L’agente e la CLI espongono vie di fuga per payload nativi come
componentsdi Discord,blocksdi Slack,buttonsdi Telegram o Mattermost ecarddi Teams o Feishu. ReplyPayload.channelDatatrasporta sia suggerimenti di trasporto sia envelope UI nativi.- Il modello generico
interactiveesiste, ma è più ristretto dei layout più ricchi già usati da Discord, Slack, Teams, Feishu, LINE, Telegram e Mattermost.
Questo rende il core consapevole delle forme UI native, indebolisce la pigrizia runtime dei plugin e offre agli agenti troppi modi specifici per provider per esprimere lo stesso intento del messaggio.
Obiettivi
- Il core decide la migliore presentazione semantica per un messaggio in base alle capacità dichiarate.
- Le estensioni dichiarano capacità e renderizzano la presentazione semantica in payload di trasporto nativi.
- La Web Control UI resta separata dall’interfaccia nativa della chat.
- I payload nativi dei canali non sono esposti tramite la superficie di messaggistica condivisa dell’agente o della CLI.
- Le funzionalità di presentazione non supportate degradano automaticamente alla migliore rappresentazione testuale.
- Il comportamento di recapito, come fissare un messaggio inviato, è metadato generico di recapito, non presentazione.
Non obiettivi
- Nessuno shim di compatibilità all’indietro per
buildCrossContextComponents. - Nessuna via di fuga nativa pubblica per
components,blocks,buttonsocard. - Nessuna importazione core di librerie UI native dei canali.
- Nessun seam SDK specifico per provider per i canali inclusi.
Modello target
Aggiungi un campo presentation posseduto dal core a ReplyPayload.
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 diventa un sottoinsieme di presentation durante la migrazione:
- Il blocco di testo
interactiveviene mappato apresentation.blocks[].type = "text". - Il blocco di pulsanti
interactiveviene mappato apresentation.blocks[].type = "buttons". - Il blocco di selezione
interactiveviene mappato apresentation.blocks[].type = "select".
Gli schemi esterni dell’agente e della CLI ora usano presentation; interactive resta un helper interno legacy di parsing/rendering per i produttori di risposte esistenti.
Metadati di recapito
Aggiungi un campo delivery posseduto dal core per il comportamento di invio che non è UI.
type ReplyPayloadDelivery = {
pin?:
| boolean
| {
enabled: boolean;
notify?: boolean;
required?: boolean;
};
};
Semantica:
delivery.pin = truesignifica fissare il primo messaggio recapitato con successo.notifyha valore predefinitofalse.requiredha valore predefinitofalse; i canali non supportati o il fissaggio non riuscito degradano automaticamente continuando il recapito.- Le azioni manuali di messaggistica
pin,unpinelist-pinsrestano per i messaggi esistenti.
L’attuale associazione del topic ACP di Telegram dovrebbe passare da channelData.telegram.pin = true a delivery.pin = true.
Contratto di capacità runtime
Aggiungi hook di rendering per presentazione e recapito all’adapter runtime in uscita, non al plugin del canale del control plane.
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>;
};
Comportamento del core:
- Risolvi il canale di destinazione e l’adapter runtime.
- Richiedi le capacità di presentazione.
- Degrada i blocchi non supportati prima del rendering.
- Chiama
renderPresentation. - Se non esiste alcun renderer, converti la presentazione in fallback testuale.
- Dopo un invio riuscito, chiama
pinDeliveredMessagequandodelivery.pinè richiesto e supportato.
Mappatura dei canali
Discord:
- Renderizza
presentationin componenti v2 e contenitori Carbon in moduli solo runtime. - Mantieni gli helper dei colori di accento in moduli leggeri.
- Rimuovi le importazioni di
DiscordUiContainerdal codice del control plane del plugin del canale.
Slack:
- Renderizza
presentationin Block Kit. - Rimuovi l’input
blocksdi agente e CLI.
Telegram:
- Renderizza testo, contesto e divisori come testo.
- Renderizza azioni e selezione come tastiere inline quando configurato e consentito per la superficie di destinazione.
- Usa il fallback testuale quando i pulsanti inline sono disabilitati.
- Sposta il fissaggio del topic ACP in
delivery.pin.
Mattermost:
- Renderizza le azioni come pulsanti interattivi quando configurato.
- Renderizza gli altri blocchi come fallback testuale.
MS Teams:
- Renderizza
presentationin Adaptive Cards. - Mantieni le azioni manuali pin/unpin/list-pins.
- Implementa opzionalmente
pinDeliveredMessagese il supporto Graph è affidabile per la conversazione di destinazione.
Feishu:
- Renderizza
presentationin schede interattive. - Mantieni le azioni manuali pin/unpin/list-pins.
- Implementa opzionalmente
pinDeliveredMessageper il fissaggio dei messaggi inviati se il comportamento dell’API è affidabile.
LINE:
- Renderizza
presentationin messaggi Flex o template dove possibile. - Ripiega sul testo per i blocchi non supportati.
- Rimuovi i payload UI di LINE da
channelData.
Canali semplici o limitati:
- Converti la presentazione in testo con formattazione conservativa.
Passaggi di refactor
- Riapplica la correzione di rilascio Discord che separa
ui-colors.tsdall’interfaccia basata su Carbon e rimuoveDiscordUiContainerdaextensions/discord/src/channel.ts. - Aggiungi
presentationedeliveryaReplyPayload, alla normalizzazione dei payload in uscita, ai riepiloghi di recapito e ai payload degli hook. - Aggiungi lo schema
MessagePresentatione gli helper di parsing in un sotto-percorso SDK/runtime ristretto. - Sostituisci le capacità dei messaggi
buttons,cards,componentseblockscon capacità di presentazione semantica. - Aggiungi hook dell’adapter runtime in uscita per rendering della presentazione e fissaggio del recapito.
- Sostituisci la costruzione dei componenti cross-context con
buildCrossContextPresentation. - Elimina
src/infra/outbound/channel-adapters.tse rimuovibuildCrossContextComponentsdai tipi dei plugin dei canali. - Modifica
maybeApplyCrossContextMarkerper allegarepresentationinvece dei parametri nativi. - Aggiorna i percorsi di invio di plugin-dispatch per consumare solo presentazione semantica e metadati di recapito.
- Rimuovi i parametri di payload nativi di agente e CLI:
components,blocks,buttonsecard. - Rimuovi gli helper SDK che creano schemi nativi degli strumenti di messaggistica, sostituendoli con helper dello schema di presentazione.
- Rimuovi envelope UI/nativi da
channelData; mantieni solo i metadati di trasporto finché ogni campo rimanente non viene revisionato. - Migra i renderer di Discord, Slack, Telegram, Mattermost, MS Teams, Feishu e LINE.
- Aggiorna la documentazione per la CLI dei messaggi, le pagine dei canali, l’SDK dei plugin e il ricettario delle capacità.
- Esegui la profilazione del fanout delle importazioni per Discord e gli entrypoint dei canali interessati.
I passaggi 1-11 e 13-14 sono implementati in questo refactor per i contratti dell’agente condiviso, della CLI, delle capacità dei plugin e degli adapter in uscita. Il passaggio 12 resta un intervento di pulizia interna più profondo per gli envelope di trasporto channelData privati dei provider. Il passaggio 15 resta una validazione di follow-up se vogliamo numeri quantificati sul fanout delle importazioni oltre al gate di tipi/test.
Test
Aggiungi o aggiorna:
- Test di normalizzazione della presentazione.
- Test di degradazione automatica della presentazione per blocchi non supportati.
- Test del marcatore cross-context per plugin dispatch e percorsi di recapito core.
- Test della matrice di rendering dei canali per Discord, Slack, Telegram, Mattermost, MS Teams, Feishu, LINE e fallback testuale.
- Test dello schema degli strumenti di messaggistica che dimostrino la rimozione dei campi nativi.
- Test della CLI che dimostrino la rimozione dei flag nativi.
- Regressione sulla pigrizia delle importazioni dell’entrypoint Discord relativa a Carbon.
- Test di fissaggio del recapito per Telegram e fallback generico.
Questioni aperte
delivery.pindovrebbe essere implementato per Discord, Slack, MS Teams e Feishu nel primo passaggio, o inizialmente solo per Telegram?deliverydovrebbe infine assorbire campi esistenti comereplyToId,replyToCurrent,silenteaudioAsVoice, o restare focalizzato sui comportamenti post-invio?- La presentazione dovrebbe supportare direttamente immagini o riferimenti a file, oppure per ora i media dovrebbero restare separati dal layout UI?