Hooks

Cette rubrique décrit comment utiliser des hooks pour exécuter du code personnalisé à des moments clés du cycle de vie de l’agent. Les hooks vous permettent d’intercepter les appels aux outils, d’auditer le comportement des agents, de faire respecter des politiques, d’injecter du contexte et de contrôler le flux d’exécution.

Comment fonctionnent les hooks

Les hooks suivent un processus en quatre étapes : un événement se déclenche, le SDK vérifie si une correspondance s’applique, il appelle votre rappel, puis votre rappel renvoie une décision qui contrôle la suite des opérations.

  1. L’agent déclenche un événement (par exemple, il s’agit d’appeler un outil).

  2. Le SDK vérifie chaque correspondance de hook enregistrée pour ce type d’événement.

  3. Si une correspondance correspond (ou n’a pas de modèle de correspondance, c’est-à-dire qu’elle correspond à tout), le SDK appelle les fonctions de rappel associées.

  4. Chaque rappel renvoie un objet de sortie qui peut autoriser, bloquer ou modifier l’opération.

Événements de hooks

Les événements suivants sont disponibles :

Événement

Lorsqu’il se déclenche

PreToolUse

Avant l’exécution d’un outil. Peut bloquer l’outil ou modifier son entrée.

PostToolUse

Après l’exécution réussie d’un outil. Peut injecter du contexte supplémentaire.

PostToolUseFailure

Après l’échec de l’exécution d’un outil.

UserPromptSubmit

Lorsque l’utilisateur envoie une invite. Peut injecter du contexte supplémentaire.

Stop

Lorsque l’agent est sur le point de s’arrêter. Peut injecter du contexte ou interrompre la session.

SubagentStart

Lorsqu’un sous-agent démarre.

SubagentStop

Lorsqu’un sous-agent est sur le point de s’arrêter.

PreCompact

Avant que la conversation ne soit compactée (résumée pour s’adapter à la fenêtre contextuelle).

Notification

Lorsque l’agent émet une notification.

PermissionRequest

Lorsqu’un contrôle d’autorisation d’outil se produit.

Configuration des hooks

Transmettez des hooks via l’option hooks lors de la création d’une session. Chaque événement de hook correspond à une liste de correspondances, et chaque correspondance contient une liste de fonctions de rappel.

import { createCortexCodeSession } from "cortex-code-agent-sdk";

const session = await createCortexCodeSession({
  cwd: process.cwd(),
  hooks: {
    PreToolUse: [
      {
        matcher: "Bash",
        hooks: [
          async (input, toolUseId, context) => {
            console.log("Bash command:", input.tool_input);
            return {};
          },
        ],
      },
    ],
  },
});

Correspondances

Chaque correspondance de hook présente trois champs :

Champ

Type

Description

matcher

string (facultatif)

Un modèle regex utilisé par les événements qui prennent en charge la correspondance. PreToolUse, PostToolUse et PermissionRequest correspondent au nom de l’outil. Notification correspond au type de notification. PreCompact correspond à la valeur de déclenchement ("auto" ou "manual"). S’il est omis, le hook se déclenche pour toutes les valeurs de cet événement.

hooks

Liste de rappels

Une ou plusieurs fonctions de rappel à exécuter lorsque la correspondance est établie.

timeout

number (facultatif)

Temps maximum en secondes pour tous les rappels de cette correspondance. La valeur par défaut est 60.

Le champ matcher accepte n’importe quel modèle regex valide. Par exemple :

  • "Bash" : ne correspond qu’à l’outil Bash

  • "Write|Edit" : correspond à Écrire ou Modifier

  • ".*" : correspond à tous les outils (équivalent à l’omission de la correspondance)

Entrées de rappel

Chaque rappel reçoit trois arguments :

Argument

Description

input

Un objet contenant des données spécifiques à l’événement. Tous les événements incluent session_id, transcript_path, cwd, permission_mode et hook_event_name. Les événements d’outil incluent également tool_name, tool_input et tool_use_id.

toolUseId / tool_use_id

L’ID d’utilisation de l’outil (pour les événements liés à l’outil) ou null.

context

Un objet de contexte. Réservé pour une utilisation future (par exemple, signaux d’annulation).

Les champs d’entrée varient selon l’événement :

Événement

Champs d’entrée supplémentaires

PreToolUse

tool_name, tool_input, tool_use_id

PostToolUse

tool_name, tool_input, tool_response, tool_use_id

PostToolUseFailure

tool_name, tool_input, tool_use_id, error, is_interrupt facultatif

UserPromptSubmit

prompt

Stop

stop_hook_active

SubagentStart

agent_id, agent_type

SubagentStop

stop_hook_active, agent_id, agent_transcript_path, agent_type

PreCompact

trigger ("manual" ou "auto"), custom_instructions

Notification

message, notification_type, title facultatif

PermissionRequest

tool_name, tool_input, permission_suggestions facultatif

Les hooks liés au cycle de vie des outils et PermissionRequest peuvent également inclure des champs agent_id et agent_type facultatifs lorsqu’ils sont déclenchés par un sous-agent.

Sorties de rappel

Les rappels renvoient un objet de sortie qui contrôle l’exécution. Les champs suivants sont disponibles :

Champ

Type

Description

continue / continue_

boolean

