Building plugins
Hooks de Plugin
Les hooks de Plugin sont des points dâextension dans le processus pour les plugins OpenClaw. Utilisez-les lorsquâun plugin doit inspecter ou modifier les exĂ©cutions dâagents, les appels dâoutils, le flux de messages, le cycle de vie des sessions, le routage des sous-agents, les installations ou le dĂ©marrage du Gateway.
Utilisez plutĂŽt les hooks internes lorsque vous voulez un petit
script HOOK.md installĂ© par lâopĂ©rateur pour les Ă©vĂ©nements de commande et de Gateway tels que
/new, /reset, /stop, agent:bootstrap ou gateway:startup.
Démarrage rapide
Enregistrez des hooks de plugin typĂ©s avec api.on(...) depuis lâentrĂ©e de votre plugin :
export default definePluginEntry({ id: "tool-preflight", name: "Tool Preflight", register(api) { api.on( "before_tool_call", async (event) => { if (event.toolName !== "web_search") { return; } return { requireApproval: { title: "Run web search", description: `Allow search query: ${String(event.params.query ?? "")}`, severity: "info", timeoutMs: 60_000, timeoutBehavior: "deny", }, }; }, { priority: 50 }, ); },});Les gestionnaires de hooks sâexĂ©cutent sĂ©quentiellement par priority dĂ©croissante. Les hooks
ayant la mĂȘme prioritĂ© conservent lâordre dâenregistrement.
api.on(name, handler, opts?) accepte :
priority- ordre des gestionnaires (les valeurs les plus Ă©levĂ©es sâexĂ©cutent dâabord).timeoutMs- budget optionnel par hook. Lorsquâil est dĂ©fini, lâexĂ©cuteur de hooks interrompt ce gestionnaire une fois le budget Ă©coulĂ© et continue avec le suivant, au lieu de laisser une configuration lente ou un travail de rappel consommer le dĂ©lai dâexpiration de modĂšle configurĂ© par lâappelant. Omettez-le pour utiliser le dĂ©lai dâobservation/dĂ©cision par dĂ©faut que lâexĂ©cuteur de hooks applique de façon gĂ©nĂ©rique.
Les opérateurs peuvent aussi définir des budgets de hooks sans modifier le code du plugin :
{ "plugins": { "entries": { "my-plugin": { "hooks": { "timeoutMs": 30000, "timeouts": { "before_prompt_build": 90000, "agent_end": 60000 } } } } }}hooks.timeouts.<hookName> remplace hooks.timeoutMs, qui remplace la valeur
api.on(..., { timeoutMs }) dĂ©finie par lâauteur du plugin. Chaque valeur configurĂ©e doit
ĂȘtre un entier positif infĂ©rieur ou Ă©gal Ă 600000 millisecondes. PrĂ©fĂ©rez les remplacements par hook
pour les hooks connus comme lents, afin quâun plugin ne reçoive pas un budget plus long
partout.
Chaque hook reçoit event.context.pluginConfig, la configuration résolue pour le
plugin qui a enregistré ce gestionnaire. Utilisez-la pour les décisions de hook qui nécessitent
les options actuelles du plugin ; OpenClaw lâinjecte par gestionnaire sans muter lâobjet
dâĂ©vĂ©nement partagĂ© vu par les autres plugins.
Catalogue des hooks
Les hooks sont regroupĂ©s selon la surface quâils Ă©tendent. Les noms en gras acceptent un rĂ©sultat de dĂ©cision (bloquer, annuler, remplacer ou demander une approbation) ; tous les autres sont uniquement dâobservation.
Tour dâagent
before_model_resolve- remplacer le fournisseur ou le modĂšle avant le chargement des messages de sessionagent_turn_prepare- consommer les injections de tour de plugin en file dâattente et ajouter du contexte au mĂȘme tour avant les hooks de promptbefore_prompt_build- ajouter du contexte dynamique ou du texte de prompt systĂšme avant lâappel au modĂšlebefore_agent_start- phase combinĂ©e uniquement pour compatibilitĂ© ; prĂ©fĂ©rez les deux hooks ci-dessusbefore_agent_run- inspecter le prompt final et les messages de session avant lâenvoi au modĂšle, et Ă©ventuellement bloquer lâexĂ©cutionbefore_agent_reply- court-circuiter le tour du modĂšle avec une rĂ©ponse synthĂ©tique ou le silencebefore_agent_finalize- inspecter la rĂ©ponse finale naturelle et demander un passage de modĂšle supplĂ©mentaireagent_end- observer les messages finaux, lâĂ©tat de succĂšs et la durĂ©e dâexĂ©cutionheartbeat_prompt_contribution- ajouter du contexte uniquement Heartbeat pour les plugins de surveillance en arriĂšre-plan et de cycle de vie
Observation de la conversation
model_call_started/model_call_ended- observer les mĂ©tadonnĂ©es assainies dâappel fournisseur/modĂšle, le minutage, le rĂ©sultat et les hachages bornĂ©s dâidentifiants de requĂȘte, sans contenu de prompt ni de rĂ©ponsellm_input- observer lâentrĂ©e du fournisseur (prompt systĂšme, prompt, historique)llm_output- observer la sortie du fournisseur, lâutilisation et lecontextTokenBudgetrĂ©solu lorsquâil est disponible
Outils
before_tool_call- réécrire les paramĂštres dâoutil, bloquer lâexĂ©cution ou demander une approbationafter_tool_call- observer les rĂ©sultats dâoutils, les erreurs et la durĂ©eresolve_exec_env- fournir des variables dâenvironnement appartenant au plugin Ăexectool_result_persist- réécrire le message de lâassistant produit Ă partir dâun rĂ©sultat dâoutilbefore_message_write- inspecter ou bloquer une Ă©criture de message en cours (rare)
Messages et livraison
inbound_claim- revendiquer un message entrant avant le routage de lâagent (rĂ©ponses synthĂ©tiques)message_receivedâ observer le contenu entrant, lâexpĂ©diteur, le fil et les mĂ©tadonnĂ©esmessage_sendingâ réécrire le contenu sortant ou annuler la livraisonreply_payload_sendingâ modifier ou annuler les charges utiles de rĂ©ponse normalisĂ©es avant la livraisonmessage_sentâ observer le succĂšs ou lâĂ©chec de la livraison sortantebefore_dispatch- inspecter ou réécrire une distribution sortante avant le transfert au canalreply_dispatch- participer au pipeline final de distribution de rĂ©ponse
Sessions et Compaction
session_start/session_end- suivre les limites du cycle de vie des sessions. Lereasonde lâĂ©vĂ©nement est lâun denew,reset,idle,daily,compaction,deleted,shutdown,restartouunknown. Les valeursshutdownetrestartse dĂ©clenchent depuis le finaliseur dâarrĂȘt du gateway lorsque le processus est arrĂȘtĂ© ou redĂ©marrĂ© alors que des sessions sont encore actives, afin que les plugins en aval (comme les magasins de mĂ©moire ou de transcriptions) puissent finaliser des lignes fantĂŽmes qui resteraient autrement dans un Ă©tat ouvert aprĂšs les redĂ©marrages. Le finaliseur est bornĂ© afin quâun plugin lent ne puisse pas bloquer SIGTERM/SIGINT.before_compaction/after_compaction- observer ou annoter les cycles de compactionbefore_reset- observer les Ă©vĂ©nements de rĂ©initialisation de session (/reset, rĂ©initialisations programmatiques)
Sous-agents
subagent_spawned/subagent_ended- observer le lancement et lâachĂšvement dâun sous-agent.subagent_delivery_target- hook de compatibilitĂ© pour la livraison dâachĂšvement lorsquâaucune liaison de session cĆur ne peut projeter une route.subagent_spawning- hook de compatibilitĂ© obsolĂšte. Le cĆur prĂ©pare dĂ©sormais les liaisons de sous-agentthread: truevia des adaptateurs de liaison de session de canal avant le dĂ©clenchement desubagent_spawned.subagent_spawnedinclutresolvedModeletresolvedProviderlorsquâOpenClaw a rĂ©solu le modĂšle natif de la session enfant avant le lancement.subagent_endedtransportetargetSessionKey(identitĂ© â cela correspond Ăsubagent_spawned.childSessionKey),targetKind("subagent"ou"acp"),reason,outcomeoptionnel ("ok","error","timeout","killed","reset"ou"deleted"),erroroptionnel,runId,endedAt,accountIdetsendFarewell. Il nâinclut pasagentIdnichildSessionKey; utiliseztargetSessionKeypour le corrĂ©ler Ă lâĂ©vĂ©nementsubagent_spawnedcorrespondant.
Cycle de vie
gateway_start/gateway_stop- dĂ©marrer ou arrĂȘter les services appartenant au plugin avec le Gatewaydeactivate- alias de compatibilitĂ© obsolĂšte pourgateway_stop; utilisezgateway_stopdans les nouveaux pluginscron_changed- observer les changements de cycle de vie Cron appartenant au gateway (ajoutĂ©, mis Ă jour, supprimĂ©, dĂ©marrĂ©, terminĂ©, planifiĂ©)before_install- inspecter le matĂ©riel dâinstallation de Skill ou de plugin prĂ©parĂ© depuis un runtime de plugin chargĂ©
Déboguer les hooks de runtime
Utilisez before_model_resolve lorsquâun plugin doit changer le fournisseur ou le modĂšle
pour un tour dâagent. Il sâexĂ©cute avant la rĂ©solution du modĂšle ; llm_output ne sâexĂ©cute quâaprĂšs
quâune tentative de modĂšle a produit une sortie dâassistant.
Pour prouver le modĂšle de session effectif, inspectez les enregistrements de runtime, puis
utilisez openclaw sessions ou les surfaces de session/statut du Gateway. Lors du débogage
des charges utiles de fournisseur, démarrez le Gateway avec --raw-stream et
--raw-stream-path <path> ; ces indicateurs écrivent les événements bruts de flux de modÚle dans un fichier jsonl.
Politique dâappel dâoutil
before_tool_call reçoit :
event.toolNameevent.paramsevent.toolKindetevent.toolInputKindoptionnels, discriminateurs faisant autoritĂ© cĂŽtĂ© hĂŽte pour les outils qui partagent intentionnellement des noms ; par exemple, les appelsexecexternes en mode code utilisenttoolKind: "code_mode_exec"et incluenttoolInputKind: "javascript" | "typescript"lorsque le langage dâentrĂ©e est connuevent.derivedPathsoptionnel, contenant des indications de chemins cibles dĂ©rivĂ©es par lâhĂŽte au mieux pour les enveloppes dâoutils bien connues telles queapply_patch; lorsquâils sont prĂ©sents, ces chemins peuvent ĂȘtre incomplets ou peuvent sur-approximer ce que lâoutil touchera rĂ©ellement (par exemple, avec des entrĂ©es mal formĂ©es ou partielles)event.runIdoptionnelevent.toolCallIdoptionnel- champs de contexte tels que
ctx.agentId,ctx.sessionKey,ctx.sessionId,ctx.runId,ctx.jobId(défini sur les exécutions pilotées par Cron),ctx.toolKind,ctx.toolInputKindetctx.tracede diagnostic
Il peut renvoyer :
type BeforeToolCallResult = { params?: Record<string, unknown>; block?: boolean; blockReason?: string; requireApproval?: { title: string; description: string; severity?: "info" | "warning" | "critical"; timeoutMs?: number; timeoutBehavior?: "allow" | "deny"; allowedDecisions?: Array<"allow-once" | "allow-always" | "deny">; pluginId?: string; onResolution?: ( decision: "allow-once" | "allow-always" | "deny" | "timeout" | "cancelled", ) => Promise<void> | void; };};Comportement de garde des hooks pour les hooks de cycle de vie typés :
block: trueest terminal et ignore les gestionnaires de prioritĂ© infĂ©rieure.block: falseest traitĂ© comme une absence de dĂ©cision.paramsréécrit les paramĂštres de lâoutil pour lâexĂ©cution.requireApprovalmet lâexĂ©cution de lâagent en pause et interroge lâutilisateur via les approbations de plugin. La commande/approvepeut approuver Ă la fois les approbations exec et les approbations de plugin. Dans les relais natifsPreToolUseen mode rapport du serveur dâapplication Codex, cela est diffĂ©rĂ© jusquâĂ la demande dâapprobation correspondante du serveur dâapplication ; consultez runtime du harnais Codex.- Un
block: truede prioritĂ© infĂ©rieure peut toujours bloquer aprĂšs quâun hook de prioritĂ© supĂ©rieure a demandĂ© une approbation. onResolutionreçoit la dĂ©cision dâapprobation rĂ©solue -allow-once,allow-always,deny,timeoutoucancelled.
Consultez demandes dâautorisations de Plugin pour
le routage des approbations, le comportement de décision et quand utiliser requireApproval au lieu
dâoutils optionnels ou dâapprobations exec.
Les plugins qui ont besoin dâune politique de niveau hĂŽte peuvent enregistrer des politiques dâoutils de confiance avec
api.registerTrustedToolPolicy(...). Celles-ci sâexĂ©cutent avant les hooks
before_tool_call ordinaires et avant les décisions de hook normales. Les politiques de confiance groupées
sâexĂ©cutent dâabord ; les politiques de confiance des plugins installĂ©s sâexĂ©cutent ensuite dans lâordre de chargement
des plugins ; les hooks before_tool_call ordinaires sâexĂ©cutent aprĂšs elles. Les plugins groupĂ©s conservent
le chemin de politique de confiance existant. Les plugins installĂ©s doivent ĂȘtre explicitement activĂ©s
et déclarer chaque identifiant de politique dans contracts.trustedToolPolicies ; les identifiants non déclarés
sont rejetĂ©s avant lâenregistrement. Les identifiants de politique sont limitĂ©s au plugin qui les enregistre,
de sorte que diffĂ©rents plugins peuvent rĂ©utiliser le mĂȘme identifiant local. Utilisez ce niveau uniquement
pour les garde-fous de confiance hĂŽte tels que la politique dâespace de travail, lâapplication de budgets ou
la sécurité des workflows réservés.
Hook dâenvironnement exec
resolve_exec_env permet aux plugins de fournir des variables dâenvironnement aux invocations de lâoutil exec
aprĂšs la construction de lâenvironnement exec de base et avant lâexĂ©cution de la
commande. Il reçoit :
event.sessionKeyevent.toolName, actuellement toujours"exec"event.host, lâun de"gateway","sandbox"ou"node"- champs de contexte tels que
ctx.agentId,ctx.sessionKey,ctx.messageProvideretctx.channelId
Renvoyez un Record<string, string> Ă fusionner dans lâenvironnement exec. Les gestionnaires
sâexĂ©cutent par ordre de prioritĂ©, et les rĂ©sultats des hooks ultĂ©rieurs remplacent les rĂ©sultats des hooks prĂ©cĂ©dents pour
la mĂȘme clĂ©.
La sortie du hook est filtrĂ©e par la stratĂ©gie des clĂ©s dâenvironnement dâexĂ©cution de lâhĂŽte avant
dâĂȘtre fusionnĂ©e. Les clĂ©s invalides, PATH et les clĂ©s dangereuses de
remplacement de lâhĂŽte telles que LD_*, DYLD_*, NODE_OPTIONS, les variables de proxy et les variables de remplacement TLS
sont supprimĂ©es. Lâenvironnement filtrĂ© du plugin est inclus dans les mĂ©tadonnĂ©es
dâapprobation/dâaudit du Gateway et transmis aux requĂȘtes dâexĂ©cution node-host.
Persistance des rĂ©sultats dâoutil
Les rĂ©sultats dâoutil peuvent inclure des details structurĂ©s pour le rendu dâinterface, les diagnostics,
le routage de mĂ©dias ou les mĂ©tadonnĂ©es appartenant au plugin. Traitez details comme des mĂ©tadonnĂ©es dâexĂ©cution,
pas comme du contenu de prompt :
- OpenClaw supprime
toolResult.detailsavant le rejeu fournisseur et lâentrĂ©e de Compaction afin que les mĂ©tadonnĂ©es ne deviennent pas du contexte de modĂšle. - Les entrĂ©es de session persistĂ©es conservent uniquement des
detailsbornĂ©s. Les dĂ©tails trop volumineux sont remplacĂ©s par un rĂ©sumĂ© compact etpersistedDetailsTruncated: true. tool_result_persistetbefore_message_writesâexĂ©cutent avant le plafond final de persistance. Les hooks doivent tout de mĂȘme garder lesdetailsrenvoyĂ©s petits et Ă©viter de placer du texte pertinent pour le prompt uniquement dansdetails; placez la sortie dâoutil visible par le modĂšle danscontent.
Hooks de prompt et de modĂšle
Utilisez les hooks spécifiques à la phase pour les nouveaux plugins :
before_model_resolve: reçoit uniquement le prompt courant et les mĂ©tadonnĂ©es des piĂšces jointes. RenvoyezproviderOverrideoumodelOverride.agent_turn_prepare: reçoit le prompt courant, les messages de session prĂ©parĂ©s et toutes les injections en file exactement une fois drainĂ©es pour cette session. RenvoyezprependContextouappendContext.before_prompt_build: reçoit le prompt courant et les messages de session. RenvoyezprependContext,appendContext,systemPrompt,prependSystemContextouappendSystemContext.heartbeat_prompt_contribution: sâexĂ©cute uniquement pour les tours Heartbeat et renvoieprependContextouappendContext. Il est destinĂ© aux moniteurs en arriĂšre-plan qui doivent rĂ©sumer lâĂ©tat courant sans modifier les tours initiĂ©s par lâutilisateur.
before_agent_start reste disponible pour compatibilité. Préférez les hooks explicites ci-dessus
afin que votre plugin ne dĂ©pende pas dâune phase combinĂ©e hĂ©ritĂ©e.
before_agent_run sâexĂ©cute aprĂšs la construction du prompt et avant toute entrĂ©e de modĂšle,
y compris le chargement dâimages local au prompt et lâobservation llm_input. Il reçoit
lâentrĂ©e utilisateur courante sous forme de prompt, plus lâhistorique de session chargĂ© dans messages
et le prompt systĂšme actif. Renvoyez { outcome: "block", reason, message? }
pour arrĂȘter lâexĂ©cution avant que le modĂšle puisse lire le prompt. reason est interne ;
message est le remplacement visible par lâutilisateur. Les seuls rĂ©sultats pris en charge sont
pass et block ; les formes de décision non prises en charge échouent en mode fermé.
Lorsquâune exĂ©cution est bloquĂ©e, OpenClaw stocke uniquement le texte de remplacement dans
message.content, plus des mĂ©tadonnĂ©es de blocage non sensibles telles que lâidentifiant du plugin
bloquant et lâhorodatage. Le texte utilisateur dâorigine nâest pas conservĂ© dans la transcription ni dans le contexte
futur. Les raisons internes de blocage sont traitées comme sensibles et exclues des charges utiles de
transcription, dâhistorique, de diffusion, de journalisation et de diagnostic. LâobservabilitĂ©
doit utiliser des champs assainis tels que lâidentifiant du bloqueur, le rĂ©sultat, lâhorodatage ou une catĂ©gorie
sûre.
before_agent_start et agent_end incluent event.runId quand OpenClaw peut
identifier lâexĂ©cution active. La mĂȘme valeur est Ă©galement disponible sur ctx.runId.
Les exĂ©cutions pilotĂ©es par Cron exposent aussi ctx.jobId (lâidentifiant de la tĂąche cron dâorigine) afin que
les hooks de plugin puissent limiter les métriques, effets de bord ou états à une tùche planifiée
spécifique.
Pour les exĂ©cutions issues dâun canal, ctx.channel et ctx.messageProvider identifient
la surface fournisseur telle que discord ou telegram, tandis que ctx.channelId est
lâidentifiant de cible de conversation quand OpenClaw peut en dĂ©duire un Ă partir de la clĂ© de session
ou des métadonnées de livraison.
Lorsque lâidentitĂ© de lâexpĂ©diteur est disponible, les contextes de hook dâagent incluent Ă©galement :
ctx.senderIdâ ID dâexpĂ©diteur limitĂ© au canal (par exemple Feishuopen_id, ID utilisateur Discord). RenseignĂ© lorsque lâexĂ©cution provient dâun message utilisateur avec des mĂ©tadonnĂ©es dâexpĂ©diteur connues.ctx.chatIdâ identifiant de conversation natif du transport (par exemple Feishuchat_id, Telegramchat_id). RenseignĂ© lorsque le canal dâorigine fournit un ID de conversation natif.ctx.channelContext.sender.idâ le mĂȘme ID dâexpĂ©diteur quectx.senderId, sous un objet appartenant au canal que les plugins peuvent Ă©tendre avec des champs propres au canal.ctx.channelContext.chat.idâ le mĂȘme ID de conversation quectx.chatId, sous un objet appartenant au canal que les plugins peuvent Ă©tendre avec des champs propres au canal.
Le cĆur dĂ©finit uniquement les champs id imbriquĂ©s. Les plugins de canal qui transmettent des mĂ©tadonnĂ©es
dâexpĂ©diteur ou de chat plus riches via lâassistant entrant peuvent augmenter
PluginHookChannelSenderContext ou PluginHookChannelChatContext depuis
openclaw/plugin-sdk/channel-inbound :
declare module "openclaw/plugin-sdk/channel-inbound" { interface PluginHookChannelSenderContext { unionId?: string; userId?: string; }}Les plugins de canal transmettent ces champs via lâassistant SDK entrant :
buildChannelInboundEventContext({ // ... channelContext: { sender: { id: senderOpenId, unionId, userId }, chat: { id: chatId }, },});Ces champs sont facultatifs et absents pour les exĂ©cutions dâorigine systĂšme (Heartbeat, cron, exec-event).
ctx.senderExternalId reste disponible comme champ déprécié de compatibilité source pour
les anciens plugins. Le cĆur ne le renseigne pas ; les nouvelles identitĂ©s dâexpĂ©diteur propres au canal
doivent rĂ©sider sous ctx.channelContext.sender via lâaugmentation de module.
agent_end est un hook dâobservation. Les chemins Gateway et de harnais persistant lâexĂ©cutent
en fire-and-forget aprÚs le tour, tandis que les chemins CLI ponctuels et de courte durée attendent la
promesse du hook avant le nettoyage du processus afin que les plugins approuvés puissent vider
lâobservabilitĂ© terminale ou capturer lâĂ©tat. LâexĂ©cuteur de hook applique un dĂ©lai dâexpiration de 30 secondes afin quâun
plugin bloqué ou un point de terminaison intégré ne puisse pas laisser la promesse du hook en attente
indĂ©finiment. Un dĂ©lai dâexpiration est journalisĂ© et OpenClaw continue ; il nâannule pas
le travail rĂ©seau appartenant au plugin, sauf si le plugin utilise aussi son propre signal dâabandon.
Utilisez model_call_started et model_call_ended pour la tĂ©lĂ©mĂ©trie dâappel fournisseur
qui ne doit pas recevoir de prompts bruts, dâhistorique, de rĂ©ponses, dâen-tĂȘtes, de corps de requĂȘte
ou dâID de requĂȘte fournisseur. Ces hooks incluent des mĂ©tadonnĂ©es stables telles que
runId, callId, provider, model, api/transport facultatifs, les champs terminaux
durationMs/outcome, et upstreamRequestIdHash quand OpenClaw peut dériver un
hachage bornĂ© dâID de requĂȘte fournisseur. Lorsque lâexĂ©cution a rĂ©solu les mĂ©tadonnĂ©es de fenĂȘtre de contexte,
lâĂ©vĂ©nement et le contexte du hook incluent aussi contextTokenBudget, le
budget effectif de tokens aprĂšs les plafonds de modĂšle/configuration/agent, ainsi que
contextWindowSource et contextWindowReferenceTokens quand un plafond inférieur a été
appliqué.
before_agent_finalize sâexĂ©cute uniquement lorsquâun harnais est sur le point dâaccepter une rĂ©ponse finale
naturelle de lâassistant. Ce nâest pas le chemin dâannulation /stop et il ne
sâexĂ©cute pas lorsque lâutilisateur abandonne un tour. Renvoyez { action: "revise", reason } pour demander
au harnais une passe de modÚle supplémentaire avant la finalisation, { action: "finalize", reason? } pour forcer la finalisation, ou omettez un résultat pour continuer.
Les hooks natifs Codex Stop sont relayés dans ce hook sous forme de décisions OpenClaw
before_agent_finalize.
Lors du renvoi de action: "revise", les plugins peuvent inclure des métadonnées retry pour rendre
la passe de modÚle supplémentaire bornée et sûre à rejouer :
type BeforeAgentFinalizeRetry = { instruction: string; idempotencyKey?: string; maxAttempts?: number;};instruction est ajouté à la raison de révision envoyée au harnais.
idempotencyKey permet Ă lâhĂŽte de compter les nouvelles tentatives pour la mĂȘme requĂȘte de plugin entre
des décisions de finalisation équivalentes, et maxAttempts plafonne le nombre de passes supplémentaires que
lâhĂŽte autorisera avant de poursuivre avec la rĂ©ponse finale naturelle.
Les plugins non intégrés qui ont besoin de hooks de conversation bruts (before_model_resolve,
before_agent_reply, llm_input, llm_output, before_agent_finalize,
agent_end ou before_agent_run) doivent définir :
{ "plugins": { "entries": { "my-plugin": { "hooks": { "allowConversationAccess": true } } } }}Les hooks qui modifient le prompt et les injections durables au tour suivant peuvent ĂȘtre dĂ©sactivĂ©s par plugin
avec plugins.entries.<id>.hooks.allowPromptInjection=false.
Extensions de session et injections au tour suivant
Les plugins de workflow peuvent persister un petit état de session compatible JSON avec
api.registerSessionExtension(...) et le mettre à jour via la méthode Gateway
sessions.pluginPatch. Les lignes de session projettent lâĂ©tat dâextension enregistrĂ©
via pluginExtensions, ce qui permet Ă Control UI et Ă dâautres clients de rendre
lâĂ©tat appartenant au plugin sans connaĂźtre les internes du plugin.
Utilisez api.enqueueNextTurnInjection(...) lorsquâun plugin a besoin quâun contexte durable
atteigne le prochain tour de modĂšle exactement une fois. OpenClaw draine les injections en file avant
les hooks de prompt, supprime les injections expirées et déduplique par idempotencyKey
par plugin. Câest le bon point dâintĂ©gration pour les reprises dâapprobation, les rĂ©sumĂ©s de stratĂ©gie,
les deltas de moniteur en arriĂšre-plan et les continuations de commande qui doivent ĂȘtre visibles par
le modĂšle au prochain tour mais ne doivent pas devenir du texte de prompt systĂšme permanent.
Les sĂ©mantiques de nettoyage font partie du contrat. Les rappels de nettoyage dâextension de session et
de cycle de vie dâexĂ©cution reçoivent reset, delete, disable ou
restart. LâhĂŽte supprime lâĂ©tat dâextension de session persistant du plugin propriĂ©taire
et les injections au tour suivant en attente pour reset/delete/disable ; restart conserve
lâĂ©tat de session durable tandis que les rappels de nettoyage permettent aux plugins de libĂ©rer les tĂąches
de planificateur, le contexte dâexĂ©cution et dâautres ressources hors bande de lâancienne gĂ©nĂ©ration
dâexĂ©cution.
Hooks de message
Utilisez les hooks de message pour le routage et la politique de livraison au niveau du canal :
message_received: observe le contenu entrant, lâexpĂ©diteur,threadId,messageId,senderId, la corrĂ©lation optionnelle dâexĂ©cution/session et les mĂ©tadonnĂ©es.message_sending: réécritcontentou renvoie{ cancel: true }.reply_payload_sending: réécrit les objetsReplyPayloadnormalisĂ©s (y comprispresentation,delivery, les rĂ©fĂ©rences mĂ©dia et le texte) ou renvoie{ cancel: true }.message_sent: observe la rĂ©ussite ou lâĂ©chec final.
Pour les réponses TTS uniquement audio, content peut contenir la transcription parlée masquée
mĂȘme lorsque la charge utile du canal nâa aucun texte/sous-titre visible. La réécriture de ce
content met uniquement Ă jour la transcription visible par le hook ; elle nâest pas rendue comme
sous-titre média.
Les événements reply_payload_sending peuvent inclure usageState, un instantané live
best-effort par tour du modĂšle/de lâutilisation/du contexte. La livraison durable, le rejeu rĂ©cupĂ©rĂ© et
les rĂ©ponses sans corrĂ©lation exacte dâexĂ©cution lâomettent.
Les contextes de hook de message exposent des champs de corrĂ©lation stables lorsquâils sont disponibles :
ctx.sessionKey, ctx.runId, ctx.messageId, ctx.senderId, ctx.trace,
ctx.traceId, ctx.spanId, ctx.parentSpanId et ctx.callDepth. Les contextes entrants
et before_dispatch exposent également des métadonnées de réponse lorsque le canal dispose
de données de message cité filtrées par visibilité : replyToId, replyToIdFull,
replyToBody, replyToSender et replyToIsQuote. Préférez ces champs de premiÚre classe
avant de lire les métadonnées héritées.
PrĂ©fĂ©rez les champs typĂ©s threadId et replyToId avant dâutiliser des mĂ©tadonnĂ©es
propres au canal.
RÚgles de décision :
message_sendingaveccancel: trueest terminal.message_sendingaveccancel: falseest traité comme une absence de décision.- Le
contentréécrit continue vers les points dâaccroche de prioritĂ© infĂ©rieure, sauf si un point dâaccroche ultĂ©rieur annule la livraison. reply_payload_sendingsâexĂ©cute aprĂšs la normalisation de la charge utile et avant la livraison par le canal, y compris pour les rĂ©ponses routĂ©es vers le canal dâorigine. Les gestionnaires sâexĂ©cutent sĂ©quentiellement et chaque gestionnaire voit la derniĂšre charge utile produite par les gestionnaires de prioritĂ© supĂ©rieure.- Les charges utiles
reply_payload_sendingnâexposent pas les marqueurs de confiance du runtime tels quetrustedLocalMedia; les plugins peuvent modifier la forme de la charge utile, mais ne peuvent pas accorder la confiance aux mĂ©dias locaux. message_sendingpeut renvoyercancelReasonet desmetadatabornĂ©es avec une annulation. Les nouvelles API du cycle de vie des messages exposent cela comme un rĂ©sultat de livraison supprimĂ©e avec la raisoncancelled_by_message_sending_hook; la livraison directe hĂ©ritĂ©e continue de renvoyer un tableau de rĂ©sultats vide par compatibilitĂ©.message_sentsert uniquement Ă lâobservation. Les Ă©checs de gestionnaire sont consignĂ©s et ne modifient pas le rĂ©sultat de livraison.
Points dâaccroche dâinstallation
Utilisez security.installPolicy pour les dĂ©cisions dâautorisation/blocage dĂ©tenues par lâopĂ©rateur. Cette
politique sâexĂ©cute depuis la configuration OpenClaw, couvre les chemins dâinstallation et de mise Ă jour de la CLI, et Ă©choue
en mode fermĂ© lorsquâelle est activĂ©e mais indisponible.
before_install est un point dâaccroche de cycle de vie du runtime de plugin. Il sâexĂ©cute aprĂšs
security.installPolicy uniquement dans le processus OpenClaw oĂč les points dâaccroche de plugin ont
dĂ©jĂ Ă©tĂ© chargĂ©s, comme les flux dâinstallation adossĂ©s au Gateway. Il est utile pour les
observations, avertissements et vĂ©rifications de compatibilitĂ© dĂ©tenus par les plugins, mais ce nâest pas la
principale frontiĂšre de sĂ©curitĂ© dâentreprise ou dâhĂŽte pour les installations. Le champ builtinScan
reste dans la charge utile de lâĂ©vĂ©nement par compatibilitĂ©, mais OpenClaw nâexĂ©cute plus
de blocage intĂ©grĂ© du code dangereux au moment de lâinstallation; il sâagit donc dâun rĂ©sultat ok
vide. Renvoyez des constats supplĂ©mentaires ou { block: true, blockReason } pour arrĂȘter
lâinstallation dans ce processus.
block: true est terminal. block: false est traité comme une absence de décision.
Les Ă©checs de gestionnaire bloquent lâinstallation en mode fermĂ©.
Cycle de vie du Gateway
Utilisez gateway_start pour les services de plugin qui ont besoin dâun Ă©tat dĂ©tenu par le Gateway. Le
contexte expose ctx.config, ctx.workspaceDir et ctx.getCron?.() pour
lâinspection et les mises Ă jour de cron. Utilisez gateway_stop pour nettoyer les
ressources de longue durée.
Ne vous appuyez pas sur le point dâaccroche interne gateway:startup pour les services de runtime
détenus par les plugins.
cron_changed se déclenche pour les événements de cycle de vie cron détenus par le gateway avec une charge utile
dâĂ©vĂ©nement typĂ©e couvrant les raisons added, updated, removed, started, finished
et scheduled. LâĂ©vĂ©nement transporte un instantanĂ© PluginHookGatewayCronJob
(incluant state.nextRunAtMs, state.lastRunStatus et
state.lastError lorsquâils sont prĂ©sents), ainsi quâun PluginHookGatewayCronDeliveryStatus
valant not-requested | delivered | not-delivered | unknown. Les événements de suppression
transportent toujours lâinstantanĂ© de la tĂąche supprimĂ©e afin que les planificateurs externes puissent
rĂ©concilier lâĂ©tat. Utilisez ctx.getCron?.() et ctx.config depuis le contexte
de runtime lors de la synchronisation de planificateurs de réveil externes, et gardez OpenClaw comme
source de vĂ©ritĂ© pour les vĂ©rifications dâĂ©chĂ©ance et lâexĂ©cution.
Dépréciations à venir
Quelques surfaces proches des points dâaccroche sont dĂ©prĂ©ciĂ©es, mais restent prises en charge. Migrez avant la prochaine version majeure :
- Enveloppes de canal en texte brut dans les gestionnaires
inbound_claimetmessage_received. LisezBodyForAgentet les blocs structurĂ©s de contexte utilisateur au lieu dâanalyser le texte dâenveloppe plat. Voir Enveloppes de canal en texte brut â BodyForAgent. before_agent_startreste disponible par compatibilitĂ©. Les nouveaux plugins doivent utiliserbefore_model_resolveetbefore_prompt_buildau lieu de la phase combinĂ©e.subagent_spawningreste disponible par compatibilitĂ© avec les anciens plugins, mais les nouveaux plugins ne doivent pas y renvoyer de routage de thread. Le cĆur prĂ©pare les liaisons de sous-agentthread: truevia des adaptateurs de liaison de session de canal avant le dĂ©clenchement desubagent_spawned.deactivatereste un alias de compatibilitĂ© de nettoyage dĂ©prĂ©ciĂ© jusquâaprĂšs le 2026-08-16. Les nouveaux plugins doivent utilisergateway_stop.onResolutiondansbefore_tool_callutilise dĂ©sormais lâunion typĂ©ePluginApprovalResolution(allow-once/allow-always/deny/timeout/cancelled) au lieu dâunstringlibre.
Pour la liste complÚte - enregistrement des capacités de mémoire, profil de raisonnement du fournisseur,
fournisseurs dâauthentification externes, types de dĂ©couverte de fournisseurs, accesseurs de runtime de tĂąche
et renommage command-auth â command-status - voir
Migration du Plugin SDK â DĂ©prĂ©ciations actives.
Associés
- Migration du Plugin SDK - dépréciations actives et calendrier de suppression
- Créer des plugins
- Vue dâensemble du Plugin SDK
- Points dâentrĂ©e des plugins
- Points dâaccroche internes
- Internes de lâarchitecture des plugins