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 :

typescript
 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 :

json
{  "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 session
  • agent_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 prompt
  • before_prompt_build - ajouter du contexte dynamique ou du texte de prompt systĂšme avant l’appel au modĂšle
  • before_agent_start - phase combinĂ©e uniquement pour compatibilitĂ© ; prĂ©fĂ©rez les deux hooks ci-dessus
  • before_agent_run - inspecter le prompt final et les messages de session avant l’envoi au modĂšle, et Ă©ventuellement bloquer l’exĂ©cution
  • before_agent_reply - court-circuiter le tour du modĂšle avec une rĂ©ponse synthĂ©tique ou le silence
  • before_agent_finalize - inspecter la rĂ©ponse finale naturelle et demander un passage de modĂšle supplĂ©mentaire
  • agent_end - observer les messages finaux, l’état de succĂšs et la durĂ©e d’exĂ©cution
  • heartbeat_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Ă©ponse
  • llm_input - observer l’entrĂ©e du fournisseur (prompt systĂšme, prompt, historique)
  • llm_output - observer la sortie du fournisseur, l’utilisation et le contextTokenBudget rĂ©solu lorsqu’il est disponible

Outils

  • before_tool_call - réécrire les paramĂštres d’outil, bloquer l’exĂ©cution ou demander une approbation
  • after_tool_call - observer les rĂ©sultats d’outils, les erreurs et la durĂ©e
  • resolve_exec_env - fournir des variables d’environnement appartenant au plugin Ă  exec
  • tool_result_persist - réécrire le message de l’assistant produit Ă  partir d’un rĂ©sultat d’outil
  • before_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Ă©es
  • message_sending — réécrire le contenu sortant ou annuler la livraison
  • reply_payload_sending — modifier ou annuler les charges utiles de rĂ©ponse normalisĂ©es avant la livraison
  • message_sent — observer le succĂšs ou l’échec de la livraison sortante
  • before_dispatch - inspecter ou réécrire une distribution sortante avant le transfert au canal
  • reply_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. Le reason de l’évĂ©nement est l’un de new, reset, idle, daily, compaction, deleted, shutdown, restart ou unknown. Les valeurs shutdown et restart se 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 compaction
  • before_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-agent thread: true via des adaptateurs de liaison de session de canal avant le dĂ©clenchement de subagent_spawned.
  • subagent_spawned inclut resolvedModel et resolvedProvider lorsqu’OpenClaw a rĂ©solu le modĂšle natif de la session enfant avant le lancement.
  • subagent_ended transporte targetSessionKey (identitĂ© — cela correspond Ă  subagent_spawned.childSessionKey), targetKind ("subagent" ou "acp"), reason, outcome optionnel ("ok", "error", "timeout", "killed", "reset" ou "deleted"), error optionnel, runId, endedAt, accountId et sendFarewell. Il n’inclut pas agentId ni childSessionKey ; utilisez targetSessionKey pour le corrĂ©ler Ă  l’évĂ©nement subagent_spawned correspondant.

Cycle de vie

  • gateway_start / gateway_stop - dĂ©marrer ou arrĂȘter les services appartenant au plugin avec le Gateway
  • deactivate - alias de compatibilitĂ© obsolĂšte pour gateway_stop ; utilisez gateway_stop dans les nouveaux plugins
  • cron_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.toolName
  • event.params
  • event.toolKind et event.toolInputKind optionnels, discriminateurs faisant autoritĂ© cĂŽtĂ© hĂŽte pour les outils qui partagent intentionnellement des noms ; par exemple, les appels exec externes en mode code utilisent toolKind: "code_mode_exec" et incluent toolInputKind: "javascript" | "typescript" lorsque le langage d’entrĂ©e est connu
  • event.derivedPaths optionnel, contenant des indications de chemins cibles dĂ©rivĂ©es par l’hĂŽte au mieux pour les enveloppes d’outils bien connues telles que apply_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.runId optionnel
  • event.toolCallId optionnel
  • 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.toolInputKind et ctx.trace de diagnostic

Il peut renvoyer :

typescript
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: true est terminal et ignore les gestionnaires de prioritĂ© infĂ©rieure.
  • block: false est traitĂ© comme une absence de dĂ©cision.
  • params réécrit les paramĂštres de l’outil pour l’exĂ©cution.
  • requireApproval met l’exĂ©cution de l’agent en pause et interroge l’utilisateur via les approbations de plugin. La commande /approve peut approuver Ă  la fois les approbations exec et les approbations de plugin. Dans les relais natifs PreToolUse en 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: true de prioritĂ© infĂ©rieure peut toujours bloquer aprĂšs qu’un hook de prioritĂ© supĂ©rieure a demandĂ© une approbation.
  • onResolution reçoit la dĂ©cision d’approbation rĂ©solue - allow-once, allow-always, deny, timeout ou cancelled.

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.sessionKey
  • event.toolName, actuellement toujours "exec"
  • event.host, l’un de "gateway", "sandbox" ou "node"
  • champs de contexte tels que ctx.agentId, ctx.sessionKey, ctx.messageProvider et ctx.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.details avant 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 details bornĂ©s. Les dĂ©tails trop volumineux sont remplacĂ©s par un rĂ©sumĂ© compact et persistedDetailsTruncated: true.
  • tool_result_persist et before_message_write s’exĂ©cutent avant le plafond final de persistance. Les hooks doivent tout de mĂȘme garder les details renvoyĂ©s petits et Ă©viter de placer du texte pertinent pour le prompt uniquement dans details ; placez la sortie d’outil visible par le modĂšle dans content.

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. Renvoyez providerOverride ou modelOverride.
  • 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. Renvoyez prependContext ou appendContext.
  • before_prompt_build : reçoit le prompt courant et les messages de session. Renvoyez prependContext, appendContext, systemPrompt, prependSystemContext ou appendSystemContext.
  • heartbeat_prompt_contribution : s’exĂ©cute uniquement pour les tours Heartbeat et renvoie prependContext ou appendContext. 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 Feishu open_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 Feishu chat_id, Telegram chat_id). RenseignĂ© lorsque le canal d’origine fournit un ID de conversation natif.
  • ctx.channelContext.sender.id — le mĂȘme ID d’expĂ©diteur que ctx.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 que ctx.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 :