Indique si le traitement doit se poursuivre. Définissez ce champ sur false pour arrêter le traitement ultérieur pour le site de hook ou la boucle en cours. Par défaut : true.

stopReason

string

Message affiché lorsque continue est défini sur false.

decision

"block"

Définissez ce champ sur "block" pour bloquer l’opération en cours.

reason

string

Message de retour de l’agent concernant la décision.

systemMessage

string

Message d’avertissement affiché à l’utilisateur.

hookSpecificOutput

object

Contrôles spécifiques à l’événement (voir ci-dessous).

Note

Le SDK Python utilise continue_ (avec un trait de soulignement de fin) au lieu de continue afin d’éviter le conflit de mots clés Python. Le SDK le convertit automatiquement en continue lors de la communication avec la CLI.

Sorties spécifiques aux hooks

Le champ hookSpecificOutput accepte des contrôles spécifiques à l’événement :

PreToolUse

Champ

Description

permissionDecision

"allow", "deny" ou "ask". Contrôle si l’outil peut s’exécuter.

permissionDecisionReason

Motif de la décision d’autorisation.

updatedInput

Entrée d’outil modifiée à utiliser à la place de l’originale.

PostToolUse

Champ

Description

additionalContext

Contexte supplémentaire injecté dans la conversation après l’exécution de l’outil.

UserPromptSubmit

Champ

Description

additionalContext

Contexte supplémentaire injecté dans la conversation.

PermissionRequest

Champ

Description

decision.behavior

"allow" ou "deny". Contrôle le résultat de l’autorisation.

decision.message

Message affiché lorsque la demande d’autorisation est refusée.

Exemples

Bloquer les outils dangereux

Empêchez l’agent d’exécuter des commandes bash spécifiques :

import { createCortexCodeSession } from "cortex-code-agent-sdk";

const session = await createCortexCodeSession({
  cwd: process.cwd(),
  hooks: {
    PreToolUse: [
      {
        matcher: "Bash",
        hooks: [
          async (input) => {
            const command = (input.tool_input as any)?.command ?? "";
            if (command.includes("rm -rf") || command.includes("DROP TABLE")) {
              return {
                decision: "block",
                reason: "Destructive commands are not allowed",
              };
            }
            return {};
          },
        ],
      },
    ],
  },
});

Autoriser automatiquement les demandes d’autorisations en lecture seule

Autorisez les demandes d’autorisations pour les outils qui ne lisent que des données :

hooks: {
  PermissionRequest: [
    {
      matcher: "Read|Glob|Grep",
      hooks: [
        async (input) => {
          return {
            hookSpecificOutput: {
              hookEventName: "PermissionRequest",
              decision: { behavior: "allow" },
            },
          };
        },
      ],
    },
  ],
}

Modifier l’entrée d’outil

Ajoutez un délai d’expiration à toutes les commandes bash avant qu’elles ne s’exécutent :

hooks: {
  PreToolUse: [
    {
      matcher: "Bash",
      hooks: [
        async (input) => {
          const originalCommand = (input.tool_input as any)?.command ?? "";
          return {
            hookSpecificOutput: {
              hookEventName: "PreToolUse",
              updatedInput: { command: `timeout 30 ${originalCommand}` },
            },
          };
        },
      ],
    },
  ],
}

Journaliser les audits

Consignez tous les appels d’outils à des fins d’audit sans affecter l’exécution :

import { createCortexCodeSession } from "cortex-code-agent-sdk";
import { appendFileSync } from "node:fs";

const session = await createCortexCodeSession({
  cwd: process.cwd(),
  hooks: {
    PostToolUse: [
      {
        hooks: [
          async (input) => {
            const entry = {
              timestamp: new Date().toISOString(),
              tool: input.tool_name,
              input: input.tool_input,
              sessionId: input.session_id,
            };
            appendFileSync("audit.log", JSON.stringify(entry) + "\n");
            return {};
          },
        ],
      },
    ],
  },
});

Hooks vs. canUseTool

Les hooks et le rappel canUseTool peuvent intercepter les appels d’outils, mais ils servent à des fins différentes :

Fonctionnalité

canUseTool

Hooks

Portée

Contrôle des autorisations de pré-exécution uniquement

Plusieurs événements du cycle de vie (cycle de vie de l’outil, soumission immédiate, arrêt, cycle de vie du sous-agent, notification et compactage)

Événements

Un : demande d’autorisation

Dix : PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, UserPromptSubmit, Stop, SubagentStart, SubagentStop, Notification et PreCompact

Correspondance de modèles

Aucune prise en charge des correspondances. Appelée pour les demandes d’autorisations qui ne sont pas encore résolues par les listes de règles.

Oui (les correspondances de regex filtrent par nom d’outil, type de notification ou déclencheur de compactage, selon l’événement)

Modifier l’entrée

Limité. updatedInput est actuellement utilisé pour les pseudo-outils acheminés via le SDK, comme AskUserQuestion et ExitPlanMode.

Oui (hookSpecificOutput.updatedInput)

Mieux adapté à

Décisions simples d’autorisation et de refus

Journalisation des audits, injection de contexte, politiques complexes, actions post-exécution

Vous pouvez utiliser les deux ensemble. Le rappel canUseTool s’exécute dans le cadre du système d’autorisation de la CLI, tandis que les hooks PreToolUse s’exécutent séparément.