Skip to main content

セッションライフサイクルフック

セッション ライフサイクル フックを使用すると、セッションの開始イベントと終了イベントに応答できます。 次の場合に使用します。

  • セッションの開始時にコンテキストを初期化する
  • セッションの終了時にリソースをクリーンアップする
  • セッション メトリックと分析を追跡する
  • セッション動作を動的に構成する

セッション開始フック {#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;

入力

フィールドタイプ説明
timestampnumberフックがトリガーされたときの Unix タイムスタンプ
cwd文字列現在の作業ディレクトリ
source
"startup"
|
"resume"
|
"new"
セッションの開始方法
initialPrompt文字列 | 未定義最初のプロンプト (指定されている場合)

アウトプット

フィールドタイプ説明
additionalContext文字列セッション開始時に追加するコンテキスト
modifiedConfigオブジェクトセッション構成をオーバーライドする

Examples

開始時にプロジェクト コンテキストを追加する

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;

入力

フィールドタイプ説明
timestampnumberフックがトリガーされたときの Unix タイムスタンプ
cwd文字列現在の作業ディレクトリ
reason文字列セッションが終了した理由 (下記参照)
finalMessage文字列 | 未定義セッションからの最後のメッセージ
error文字列 | 未定義エラーが原因でセッションが終了した場合のエラー メッセージ

終了の理由

理由説明
"complete"セッションが正常に完了しました
"error"エラーが原因でセッションが終了しました
"abort"ユーザーまたはコードによってセッションが中止されました
"timeout"セッションがタイムアウトしました
"user_exit"ユーザーがセッションを明示的に終了した

アウトプット

フィールドタイプ説明
suppressOutputboolean最後のセッション出力を抑制する
cleanupActionsstring[]実行するクリーンアップ アクションの一覧
sessionSummary文字列ログ記録/分析のセッションの概要

Examples

セッション メトリックを追跡する

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

ベスト プラクティス

  1. ** onSessionStart を高速に保つ** - ユーザーはセッションの準備が整うのを待っています。

  2. すべての終了理由を処理する - セッションが正常に終了することを想定しないでください。エラーと中止を処理します。

  3. リソースのクリーンアップ - onSessionEnd を使用して、セッション中に割り当てられたリソースを解放します。

  4. 最小状態を格納 する - セッション データを追跡する場合は、軽量に保ちます。

  5. クリーンアップ処理を冪等にする - onSessionEnd は、プロセスがクラッシュした場合に呼び出されない可能性があります。

こちらも参照ください