Passer au contenu principal

Hooks de session

hooks permet d’injecter du code dans chaque étape du cycle de vie d’une session Copilot. Vous pouvez ainsi ajouter le contrôle d’exécution d’outils, le journal d’audit, l’enrichissement de prompts, la gestion d’erreurs, etc., sans toucher au cœur de l’implémentation.

Flux des hooks

Utilisation de base

use Revolution\Copilot\Contracts\CopilotSession;
use Revolution\Copilot\Facades\Copilot;
use Revolution\Copilot\Types\SessionHooks;
use Revolution\Copilot\Types\Hooks\ErrorOccurredHookInput;
use Revolution\Copilot\Types\Hooks\ErrorOccurredHookOutput;
use Revolution\Copilot\Types\Hooks\PostToolUseHookInput;
use Revolution\Copilot\Types\Hooks\PostToolUseHookOutput;
use Revolution\Copilot\Types\Hooks\PreToolUseHookInput;
use Revolution\Copilot\Types\Hooks\PreToolUseHookOutput;
use Revolution\Copilot\Types\Hooks\SessionEndHookInput;
use Revolution\Copilot\Types\Hooks\SessionEndHookOutput;
use Revolution\Copilot\Types\Hooks\SessionStartHookInput;
use Revolution\Copilot\Types\Hooks\SessionStartHookOutput;
use Revolution\Copilot\Types\Hooks\UserPromptSubmittedHookInput;
use Revolution\Copilot\Types\Hooks\UserPromptSubmittedHookOutput;

Copilot::start(function (CopilotSession $session) {
    $response = $session->sendAndWait(prompt: 'READMEの要点をまとめて');
    dump($response->content());
}, config: [
    'model' => 'gpt-5',
    'hooks' => new SessionHooks(
        onSessionStart: function (SessionStartHookInput $input): ?SessionStartHookOutput {
            return new SessionStartHookOutput(
                additionalContext: "Project root: {$input->cwd}",
            );
        },

        onUserPromptSubmitted: function (UserPromptSubmittedHookInput $input): ?UserPromptSubmittedHookOutput {
            if (str_starts_with($input->prompt, '/fix')) {
                return new UserPromptSubmittedHookOutput(
                    modifiedPrompt: '現在のエラーを修正して、変更点を要約して。',
                );
            }

            return null;
        },

        onPreToolUse: function (PreToolUseHookInput $input): ?PreToolUseHookOutput {
            $blocked = ['bash', 'shell', 'delete_file'];

            if (in_array($input->toolName, $blocked, true)) {
                return new PreToolUseHookOutput(
                    permissionDecision: 'deny',
                    permissionDecisionReason: "{$input->toolName} n'est pas autorisé dans cet environnement",
                );
            }

            return new PreToolUseHookOutput(permissionDecision: 'allow');
        },

        onPostToolUse: function (PostToolUseHookInput $input): ?PostToolUseHookOutput {
            if ($input->toolName === 'read_file') {
                return new PostToolUseHookOutput(
                    additionalContext: 'Si nécessaire, explorez les fichiers liés et comparez-les.',
                );
            }

            return null;
        },

        onErrorOccurred: function (ErrorOccurredHookInput $input): ?ErrorOccurredHookOutput {
            if ($input->errorContext === 'model_call' && $input->recoverable) {
                return new ErrorOccurredHookOutput(
                    errorHandling: 'retry',
                    retryCount: 2,
                    userNotification: 'Nouvelle tentative suite à une erreur temporaire du modèle.',
                );
            }

            return null;
        },

        onSessionEnd: function (SessionEndHookInput $input): ?SessionEndHookOutput {
            if ($input->reason !== 'complete') {
                return new SessionEndHookOutput(
                    sessionSummary: "Session ended with reason: {$input->reason}",
                );
            }

            return null;
        },
    ),
]);

Hooks disponibles

HookMoment de déclenchementUsages principaux
onSessionStartDébut de session (new / resume / startup)Injection de contexte initial, surcharge de configuration
onUserPromptSubmittedEnvoi d’un prompt utilisateurEnrichissement, expansion de templates, filtrage d’entrée
onPreToolUseAvant l’exécution d’un outilAutoriser/refuser/demander, modifier les arguments, masquer la sortie
onPostToolUseAprès l’exécution d’un outilModification du résultat, masquage d’infos sensibles, audit
onErrorOccurredEn cas d’erreur pendant la sessionRetry, notification, classification
onSessionEndFin de sessionNettoyage, métriques, résumé de fin
Renvoyer null maintient le comportement par défaut.

Cas d’usage typiques

