跳至主要内容

会话生命周期 Hook

使用 onSessionStartonSessionEnd 钩子来初始化上下文、清理资源并在 Copilot SDK 中追踪会话指标。

谁可以使用此功能?

GitHub Copilot SDK 在所有 Copilot 计划中均可使用。

注意

Copilot SDK 目前处于公开预览阶段。功能和可用性可能会更改。

会话生命周期钩子让您能够响应会话开始和结束事件。使用它们来

  • 在会话开始时初始化上下文
  • 在会话结束时清理资源
  • 追踪会话指标和分析
  • 动态配置会话行为

会话开始钩子

当会话开始(无论是新会话还是恢复的会话)时,会调用 onSessionStart 钩子。

钩子签名

import type { SessionStartHookInput, HookInvocation, SessionStartHookOutput } from "@github/copilot-sdk";
type SessionStartHandler = (
  input: SessionStartHookInput,
  invocation: HookInvocation
) => Promise<
  SessionStartHookOutput | null | undefined
>;

有关 Python、Go 和 .NET 的钩子签名,请参阅 github/copilot-sdk 仓库。对于 Java,请参阅 github/copilot-sdk-java 仓库

输入

字段类型描述
时间戳number钩子触发时的 Unix 时间戳
cwdstring当前工作目录
来源"startup" | "resume" | "new"会话的启动方式
initialPromptstring | undefined如果提供,则为初始提示

输出

字段类型描述
additionalContextstring会话开始时要添加的上下文
modifiedConfigobject覆盖会话配置

示例

在开始时添加项目上下文

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.\n`
          + `Main language: `
          + `${projectInfo.language}\n`
          + `Package manager: `
          + `${projectInfo.packageManager}`,
      };
    },
  },
});

有关 Python 示例,请参阅 github/copilot-sdk 仓库。对于 Java,请参阅 github/copilot-sdk-java 仓库

处理会话恢复

const session = await client.createSession({
  hooks: {
    onSessionStart: async (
      input, invocation
    ) => {
      if (input.source === "resume") {
        const previousState =
          await loadSessionState(
            invocation.sessionId
          );

        return {
          additionalContext:
            `Session resumed. Previous context:\n`
            + `- Last topic: `
            + `${previousState.lastTopic}\n`
            + `- Open files: `
            + previousState.openFiles.join(", "),
        };
      }
      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 钩子。

钩子签名

import {
  HookInvocation,
  SessionEndHookInput,
  SessionEndHookOutput,
} from "@github/copilot-sdk";

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

有关 Python、Go 和 .NET 的钩子签名,请参阅 github/copilot-sdk 仓库。对于 Java,请参阅 github/copilot-sdk-java 仓库

输入

字段类型描述
时间戳number钩子触发时的 Unix 时间戳
cwdstring当前工作目录
reasonstring会话结束原因(请参见下表)
finalMessagestring | undefined会话的最后一条信息
errorstring | undefined如果会话因错误结束,则返回错误信息

结束原因

原因描述
"complete"会话正常完成
"error"会话因错误而结束
"abort"会话被用户或代码中止
"timeout"会话超时
"user_exit"用户明确结束会话

输出

字段类型描述
suppressOutputboolean抑制最终会话输出
cleanupActionsstring[]要执行的清理操作列表
sessionSummarystring用于日志/分析的会话摘要

示例

追踪会话指标

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 示例,请参阅 github/copilot-sdk 仓库。对于 Java,请参阅 github/copilot-sdk-java 仓库

清理资源

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) {
        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];
      const durationSec =
        (input.timestamp - data.startTime)
        / 1000;
      console.log(
        `Session Summary:\n`
        + `  ID: ${invocation.sessionId}\n`
        + `  Duration: ${durationSec}s\n`
        + `  Prompts: ${data.prompts}\n`
        + `  Tool calls: ${data.tools}\n`
        + `  End reason: ${input.reason}`
      );

      delete sessionData[
        invocation.sessionId
      ];
      return null;
    },
  },
});

最佳实践

  • 确保 onSessionStart 运行快速。 用户正在等待会话准备就绪。
  • 处理所有结束原因。 不要假设会话总是干净结束;请处理错误和中止情况。
  • 清理资源。 使用 onSessionEnd 释放会话期间分配的任何资源。
  • 存储最少状态。 若要追踪会话数据,请保持其轻量。
  • 使清理操作具备幂等性。 如果进程崩溃,可能不会调用 onSessionEnd

延伸阅读

© . This site is unofficial and not affiliated with GitHub, Inc.