注意
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 存储库。
输入
| 领域 | 类型 | 说明 |
|---|---|---|
timestamp | number | 触发挂钩时的 Unix 时间戳 |
cwd | 字符串 | 当前工作目录 |
source |
`"startup"`
\|
`"resume"`
\|
`"new"`
| 会话的启动方式 |
| initialPrompt | 字符串 | 未定义 | 提供的初始提示 |
输出
| 领域 | 类型 | 说明 |
|---|---|---|
additionalContext | 字符串 | 在会话开始时添加的上下文 |
modifiedConfig | 对象 | 替代会话配置 |
示例
在启动时添加项目上下文
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 存储库。
处理会话恢复
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 存储库。
输入
| 领域 | 类型 | 说明 |
|---|---|---|
timestamp | number | 触发挂钩时的 Unix 时间戳 |
cwd | 字符串 | 当前工作目录 |
reason | 字符串 | 会话结束的原因(请参阅下表) |
finalMessage | 字符串 | 未定义 | 会话中的最后一条消息 |
error | 字符串 | 未定义 | 会话因错误结束时的错误消息 |
结束原因
| 原因 | 说明 |
|---|---|
"complete" | 会话正常完成 |
"error" | 会话因错误而结束 |
"abort" | 会话已由用户或代码中止 |
"timeout" | 会话超时 |
"user_exit" | 用户显式结束会话 |
输出
| 领域 | 类型 | 说明 |
|---|---|---|
suppressOutput | 布尔 | 抑制最终会话输出 |
cleanupActions | 字符串[] | 要执行的清理操作列表 |
sessionSummary | 字符串 | 日志记录/分析会话摘要 |
示例
跟踪会话指标
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 存储库。
清理资源
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` 如果进程崩溃,则可能不会调用。
延伸阅读
-
[AUTOTITLE](/copilot/how-tos/copilot-sdk/use-hooks/quickstart) -
[AUTOTITLE](/copilot/how-tos/copilot-sdk/use-hooks/error-handling) -
[AUTOTITLE](/copilot/how-tos/copilot-sdk/use-hooks/user-prompt-submitted)