ts
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 :

ts
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 :

typescript
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 :

json
{  "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éécrit content ou renvoie { cancel: true }.
  • reply_payload_sending : réécrit les objets ReplyPayload normalisĂ©s (y compris presentation, 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_sending avec cancel: true est terminal.
  • message_sending avec cancel: false est traitĂ© comme une absence de dĂ©cision.
  • Le content réécrit continue vers les points d’accroche de prioritĂ© infĂ©rieure, sauf si un point d’accroche ultĂ©rieur annule la livraison.
  • reply_payload_sending s’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_sending n’exposent pas les marqueurs de confiance du runtime tels que trustedLocalMedia; les plugins peuvent modifier la forme de la charge utile, mais ne peuvent pas accorder la confiance aux mĂ©dias locaux.
  • message_sending peut renvoyer cancelReason et des metadata bornĂ©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 raison cancelled_by_message_sending_hook; la livraison directe hĂ©ritĂ©e continue de renvoyer un tableau de rĂ©sultats vide par compatibilitĂ©.
  • message_sent sert 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_claim et message_received. Lisez BodyForAgent et 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_start reste disponible par compatibilitĂ©. Les nouveaux plugins doivent utiliser before_model_resolve et before_prompt_build au lieu de la phase combinĂ©e.
  • subagent_spawning reste 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-agent thread: true via des adaptateurs de liaison de session de canal avant le dĂ©clenchement de subagent_spawned.
  • deactivate reste un alias de compatibilitĂ© de nettoyage dĂ©prĂ©ciĂ© jusqu’aprĂšs le 2026-08-16. Les nouveaux plugins doivent utiliser gateway_stop.
  • onResolution dans before_tool_call utilise dĂ©sormais l’union typĂ©e PluginApprovalResolution (allow-once / allow-always / deny / timeout / cancelled) au lieu d’un string libre.

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

Was this useful?
On this page

On this page