Skip to main content
Skip to content

세션 수명 주기 후크

세션 수명 주기 후크를 사용하면 세션 시작 및 종료 이벤트에 응답할 수 있습니다. 이를 사용하여 다음을 수행합니다.

  • 세션이 시작될 때 컨텍스트 초기화
  • 세션이 종료되면 리소스 정리
  • 세션 메트릭 및 분석 추적
  • 동적으로 세션 동작 구성

세션 시작 후크

세션이 onSessionStart 시작될 때 후크가 호출됩니다(신규 또는 다시 시작).

후크 서명

코드 언어 navigation

TypeScript
type SessionStartHandler = (
  input: SessionStartHookInput,
  invocation: HookInvocation
) => Promise<SessionStartHookOutput | null | undefined>;

입력

FieldType설명
timestampnumber후크가 트리거될 때의 Unix 타임스탬프
cwdstring현재 작업 디렉터리
source
"startup"
|
"resume"
|
"new"
세션이 시작된 방법
initialPrompt정의되지 않은 문자열 |제공된 경우 초기 프롬프트

출력

FieldType설명
additionalContextstring세션 시작 시 추가할 컨텍스트
modifiedConfigobject세션 구성 재정의

예제

시작 시 프로젝트 컨텍스트 추가

코드 언어 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(),
      };
    },
  },
});

세션 재시작 처리

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

사용자 기본 설정 로드

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

세션 끝 후크

세션이 onSessionEnd 종료되면 후크가 호출됩니다.

독립 실행형 SDK 세션은 프롬프트 간에 활성 상태로 유지됩니다. 프롬프트를 완료해도 세션이 종료되지 않습니다. 종료 후크를 실행하려면 세션의 연결을 끊거나 해제합니다.

후크 서명

코드 언어 navigation

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

입력

FieldType설명
timestampnumber후크가 트리거될 때의 Unix 타임스탬프
cwdstring현재 작업 디렉터리
reasonstring세션이 종료된 이유(아래 참조)
finalMessage정의되지 않은 문자열 |세션의 마지막 메시지
error정의되지 않은 문자열 |오류로 인해 세션이 종료된 경우 오류 메시지

종료 이유

Reason설명
"complete"세션이 정상적으로 완료됨
"error"오류로 인해 세션이 종료됨
"abort"사용자 또는 코드에 의해 세션이 중단되었습니다.
"timeout"세션 시간이 초과됨
"user_exit"사용자가 세션을 명시적으로 종료했습니다.

출력

FieldType설명
suppressOutputboolean최종 세션 출력 표시 안 함
cleanupActionsstring[]수행할 정리 작업 목록
sessionSummarystring로깅/분석을 위한 세션 요약

예제

세션 메트릭 추적

코드 언어 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;
    },
  },
});

자원을 정리하세요

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

다시 시작에 대한 세션 상태 저장

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

로그 세션 요약

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

에이전트 중지 후크

에이전트 중지 후크는 최상위 에이전트가 자연스럽게 턴의 끝에 도달하면 실행됩니다. 이는 onSessionEnd와는 별개입니다: 세션은 계속 활성 상태로 유지되며, 후크는 다른 에이전트 턴을 요청할 수 있습니다.

언어핸들러
Node.js/ TypeScriptonAgentStop
Pythonon_agent_stop
GoOnAgentStop
.NETOnAgentStop
러스트on_agent_stop
JavasetOnAgentStop

입력

공용 멤버 이름은 각 언어의 대/소문자 규칙을 따릅니다.

MeaningNode.js/PythonGo/.NET러스트Java
에이전트가 중지된 이유(예: end_turnstopReasonStopReasonstop_reasongetStopReason()
디스크 내 세션 기록 경로transcriptPathTranscriptPathtranscript_pathgetTranscriptPath()
이전 블록 결정이 이미 이 계속 진행을 강제했는지 여부stopHookActiveStopHookActivestop_hook_activegetStopHookActive()

출력

에이전트를 중지할 출력을 반환하지 않습니다. 다른 사용자 메시지를 큐에 넣기 위해 블록 결정을 반환하고 계속합니다.

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

이 후크로 인해 이미 계속된 에이전트를 반복적으로 차단하지 않도록 위에 나열된 활성 중지 멤버를 사용합니다. 또한 런타임은 연속 블록 결정의 한도를 지정합니다.

모범 사례

  1. 빠르게 유지 onSessionStart - 사용자가 세션이 준비되기를 기다리고 있습니다.

  2. 모든 끝 이유 처리 - 세션이 완전히 종료된다고 가정하지 마세요. 오류 및 중단을 처리합니다.

  3. 리소스 정리 - 세션 중에 할당된 모든 리소스를 해제하는 데 사용합니다 onSessionEnd .

  4. 최소 상태 저장 - 세션 데이터를 추적하는 경우 경량으로 유지합니다.

  5. 정리 작업이 멱등성을 갖도록 하세요 - onSessionEnd 프로세스가 충돌하면 호출되지 않을 수 있습니다.

참고하십시오