1) Contrôle des permissions (Permission control)

  • Utilisez onPreToolUse en mode allow-list
  • Les opérations destructrices déclenchent une validation humaine via permissionDecision: 'ask'
  • Précisez la raison du refus avec permissionDecisionReason
  • Les noms d’outils candidats se trouvent dans la liste Outils (ex. view, glob, bash)

2) Audit / conformité

  • Combinez les hooks du cycle de vie pour collecter des événements d’audit
  • Persistez les données collectées par ID de session

3) Enrichissement du prompt

  • Ajoutez à additionalContext les infos projet (langage, framework, conventions) via onSessionStart
  • Développez les raccourcis (/fix, /test) dans onUserPromptSubmitted

4) Filtrage des résultats

  • Masquez les API keys / tokens / mots de passe dans onPostToolUse
  • Résumez les résultats trop longs et ne renvoyez le détail qu’à la demande

5) Récupération d’erreur

  • Dans onErrorOccurred, effectuez un retry uniquement si model_call et recoverable=true
  • En cas d’erreur non récupérable, notifiez brièvement l’utilisateur via userNotification

6) Métriques de session

  • Enregistrez l’heure de début dans onSessionStart
  • Incrémentez les compteurs dans onPreToolUse / onUserPromptSubmitted
  • Émettez la durée, le nombre d’outils et la raison de fin dans onSessionEnd

Types d’entrée / sortie des hooks

Entrée commune (BaseHookInput)

PropriétéTypeDescription
timestampintInstant de déclenchement du hook (Unix ms)
cwdstringRépertoire de travail courant

PreToolUseHookInput

PropriétéTypeDescription
toolNamestringNom de l’outil à exécuter
toolArgsmixedArguments prévus

PreToolUseHookOutput

PropriétéTypeDescription
permissionDecision?stringallow / deny / ask
permissionDecisionReason?stringRaison du refus/de la demande
modifiedArgsmixedArguments après modification
additionalContext?stringContexte supplémentaire
suppressOutput?boolMasquer la sortie de l’outil

PostToolUseHookInput

PropriétéTypeDescription
toolNamestringNom de l’outil exécuté
toolArgsmixedArguments utilisés
toolResultToolResultObject|arrayRésultat de l’outil

PostToolUseHookOutput

PropriétéTypeDescription
modifiedResultToolResultObject|array|nullRésultat modifié
additionalContext?stringContexte supplémentaire
suppressOutput?boolMasquer l’affichage du résultat

UserPromptSubmittedHookInput

PropriétéTypeDescription
promptstringPrompt saisi par l’utilisateur

UserPromptSubmittedHookOutput

PropriétéTypeDescription
modifiedPrompt?stringPrompt modifié
additionalContext?stringContexte complémentaire
suppressOutput?boolMasquer l’affichage de la réponse

SessionStartHookInput

PropriétéTypeDescription
sourcestringstartup / resume / new
initialPrompt?stringPrompt initial

SessionStartHookOutput

PropriétéTypeDescription
additionalContext?stringContexte initial de session
modifiedConfig?arraySurcharge partielle de la configuration de session

SessionEndHookInput

PropriétéTypeDescription
reasonstringcomplete / error / abort / timeout / user_exit
finalMessage?stringMessage final
error?stringErreur de fin

SessionEndHookOutput

PropriétéTypeDescription
suppressOutput?boolMasquer la sortie finale
cleanupActions?arrayInfos sur le nettoyage effectué
sessionSummary?stringRésumé de session

ErrorOccurredHookInput

PropriétéTypeDescription
errorstringMessage d’erreur
errorContext?stringParmi model_call / tool_execution / system / user_input
recoverableboolRécupérable ou non

ErrorOccurredHookOutput

PropriétéTypeDescription
suppressOutput?boolMasquer l’affichage de l’erreur
errorHandling?stringretry / skip / abort
retryCount?intNombre de tentatives
userNotification?stringNotification adressée à l’utilisateur

ToolResultObject

Objet standard représentant le résultat d’exécution d’un outil.
PropriétéTypeDescription
textResultForLlm?stringRésultat texte à transmettre au LLM
resultType?stringsuccess / failure / rejected / denied
resultForAssistant?arrayDonnées de résultat destinées à l’assistant

Bonnes pratiques

  1. N’exécutez pas trop de traitements synchrones lourds à l’intérieur des hooks. Passez à de l’asynchrone si nécessaire.
  2. Quand aucun changement n’est requis, renvoyez null pour laisser le comportement par défaut.
  3. Explicitez autant que possible permissionDecision.
  4. Ne masquez pas trop les erreurs critiques : conservez des chemins de log/notification.
  5. Gérez l’état par ID de session et nettoyez dans onSessionEnd.
Pour les dernières informations, consultez le dépôt GitHub.
Dernière modification le 13 juillet 2026