Interni dei plugin
Questo è il riferimento di architettura approfondito. Per guide pratiche, vedi:
- Installa e usa i plugin — guida per l’utente
- Guida introduttiva — primo tutorial sui plugin
- Plugin di canale — crea un canale di messaggistica
- Plugin provider — crea un provider di modelli
- Panoramica dell’SDK — mappa degli import e API di registrazione
Modello pubblico delle capacità
Le capacità sono il modello pubblico dei plugin nativi all’interno di OpenClaw. Ogni plugin nativo OpenClaw si registra in uno o più tipi di capacità:| Capacità | Metodo di registrazione | Plugin di esempio |
|---|---|---|
| Inferenza testuale | api.registerProvider(...) | openai, anthropic |
| Backend di inferenza CLI | api.registerCliBackend(...) | openai, anthropic |
| Voce | api.registerSpeechProvider(...) | elevenlabs, microsoft |
| Trascrizione in tempo reale | api.registerRealtimeTranscriptionProvider(...) | openai |
| Voce in tempo reale | api.registerRealtimeVoiceProvider(...) | openai |
| Comprensione dei media | api.registerMediaUnderstandingProvider(...) | openai, google |
| Generazione di immagini | api.registerImageGenerationProvider(...) | openai, google, fal, minimax |
| Generazione musicale | api.registerMusicGenerationProvider(...) | google, minimax |
| Generazione video | api.registerVideoGenerationProvider(...) | qwen |
| Recupero web | api.registerWebFetchProvider(...) | firecrawl |
| Ricerca web | api.registerWebSearchProvider(...) | google |
| Canale / messaggistica | api.registerChannel(...) | msteams, matrix |
Posizione sulla compatibilità esterna
Il modello delle capacità è integrato nel core ed è usato oggi dai plugin bundled/nativi, ma la compatibilità dei plugin esterni richiede ancora un criterio più rigoroso di “è esportato, quindi è congelato”. Indicazioni attuali:- plugin esterni esistenti: mantenere funzionanti le integrazioni basate su hook; trattare questo come riferimento di compatibilità
- nuovi plugin bundled/nativi: preferire la registrazione esplicita delle capacità invece di accessi specifici del vendor o nuovi design solo hook
- plugin esterni che adottano la registrazione delle capacità: consentito, ma trattare le superfici helper specifiche per capacità come in evoluzione, a meno che la documentazione non indichi esplicitamente che un contratto è stabile
- le API di registrazione delle capacità sono la direzione prevista
- gli hook legacy restano il percorso più sicuro per evitare rotture nei plugin esterni durante la transizione
- i sottopercorsi helper esportati non sono tutti equivalenti; preferisci il contratto ristretto documentato, non esportazioni helper incidentali
Forme dei plugin
OpenClaw classifica ogni plugin caricato in una forma in base al suo reale comportamento di registrazione (non solo ai metadati statici):- plain-capability — registra esattamente un tipo di capacità (per esempio un
plugin solo provider come
mistral) - hybrid-capability — registra più tipi di capacità (per esempio
openaipossiede inferenza testuale, voce, comprensione dei media e generazione di immagini) - hook-only — registra solo hook (tipizzati o personalizzati), nessuna capacità, strumento, comando o servizio
- non-capability — registra strumenti, comandi, servizi o route ma nessuna capacità
openclaw plugins inspect <id> per vedere la forma di un plugin e la
suddivisione delle capacità. Vedi Riferimento CLI per i dettagli.
Hook legacy
L’hookbefore_agent_start resta supportato come percorso di compatibilità per
i plugin solo hook. Plugin legacy reali continuano a dipenderne.
Direzione:
- mantenerlo funzionante
- documentarlo come legacy
- preferire
before_model_resolveper il lavoro di override di modello/provider - preferire
before_prompt_buildper il lavoro di modifica del prompt - rimuoverlo solo dopo che l’uso reale sarà diminuito e la copertura dei fixture avrà dimostrato la sicurezza della migrazione
Segnali di compatibilità
Quando eseguiopenclaw doctor o openclaw plugins inspect <id>, potresti vedere
una di queste etichette:
| Segnale | Significato |
|---|---|
| config valid | La configurazione viene analizzata correttamente e i plugin vengono risolti |
| compatibility advisory | Il plugin usa un pattern supportato ma più vecchio (ad es. hook-only) |
| legacy warning | Il plugin usa before_agent_start, che è deprecato |
| hard error | La configurazione non è valida o il plugin non è riuscito a caricarsi |
hook-only né before_agent_start romperanno il tuo plugin oggi —
hook-only è un avviso, e before_agent_start genera solo un warning. Questi
segnali compaiono anche in openclaw status --all e openclaw plugins doctor.
Panoramica dell’architettura
Il sistema di plugin di OpenClaw ha quattro livelli:- Manifest + individuazione
OpenClaw trova i plugin candidati dai percorsi configurati, dalle radici del workspace,
dalle radici globali delle estensioni e dalle estensioni bundled. L’individuazione legge prima
i manifest nativi
openclaw.plugin.jsone i manifest bundle supportati. - Abilitazione + validazione Il core decide se un plugin individuato è abilitato, disabilitato, bloccato o selezionato per uno slot esclusivo come la memoria.
- Caricamento di runtime I plugin nativi OpenClaw vengono caricati in-process tramite jiti e registrano capacità in un registro centrale. I bundle compatibili vengono normalizzati in record del registro senza importare il codice di runtime.
- Consumo della superficie Il resto di OpenClaw legge il registro per esporre strumenti, canali, configurazione dei provider, hook, route HTTP, comandi CLI e servizi.
- i metadati in fase di parsing provengono da
registerCli(..., { descriptors: [...] }) - il vero modulo CLI del plugin può restare lazy e registrarsi alla prima invocazione
- l’individuazione + la validazione della configurazione dovrebbero funzionare da metadati di manifest/schema senza eseguire il codice del plugin
- il comportamento di runtime nativo proviene dal percorso
register(api)del modulo plugin
Plugin di canale e strumento condiviso dei messaggi
I plugin di canale non devono registrare uno strumento separato di invio/modifica/reazione per le normali azioni di chat. OpenClaw mantiene un unico strumentomessage condiviso nel core, e
i plugin di canale possiedono il rilevamento e l’esecuzione specifici del canale dietro di esso.
Il confine attuale è:
- il core possiede l’host dello strumento
messagecondiviso, il wiring del prompt, la gestione di sessione/thread e il dispatch dell’esecuzione - i plugin di canale possiedono il rilevamento di azioni con ambito, il rilevamento delle capacità e qualsiasi frammento di schema specifico del canale
- i plugin di canale possiedono la grammatica di conversazione della sessione specifica del provider, come il modo in cui gli ID conversazione codificano gli ID thread o ereditano dalle conversazioni padre
- i plugin di canale eseguono l’azione finale tramite il loro adattatore di azione
ChannelMessageActionAdapter.describeMessageTool(...). Questa chiamata di individuazione unificata
consente a un plugin di restituire insieme le sue azioni visibili, capacità e contributi di schema
così che questi elementi non divergano tra loro.
Il core passa l’ambito di runtime a questo passaggio di individuazione. I campi importanti includono:
accountIdcurrentChannelIdcurrentThreadTscurrentMessageIdsessionKeysessionIdagentIdrequesterSenderIdinbound attendibile
message del core.
Per questo motivo le modifiche di routing dell’embedded runner restano lavoro del plugin: il runner è
responsabile dell’inoltro dell’identità corrente di chat/sessione al confine di individuazione del plugin
affinché lo strumento message condiviso esponga la superficie posseduta dal canale corretta
per il turno corrente.
Per gli helper di esecuzione posseduti dal canale, i plugin bundled dovrebbero mantenere il runtime di esecuzione
all’interno dei propri moduli di estensione. Il core non possiede più i runtime di azione dei messaggi per Discord,
Slack, Telegram o WhatsApp sotto src/agents/tools.
Non pubblichiamo sottopercorsi separati plugin-sdk/*-action-runtime, e i plugin bundled
dovrebbero importare direttamente il proprio codice di runtime locale dai
loro moduli posseduti dall’estensione.
Lo stesso confine si applica in generale alle seam SDK con nome del provider: il core non dovrebbe
importare barrel di convenienza specifici del canale per estensioni come Slack, Discord, Signal,
WhatsApp o simili. Se il core ha bisogno di un comportamento, o consuma il barrel api.ts / runtime-api.ts
del plugin bundled stesso, oppure promuove la necessità in una capacità generica ristretta nell’SDK condiviso.
Per i sondaggi in particolare, ci sono due percorsi di esecuzione:
outbound.sendPollè la base condivisa per i canali che si adattano al modello comune di sondaggioactions.handleAction("poll")è il percorso preferito per la semantica dei sondaggi specifica del canale o per parametri di sondaggio aggiuntivi
Modello di proprietà delle capacità
OpenClaw tratta un plugin nativo come confine di proprietà per un’azienda o una funzionalità, non come un contenitore di integrazioni non correlate. Questo significa:- un plugin aziendale dovrebbe di solito possedere tutte le superfici OpenClaw-facing di quell’azienda
- un plugin di funzionalità dovrebbe di solito possedere l’intera superficie della funzionalità che introduce
- i canali dovrebbero consumare capacità condivise del core invece di reimplementare in modo ad hoc il comportamento del provider
- il plugin bundled
openaipossiede il comportamento del provider di modelli OpenAI e il comportamento OpenAI per voce + voce in tempo reale + comprensione dei media + generazione di immagini - il plugin bundled
elevenlabspossiede il comportamento vocale ElevenLabs - il plugin bundled
microsoftpossiede il comportamento vocale Microsoft - il plugin bundled
googlepossiede il comportamento del provider di modelli Google più il comportamento Google per comprensione dei media + generazione di immagini + ricerca web - il plugin bundled
firecrawlpossiede il comportamento Firecrawl di recupero web - i plugin bundled
minimax,mistral,moonshotezaipossiedono i loro backend di comprensione dei media - il plugin bundled
qwenpossiede il comportamento di provider testuale Qwen più il comportamento di comprensione dei media e generazione video - il plugin
voice-callè un plugin di funzionalità: possiede trasporto delle chiamate, strumenti, CLI, route e bridging del media-stream Twilio, ma consuma le capacità condivise di voce più trascrizione in tempo reale e voce in tempo reale invece di importare direttamente i plugin vendor
- OpenAI si trova in un unico plugin anche se copre modelli testuali, voce, immagini e futuro video
- un altro vendor può fare lo stesso per la propria area di superficie
- i canali non si preoccupano di quale plugin vendor possieda il provider; consumano il contratto di capacità condiviso esposto dal core
- plugin = confine di proprietà
- capability = contratto del core che più plugin possono implementare o consumare
- definire la capacità mancante nel core
- esporla tramite l’API/runtime dei plugin in modo tipizzato
- collegare canali/funzionalità a quella capacità
- lasciare che i plugin vendor registrino le implementazioni
Stratificazione delle capacità
Usa questo modello mentale quando decidi dove deve stare il codice:- livello di capacità del core: orchestrazione condivisa, policy, fallback, regole di merge della configurazione, semantica di consegna e contratti tipizzati
- livello del plugin vendor: API specifiche del vendor, autenticazione, cataloghi di modelli, sintesi vocale, generazione di immagini, futuri backend video, endpoint di utilizzo
- livello del plugin di canale/funzionalità: integrazione Slack/Discord/voice-call/ecc. che consuma capacità del core e le presenta su una superficie
- il core possiede la policy TTS al momento della risposta, l’ordine di fallback, le preferenze e la consegna sui canali
openai,elevenlabsemicrosoftpossiedono le implementazioni di sintesivoice-callconsuma l’helper di runtime TTS per la telefonia
Esempio di plugin aziendale multi-capacità
Un plugin aziendale dovrebbe risultare coeso dall’esterno. Se OpenClaw ha contratti condivisi per modelli, voce, trascrizione in tempo reale, voce in tempo reale, comprensione dei media, generazione di immagini, generazione video, recupero web e ricerca web, un vendor può possedere tutte le proprie superfici in un unico posto:- un plugin possiede la superficie del vendor
- il core continua a possedere i contratti di capacità
- i plugin di canale e di funzionalità consumano helper
api.runtime.*, non codice del vendor - i test di contratto possono verificare che il plugin abbia registrato le capacità che dichiara di possedere
Esempio di capacità: comprensione video
OpenClaw tratta già la comprensione di immagini/audio/video come un’unica capacità condivisa. Lo stesso modello di proprietà si applica anche qui:- il core definisce il contratto di comprensione dei media
- i plugin vendor registrano
describeImage,transcribeAudioedescribeVideosecondo necessità - i plugin di canale e di funzionalità consumano il comportamento condiviso del core invece di collegarsi direttamente al codice del vendor
api.registerVideoGenerationProvider(...) rispetto a esso.
Hai bisogno di una checklist concreta di rollout? Vedi
Capability Cookbook.
Contratti e applicazione
La superficie API dei plugin è intenzionalmente tipizzata e centralizzata inOpenClawPluginApi. Questo contratto definisce i punti di registrazione supportati e
gli helper di runtime su cui un plugin può fare affidamento.
Perché questo è importante:
- gli autori di plugin ottengono un unico standard interno stabile
- il core può rifiutare proprietà duplicate, ad esempio due plugin che registrano lo stesso ID provider
- l’avvio può mostrare diagnostica utile per registrazioni non valide
- i test di contratto possono imporre la proprietà dei plugin bundled e prevenire derive silenziose
- applicazione della registrazione a runtime Il registro dei plugin valida le registrazioni mentre i plugin vengono caricati. Esempi: ID provider duplicati, ID provider vocali duplicati e registrazioni non valide producono diagnostica dei plugin invece di comportamenti indefiniti.
- test di contratto I plugin bundled vengono acquisiti nei registri di contratto durante le esecuzioni di test così OpenClaw può verificare esplicitamente la proprietà. Oggi questo viene usato per provider di modelli, provider vocali, provider di ricerca web e proprietà delle registrazioni bundled.
Cosa appartiene a un contratto
I buoni contratti dei plugin sono:- tipizzati
- piccoli
- specifici per capacità
- posseduti dal core
- riutilizzabili da più plugin
- consumabili da canali/funzionalità senza conoscenza del vendor
- policy specifiche del vendor nascoste nel core
- vie di fuga specifiche per un singolo plugin che aggirano il registro
- codice di canale che entra direttamente in un’implementazione vendor
- oggetti di runtime ad hoc che non fanno parte di
OpenClawPluginApioapi.runtime
Modello di esecuzione
I plugin nativi OpenClaw vengono eseguiti in-process con il Gateway. Non sono sandboxed. Un plugin nativo caricato ha lo stesso confine di fiducia a livello di processo del codice core. Implicazioni:- un plugin nativo può registrare strumenti, gestori di rete, hook e servizi
- un bug in un plugin nativo può mandare in crash o destabilizzare il gateway
- un plugin nativo malevolo equivale a esecuzione di codice arbitrario all’interno del processo OpenClaw
@openclaw/<id> per impostazione predefinita, oppure un suffisso tipizzato approvato come
-provider, -plugin, -speech, -sandbox o -media-understanding quando
il pacchetto espone intenzionalmente un ruolo di plugin più ristretto.
Nota importante sulla fiducia:
plugins.allowsi fida degli ID plugin, non della provenienza della sorgente.- Un plugin del workspace con lo stesso ID di un plugin bundled oscura intenzionalmente la copia bundled quando quel plugin del workspace è abilitato/in allowlist.
- Questo è normale e utile per sviluppo locale, test di patch e hotfix.
Confine di esportazione
OpenClaw esporta capacità, non comodità di implementazione. Mantieni pubblica la registrazione delle capacità. Riduci le esportazioni helper non contrattuali:- sottopercorsi helper specifici dei plugin bundled
- sottopercorsi di plumbing di runtime non destinati a essere API pubbliche
- helper di comodità specifici del vendor
- helper di setup/onboarding che sono dettagli di implementazione
plugin-sdk/feishu, plugin-sdk/feishu-setup, plugin-sdk/zalo,
plugin-sdk/zalo-setup e diverse seam plugin-sdk/matrix*. Trattali come
esportazioni riservate a dettagli di implementazione, non come pattern SDK consigliato per
nuovi plugin di terze parti.
Pipeline di caricamento
All’avvio, OpenClaw esegue approssimativamente questo:- individua le root candidate dei plugin
- legge i manifest nativi o dei bundle compatibili e i metadati dei pacchetti
- rifiuta i candidati non sicuri
- normalizza la configurazione dei plugin (
plugins.enabled,allow,deny,entries,slots,load.paths) - decide l’abilitazione per ogni candidato
- carica i moduli nativi abilitati tramite jiti
- chiama gli hook nativi
register(api)(oactivate(api)— un alias legacy) e raccoglie le registrazioni nel registro dei plugin - espone il registro alle superfici di comandi/runtime
activate è un alias legacy di register — il loader risolve quello presente (def.register ?? def.activate) e lo chiama nello stesso punto. Tutti i plugin bundled usano register; per i nuovi plugin preferisci register.Comportamento manifest-first
Il manifest è la fonte di verità del control plane. OpenClaw lo usa per:- identificare il plugin
- individuare canali/Skills/schema di configurazione dichiarati o capacità del bundle
- validare
plugins.entries.<id>.config - arricchire etichette/segnaposto della Control UI
- mostrare metadati di installazione/catalogo
- preservare descrittori economici di attivazione e setup senza caricare il runtime del plugin
activation e setup del manifest restano nel control plane.
Sono descrittori di soli metadati per la pianificazione dell’attivazione e l’individuazione del setup;
non sostituiscono la registrazione a runtime, register(...) o setupEntry.
L’individuazione del setup ora preferisce ID posseduti dal descrittore come setup.providers e
setup.cliBackends per restringere i plugin candidati prima di ricorrere a
setup-api per i plugin che hanno ancora bisogno di hook di runtime al momento del setup. Se più di
un plugin individuato rivendica lo stesso ID normalizzato di provider di setup o backend CLI, la ricerca del setup rifiuta il proprietario ambiguo invece di basarsi sull’ordine di individuazione.
Cosa mette in cache il loader
OpenClaw mantiene brevi cache in-process per:- risultati di individuazione
- dati del registro dei manifest
- registri dei plugin caricati
- Imposta
OPENCLAW_DISABLE_PLUGIN_DISCOVERY_CACHE=1oOPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE=1per disabilitare queste cache. - Regola le finestre della cache con
OPENCLAW_PLUGIN_DISCOVERY_CACHE_MSeOPENCLAW_PLUGIN_MANIFEST_CACHE_MS.
Modello di registro
I plugin caricati non mutano direttamente globali casuali del core. Si registrano in un registro centrale dei plugin. Il registro tiene traccia di:- record dei plugin (identità, sorgente, origine, stato, diagnostica)
- strumenti
- hook legacy e hook tipizzati
- canali
- provider
- gestori RPC del gateway
- route HTTP
- registrar CLI
- servizi in background
- comandi posseduti dal plugin
- modulo del plugin -> registrazione nel registro
- runtime del core -> consumo del registro
Callback di binding della conversazione
I plugin che associano una conversazione possono reagire quando un’approvazione viene risolta. Usaapi.onConversationBindingResolved(...) per ricevere un callback dopo che una richiesta di binding viene approvata o negata:
status:"approved"o"denied"decision:"allow-once","allow-always"o"deny"binding: il binding risolto per le richieste approvaterequest: il riepilogo della richiesta originale, il suggerimento di distacco, l’ID del mittente e i metadati della conversazione
Hook di runtime del provider
I plugin provider ora hanno due livelli:- metadati del manifest:
providerAuthEnvVarsper un lookup economico dell’autenticazione provider tramite env prima del caricamento del runtime,providerAuthAliasesper varianti del provider che condividono autenticazione,channelEnvVarsper un lookup economico dell’env/setup del canale prima del caricamento del runtime, piùproviderAuthChoicesper etichette economiche di onboarding/scelta di autenticazione e metadati dei flag CLI prima del caricamento del runtime - hook in fase di configurazione:
catalog/ legacydiscoverypiùapplyConfigDefaults - hook di runtime:
normalizeModelId,normalizeTransport,normalizeConfig,applyNativeStreamingUsageCompat,resolveConfigApiKey,resolveSyntheticAuth,resolveExternalAuthProfiles,shouldDeferSyntheticProfileAuth,resolveDynamicModel,prepareDynamicModel,normalizeResolvedModel,contributeResolvedModelCompat,capabilities,normalizeToolSchemas,inspectToolSchemas,resolveReasoningOutputMode,prepareExtraParams,createStreamFn,wrapStreamFn,resolveTransportTurnState,resolveWebSocketSessionPolicy,formatApiKey,refreshOAuth,buildAuthDoctorHint,matchesContextOverflowError,classifyFailoverReason,isCacheTtlEligible,buildMissingAuthMessage,suppressBuiltInModel,augmentModelCatalog,isBinaryThinking,supportsXHighThinking,resolveDefaultThinkingLevel,isModernModelRef,prepareRuntimeAuth,resolveUsageAuth,fetchUsageSnapshot,createEmbeddingProvider,buildReplayPolicy,sanitizeReplayHistory,validateReplayTurns,onModelSelected
providerAuthEnvVars quando il provider ha credenziali basate su env
che i percorsi generici di autenticazione/stato/selettore di modelli devono vedere senza caricare il runtime del plugin.
Usa il manifest providerAuthAliases quando un ID provider deve riutilizzare
le variabili env, i profili di autenticazione, l’autenticazione supportata dalla configurazione e la scelta di onboarding della chiave API di un altro ID provider.
Usa il manifest providerAuthChoices quando le superfici CLI di onboarding/scelta di autenticazione
devono conoscere l’ID di scelta del provider, le etichette di gruppo e il semplice wiring di autenticazione a flag singolo senza caricare il runtime del provider. Mantieni envVars del runtime provider per suggerimenti rivolti all’operatore come etichette di onboarding o variabili di setup per
client-id/client-secret OAuth.
Usa il manifest channelEnvVars quando un canale ha autenticazione o setup guidati da env che
i fallback generici di shell-env, i controlli di configurazione/stato o i prompt di setup devono vedere
senza caricare il runtime del canale.
Ordine e uso degli hook
Per i plugin modello/provider, OpenClaw chiama gli hook approssimativamente in questo ordine. La colonna “Quando usarlo” è la guida rapida per decidere.| # | Hook | Cosa fa | Quando usarlo |
|---|---|---|---|
| 1 | catalog | Pubblica la configurazione del provider in models.providers durante la generazione di models.json | Il provider possiede un catalogo o valori predefiniti di base URL |
| 2 | applyConfigDefaults | Applica valori predefiniti globali di configurazione posseduti dal provider durante la materializzazione della configurazione | I valori predefiniti dipendono dalla modalità di autenticazione, dall’env o dalla semantica della famiglia di modelli del provider |
| — | (built-in model lookup) | OpenClaw prova prima il normale percorso registro/catalogo | (non è un hook del plugin) |
| 3 | normalizeModelId | Normalizza alias legacy o preview degli ID modello prima del lookup | Il provider possiede la pulizia degli alias prima della risoluzione del modello canonico |
| 4 | normalizeTransport | Normalizza api / baseUrl della famiglia provider prima dell’assemblaggio generico del modello | Il provider possiede la pulizia del trasporto per ID provider personalizzati nella stessa famiglia di trasporto |
| 5 | normalizeConfig | Normalizza models.providers.<id> prima della risoluzione del runtime/provider | Il provider richiede una pulizia della configurazione che dovrebbe stare con il plugin; gli helper bundled della famiglia Google fanno anche da backstop per le voci di configurazione Google supportate |
| 6 | applyNativeStreamingUsageCompat | Applica riscritture di compatibilità dell’uso dello streaming nativo ai provider di configurazione | Il provider richiede correzioni dei metadati di uso dello streaming nativo guidate dall’endpoint |
| 7 | resolveConfigApiKey | Risolve l’autenticazione con marker env per i provider di configurazione prima del caricamento dell’autenticazione di runtime | Il provider ha una risoluzione della chiave API con marker env posseduta dal provider; anche amazon-bedrock ha qui un resolver integrato per il marker env AWS |
| 8 | resolveSyntheticAuth | Espone autenticazione locale/self-hosted o supportata dalla configurazione senza persistere testo in chiaro | Il provider può operare con un marker di credenziale sintetico/locale |
| 9 | resolveExternalAuthProfiles | Sovrappone profili di autenticazione esterni posseduti dal provider; persistence predefinito è runtime-only per credenziali possedute da CLI/app | Il provider riutilizza credenziali di autenticazione esterna senza persistere refresh token copiati |
| 10 | shouldDeferSyntheticProfileAuth | Abbassa la priorità dei placeholder sintetici di profilo memorizzati rispetto all’autenticazione supportata da env/config | Il provider memorizza profili placeholder sintetici che non dovrebbero avere la precedenza |
| 11 | resolveDynamicModel | Fallback sincrono per ID modello posseduti dal provider non ancora presenti nel registro locale | Il provider accetta ID modello upstream arbitrari |
| 12 | prepareDynamicModel | Warm-up asincrono, poi resolveDynamicModel viene eseguito di nuovo | Il provider ha bisogno di metadati di rete prima di risolvere ID sconosciuti |
| 13 | normalizeResolvedModel | Riscrittura finale prima che l’embedded runner usi il modello risolto | Il provider richiede riscritture del trasporto ma usa comunque un trasporto del core |
| 14 | contributeResolvedModelCompat | Contribuisce flag di compatibilità per modelli vendor dietro un altro trasporto compatibile | Il provider riconosce i propri modelli su trasporti proxy senza assumere il controllo del provider |
| 15 | capabilities | Metadati di trascrizione/strumentazione posseduti dal provider usati dalla logica condivisa del core | Il provider richiede peculiarità della trascrizione/della famiglia del provider |
| 16 | normalizeToolSchemas | Normalizza gli schemi degli strumenti prima che l’embedded runner li veda | Il provider richiede pulizia dello schema della famiglia di trasporto |
| 17 | inspectToolSchemas | Espone diagnostica degli schemi posseduta dal provider dopo la normalizzazione | Il provider vuole warning sulle keyword senza insegnare al core regole specifiche del provider |
| 18 | resolveReasoningOutputMode | Seleziona il contratto di output del ragionamento nativo rispetto a quello con tag | Il provider richiede output di ragionamento/finale con tag invece di campi nativi |
| 19 | prepareExtraParams | Normalizzazione dei parametri della richiesta prima dei wrapper generici delle opzioni di stream | Il provider richiede parametri di richiesta predefiniti o pulizia dei parametri per provider |
| 20 | createStreamFn | Sostituisce completamente il normale percorso di stream con un trasporto personalizzato | Il provider richiede un protocollo wire personalizzato, non solo un wrapper |
| 21 | wrapStreamFn | Wrapper dello stream dopo l’applicazione dei wrapper generici | Il provider richiede wrapper di compatibilità per header/body/modello della richiesta senza un trasporto personalizzato |
| 22 | resolveTransportTurnState | Collega header o metadati nativi per turno al trasporto | Il provider vuole che i trasporti generici inviino l’identità del turno nativa del provider |
| 23 | resolveWebSocketSessionPolicy | Collega header WebSocket nativi o una policy di cool-down della sessione | Il provider vuole che i trasporti WS generici regolino gli header di sessione o la policy di fallback |
| 24 | formatApiKey | Formatter del profilo di autenticazione: il profilo memorizzato diventa la stringa apiKey di runtime | Il provider memorizza metadati di autenticazione aggiuntivi e richiede una forma personalizzata del token di runtime |
| 25 | refreshOAuth | Override dell’aggiornamento OAuth per endpoint di refresh personalizzati o policy di errore nel refresh | Il provider non rientra nei refresher condivisi pi-ai |
| 26 | buildAuthDoctorHint | Suggerimento di riparazione aggiunto quando il refresh OAuth fallisce | Il provider richiede indicazioni di riparazione dell’autenticazione possedute dal provider dopo un errore di refresh |
| 27 | matchesContextOverflowError | Matcher posseduto dal provider per overflow della finestra di contesto | Il provider ha errori raw di overflow che le euristiche generiche non intercetterebbero |
| 28 | classifyFailoverReason | Classificazione della ragione di failover posseduta dal provider | Il provider può mappare errori raw di API/trasporto a rate-limit/sovraccarico/ecc. |
| 29 | isCacheTtlEligible | Policy della prompt-cache per provider proxy/backhaul | Il provider richiede gating TTL della cache specifico per il proxy |
| 30 | buildMissingAuthMessage | Sostituzione del messaggio generico di recupero per autenticazione mancante | Il provider richiede un suggerimento di recupero per autenticazione mancante specifico del provider |
| 31 | suppressBuiltInModel | Soppressione di modelli upstream obsoleti più eventuale suggerimento d’errore rivolto all’utente | Il provider deve nascondere righe upstream obsolete o sostituirle con un suggerimento del vendor |
| 32 | augmentModelCatalog | Righe di catalogo sintetiche/finali aggiunte dopo l’individuazione | Il provider richiede righe sintetiche di forward-compat in models list e nei selettori |
| 33 | isBinaryThinking | Toggle di ragionamento on/off per provider con binary thinking | Il provider espone solo ragionamento binario attivo/disattivo |
| 34 | supportsXHighThinking | Supporto al ragionamento xhigh per modelli selezionati | Il provider vuole xhigh solo su un sottoinsieme di modelli |
| 35 | resolveDefaultThinkingLevel | Livello /think predefinito per una specifica famiglia di modelli | Il provider possiede la policy /think predefinita per una famiglia di modelli |
| 36 | isModernModelRef | Matcher di modelli moderni per filtri di profili live e selezione smoke | Il provider possiede il matching del modello preferito per live/smoke |
| 37 | prepareRuntimeAuth | Scambia una credenziale configurata con il token/chiave effettivo di runtime subito prima dell’inferenza | Il provider richiede uno scambio di token o una credenziale di richiesta di breve durata |
| 38 | resolveUsageAuth | Risolve le credenziali di utilizzo/fatturazione per /usage e superfici di stato correlate | Il provider richiede parsing personalizzato del token di utilizzo/quota o una credenziale di utilizzo diversa |
| 39 | fetchUsageSnapshot | Recupera e normalizza snapshot di utilizzo/quota specifici del provider dopo che l’autenticazione è risolta | Il provider richiede un endpoint di utilizzo specifico del provider o un parser del payload |
| 40 | createEmbeddingProvider | Costruisce un adattatore di embedding posseduto dal provider per memoria/ricerca | Il comportamento di embedding della memoria appartiene al plugin provider |
| 41 | buildReplayPolicy | Restituisce una policy di replay che controlla la gestione della trascrizione per il provider | Il provider richiede una policy personalizzata per la trascrizione (ad esempio la rimozione dei blocchi di thinking) |
| 42 | sanitizeReplayHistory | Riscrive la cronologia di replay dopo la pulizia generica della trascrizione | Il provider richiede riscritture di replay specifiche del provider oltre agli helper condivisi di compattazione |
| 43 | validateReplayTurns | Validazione finale o rimodellamento dei turni di replay prima dell’embedded runner | Il trasporto del provider richiede una validazione dei turni più rigorosa dopo la sanitizzazione generica |
| 44 | onModelSelected | Esegue effetti collaterali post-selezione posseduti dal provider | Il provider richiede telemetria o stato posseduto dal provider quando un modello diventa attivo |
normalizeModelId, normalizeTransport e normalizeConfig controllano prima il
plugin provider corrispondente, poi passano agli altri plugin provider capaci di hook
finché uno non modifica effettivamente l’ID del modello o il trasporto/la configurazione. Questo mantiene
funzionanti gli shim di alias/compatibilità del provider senza richiedere al chiamante di sapere quale
plugin bundled possiede la riscrittura. Se nessun hook provider riscrive una voce di configurazione supportata
della famiglia Google, il normalizzatore di configurazione Google bundled applica comunque
quella pulizia di compatibilità.
Se il provider richiede un protocollo wire completamente personalizzato o un esecutore di richieste personalizzato,
si tratta di una classe diversa di estensione. Questi hook servono per il comportamento del provider
che continua a essere eseguito nel normale loop di inferenza di OpenClaw.
Esempio di provider
Esempi integrati
- Anthropic usa
resolveDynamicModel,capabilities,buildAuthDoctorHint,resolveUsageAuth,fetchUsageSnapshot,isCacheTtlEligible,resolveDefaultThinkingLevel,applyConfigDefaults,isModernModelRefewrapStreamFnperché possiede la forward-compat di Claude 4.6, i suggerimenti della famiglia provider, la guida di riparazione dell’autenticazione, l’integrazione dell’endpoint di utilizzo, l’idoneità della prompt-cache, i valori predefiniti di configurazione sensibili all’autenticazione, la policy di thinking predefinita/adattiva di Claude e il model shaping dello stream specifico di Anthropic per header beta,/fast/serviceTierecontext1m. - Gli helper di stream specifici di Claude di Anthropic restano per ora nella
propria seam pubblica
api.ts/contract-api.tsdel plugin bundled. Questa superficie del pacchetto esportawrapAnthropicProviderStream,resolveAnthropicBetas,resolveAnthropicFastMode,resolveAnthropicServiceTiere i builder di wrapper Anthropic di livello inferiore invece di ampliare l’SDK generico attorno alle regole degli header beta di un solo provider. - OpenAI usa
resolveDynamicModel,normalizeResolvedModelecapabilitiespiùbuildMissingAuthMessage,suppressBuiltInModel,augmentModelCatalog,supportsXHighThinkingeisModernModelRefperché possiede la forward-compat di GPT-5.4, la normalizzazione diretta di OpenAIopenai-completions->openai-responses, i suggerimenti di autenticazione consapevoli di Codex, la soppressione di Spark, le righe sintetiche dell’elenco OpenAI e la policy di thinking / modello live di GPT-5; la famiglia di streamopenai-responses-defaultspossiede i wrapper condivisi nativi di OpenAI Responses per header di attribuzione,/fast/serviceTier, verbosità del testo, ricerca web nativa di Codex, model shaping del payload di compatibilità del reasoning e gestione del contesto di Responses. - OpenRouter usa
catalogpiùresolveDynamicModeleprepareDynamicModelperché il provider è pass-through e può esporre nuovi ID modello prima che il catalogo statico di OpenClaw venga aggiornato; usa anchecapabilities,wrapStreamFneisCacheTtlEligibleper mantenere header di richiesta specifici del provider, metadati di routing, patch del reasoning e policy della prompt-cache fuori dal core. La sua policy di replay proviene dalla famigliapassthrough-gemini, mentre la famiglia di streamopenrouter-thinkingpossiede l’iniezione del reasoning del proxy e i salti per modello non supportato /auto. - GitHub Copilot usa
catalog,auth,resolveDynamicModelecapabilitiespiùprepareRuntimeAuthefetchUsageSnapshotperché ha bisogno di login dispositivo posseduto dal provider, comportamento di fallback del modello, peculiarità della trascrizione di Claude, uno scambio token GitHub -> token Copilot e un endpoint di utilizzo posseduto dal provider. - OpenAI Codex usa
catalog,resolveDynamicModel,normalizeResolvedModel,refreshOAutheaugmentModelCatalogpiùprepareExtraParams,resolveUsageAuthefetchUsageSnapshotperché continua a funzionare sui trasporti OpenAI del core ma possiede la propria normalizzazione di trasporto/base URL, la policy di fallback per il refresh OAuth, la scelta predefinita del trasporto, le righe sintetiche del catalogo Codex e l’integrazione dell’endpoint di utilizzo di ChatGPT; condivide la stessa famiglia di streamopenai-responses-defaultsdi OpenAI diretto. - Google AI Studio e Gemini CLI OAuth usano
resolveDynamicModel,buildReplayPolicy,sanitizeReplayHistory,resolveReasoningOutputMode,wrapStreamFneisModernModelRefperché la famiglia di replaygoogle-geminipossiede il fallback di forward-compat di Gemini 3.1, la validazione nativa del replay Gemini, la sanitizzazione del replay di bootstrap, la modalità di output del reasoning con tag e il matching dei modelli moderni, mentre la famiglia di streamgoogle-thinkingpossiede la normalizzazione del payload di thinking di Gemini; Gemini CLI OAuth usa ancheformatApiKey,resolveUsageAuthefetchUsageSnapshotper formattazione del token, parsing del token e collegamento dell’endpoint quota. - Anthropic Vertex usa
buildReplayPolicytramite la famiglia di replayanthropic-by-modelcosì la pulizia del replay specifica di Claude resta limitata agli ID Claude invece che a ogni trasportoanthropic-messages. - Amazon Bedrock usa
buildReplayPolicy,matchesContextOverflowError,classifyFailoverReasoneresolveDefaultThinkingLevelperché possiede la classificazione degli errori specifica di Bedrock per throttling/non pronto/overflow del contesto per il traffico Anthropic-on-Bedrock; la sua policy di replay condivide comunque lo stesso guard solo-Claudeanthropic-by-model. - OpenRouter, Kilocode, Opencode e Opencode Go usano
buildReplayPolicytramite la famiglia di replaypassthrough-geminiperché fanno da proxy ai modelli Gemini tramite trasporti compatibili con OpenAI e necessitano della sanitizzazione della thought-signature di Gemini senza validazione nativa del replay Gemini né riscritture di bootstrap. - MiniMax usa
buildReplayPolicytramite la famiglia di replayhybrid-anthropic-openaiperché un unico provider possiede sia la semantica di messaggi Anthropic sia quella compatibile con OpenAI; mantiene la rimozione dei blocchi di thinking solo-Claude sul lato Anthropic, mentre riporta la modalità di output del reasoning a quella nativa, e la famiglia di streamminimax-fast-modepossiede le riscritture del modello in fast mode sul percorso di stream condiviso. - Moonshot usa
catalogpiùwrapStreamFnperché continua a usare il trasporto OpenAI condiviso ma richiede una normalizzazione del payload di thinking posseduta dal provider; la famiglia di streammoonshot-thinkingmappa la configurazione più lo stato/thinksul proprio payload nativo di binary thinking. - Kilocode usa
catalog,capabilities,wrapStreamFneisCacheTtlEligibleperché ha bisogno di header di richiesta posseduti dal provider, normalizzazione del payload di reasoning, suggerimenti di trascrizione Gemini e gating TTL della cache Anthropic; la famiglia di streamkilocode-thinkingmantiene l’iniezione del thinking Kilo sul percorso di stream proxy condiviso saltandokilo/autoe altri ID modello proxy che non supportano payload di reasoning espliciti. - Z.AI usa
resolveDynamicModel,prepareExtraParams,wrapStreamFn,isCacheTtlEligible,isBinaryThinking,isModernModelRef,resolveUsageAuthefetchUsageSnapshotperché possiede il fallback GLM-5, i valori predefinititool_stream, la UX del binary thinking, il matching dei modelli moderni e sia l’autenticazione per l’utilizzo sia il recupero della quota; la famiglia di streamtool-stream-default-onmantiene il wrappertool_streamattivo per impostazione predefinita fuori dalla colla scritta a mano per singolo provider. - xAI usa
normalizeResolvedModel,normalizeTransport,contributeResolvedModelCompat,prepareExtraParams,wrapStreamFn,resolveSyntheticAuth,resolveDynamicModeleisModernModelRefperché possiede la normalizzazione nativa del trasporto xAI Responses, le riscritture alias della fast mode di Grok, iltool_streampredefinito, la pulizia di strict-tool / payload di reasoning, il riuso dell’autenticazione di fallback per gli strumenti posseduti dal plugin, la risoluzione forward-compat del modello Grok e patch di compatibilità possedute dal provider come il profilo di schema degli strumenti xAI, keyword di schema non supportate,web_searchnativo e la decodifica delle entità HTML negli argomenti delle chiamate di strumenti. - Mistral, OpenCode Zen e OpenCode Go usano solo
capabilitiesper mantenere le peculiarità di trascrizione/strumentazione fuori dal core. - I provider bundled solo catalogo come
byteplus,cloudflare-ai-gateway,huggingface,kimi-coding,nvidia,qianfan,synthetic,together,venice,vercel-ai-gatewayevolcengineusano solocatalog. - Qwen usa
catalogper il proprio provider testuale più registrazioni condivise di comprensione dei media e generazione video per le sue superfici multimodali. - MiniMax e Xiaomi usano
catalogpiù hook di utilizzo perché il loro comportamento/usageè posseduto dal plugin anche se l’inferenza continua a passare attraverso i trasporti condivisi.
Helper di runtime
I plugin possono accedere a helper selezionati del core tramiteapi.runtime. Per la TTS:
textToSpeechrestituisce il normale payload di output TTS del core per superfici file/messaggio vocale.- Usa la configurazione core
messages.ttse la selezione del provider. - Restituisce buffer audio PCM + sample rate. I plugin devono ricampionare/codificare per i provider.
listVoicesè facoltativo per provider. Usalo per selettori vocali o flussi di setup posseduti dal vendor.- Gli elenchi di voci possono includere metadati più ricchi come locale, genere e tag di personalità per selettori consapevoli del provider.
- OpenAI ed ElevenLabs supportano oggi la telefonia. Microsoft no.
api.registerSpeechProvider(...).
- Mantieni nel core la policy TTS, il fallback e la consegna delle risposte.
- Usa i provider vocali per il comportamento di sintesi posseduto dal vendor.
- L’input legacy Microsoft
edgeviene normalizzato all’ID providermicrosoft. - Il modello di proprietà preferito è orientato all’azienda: un solo plugin vendor può possedere provider testuali, vocali, di immagini e futuri provider media man mano che OpenClaw aggiunge questi contratti di capacità.
- Mantieni orchestrazione, fallback, configurazione e wiring dei canali nel core.
- Mantieni il comportamento del vendor nel plugin provider.
- L’espansione additiva dovrebbe restare tipizzata: nuovi metodi facoltativi, nuovi campi risultato facoltativi, nuove capacità facoltative.
- La generazione video segue già lo stesso pattern:
- il core possiede il contratto di capacità e l’helper di runtime
- i plugin vendor registrano
api.registerVideoGenerationProvider(...) - i plugin di funzionalità/canale consumano
api.runtime.videoGeneration.*
api.runtime.mediaUnderstanding.*è la superficie condivisa preferita per la comprensione di immagini/audio/video.- Usa la configurazione audio media-understanding del core (
tools.media.audio) e l’ordine di fallback del provider. - Restituisce
{ text: undefined }quando non viene prodotto alcun output di trascrizione (per esempio input saltato/non supportato). api.runtime.stt.transcribeAudioFile(...)resta come alias di compatibilità.
api.runtime.subagent:
provideremodelsono override facoltativi per singola esecuzione, non modifiche persistenti della sessione.- OpenClaw onora questi campi di override solo per chiamanti attendibili.
- Per le esecuzioni di fallback possedute dal plugin, gli operatori devono effettuare l’opt-in con
plugins.entries.<id>.subagent.allowModelOverride: true. - Usa
plugins.entries.<id>.subagent.allowedModelsper limitare i plugin attendibili a target canonici specificiprovider/model, oppure"*"per consentire esplicitamente qualsiasi target. - Le esecuzioni subagent di plugin non attendibili continuano a funzionare, ma le richieste di override vengono rifiutate invece di ricadere silenziosamente nel fallback.
api.registerWebSearchProvider(...).
Note:
- Mantieni nel core la selezione del provider, la risoluzione delle credenziali e la semantica condivisa delle richieste.
- Usa i provider di ricerca web per i trasporti di ricerca specifici del vendor.
api.runtime.webSearch.*è la superficie condivisa preferita per i plugin di funzionalità/canale che hanno bisogno di comportamento di ricerca senza dipendere dal wrapper dello strumento agente.
api.runtime.imageGeneration
generate(...): genera un’immagine usando la catena di provider di generazione immagini configurata.listProviders(...): elenca i provider di generazione immagini disponibili e le loro capacità.
Route HTTP del Gateway
I plugin possono esporre endpoint HTTP conapi.registerHttpRoute(...).
path: percorso della route sotto il server HTTP del gateway.auth: obbligatorio. Usa"gateway"per richiedere la normale autenticazione del gateway, oppure"plugin"per autenticazione/validazione webhook gestita dal plugin.match: facoltativo."exact"(predefinito) oppure"prefix".replaceExisting: facoltativo. Consente allo stesso plugin di sostituire la propria registrazione di route esistente.handler: restituiscetruequando la route ha gestito la richiesta.
api.registerHttpHandler(...)è stato rimosso e causerà un errore di caricamento del plugin. Usa inveceapi.registerHttpRoute(...).- Le route dei plugin devono dichiarare
authesplicitamente. - I conflitti esatti
path + matchvengono rifiutati a meno chereplaceExisting: true, e un plugin non può sostituire la route di un altro plugin. - Le route sovrapposte con livelli
authdiversi vengono rifiutate. Mantieni le catene di fallthroughexact/prefixsolo allo stesso livello di auth. - Le route
auth: "plugin"non ricevono automaticamente scope di runtime operatore. Servono per webhook/validazione firme gestiti dal plugin, non per chiamate helper del Gateway con privilegi. - Le route
auth: "gateway"vengono eseguite all’interno di uno scope di runtime della richiesta Gateway, ma tale scope è intenzionalmente conservativo:- l’autenticazione bearer con segreto condiviso (
gateway.auth.mode = "token"/"password") mantiene gli scope di runtime delle route plugin fissati aoperator.write, anche se il chiamante inviax-openclaw-scopes - le modalità HTTP affidabili basate su identità (per esempio
trusted-proxyogateway.auth.mode = "none"su un ingresso privato) onoranox-openclaw-scopessolo quando l’header è esplicitamente presente - se
x-openclaw-scopesè assente in quelle richieste di route plugin basate su identità, lo scope di runtime ricade suoperator.write
- l’autenticazione bearer con segreto condiviso (
- Regola pratica: non presumere che una route plugin con autenticazione gateway sia implicitamente una superficie admin. Se la tua route richiede comportamento solo admin, richiedi una modalità di autenticazione basata su identità e documenta il contratto esplicito dell’header
x-openclaw-scopes.
Percorsi di import dell’SDK plugin
Usa i sottopercorsi dell’SDK invece dell’import monoliticoopenclaw/plugin-sdk quando
scrivi plugin:
openclaw/plugin-sdk/plugin-entryper le primitive di registrazione dei plugin.openclaw/plugin-sdk/coreper il contratto generico condiviso rivolto ai plugin.openclaw/plugin-sdk/config-schemaper l’esportazione dello schema Zod rootopenclaw.json(OpenClawSchema).- Primitive stabili di canale come
openclaw/plugin-sdk/channel-setup,openclaw/plugin-sdk/setup-runtime,openclaw/plugin-sdk/setup-adapter-runtime,openclaw/plugin-sdk/setup-tools,openclaw/plugin-sdk/channel-pairing,openclaw/plugin-sdk/channel-contract,openclaw/plugin-sdk/channel-feedback,openclaw/plugin-sdk/channel-inbound,openclaw/plugin-sdk/channel-lifecycle,openclaw/plugin-sdk/channel-reply-pipeline,openclaw/plugin-sdk/command-auth,openclaw/plugin-sdk/secret-inputeopenclaw/plugin-sdk/webhook-ingressper il wiring condiviso di setup/auth/reply/webhook.channel-inboundè la sede condivisa per debounce, corrispondenza delle mention, helper della mention-policy inbound, formattazione delle envelope e helper del contesto delle envelope inbound.channel-setupè la seam ristretta di setup con installazione facoltativa.setup-runtimeè la superficie di setup sicura per il runtime usata dasetupEntry/ avvio differito, inclusi gli adattatori di patch di setup sicuri per l’import.setup-adapter-runtimeè la seam dell’adattatore di setup account consapevole dell’env.setup-toolsè la piccola seam helper per CLI/archivi/documentazione (formatCliCommand,detectBinary,extractArchive,resolveBrewExecutable,formatDocsLink,CONFIG_DIR). - Sottopercorsi di dominio come
openclaw/plugin-sdk/channel-config-helpers,openclaw/plugin-sdk/allow-from,openclaw/plugin-sdk/channel-config-schema,openclaw/plugin-sdk/telegram-command-config,openclaw/plugin-sdk/channel-policy,openclaw/plugin-sdk/approval-gateway-runtime,openclaw/plugin-sdk/approval-handler-adapter-runtime,openclaw/plugin-sdk/approval-handler-runtime,openclaw/plugin-sdk/approval-runtime,openclaw/plugin-sdk/config-runtime,openclaw/plugin-sdk/infra-runtime,openclaw/plugin-sdk/agent-runtime,openclaw/plugin-sdk/lazy-runtime,openclaw/plugin-sdk/reply-history,openclaw/plugin-sdk/routing,openclaw/plugin-sdk/status-helpers,openclaw/plugin-sdk/text-runtime,openclaw/plugin-sdk/runtime-storeeopenclaw/plugin-sdk/directory-runtimeper helper condivisi di runtime/configurazione.telegram-command-configè la seam pubblica ristretta per normalizzazione/validazione dei comandi personalizzati Telegram e resta disponibile anche se la superficie di contratto Telegram bundled è temporaneamente non disponibile.text-runtimeè la seam condivisa per testo/Markdown/logging, inclusi stripping del testo visibile all’assistente, helper di rendering/chunking Markdown, helper di redazione, helper dei tag direttiva e utilità di testo sicuro. - Le seam di canale specifiche per l’approvazione dovrebbero preferire un singolo contratto
approvalCapabilitysul plugin. Il core legge poi autenticazione di approvazione, consegna, render, routing nativo e comportamento lazy del gestore nativo tramite quella sola capacità invece di mescolare il comportamento di approvazione in campi non correlati del plugin. openclaw/plugin-sdk/channel-runtimeè deprecato e rimane solo come shim di compatibilità per plugin meno recenti. Il nuovo codice dovrebbe importare invece le primitive generiche più ristrette, e il codice del repo non dovrebbe aggiungere nuovi import dello shim.- Gli interni delle estensioni bundled restano privati. I plugin esterni dovrebbero usare solo i sottopercorsi
openclaw/plugin-sdk/*. Il codice core/test di OpenClaw può usare i punti di ingresso pubblici del repo sotto la root di un pacchetto plugin comeindex.js,api.js,runtime-api.js,setup-entry.jse file a ambito ristretto comelogin-qr-api.js. Non importare maisrc/*di un pacchetto plugin dal core o da un’altra estensione. - Suddivisione dei punti di ingresso del repo:
<plugin-package-root>/api.jsè il barrel helper/tipi,<plugin-package-root>/runtime-api.jsè il barrel solo runtime,<plugin-package-root>/index.jsè l’entry del plugin bundled, e<plugin-package-root>/setup-entry.jsè l’entry del plugin di setup. - Esempi attuali di provider bundled:
- Anthropic usa
api.js/contract-api.jsper helper di stream Claude comewrapAnthropicProviderStream, helper per header beta e parsing diservice_tier. - OpenAI usa
api.jsper builder provider, helper del modello predefinito e builder provider realtime. - OpenRouter usa
api.jsper il proprio builder provider più helper di onboarding/configurazione, mentreregister.runtime.jspuò ancora riesportare helper genericiplugin-sdk/provider-streamper uso locale nel repo.
- Anthropic usa
- I punti di ingresso pubblici caricati tramite facade preferiscono lo snapshot attivo della configurazione di runtime quando esiste, poi ricadono sul file di configurazione risolto su disco quando OpenClaw non sta ancora servendo uno snapshot di runtime.
- Le primitive generiche condivise restano il contratto pubblico preferito dell’SDK. Esiste ancora un piccolo
insieme di compatibilità riservato di seam helper brandizzate per canali bundled. Trattale come seam di manutenzione/compatibilità bundled, non come nuovi target di import per terze parti; i nuovi contratti cross-channel dovrebbero comunque arrivare su sottopercorsi generici
plugin-sdk/*o sui barrel locali del pluginapi.js/runtime-api.js.
- Evita il barrel root
openclaw/plugin-sdkper il nuovo codice. - Preferisci prima le primitive stabili e ristrette. I sottopercorsi più recenti setup/pairing/reply/
feedback/contract/inbound/threading/command/secret-input/webhook/infra/
allowlist/status/message-tool sono il contratto previsto per il nuovo
lavoro su plugin bundled ed esterni.
Il parsing/matching dei target appartiene a
openclaw/plugin-sdk/channel-targets. I gate delle azioni sui messaggi e gli helper message-id delle reazioni appartengono aopenclaw/plugin-sdk/channel-actions. - I barrel helper specifici delle estensioni bundled non sono stabili per impostazione predefinita. Se un
helper serve solo a un’estensione bundled, tienilo dietro la seam locale
api.jsoruntime-api.jsdell’estensione invece di promuoverlo inopenclaw/plugin-sdk/<extension>. - Le nuove seam helper condivise dovrebbero essere generiche, non brandizzate per canale. Il parsing condiviso dei target
appartiene a
openclaw/plugin-sdk/channel-targets; gli interni specifici del canale restano dietro la seam localeapi.jsoruntime-api.jsdel plugin proprietario. - Sottopercorsi specifici della capacità come
image-generation,media-understandingespeechesistono perché i plugin bundled/nativi li usano oggi. La loro presenza non significa di per sé che ogni helper esportato sia un contratto esterno congelato a lungo termine.
Schemi dello strumento dei messaggi
I plugin dovrebbero possedere i contributi di schema specifici del canale perdescribeMessageTool(...).
Mantieni i campi specifici del provider nel plugin, non nel core condiviso.
Per frammenti di schema condivisi e portabili, riusa gli helper generici esportati tramite
openclaw/plugin-sdk/channel-actions:
createMessageToolButtonsSchema()per payload in stile griglia di pulsanticreateMessageToolCardSchema()per payload di card strutturate
Risoluzione dei target di canale
I plugin di canale dovrebbero possedere la semantica dei target specifica del canale. Mantieni generico l’host outbound condiviso e usa la superficie dell’adattatore di messaggistica per le regole del provider:messaging.inferTargetChatType({ to })decide se un target normalizzato deve essere trattato comedirect,groupochannelprima del lookup nella directory.messaging.targetResolver.looksLikeId(raw, normalized)dice al core se un input deve saltare direttamente alla risoluzione simile a ID invece che alla ricerca nella directory.messaging.targetResolver.resolveTarget(...)è il fallback del plugin quando il core ha bisogno di una risoluzione finale posseduta dal provider dopo la normalizzazione o dopo un mancato riscontro nella directory.messaging.resolveOutboundSessionRoute(...)possiede la costruzione della route di sessione specifica del provider una volta che un target è stato risolto.
- Usa
inferTargetChatTypeper decisioni di categoria che dovrebbero avvenire prima della ricerca in peer/gruppi. - Usa
looksLikeIdper controlli del tipo “tratta questo come ID target esplicito/nativo”. - Usa
resolveTargetper il fallback di normalizzazione specifico del provider, non per una ricerca ampia nella directory. - Mantieni gli ID nativi del provider come chat id, thread id, JID, handle e room
id dentro valori
targeto parametri specifici del provider, non in campi SDK generici.
Directory supportate dalla configurazione
I plugin che derivano voci di directory dalla configurazione dovrebbero mantenere quella logica nel plugin e riutilizzare gli helper condivisi diopenclaw/plugin-sdk/directory-runtime.
Usalo quando un canale ha peer/gruppi supportati dalla configurazione come:
- peer DM guidati da allowlist
- mappe configurate di canali/gruppi
- fallback statici della directory con ambito account
directory-runtime gestiscono solo operazioni generiche:
- filtraggio delle query
- applicazione del limite
- helper di deduplica/normalizzazione
- costruzione di
ChannelDirectoryEntry[]
Cataloghi provider
I plugin provider possono definire cataloghi di modelli per l’inferenza conregisterProvider({ catalog: { run(...) { ... } } }).
catalog.run(...) restituisce la stessa forma che OpenClaw scrive in
models.providers:
{ provider }per una voce provider{ providers }per più voci provider
catalog quando il plugin possiede ID modello specifici del provider, valori predefiniti di base URL
o metadati di modello protetti da autenticazione.
catalog.order controlla quando il catalogo di un plugin viene unito rispetto ai
provider impliciti integrati di OpenClaw:
simple: provider semplici guidati da chiave API o envprofile: provider che compaiono quando esistono profili di autenticazionepaired: provider che sintetizzano più voci provider correlatelate: ultimo passaggio, dopo gli altri provider impliciti
discoverycontinua a funzionare come alias legacy- se sono registrati sia
catalogsiadiscovery, OpenClaw usacatalog
Ispezione in sola lettura dei canali
Se il tuo plugin registra un canale, preferisci implementareplugin.config.inspectAccount(cfg, accountId) insieme a resolveAccount(...).
Perché:
resolveAccount(...)è il percorso di runtime. Può presumere che le credenziali siano completamente materializzate e può fallire rapidamente quando mancano segreti richiesti.- I percorsi di comando in sola lettura come
openclaw status,openclaw status --all,openclaw channels status,openclaw channels resolvee i flussi di doctor/riparazione della configurazione non dovrebbero aver bisogno di materializzare credenziali di runtime solo per descrivere la configurazione.
inspectAccount(...):
- Restituire solo lo stato descrittivo dell’account.
- Preservare
enabledeconfigured. - Includere campi di sorgente/stato delle credenziali quando rilevanti, come:
tokenSource,tokenStatusbotTokenSource,botTokenStatusappTokenSource,appTokenStatussigningSecretSource,signingSecretStatus
- Non è necessario restituire i valori raw dei token solo per riportare la
disponibilità in sola lettura. Restituire
tokenStatus: "available"(e il relativo campo di sorgente) è sufficiente per i comandi in stile status. - Usa
configured_unavailablequando una credenziale è configurata tramite SecretRef ma non disponibile nel percorso di comando corrente.
Package pack
Una directory plugin può includere unpackage.json con openclaw.extensions:
name/<fileBase>.
Se il tuo plugin importa dipendenze npm, installale in quella directory così
node_modules sia disponibile (npm install / pnpm install).
Guardrail di sicurezza: ogni voce openclaw.extensions deve restare all’interno della directory plugin
dopo la risoluzione dei symlink. Le voci che escono dalla directory del pacchetto vengono
rifiutate.
Nota di sicurezza: openclaw plugins install installa le dipendenze del plugin con
npm install --omit=dev --ignore-scripts (nessuno script lifecycle, nessuna dipendenza dev a runtime). Mantieni gli alberi delle dipendenze dei plugin in “pure JS/TS” ed evita pacchetti che richiedono build postinstall.
Facoltativo: openclaw.setupEntry può puntare a un modulo leggero solo setup.
Quando OpenClaw ha bisogno di superfici di setup per un plugin di canale disabilitato, oppure
quando un plugin di canale è abilitato ma ancora non configurato, carica setupEntry
invece dell’entry completa del plugin. Questo mantiene avvio e setup più leggeri
quando l’entry principale del plugin collega anche strumenti, hook o altro codice
solo runtime.
Facoltativo: openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen
può includere un plugin di canale nello stesso percorso setupEntry durante la fase di
avvio pre-listen del gateway, anche quando il canale è già configurato.
Usalo solo quando setupEntry copre completamente la superficie di avvio che deve esistere
prima che il gateway inizi ad ascoltare. In pratica, questo significa che l’entry di setup
deve registrare ogni capacità posseduta dal canale da cui dipende l’avvio, come:
- la registrazione del canale stessa
- eventuali route HTTP che devono essere disponibili prima che il gateway inizi ad ascoltare
- eventuali metodi gateway, strumenti o servizi che devono esistere durante quella stessa finestra
singleAccountKeysToMovenamedAccountPromotionKeysresolveSingleAccountPromotionTarget(...)
channels.<id>.accounts.* senza caricare l’entry completa del plugin.
Matrix è l’esempio bundled attuale: sposta solo le chiavi auth/bootstrap in un
account promosso con nome quando esistono già account con nome e può preservare una
chiave default-account configurata non canonica invece di creare sempre
accounts.default.
Questi adattatori di patch setup mantengono lazy l’individuazione della superficie contrattuale bundled. Il tempo di import resta leggero; la superficie di promozione viene caricata solo al primo utilizzo invece di rientrare nell’avvio del canale bundled all’import del modulo.
Quando queste superfici di avvio includono metodi RPC del gateway, mantienili su un
prefisso specifico del plugin. I namespace admin del core (config.*,
exec.approvals.*, wizard.*, update.*) restano riservati e vengono sempre risolti
a operator.admin, anche se un plugin richiede uno scope più ristretto.
Esempio:
Metadati del catalogo dei canali
I plugin di canale possono pubblicizzare metadati di setup/individuazione tramiteopenclaw.channel e
suggerimenti di installazione tramite openclaw.install. Questo mantiene il core privo di dati di catalogo.
Esempio:
openclaw.channel oltre all’esempio minimo:
detailLabel: etichetta secondaria per superfici più ricche di catalogo/statodocsLabel: sovrascrive il testo del link per il collegamento alla documentazionepreferOver: ID plugin/canale a priorità più bassa che questa voce di catalogo dovrebbe superareselectionDocsPrefix,selectionDocsOmitLabel,selectionExtras: controlli di testo per la superficie di selezionemarkdownCapable: segna il canale come capace di Markdown per le decisioni di formattazione outboundexposure.configured: nasconde il canale dalle superfici di elenco dei canali configurati quando impostato sufalseexposure.setup: nasconde il canale dai picker interattivi di setup/configurazione quando impostato sufalseexposure.docs: segna il canale come interno/privato per le superfici di navigazione della documentazioneshowConfigured/showInSetup: alias legacy ancora accettati per compatibilità; preferisciexposurequickstartAllowFrom: include il canale nel flusso standard quickstartallowFromforceAccountBinding: richiede un account binding esplicito anche quando esiste un solo accountpreferSessionLookupForAnnounceTarget: preferisce il lookup di sessione durante la risoluzione dei target di annuncio
~/.openclaw/mpm/plugins.json~/.openclaw/mpm/catalog.json~/.openclaw/plugins/catalog.json
OPENCLAW_PLUGIN_CATALOG_PATHS (o OPENCLAW_MPM_CATALOG_PATHS) a
uno o più file JSON (delimitati da virgole/punto e virgola/PATH). Ogni file dovrebbe
contenere { "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] }. Il parser accetta anche "packages" o "plugins" come alias legacy per la chiave "entries".
Plugin del motore di contesto
I plugin del motore di contesto possiedono l’orchestrazione del contesto di sessione per ingestione, assemblaggio e compattazione. Registrali dal tuo plugin conapi.registerContextEngine(id, factory), poi seleziona il motore attivo con
plugins.slots.contextEngine.
Usa questo quando il tuo plugin deve sostituire o estendere la pipeline di contesto
predefinita invece di limitarsi ad aggiungere ricerca nella memoria o hook.
compact()
implementato e delegalo esplicitamente:
Aggiunta di una nuova capacità
Quando un plugin ha bisogno di un comportamento che non rientra nell’API attuale, non aggirare il sistema dei plugin con un accesso privato interno. Aggiungi la capacità mancante. Sequenza consigliata:- definire il contratto del core Decidi quale comportamento condiviso dovrebbe possedere il core: policy, fallback, merge della configurazione, ciclo di vita, semantica rivolta ai canali e forma dell’helper di runtime.
- aggiungere superfici tipizzate di registrazione/runtime dei plugin
Estendi
OpenClawPluginApie/oapi.runtimecon la superficie di capacità tipizzata più piccola utile. - collegare i consumer del core + canale/funzionalità I canali e i plugin di funzionalità dovrebbero consumare la nuova capacità tramite il core, non importando direttamente un’implementazione vendor.
- registrare implementazioni vendor I plugin vendor registrano poi i propri backend rispetto alla capacità.
- aggiungere copertura contrattuale Aggiungi test così che proprietà e forma di registrazione restino esplicite nel tempo.
Checklist della capacità
Quando aggiungi una nuova capacità, l’implementazione dovrebbe di solito toccare queste superfici insieme:- tipi di contratto del core in
src/<capability>/types.ts - runner/helper di runtime del core in
src/<capability>/runtime.ts - superficie di registrazione dell’API plugin in
src/plugins/types.ts - wiring del registro dei plugin in
src/plugins/registry.ts - esposizione di runtime del plugin in
src/plugins/runtime/*quando i plugin di funzionalità/canale devono consumarla - helper di acquisizione/test in
src/test-utils/plugin-registration.ts - asserzioni di proprietà/contratto in
src/plugins/contracts/registry.ts - documentazione per operatori/plugin in
docs/
Template della capacità
Pattern minimo:- il core possiede il contratto di capacità + l’orchestrazione
- i plugin vendor possiedono le implementazioni vendor
- i plugin di funzionalità/canale consumano helper di runtime
- i test di contratto mantengono esplicita la proprietà