Skip to main content

Hooks du cycle de vie de la session

Les hooks de cycle de vie de session vous permettent de répondre aux événements de début et de fin de session. Utilisez-les pour :

  • Initialiser le contexte lorsque les sessions commencent
  • Nettoyer les ressources lorsque les sessions se terminent
  • Suivre les métriques de session et l'analyse
  • Configurer dynamiquement le comportement de session

Point d’ancrage de début de session {#session-start}

Le onSessionStart hook est appelé lorsqu’une session commence (nouvelle ou reprise).

Signature du hook

Langages de code navigation

TypeScript
import type { SessionStartHookInput, HookInvocation, SessionStartHookOutput } from "@github/copilot-sdk";
type SessionStartHandler = (
  input: SessionStartHookInput,
  invocation: HookInvocation
) => Promise<SessionStartHookOutput | null | undefined>;
type SessionStartHandler = (
  input: SessionStartHookInput,
  invocation: HookInvocation
) => Promise<SessionStartHookOutput | null | undefined>;

Input

ChampCatégorieDescription
timestampnumberHorodatage Unix lorsque le hook a été déclenché
cwdstringRépertoire de travail actuel
source
"startup"
|
"resume"
|
"new"
Démarrage de la session
initialPromptchaîne | non définieInvitation initiale si disponible

Sortie

ChampCatégorieDescription
additionalContextstringContexte à ajouter au démarrage de la session
modifiedConfigObjetRemplacer la configuration de session

Exemples

Ajouter un contexte de projet au début

Langages de code navigation

TypeScript
const session = await client.createSession({
  hooks: {
    onSessionStart: async (input, invocation) => {
      console.log(`Session ${invocation.sessionId} started (${input.source})`);
      
      const projectInfo = await detectProjectType(input.cwd);
      
      return {
        additionalContext: `
This is a ${projectInfo.type} project.
Main language: ${projectInfo.language}
Package manager: ${projectInfo.packageManager}
        `.trim(),
      };
    },
  },
});

Gérer la reprise de session

const session = await client.createSession({
  hooks: {
    onSessionStart: async (input, invocation) => {
      if (input.source === "resume") {
        // Load previous session state
        const previousState = await loadSessionState(invocation.sessionId);
        
        return {
          additionalContext: `
Session resumed. Previous context:
- Last topic: ${previousState.lastTopic}
- Open files: ${previousState.openFiles.join(", ")}
          `.trim(),
        };
      }
      return null;
    },
  },
});

Charger les préférences utilisateur

const session = await client.createSession({
  hooks: {
    onSessionStart: async () => {
      const preferences = await loadUserPreferences();
      
      const contextParts = [];
      
      if (preferences.language) {
        contextParts.push(`Preferred language: ${preferences.language}`);
      }
      if (preferences.codeStyle) {
        contextParts.push(`Code style: ${preferences.codeStyle}`);
      }
      if (preferences.verbosity === "concise") {
        contextParts.push("Keep responses brief and to the point.");
      }
      
      return {
        additionalContext: contextParts.join("\n"),
      };
    },
  },
});

Hook de fin de session {#session-end}

Le onSessionEnd hook est appelé lorsqu’une session se termine.

Signature du hook

Langages de code navigation

TypeScript
type SessionEndHandler = (
  input: SessionEndHookInput,
  invocation: HookInvocation
) => Promise<SessionEndHookOutput | null | undefined>;

Input

ChampCatégorieDescription
timestampnumberHorodatage Unix lorsque le hook a été déclenché
cwdstringRépertoire de travail actuel
reasonstringPourquoi la session s’est terminée (voir ci-dessous)
finalMessagechaîne | non définieDernier message de la session
errorchaîne | non définieMessage d’erreur si la session s’est terminée en raison d’une erreur

Raisons de fin

ReasonDescription
"complete"Session terminée normalement
"error"Session terminée en raison d’une erreur
"abort"La session a été abandonnée par l’utilisateur ou le code
"timeout"La session a expiré
"user_exit"L’utilisateur a explicitement terminé la session

Sortie

ChampCatégorieDescription
suppressOutputbooléen**
Masquer la sortie finale de session
cleanupActionschaîne de caractères[]Liste des actions de nettoyage à effectuer
sessionSummarystringRésumé de la session pour la journalisation des événements et les analyses

Exemples

Suivre les métriques de session

Langages de code navigation

TypeScript
const sessionStartTimes = new Map<string, number>();

const session = await client.createSession({
  hooks: {
    onSessionStart: async (input, invocation) => {
      sessionStartTimes.set(invocation.sessionId, input.timestamp);
      return null;
    },
    onSessionEnd: async (input, invocation) => {
      const startTime = sessionStartTimes.get(invocation.sessionId);
      const duration = startTime ? input.timestamp - startTime : 0;
      
      await recordMetrics({
        sessionId: invocation.sessionId,
        duration,
        endReason: input.reason,
      });
      
      sessionStartTimes.delete(invocation.sessionId);
      return null;
    },
  },
});

Nettoyer les ressources

const sessionResources = new Map<string, { tempFiles: string[] }>();

const session = await client.createSession({
  hooks: {
    onSessionStart: async (input, invocation) => {
      sessionResources.set(invocation.sessionId, { tempFiles: [] });
      return null;
    },
    onSessionEnd: async (input, invocation) => {
      const resources = sessionResources.get(invocation.sessionId);
      
      if (resources) {
        // Clean up temp files
        for (const file of resources.tempFiles) {
          await fs.unlink(file).catch(() => {});
        }
        sessionResources.delete(invocation.sessionId);
      }
      
      console.log(`Session ${invocation.sessionId} ended: ${input.reason}`);
      return null;
    },
  },
});

Enregistrer l’état de session pour reprendre

const session = await client.createSession({
  hooks: {
    onSessionEnd: async (input, invocation) => {
      if (input.reason !== "error") {
        // Save state for potential resume
        await saveSessionState(invocation.sessionId, {
          endTime: input.timestamp,
          cwd: input.cwd,
          reason: input.reason,
        });
      }
      return null;
    },
  },
});

Résumé de la session de journalisation

const sessionData: Record<string, { prompts: number; tools: number; startTime: number }> = {};

const session = await client.createSession({
  hooks: {
    onSessionStart: async (input, invocation) => {
      sessionData[invocation.sessionId] = { 
        prompts: 0, 
        tools: 0, 
        startTime: input.timestamp 
      };
      return null;
    },
    onUserPromptSubmitted: async (_, invocation) => {
      sessionData[invocation.sessionId].prompts++;
      return null;
    },
    onPreToolUse: async (_, invocation) => {
      sessionData[invocation.sessionId].tools++;
      return { permissionDecision: "allow" };
    },
    onSessionEnd: async (input, invocation) => {
      const data = sessionData[invocation.sessionId];
      console.log(`
Session Summary:
  ID: ${invocation.sessionId}
  Duration: ${(input.timestamp - data.startTime) / 1000}s
  Prompts: ${data.prompts}
  Tool calls: ${data.tools}
  End reason: ${input.reason}
      `.trim());
      
      delete sessionData[invocation.sessionId];
      return null;
    },
  },
});

Crochet d’arrêt de l’agent {#agent-stop}

Le crochet d’arrêt de l’agent s’exécute lorsque l’agent de niveau supérieur atteint naturellement la fin d’un tour. Il est distinct de onSessionEnd: la session reste active et le hook peut demander un autre tour d’agent.

LanguageGestionnaire
Node.js / TypeScriptonAgentStop
Pythonon_agent_stop
GoOnAgentStop
.NETOnAgentStop
Ruston_agent_stop
JavasetOnAgentStop

Input

Les noms des membres publics suivent les conventions de casse de chaque langue :

SensNode.js / PythonGo / .NETRustJava
Pourquoi l’agent s’est arrêté, par exemple end_turnstopReasonStopReasonstop_reasongetStopReason()
Chemin d’accès à la transcription de session sur disquetranscriptPathTranscriptPathtranscript_pathgetTranscriptPath()
Si une décision de bloc antérieure a déjà forcé cette continuationstopHookActiveStopHookActivestop_hook_activegetStopHookActive()

Sortie

Retournez aucune sortie pour laisser l’agent s’arrêter. Renvoyer une décision de bloc pour mettre un autre message utilisateur en file d’attente et continuer :

{
  "decision": "block",
  "reason": "Run the final validation and fix any failures."
}

Utilisez le membre actif-stop listé ci-dessus pour éviter de bloquer à plusieurs reprises un agent qui a déjà continué en raison de ce crochet. Le runtime limite également les décisions de bloc consécutives.

Bonnes pratiques

  1. Assurez onSessionStart la rapidité - Les utilisateurs attendent que la session soit prête.

  2. Gérer toutes les raisons de fin - Ne partez pas du principe que les sessions se terminent correctement ; gérer les erreurs et les abandons.

  3. Libérer les ressources - Utilisez onSessionEnd pour libérer les ressources allouées pendant la session.

  4. Stocker un état minimal : si vous effectuez le suivi des données de session, veillez à les limiter au strict nécessaire.

  5. Rendez le nettoyage idempotent - onSessionEnd peut ne pas être appelé si le processus se bloque.

Voir aussi