Creazione di Plugin di canale
Questa guida illustra come creare un plugin di canale che collega OpenClaw a una piattaforma di messaggistica. Alla fine avrai un canale funzionante con sicurezza DM, pairing, threading delle risposte e messaggistica in uscita.Se non hai mai creato prima alcun plugin OpenClaw, leggi prima
Getting Started per la struttura di base del
pacchetto e l’impostazione del manifest.
Come funzionano i plugin di canale
I plugin di canale non hanno bisogno di strumenti propri per inviare/modificare/reagire. OpenClaw mantiene in core un unico strumentomessage condiviso. Il tuo plugin gestisce:
- Config — risoluzione dell’account e procedura guidata di configurazione
- Security — criteri DM e allowlist
- Pairing — flusso di approvazione DM
- Session grammar — come gli id di conversazione specifici del provider vengono mappati alle chat di base, agli id thread e ai fallback padre
- Outbound — invio di testo, media e sondaggi alla piattaforma
- Threading — come vengono organizzate le risposte in thread
- Heartbeat typing — segnali opzionali di digitazione/occupato per i target di consegna heartbeat
:thread: e il dispatch.
Se il tuo canale supporta indicatori di digitazione al di fuori delle risposte in ingresso, esponi
heartbeat.sendTyping(...) nel plugin di canale. Il core lo richiama con il
target di consegna heartbeat risolto prima che inizi l’esecuzione del modello heartbeat e
usa il ciclo di vita condiviso di keepalive/cleanup della digitazione. Aggiungi heartbeat.clearTyping(...)
quando la piattaforma richiede un segnale esplicito di arresto.
Se il tuo canale aggiunge parametri dello strumento message che trasportano sorgenti multimediali, esponi quei
nomi di parametro tramite describeMessageTool(...).mediaSourceParams. Il core usa
questo elenco esplicito per la normalizzazione dei percorsi sandbox e per i criteri di accesso ai media in uscita,
così i plugin non hanno bisogno di casi speciali nel core condiviso per parametri specifici del provider
come avatar, allegati o immagini di copertina.
Preferisci restituire una mappa indicizzata per azione come
{ "set-profile": ["avatarUrl", "avatarPath"] } in modo che azioni non correlate non
ereditino gli argomenti media di un’altra azione. Un array piatto continua a funzionare per parametri
che sono intenzionalmente condivisi tra tutte le azioni esposte.
Se la tua piattaforma memorizza ambito aggiuntivo negli id di conversazione, mantieni quel parsing
nel plugin con messaging.resolveSessionConversation(...). Questo è l’hook canonico
per mappare rawId all’id di conversazione di base, all’eventuale id thread,
a baseConversationId esplicito e a qualsiasi parentConversationCandidates.
Quando restituisci parentConversationCandidates, mantienili ordinati dal
padre più specifico a quello più ampio/conversazione di base.
I plugin bundled che hanno bisogno dello stesso parsing prima che il registro dei canali venga avviato
possono anche esporre un file session-key-api.ts di primo livello con una
esportazione resolveSessionConversation(...) corrispondente. Il core usa questa superficie
sicura per il bootstrap solo quando il registro runtime dei plugin non è ancora disponibile.
messaging.resolveParentConversationCandidates(...) rimane disponibile come
fallback di compatibilità legacy quando un plugin ha bisogno solo di fallback padre
in aggiunta all’id generico/raw. Se entrambi gli hook esistono, il core usa prima
resolveSessionConversation(...).parentConversationCandidates e ricorre a
resolveParentConversationCandidates(...) solo quando l’hook canonico
li omette.
Approvazioni e capacità del canale
La maggior parte dei plugin di canale non ha bisogno di codice specifico per le approvazioni.- Il core gestisce
/approvenella stessa chat, i payload dei pulsanti di approvazione condivisi e la consegna di fallback generica. - Preferisci un unico oggetto
approvalCapabilitynel plugin di canale quando il canale necessita di comportamento specifico per le approvazioni. ChannelPlugin.approvalsè rimosso. Inserisci i fatti di consegna/rendering/auth delle approvazioni inapprovalCapability.plugin.authè solo per login/logout; il core non legge più da quell’oggetto gli hook auth delle approvazioni.approvalCapability.authorizeActorActioneapprovalCapability.getActionAvailabilityStatesono la seam canonica per l’auth delle approvazioni.- Usa
approvalCapability.getActionAvailabilityStateper la disponibilità dell’auth di approvazione nella stessa chat. - Se il tuo canale espone approvazioni exec native, usa
approvalCapability.getExecInitiatingSurfaceStateper lo stato della superficie iniziale/client nativo quando differisce dall’auth di approvazione nella stessa chat. Il core usa questo hook specifico per exec per distinguereenableddadisabled, decidere se il canale iniziale supporta approvazioni exec native e includere il canale nelle indicazioni di fallback del client nativo.createApproverRestrictedNativeApprovalCapability(...)lo compila per il caso comune. - Usa
outbound.shouldSuppressLocalPayloadPromptooutbound.beforeDeliverPayloadper comportamenti del ciclo di vita del payload specifici del canale, come nascondere prompt locali di approvazione duplicati o inviare indicatori di digitazione prima della consegna. - Usa
approvalCapability.deliverysolo per il routing nativo delle approvazioni o la soppressione del fallback. - Usa
approvalCapability.nativeRuntimeper i fatti di approvazione nativa gestiti dal canale. Mantienilo lazy negli entrypoint caldi del canale concreateLazyChannelApprovalNativeRuntimeAdapter(...), che può importare il tuo modulo runtime on demand pur permettendo al core di assemblare il ciclo di vita dell’approvazione. - Usa
approvalCapability.rendersolo quando un canale ha davvero bisogno di payload di approvazione personalizzati invece del renderer condiviso. - Usa
approvalCapability.describeExecApprovalSetupquando il canale vuole che la risposta del percorso disabilitato spieghi le esatte manopole di configurazione necessarie per abilitare le approvazioni exec native. L’hook riceve{ channel, channelLabel, accountId }; i canali con account nominati devono renderizzare percorsi con ambito account comechannels.<channel>.accounts.<id>.execApprovals.*invece dei default di primo livello. - Se un canale può dedurre identità DM stabili simili a proprietari dalla configurazione esistente, usa
createResolvedApproverActionAuthAdapterdaopenclaw/plugin-sdk/approval-runtimeper limitare/approvenella stessa chat senza aggiungere logica core specifica per le approvazioni. - Se un canale ha bisogno della consegna nativa delle approvazioni, mantieni il codice del canale focalizzato sulla normalizzazione del target più i fatti di trasporto/presentazione. Usa
createChannelExecApprovalProfile,createChannelNativeOriginTargetResolver,createChannelApproverDmTargetResolverecreateApproverRestrictedNativeApprovalCapabilitydaopenclaw/plugin-sdk/approval-runtime. Inserisci i fatti specifici del canale dietroapprovalCapability.nativeRuntime, idealmente tramitecreateChannelApprovalNativeRuntimeAdapter(...)ocreateLazyChannelApprovalNativeRuntimeAdapter(...), così il core può assemblare l’handler e gestire filtro delle richieste, routing, deduplica, scadenza, sottoscrizione Gateway e avvisi di instradamento altrove.nativeRuntimeè suddiviso in alcune seam più piccole: availability— se l’account è configurato e se una richiesta deve essere gestitapresentation— mappa il view model di approvazione condiviso in payload nativi pending/resolved/expired o azioni finalitransport— prepara i target più l’invio/aggiornamento/eliminazione dei messaggi di approvazione nativiinteractions— hook opzionali bind/unbind/clear-action per pulsanti o reazioni nativeobserve— hook opzionali per la diagnostica di consegna- Se il canale ha bisogno di oggetti gestiti dal runtime come un client, token, app Bolt o ricevitore Webhook, registrali tramite
openclaw/plugin-sdk/channel-runtime-context. Il registro generico runtime-context permette al core di avviare handler guidati dalle capacità a partire dallo stato di avvio del canale senza aggiungere codice wrapper specifico per le approvazioni. - Ricorri a
createChannelApprovalHandlerocreateChannelNativeApprovalRuntimedi livello più basso solo quando la seam guidata dalle capacità non è ancora abbastanza espressiva. - I canali di approvazione nativa devono instradare sia
accountIdsiaapprovalKindattraverso quegli helper.accountIdmantiene l’ambito dei criteri di approvazione multi-account sul corretto account bot, eapprovalKindmantiene disponibile per il canale il comportamento exec rispetto a quello di approvazione plugin senza rami hardcoded nel core. - Il core ora gestisce anche gli avvisi di reinstradamento delle approvazioni. I plugin di canale non devono inviare i propri messaggi di follow-up “l’approvazione è andata ai DM / a un altro canale” da
createChannelNativeApprovalRuntime; invece, esponi un routing accurato tra origine e DM dell’approvatore tramite gli helper condivisi di capability di approvazione e lascia che il core aggreghi le consegne effettive prima di pubblicare un eventuale avviso nella chat iniziale. - Mantieni il tipo di id di approvazione consegnato end-to-end. I client nativi non devono dedurre o riscrivere il routing dell’approvazione exec rispetto a plugin in base allo stato locale del canale.
- Diversi tipi di approvazione possono esporre intenzionalmente superfici native differenti.
Esempi bundled attuali:
- Slack mantiene disponibile il routing di approvazione nativa sia per gli id exec sia per quelli plugin.
- Matrix mantiene lo stesso routing DM/canale nativo e la stessa UX a reazioni per le approvazioni exec e plugin, pur consentendo comunque che l’auth differisca in base al tipo di approvazione.
createApproverRestrictedNativeApprovalAdapteresiste ancora come wrapper di compatibilità, ma il nuovo codice deve preferire il builder di capability ed esporreapprovalCapabilitynel plugin.
openclaw/plugin-sdk/approval-auth-runtimeopenclaw/plugin-sdk/approval-client-runtimeopenclaw/plugin-sdk/approval-delivery-runtimeopenclaw/plugin-sdk/approval-gateway-runtimeopenclaw/plugin-sdk/approval-handler-adapter-runtimeopenclaw/plugin-sdk/approval-handler-runtimeopenclaw/plugin-sdk/approval-native-runtimeopenclaw/plugin-sdk/approval-reply-runtimeopenclaw/plugin-sdk/channel-runtime-context
openclaw/plugin-sdk/setup-runtime,
openclaw/plugin-sdk/setup-adapter-runtime,
openclaw/plugin-sdk/reply-runtime,
openclaw/plugin-sdk/reply-dispatch-runtime,
openclaw/plugin-sdk/reply-reference e
openclaw/plugin-sdk/reply-chunking quando non ti serve la superficie umbrella
più ampia.
Per la setup in particolare:
openclaw/plugin-sdk/setup-runtimecopre gli helper di setup sicuri per il runtime: adattatori di patch setup sicuri all’import (createPatchedAccountSetupAdapter,createEnvPatchedAccountSetupAdapter,createSetupInputPresenceValidator), output delle note di lookup,promptResolvedAllowFrom,splitSetupEntriese i builder del proxy di setup delegatoopenclaw/plugin-sdk/setup-adapter-runtimeè la seam adattatore stretta consapevole dell’env percreateEnvPatchedAccountSetupAdapteropenclaw/plugin-sdk/channel-setupcopre i builder setup a installazione opzionale più alcune primitive sicure per il setup:createOptionalChannelSetupSurface,createOptionalChannelSetupAdapter,
channelEnvVars. Mantieni envVars del runtime del canale o costanti locali
solo per il testo rivolto agli operatori.
Se il tuo canale può comparire in status, channels list, channels status o
nelle scansioni SecretRef prima che il runtime del plugin si avvii, aggiungi openclaw.setupEntry in
package.json. Quell’entrypoint deve essere sicuro da importare in percorsi di comando in sola lettura
e deve restituire i metadati del canale, l’adattatore config sicuro per il setup, l’adattatore di stato
e i metadati del target secret del canale necessari per quei riepiloghi. Non avviare
client, listener o runtime di trasporto dall’entry di setup.
createOptionalChannelSetupWizard, DEFAULT_ACCOUNT_ID,
createTopLevelChannelDmPolicy, setSetupChannelEnabled e
splitSetupEntries
- usa la seam più ampia
openclaw/plugin-sdk/setupsolo quando hai bisogno anche degli helper condivisi più pesanti di setup/config comemoveSingleAccountChannelSectionToDefaultAccount(...)
createOptionalChannelSetupSurface(...). L’adattatore/procedura guidata generati
falliscono in modo chiuso sulle scritture di configurazione e sulla finalizzazione, e riusano
lo stesso messaggio di installazione richiesta in validazione, finalize e testo con link alla documentazione.
Per altri percorsi caldi del canale, preferisci gli helper stretti rispetto alle
superfici legacy più ampie:
openclaw/plugin-sdk/account-core,openclaw/plugin-sdk/account-id,openclaw/plugin-sdk/account-resolutioneopenclaw/plugin-sdk/account-helpersper la configurazione multi-account e il fallback dell’account predefinitoopenclaw/plugin-sdk/inbound-envelopeeopenclaw/plugin-sdk/inbound-reply-dispatchper il wiring di route/envelope in ingresso e record-and-dispatchopenclaw/plugin-sdk/messaging-targetsper parsing/matching dei targetopenclaw/plugin-sdk/outbound-mediaeopenclaw/plugin-sdk/outbound-runtimeper il caricamento dei media più le delegate di identità/invio in uscita e la pianificazione del payloadbuildThreadAwareOutboundSessionRoute(...)daopenclaw/plugin-sdk/channel-corequando una route in uscita deve preservare unreplyToId/threadIdesplicito o recuperare la sessione corrente:thread:dopo che la chiave di sessione di base continua comunque a corrispondere. I plugin provider possono sovrascrivere precedenza, comportamento del suffisso e normalizzazione dell’id thread quando la loro piattaforma ha semantiche native di consegna nei thread.openclaw/plugin-sdk/thread-bindings-runtimeper il ciclo di vita dei thread-binding e la registrazione degli adattatoriopenclaw/plugin-sdk/agent-media-payloadsolo quando è ancora richiesto un layout legacy dei campi del payload agent/mediaopenclaw/plugin-sdk/telegram-command-configper la normalizzazione dei comandi personalizzati di Telegram, la validazione di duplicati/conflitti e un contratto di configurazione dei comandi stabile nel fallback
Criteri delle menzioni in ingresso
Mantieni la gestione delle menzioni in ingresso suddivisa in due livelli:- raccolta delle evidenze gestita dal plugin
- valutazione dei criteri condivisa
openclaw/plugin-sdk/channel-mention-gating per le decisioni sui criteri delle menzioni.
Usa openclaw/plugin-sdk/channel-inbound solo quando hai bisogno del barrel helper
più ampio per l’inbound.
Adatto alla logica locale del plugin:
- rilevamento della risposta al bot
- rilevamento della citazione del bot
- controlli di partecipazione al thread
- esclusioni di messaggi di servizio/sistema
- cache native della piattaforma necessarie per dimostrare la partecipazione del bot
requireMention- risultato di menzione esplicita
- allowlist di menzioni implicite
- bypass dei comandi
- decisione finale di skip
- Calcola i fatti locali sulle menzioni.
- Passa questi fatti a
resolveInboundMentionDecision({ facts, policy }). - Usa
decision.effectiveWasMentioned,decision.shouldBypassMentionedecision.shouldSkipnel tuo gate inbound.
api.runtime.channel.mentions espone gli stessi helper condivisi per le menzioni per
i plugin di canale bundled che già dipendono dall’iniezione runtime:
buildMentionRegexesmatchesMentionPatternsmatchesMentionWithExplicitimplicitMentionKindWhenresolveInboundMentionDecision
implicitMentionKindWhen e
resolveInboundMentionDecision, importa da
openclaw/plugin-sdk/channel-mention-gating per evitare di caricare helper runtime
inbound non correlati.
I vecchi helper resolveMentionGating* restano in
openclaw/plugin-sdk/channel-inbound solo come esportazioni di compatibilità. Il nuovo codice
deve usare resolveInboundMentionDecision({ facts, policy }).
Guida passo passo
Pacchetto e manifest
Crea i file standard del plugin. Il campo
channel in package.json è
ciò che rende questo un plugin di canale. Per la superficie completa dei metadati del pacchetto,
vedi Plugin Setup and Config:Crea l'oggetto plugin di canale
L’interfaccia
ChannelPlugin ha molte superfici adattatore opzionali. Inizia con
il minimo — id e setup — e aggiungi adattatori secondo necessità.Crea src/channel.ts:src/channel.ts
Cosa fa per te createChatChannelPlugin
Cosa fa per te createChatChannelPlugin
Invece di implementare manualmente interfacce adattatore di basso livello, passi
opzioni dichiarative e il builder le compone:
Puoi anche passare oggetti adattatore grezzi invece delle opzioni dichiarative
se hai bisogno del pieno controllo.
| Option | Cosa collega |
|---|---|
security.dm | Resolver di sicurezza DM con ambito dai campi di configurazione |
pairing.text | Flusso di pairing DM basato su testo con scambio di codice |
threading | Resolver della modalità reply-to (fissa, con ambito account o personalizzata) |
outbound.attachedResults | Funzioni di invio che restituiscono metadati del risultato (ID messaggio) |
Collega l'entry point
Crea Inserisci i descrittori CLI gestiti dal canale in
index.ts:index.ts
registerCliMetadata(...) così OpenClaw
può mostrarli nell’help root senza attivare il runtime completo del canale,
mentre i normali caricamenti completi continuano a rilevare gli stessi descrittori per la vera registrazione
dei comandi. Mantieni registerFull(...) per il lavoro solo runtime.
Se registerFull(...) registra metodi RPC Gateway, usa un
prefisso specifico del plugin. I namespace amministrativi del core (config.*,
exec.approvals.*, wizard.*, update.*) restano riservati e si
risolvono sempre in operator.admin.
defineChannelPluginEntry gestisce automaticamente la divisione delle modalità di registrazione. Vedi
Entry Points per tutte le
opzioni.Aggiungi un'entry di setup
Crea OpenClaw carica questa entry invece dell’entry completa quando il canale è disabilitato
o non configurato. Evita di caricare codice runtime pesante durante i flussi di setup.
Vedi Setup and Config per i dettagli.I canali workspace bundled che separano le esportazioni sicure per il setup in moduli
sidecar possono usare
setup-entry.ts per un caricamento leggero durante l’onboarding:setup-entry.ts
defineBundledChannelSetupEntry(...) da
openclaw/plugin-sdk/channel-entry-contract quando hanno bisogno anche di un
setter runtime esplicito al tempo di setup.Gestisci i messaggi in ingresso
Il tuo plugin deve ricevere messaggi dalla piattaforma e inoltrarli a
OpenClaw. Il pattern tipico è un Webhook che verifica la richiesta e
la invia tramite l’handler inbound del tuo canale:
La gestione dei messaggi in ingresso è specifica del canale. Ogni plugin di canale gestisce
la propria pipeline inbound. Guarda i plugin di canale bundled
(per esempio il pacchetto plugin di Microsoft Teams o Google Chat) per pattern reali.
Test
Scrivi test colocati in Per gli helper di test condivisi, vedi Testing.
src/channel.test.ts:src/channel.test.ts
Struttura dei file
Argomenti avanzati
Opzioni di threading
Modalità di risposta fisse, con ambito account o personalizzate
Integrazione dello strumento message
describeMessageTool e discovery delle azioni
Risoluzione del target
inferTargetChatType, looksLikeId, resolveTarget
Helper runtime
TTS, STT, media, subagent tramite api.runtime
Alcune seam helper bundled esistono ancora per la manutenzione dei plugin bundled e
la compatibilità. Non sono il pattern consigliato per i nuovi plugin di canale;
preferisci i sottopercorsi generici channel/setup/reply/runtime dalla superficie SDK
comune a meno che tu non stia mantenendo direttamente quella famiglia di plugin bundled.
Passi successivi
- Provider Plugins — se il tuo plugin fornisce anche modelli
- SDK Overview — riferimento completo per gli import subpath
- SDK Testing — utility di test e test di contratto
- Plugin Manifest — schema completo del manifest