- 세션이 시작될 때 컨텍스트 초기화
- 세션이 종료되면 리소스 정리
- 세션 메트릭 및 분석 추적
- 동적으로 세션 동작 구성
세션 시작 후크 {#session-start}
세션이 onSessionStart 시작될 때 후크가 호출됩니다(신규 또는 다시 시작).
후크 서명
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>;
Python
from copilot.session import SessionStartHookInput, SessionStartHookOutput
from typing import Callable, Awaitable
SessionStartHandler = Callable[
[SessionStartHookInput, dict[str, str]],
Awaitable[SessionStartHookOutput | None]
]
SessionStartHandler = Callable[
[SessionStartHookInput, dict[str, str]],
Awaitable[SessionStartHookOutput | None]
]
Go
package main
import copilot "github.com/github/copilot-sdk/go"
type SessionStartHandler func(
input copilot.SessionStartHookInput,
invocation copilot.HookInvocation,
) (*copilot.SessionStartHookOutput, error)
func main() {}
type SessionStartHandler func(
input SessionStartHookInput,
invocation HookInvocation,
) (*SessionStartHookOutput, error)
.NET
using GitHub.Copilot;
public delegate Task<SessionStartHookOutput?> SessionStartHandler(
SessionStartHookInput input,
HookInvocation invocation);
public delegate Task<SessionStartHookOutput?> SessionStartHandler(
SessionStartHookInput input,
HookInvocation invocation);
Java
import com.github.copilot.sdk.json.*;
SessionStartHandler sessionStartHandler;
입력
| Field | Type | 설명 |
|---|---|---|
timestamp | number | 후크가 트리거될 때의 Unix 타임스탬프 |
cwd | string | 현재 작업 디렉터리 |
source | ||
"startup" | ||
| | | ||
"resume" | ||
| | | ||
"new" | ||
| 세션이 시작된 방법 | ||
initialPrompt | 정의되지 않은 문자열 | | 제공된 경우 초기 프롬프트 |
출력
| Field | Type | 설명 |
|---|---|---|
additionalContext | string | 세션 시작 시 추가할 컨텍스트 |
modifiedConfig | object | 세션 구성 재정의 |
예제
시작 시 프로젝트 컨텍스트 추가
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(),
};
},
},
});
Python
from copilot.session import PermissionHandler
async def on_session_start(input_data, invocation):
print(f"Session {invocation['session_id']} started ({input_data['source']})")
project_info = await detect_project_type(input_data["cwd"])
return {
"additionalContext": f"""
This is a {project_info['type']} project.
Main language: {project_info['language']}
Package manager: {project_info['packageManager']}
""".strip()
}
session = await client.create_session(on_permission_request=PermissionHandler.approve_all, hooks={"on_session_start": on_session_start})
세션 다시 시작 처리
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"),
};
},
},
});
세션 종료 후크 {#session-end}
세션이 onSessionEnd 종료되면 후크가 호출됩니다.
후크 서명
TypeScript
type SessionEndHandler = (
input: SessionEndHookInput,
invocation: HookInvocation
) => Promise<SessionEndHookOutput | null | undefined>;
Python
from copilot.session import SessionEndHookInput
from typing import Callable, Awaitable
SessionEndHandler = Callable[
[SessionEndHookInput, dict[str, str]],
Awaitable[None]
]
SessionEndHandler = Callable[
[SessionEndHookInput, dict[str, str]],
Awaitable[SessionEndHookOutput | None]
]
Go
package main
import copilot "github.com/github/copilot-sdk/go"
type SessionEndHandler func(
input copilot.SessionEndHookInput,
invocation copilot.HookInvocation,
) error
func main() {}
type SessionEndHandler func(
input SessionEndHookInput,
invocation HookInvocation,
) (*SessionEndHookOutput, error)
.NET
public delegate Task<SessionEndHookOutput?> SessionEndHandler(
SessionEndHookInput input,
HookInvocation invocation);
Java
import com.github.copilot.sdk.json.*;
SessionEndHandler sessionEndHandler;
입력
| Field | Type | 설명 |
|---|---|---|
timestamp | number | 후크가 트리거될 때의 Unix 타임스탬프 |
cwd | string | 현재 작업 디렉터리 |
reason | string | 세션이 종료된 이유(아래 참조) |
finalMessage | 정의되지 않은 문자열 | | 세션의 마지막 메시지 |
error | 정의되지 않은 문자열 | | 오류로 인해 세션이 종료된 경우 오류 메시지 |
종료 이유
| Reason | 설명 |
|---|---|
"complete" | 세션이 정상적으로 완료됨 |
"error" | 오류로 인해 세션이 종료됨 |
"abort" | 사용자 또는 코드에 의해 세션이 중단되었습니다. |
"timeout" | 세션 시간이 초과됨 |
"user_exit" | 사용자가 세션을 명시적으로 종료했습니다. |
출력
| Field | Type | 설명 |
|---|---|---|
suppressOutput | boolean | 최종 세션 출력 표시 안 함 |
cleanupActions | string[] | 수행할 정리 작업 목록 |
sessionSummary | string | 로깅/분석을 위한 세션 요약 |
예제
세션 메트릭 추적
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;
},
},
});
Python
from copilot.session import PermissionHandler
session_start_times = {}
async def on_session_start(input_data, invocation):
session_start_times[invocation["session_id"]] = input_data["timestamp"]
return None
async def on_session_end(input_data, invocation):
start_time = session_start_times.get(invocation["session_id"])
duration = input_data["timestamp"] - start_time if start_time else 0
await record_metrics({
"session_id": invocation["session_id"],
"duration": duration,
"end_reason": input_data["reason"],
})
session_start_times.pop(invocation["session_id"], None)
return None
session = await client.create_session(on_permission_request=PermissionHandler.approve_all, hooks={
"on_session_start": on_session_start,
"on_session_end": on_session_end,
})
자원을 정리하세요
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;
},
},
});
모범 사례
-
빠르게 유지
onSessionStart- 사용자가 세션이 준비되기를 기다리고 있습니다. -
모든 끝 이유 처리 - 세션이 완전히 종료된다고 가정하지 마세요. 오류 및 중단을 처리합니다.
-
리소스 정리 - 세션 중에 할당된 모든 리소스를 해제하는 데 사용합니다
onSessionEnd. -
최소 상태 저장 - 세션 데이터를 추적하는 경우 경량으로 유지합니다.
-
정리 작업이 멱등성을 갖도록 하세요 -
onSessionEnd프로세스가 충돌하면 호출되지 않을 수 있습니다.