Plugins
Presentazione dei messaggi
La presentazione dei messaggi è il contratto condiviso di OpenClaw per un'interfaccia chat in uscita ricca. Consente ad agenti, comandi CLI, flussi di approvazione e plugin di descrivere una sola volta l'intento del messaggio, mentre ogni plugin di canale esegue il rendering nella migliore forma nativa possibile.
Usa la presentazione per un'interfaccia messaggio portabile:
- sezioni di testo
- piccolo testo di contesto/piè di pagina
- divisori
- pulsanti
- menu di selezione
- titolo e tono della scheda
Non aggiungere al tool messaggio condiviso nuovi campi nativi del provider come Discord components, Slack
blocks, Telegram buttons, Teams card o Feishu card. Questi sono output del renderer di proprietà del plugin di canale.
Contratto
Gli autori di Plugin importano il contratto pubblico da:
MessagePresentation,
ReplyPayloadDelivery,
} from "openclaw/plugin-sdk/interactive-runtime";
Forma:
type MessagePresentation = {
title?: string;
tone?: "neutral" | "info" | "success" | "warning" | "danger";
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;
};
type ReplyPayloadDelivery = {
pin?:
| boolean
| {
enabled: boolean;
notify?: boolean;
required?: boolean;
};
};
Semantica dei pulsanti:
valueè un valore di azione dell'applicazione reinstradato tramite il percorso di interazione esistente del canale quando il canale supporta controlli cliccabili.urlè un pulsante link. Può esistere senzavalue.labelè obbligatorio e viene usato anche nel fallback testuale.styleè indicativo. I renderer dovrebbero mappare gli stili non supportati su un valore predefinito sicuro, non far fallire l'invio.
Semantica della selezione:
options[].valueè il valore dell'applicazione selezionato.placeholderè indicativo e può essere ignorato dai canali senza supporto nativo per la selezione.- Se un canale non supporta le selezioni, il testo di fallback elenca le etichette.
Esempi di produttori
Scheda semplice:
{
"title": "Deploy approval",
"tone": "warning",
"blocks": [
{ "type": "text", "text": "Canary is ready to promote." },
{ "type": "context", "text": "Build 1234, staging passed." },
{
"type": "buttons",
"buttons": [
{ "label": "Approve", "value": "deploy:approve", "style": "success" },
{ "label": "Decline", "value": "deploy:decline", "style": "danger" }
]
}
]
}
Pulsante link solo URL:
{
"blocks": [
{ "type": "text", "text": "Release notes are ready." },
{
"type": "buttons",
"buttons": [{ "label": "Open notes", "url": "https://example.com/release" }]
}
]
}
Menu di selezione:
{
"title": "Choose environment",
"blocks": [
{
"type": "select",
"placeholder": "Environment",
"options": [
{ "label": "Canary", "value": "env:canary" },
{ "label": "Production", "value": "env:prod" }
]
}
]
}
Invio da CLI:
openclaw message send --channel slack \
--target channel:C123 \
--message "Deploy approval" \
--presentation '{"title":"Deploy approval","tone":"warning","blocks":[{"type":"text","text":"Canary is ready."},{"type":"buttons","buttons":[{"label":"Approve","value":"deploy:approve","style":"success"},{"label":"Decline","value":"deploy:decline","style":"danger"}]}]}'
Consegna fissata:
openclaw message send --channel telegram \
--target -1001234567890 \
--message "Topic opened" \
--pin
Consegna fissata con JSON esplicito:
{
"pin": {
"enabled": true,
"notify": true,
"required": false
}
}
Contratto del renderer
I plugin di canale dichiarano il supporto al rendering sul proprio adattatore in uscita:
const adapter: ChannelOutboundAdapter = {
deliveryMode: "direct",
presentationCapabilities: {
supported: true,
buttons: true,
selects: true,
context: true,
divider: true,
},
deliveryCapabilities: {
pin: true,
},
renderPresentation({ payload, presentation, ctx }) {
return renderNativePayload(payload, presentation, ctx);
},
async pinDeliveredMessage({ target, messageId, pin }) {
await pinNativeMessage(target, messageId, { notify: pin.notify === true });
},
};
I campi di capability sono intenzionalmente semplici booleani. Descrivono cosa il renderer può rendere interattivo, non ogni limite della piattaforma nativa. I renderer restano responsabili dei limiti specifici della piattaforma, come numero massimo di pulsanti, numero di blocchi e dimensione della scheda.
Flusso di rendering core
Quando un ReplyPayload o un'azione messaggio include presentation, il core:
- Normalizza il payload di presentazione.
- Risolve l'adattatore in uscita del canale di destinazione.
- Legge
presentationCapabilities. - Chiama
renderPresentationquando l'adattatore può eseguire il rendering del payload. - Ripiega su testo prudente quando l'adattatore è assente o non può eseguire il rendering.
- Invia il payload risultante tramite il normale percorso di consegna del canale.
- Applica i metadati di consegna come
delivery.pindopo il primo messaggio inviato con successo.
Il core possiede il comportamento di fallback, così i produttori possono restare agnostici rispetto al canale. I plugin di canale possiedono rendering nativo e gestione delle interazioni.
Regole di degradazione
La presentazione deve essere sicura da inviare su canali limitati.
Il testo di fallback include:
titlecome prima riga- blocchi
textcome normali paragrafi - blocchi
contextcome righe di contesto compatte - blocchi
dividercome separatore visivo - etichette dei pulsanti, inclusi gli URL per i pulsanti link
- etichette delle opzioni di selezione
I controlli nativi non supportati dovrebbero degradare invece di far fallire l'intero invio. Esempi:
- Telegram con pulsanti inline disabilitati invia il fallback testuale.
- Un canale senza supporto alla selezione elenca le opzioni di selezione come testo.
- Un pulsante solo URL diventa un pulsante link nativo o una riga URL di fallback.
- Gli errori di fissaggio opzionale non fanno fallire il messaggio consegnato.
L'eccezione principale è delivery.pin.required: true; se il fissaggio è richiesto come
obbligatorio e il canale non può fissare il messaggio inviato, la consegna segnala un errore.
Mappatura provider
Renderer in bundle attuali:
| Canale | Target di rendering nativo | Note |
|---|---|---|
| Discord | Componenti e contenitori di componenti | Preserva channelData.discord.components legacy per i produttori esistenti di payload nativi del provider, ma i nuovi invii condivisi dovrebbero usare presentation. |
| Slack | Block Kit | Preserva channelData.slack.blocks legacy per i produttori esistenti di payload nativi del provider, ma i nuovi invii condivisi dovrebbero usare presentation. |
| Telegram | Testo più tastiere inline | Pulsanti/selezioni richiedono la capability dei pulsanti inline per la superficie di destinazione; altrimenti viene usato il fallback testuale. |
| Mattermost | Testo più proprietà interattive | Gli altri blocchi degradano a testo. |
| Microsoft Teams | Adaptive Cards | Il testo semplice message viene incluso con la scheda quando sono forniti entrambi. |
| Feishu | Schede interattive | L'intestazione della scheda può usare title; il corpo evita di duplicare quel titolo. |
| Canali semplici | Fallback testuale | I canali senza renderer ricevono comunque un output leggibile. |
La compatibilità dei payload nativi del provider è una facilitazione di transizione per i produttori di risposte esistenti. Non è un motivo per aggiungere nuovi campi nativi condivisi.
Presentazione rispetto a InteractiveReply
InteractiveReply è il vecchio sottoinsieme interno usato dagli helper di approvazione e interazione.
Supporta:
- testo
- pulsanti
- selezioni
MessagePresentation è il contratto canonico di invio condiviso. Aggiunge:
- titolo
- tono
- contesto
- divisore
- pulsanti solo URL
- metadati di consegna generici tramite
ReplyPayload.delivery
Usa gli helper da openclaw/plugin-sdk/interactive-runtime quando colleghi codice
più vecchio:
interactiveReplyToPresentation,
normalizeMessagePresentation,
presentationToInteractiveReply,
renderMessagePresentationFallbackText,
} from "openclaw/plugin-sdk/interactive-runtime";
Il nuovo codice dovrebbe accettare o produrre direttamente MessagePresentation.
Fissaggio della consegna
Il fissaggio è un comportamento di consegna, non di presentazione. Usa delivery.pin invece di
campi nativi del provider come channelData.telegram.pin.
Semantica:
pin: truefissa il primo messaggio consegnato con successo.pin.notifyha valore predefinitofalse.pin.requiredha valore predefinitofalse.- Gli errori di fissaggio opzionale degradano e lasciano intatto il messaggio inviato.
- Gli errori di fissaggio obbligatorio fanno fallire la consegna.
- I messaggi suddivisi in chunk fissano il primo chunk consegnato, non il chunk finale.
Le azioni messaggio manuali pin, unpin e pins esistono ancora per messaggi
esistenti dove il provider supporta tali operazioni.
Checklist per autori di Plugin
- Dichiara
presentationdadescribeMessageTool(...)quando il canale può eseguire il rendering o degradare in sicurezza la presentazione semantica. - Aggiungi
presentationCapabilitiesall'adattatore in uscita del runtime. - Implementa
renderPresentationnel codice runtime, non nel codice di configurazione del Plugin del piano di controllo. - Tieni le librerie UI native fuori dai percorsi critici di setup/catalogo.
- Preserva i limiti della piattaforma nel renderer e nei test.
- Aggiungi test di fallback per pulsanti non supportati, selezioni, pulsanti URL, duplicazione titolo/testo
e invii misti
messagepiùpresentation. - Aggiungi il supporto al fissaggio della consegna tramite
deliveryCapabilities.pinepinDeliveredMessagesolo quando il provider può fissare l'id del messaggio inviato. - Non esporre nuovi campi scheda/blocco/componente/pulsante nativi del provider tramite lo schema dell'azione messaggio condivisa.