Skip to main content

Ganchos de ciclo de vida de sessão

Os ganchos de ciclo de vida da sessão permitem que você responda aos eventos de início e término da sessão. Use-os para:

  • Inicialize o contexto quando as sessões começarem
  • Limpar recursos quando as sessões terminarem
  • Acompanhar as métricas e análises da sessão
  • Configurar o comportamento da sessão dinamicamente

Gancho de início da sessão {#session-start}

O onSessionStart gancho é chamado quando uma sessão é iniciada (nova ou retomada).

Assinatura de Hook

Idiomas de código 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>;

Entrada

CampoTipoDescrição
timestampnumberCarimbo de data/hora Unix de quando o gancho foi desencadeado
cwdcadeiaDiretório de trabalho atual
source
"startup"
|
"resume"
|
"new"
Como a sessão foi iniciada
initialPromptcadeia de caracteres | indefinidaO prompt inicial, se fornecido

Saída

CampoTipoDescrição
additionalContextcadeiaContexto a ser adicionado no início da sessão
modifiedConfigobjetoSobrepor configuração de sessão

Exemplos

Adicionar contexto de projeto no início

Idiomas de código 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(),
      };
    },
  },
});

Lidar com a retomada de sessão

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;
    },
  },
});

Carregar preferências do usuário

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"),
      };
    },
  },
});

Gancho de fim de sessão {#session-end}

O onSessionEnd gancho é invocado quando uma sessão termina.

Assinatura de Hook

Idiomas de código navigation

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

Entrada

CampoTipoDescrição
timestampnumberCarimbo de data/hora Unix de quando o gancho foi desencadeado
cwdcadeiaDiretório de trabalho atual
reasoncadeiaPor que a sessão terminou (veja abaixo)
finalMessagecadeia de caracteres | indefinidaA última mensagem da sessão
errorcadeia de caracteres | indefinidaMensagem de erro se a sessão terminou devido a um erro

Motivos finais

ReasonDescrição
"complete"Sessão concluída normalmente
"error"Sessão encerrada devido a um erro
"abort"A sessão foi abortada pelo usuário ou pelo código.
"timeout"Sessão expirada
"user_exit"O usuário encerrou explicitamente a sessão

Saída

CampoTipoDescrição
suppressOutputbooleanSuprimir a saída final da sessão
cleanupActionsstring[]Lista de ações de limpeza a serem executadas
sessionSummarycadeiaResumo da sessão para registro/análise de dados

Exemplos

Acompanhar métricas de sessão

Idiomas de código 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;
    },
  },
});

Limpar os recursos

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;
    },
  },
});

Salvar o estado da sessão para retomar

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;
    },
  },
});

Resumo da sessão de log

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;
    },
  },
});

Gancho de parada do agente {#agent-stop}

O gancho de parada do agente é executado quando o agente de nível superior naturalmente atinge o final de uma curva. Ela é separada de onSessionEnd: a sessão permanece ativa e o gancho pode solicitar a volta de outro agente.

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

Entrada

Os nomes de membro público seguem as convenções de maiúsculas e minúsculas de cada idioma:

MeaningNode.js/PythonIr/.NETRustJava
Por que o agente parou, como end_turnstopReasonStopReasonstop_reasongetStopReason()
Caminho para a transcrição da sessão no discotranscriptPathTranscriptPathtranscript_pathgetTranscriptPath()
Se uma decisão de bloco anterior já forçou essa continuaçãostopHookActiveStopHookActivestop_hook_activegetStopHookActive()

Saída

Não retorne nenhuma saída para deixar o agente parar. Retorne uma decisão de bloco para enfileirar outra mensagem do usuário e continuar:

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

Use o membro de parada ativa listado acima para evitar bloquear repetidamente um agente que já tenha continuado devido a esse gancho. O runtime também limita as decisões de bloco consecutivas.

Práticas recomendadas

  1. Mantenha onSessionStart rápido – os usuários estão aguardando a sessão ficar pronta.

  2. Trate todos os motivos de encerramento – não presuma que as sessões se encerrem sem problemas; trate erros e abortos.

  3. Limpar recursos – Use onSessionEnd para liberar todos os recursos alocados durante a sessão.

  4. Armazenar o estado mínimo – se estiver acompanhando os dados da sessão, mantenha-os leves.

  5. Tornar a limpeza idempotente - onSessionEnd pode não ser chamado se o processo falhar.

Consulte também