Skip to main content

Session Lifecycle Hooks

Mit Sitzungslebenszyklus-Hooks können Sie auf Start- und Endereignisse der Sitzung reagieren. Verwenden Sie sie für:

  • Initialisieren des Kontexts, wenn Sitzungen beginnen
  • Bereinigen von Ressourcen beim Beenden von Sitzungen
  • Sitzungsmetriken und Analysen nachverfolgen
  • Dynamisches Konfigurieren des Sitzungsverhaltens

Sitzungsstart-Hook {#session-start}

Der onSessionStart Hook wird aufgerufen, wenn eine Sitzung beginnt (neu oder fortgesetzt).

Hook-Signatur

Codesprachen 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>;

Eingabe

FeldTypBeschreibung
timestampnumberUnix-Zeitstempel, zu dem der Hook ausgelöst wurde
cwdstringAktuelles Arbeitsverzeichnis
source
"startup"
|
"resume"
|
"new"
Wie die Sitzung gestartet wurde
initialPromptZeichenfolge | undefiniertDie anfängliche Eingabeaufforderung, falls angegeben

Output

FeldTypBeschreibung
additionalContextstringKontext zum Hinzufügen am Sitzungsstart
modifiedConfigObjektSitzungskonfiguration außer Kraft setzen

Beispiele

Projektkontext zu Beginn hinzufügen

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

Verwaltung der Sitzungswiederaufnahme

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

Laden von Benutzereinstellungen

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 für das Sitzungsende {#session-end}

Der onSessionEnd Hook wird aufgerufen, wenn eine Sitzung endet.

Hook-Signatur

Codesprachen navigation

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

Eingabe

FeldTypBeschreibung
timestampnumberUnix-Zeitstempel, zu dem der Hook ausgelöst wurde
cwdstringAktuelles Arbeitsverzeichnis
reasonstringWarum die Sitzung beendet wurde (siehe unten)
finalMessageZeichenfolge | undefiniertDie letzte Nachricht aus der Sitzung
errorZeichenfolge | undefiniertFehlermeldung, wenn die Sitzung aufgrund eines Fehlers beendet wurde

Endgründe

GrundBeschreibung
"complete"Die Sitzung wurde normal abgeschlossen.
"error"Sitzung aufgrund eines Fehlers beendet
"abort"Die Sitzung wurde durch den Benutzer oder durch Code abgebrochen.
"timeout"Timeout für die Sitzung
"user_exit"Der Benutzer hat die Sitzung explizit beendet.

Output

FeldTypBeschreibung
suppressOutputbooleanEndgültige Sitzungsausgabe unterdrücken
cleanupActionsstring[]Liste der auszuführenden Bereinigungsaktionen
sessionSummarystringZusammenfassung der Sitzung für Protokollierung/Analyse

Beispiele

Nachverfolgen von Sitzungsmetriken

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

Bereinigen von Ressourcen

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

Sitzungsstatus zum Fortsetzen speichern

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

Protokollsitzungszusammenfassung

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

Agent-Stopp-Hook {#agent-stop}

Der Agent-Stopp-Hook wird ausgeführt, wenn der Agent der obersten Ebene auf natürliche Weise das Ende einer Interaktion erreicht. Er ist getrennt von onSessionEnd: Die Sitzung bleibt aktiv, und der Hook kann einen weiteren Agent-Turn anfordern.

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

Eingabe

Die Namen der öffentlichen Mitglieder folgen den Groß-/Kleinschreibungskonventionen der einzelnen Sprachen:

BedeutungNode.js/PythonGehe zu /.NETRustJava
Warum der Agent gestoppt wurde, z. B. end_turnstopReasonStopReasonstop_reasongetStopReason()
Pfad zum Transkript der On-Disk-SitzungtranscriptPathTranscriptPathtranscript_pathgetTranscriptPath()
Gibt an, ob eine frühere Blockentscheidung diese Fortsetzung bereits erzwungen hatstopHookActiveStopHookActivestop_hook_activegetStopHookActive()

Output

Gibt keine Ausgabe zurück, damit der Agent beendet werden kann. Geben Sie eine Blockierentscheidung zurück, um eine weitere Benutzernachricht in die Warteschlange zu stellen und fortzufahren:

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

Verwenden Sie das oben angegebene Active-Stop-Element, um zu vermeiden, dass ein Agent, der aufgrund dieses Hooks bereits weitergelaufen ist, erneut blockiert wird. Die Laufzeit begrenzt auch aufeinander folgende Blockierungsentscheidungen.

Bewährte Methoden

  1. Sorgen Sie dafür, dass onSessionStart schnell bleibt – Die Benutzer warten darauf, dass die Sitzung einsatzbereit ist.

  2. Berücksichtigen Sie alle Gründe für die Beendigung – Gehen Sie nicht davon aus, dass Sitzungen immer ordnungsgemäß beendet werden; behandeln Sie auch Fehler und Abbrüche.

  3. Ressourcen freigeben – Verwenden Sie onSessionEnd, um alle während der Sitzung zugewiesenen Ressourcen freizugeben.

  4. Speichern Sie so wenig Status wie möglich - Wenn Sie Sitzungsdaten verfolgen, halten Sie sie so schlank wie möglich.

  5. Machen Sie die Bereinigung idempotent - onSessionEnd wird möglicherweise nicht aufgerufen, wenn der Prozess abstürzt.

Siehe auch