注意
Copilot SDK 目前处于公开预览阶段。功能和可用性可能会更改。
当您创建会话时,Copilot SDK 会维护对话历史、工具状态以及规划上下文。默认情况下,这些状态存储在内存中,会在会话结束时消失。启用持久化后,您可以在重启、容器迁移,甚至不同客户端实例之间恢复会话。有关会话状态生命周期的可视化概览,请参阅 github/copilot-sdk 仓库。
| 状态 | 会发生什么 |
|---|---|
| 创建 | sessionId 已分配 |
| 活跃 | 发送提示、工具调用、响应 |
| 已暂停 | 状态已保存到磁盘 |
| 恢复 | 状态已从磁盘加载 |
快速入门:创建可恢复会话
可恢复会话的关键是提供您自己的 sessionId(其他 SDK 可能使用 session_id)。若未提供,SDK 将生成随机 ID,之后将无法恢复该会话。
import { CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient();
// Create a session with a meaningful ID
const session = await client.createSession({
sessionId: "user-123-task-456",
model: "gpt-5.2-codex",
});
// Do some work...
await session.sendAndWait({ prompt: "Analyze my codebase" });
// Session state is automatically persisted
// You can safely close the client
Python、Go 和 C# 示例请参阅 github/copilot-sdk 仓库。Java 示例请参阅 github/copilot-sdk-java 仓库。
恢复会话
您可以在会话结束后(几分钟、几小时,甚至几天后)恢复会话。有关跨客户端会话恢复的可视化概览,请参阅 github/copilot-sdk 仓库。
// Resume from a different client instance (or after restart)
const session = await client.resumeSession("user-123-task-456");
// Continue where you left off
await session.sendAndWait({ prompt: "What did we discuss earlier?" });
Python、Go 和 C# 示例请参阅 github/copilot-sdk 仓库。Java 示例请参阅 github/copilot-sdk-java 仓库。
恢复选项
恢复会话时,您可以选择性地重新配置多个设置。这在需要更改模型、更新工具配置或修改行为时非常有用。
| 选项 | 描述 |
|---|---|
model | 更改恢复会话的模型 |
systemMessage | 覆盖或扩展系统提示 |
availableTools | 限制可用工具 |
excludedTools | 禁用特定工具 |
provider | 重新提供 BYOK 凭证(BYOK 会话必需) |
reasoningEffort | 调整推理努力级别 |
streaming | 启用/禁用流式响应 |
workingDirectory | 更改工作目录 |
configDir | 覆盖配置目录 |
mcpServers | 配置 MCP 服务器 |
customAgents | 配置自定义代理 |
agent | 按名称预先选择自定义代理 |
skillDirectories | 加载技能的目录 |
disabledSkills | 要禁用的技能 |
infiniteSessions | 配置无限会话行为 |
示例:恢复时更改模型
// Resume with a different model
const session = await client.resumeSession("user-123-task-456", {
model: "claude-sonnet-4", // Switch to a different model
reasoningEffort: "high", // Increase reasoning effort
});
在恢复的会话中使用 BYOK
使用您自己的 API 密钥时,恢复时必须重新提供提供程序配置。出于安全原因,API 密钥永远不会持久化到磁盘。
// Original session with BYOK
const session = await client.createSession({
sessionId: "user-123-task-456",
model: "gpt-5.2-codex",
provider: {
type: "azure",
endpoint: "https://my-resource.openai.azure.com",
apiKey: process.env.AZURE_OPENAI_KEY,
deploymentId: "my-gpt-deployment",
},
});
// When resuming, you MUST re-provide the provider config
const resumed = await client.resumeSession("user-123-task-456", {
provider: {
type: "azure",
endpoint: "https://my-resource.openai.azure.com",
apiKey: process.env.AZURE_OPENAI_KEY, // Required again
deploymentId: "my-gpt-deployment",
},
});
哪些内容会被持久化
会话状态保存于 ~/.copilot/session-state/{sessionId}/
~/.copilot/session-state/
└── user-123-task-456/
├── checkpoints/ # Conversation history snapshots
│ ├── 001.json # Initial state
│ ├── 002.json # After first interaction
│ └── ... # Incremental checkpoints
├── plan.md # Agent's planning state (if any)
└── files/ # Session artifacts
├── analysis.md # Files the agent created
└── notes.txt # Working documents
| 数据 | 已持久化? | 注意 |
|---|---|---|
| 对话历史 | ✅ Yes | 完整消息线程 |
| 工具调用结果 | ✅ Yes | 用于上下文的缓存 |
| 代理规划状态 | ✅ Yes | plan.md 文件 |
| 会话工件 | ✅ Yes | 位于 files/ 目录 |
| 提供程序/API 密钥 | ❌ No | 安全性:必须重新提供 |
| 内存中的工具状态 | ❌ No | 工具应保持无状态 |
会话 ID 最佳实践
选择能够表达所有权和用途的会话 ID。这使审计和清理更加容易。
| 模式 | 示例 | 使用场景 |
|---|---|---|
❌ abc123 | 随机 ID | 难以审计,无法获取所有权信息 |
✅ user-{userId}-{taskId} | user-alice-pr-review-42 | 多用户应用 |
✅ tenant-{tenantId}-{workflow} | tenant-acme-onboarding | 多租户 SaaS |
✅ {userId}-{taskId}-{timestamp} | alice-deploy-1706932800 | 基于时间的清理 |
结构化 ID 的优势
- 易于审计:“显示用户 alice 的所有会话”
- 易于清理:“删除所有早于 X 的会话”
- 自然的访问控制:从会话 ID 中解析用户 ID
示例:生成会话 ID
function createSessionId(userId: string, taskType: string): string {
const timestamp = Date.now();
return `${userId}-${taskType}-${timestamp}`;
}
const sessionId = createSessionId("alice", "code-review");
// → "alice-code-review-1706932800000"
Python 示例请参阅 github/copilot-sdk 仓库。Java 请参阅 github/copilot-sdk-java 仓库。
管理会话生命周期
列出活跃会话
// List all sessions
const sessions = await client.listSessions();
console.log(`Found ${sessions.length} sessions`);
for (const session of sessions) {
console.log(`- ${session.sessionId} (created: ${session.createdAt})`);
}
// Filter sessions by repository
const repoSessions = await client.listSessions({ repository: "owner/repo" });
清理旧会话
async function cleanupExpiredSessions(maxAgeMs: number) {
const sessions = await client.listSessions();
const now = Date.now();
for (const session of sessions) {
const age = now - new Date(session.createdAt).getTime();
if (age > maxAgeMs) {
await client.deleteSession(session.sessionId);
console.log(`Deleted expired session: ${session.sessionId}`);
}
}
}
// Clean up sessions older than 24 hours
await cleanupExpiredSessions(24 * 60 * 60 * 1000);
从会话断开连接
任务完成后,请显式断开会话,而不是等待超时。这会释放内存资源,但 保留磁盘上的会话数据,因此会话仍可在以后恢复。
try {
// Do work...
await session.sendAndWait({ prompt: "Complete the task" });
// Task complete — release in-memory resources (session can be resumed later)
await session.disconnect();
} catch (error) {
// Clean up even on error
await session.disconnect();
throw error;
}
每个 SDK 都提供惯用的自动清理模式
| 语言 | 模式 | 示例 |
|---|---|---|
| TypeScript | Symbol.asyncDispose | await using session = await client.createSession(config); |
| Python | async with context manager | async with await client.create_session(config) as session |
| C# | IAsyncDisposable | await using var session = await client.CreateSessionAsync(config); |
| Go | defer | defer session.Disconnect() |
| Java | try-with-resources | try (var session = client.createSession(config).get()) { ... } |
注意
destroy() 已被 disconnect() 替代,并将在未来的版本中移除。使用 destroy() 的现有代码仍可工作,但应迁移。
永久删除会话
要永久从磁盘中删除会话及其所有数据(对话历史、规划状态、工件),请使用 deleteSession。此操作不可逆——删除后会话 无法 恢复。
// Permanently remove session data
await client.deleteSession("user-123-task-456");
提示
disconnect() 释放内存资源,但保留磁盘上的会话数据以便后续恢复。deleteSession() 永久删除所有内容,包括磁盘上的文件。
自动清理:空闲超时
SDK 内置 30 分钟的空闲超时。没有活动的会话会自动被清理。有关空闲超时流程的可视化概览,请参阅 github/copilot-sdk 仓库。
监听空闲事件以了解何时工作完成
session.on("session.idle", (event) => {
console.log(`Session idle for ${event.idleDurationMs}ms`);
});
部署模式
模式 1:每用户一个 CLI 服务器(推荐)
适用于:强隔离、多租户环境、Azure 动态会话。可视化图示请参阅 github/copilot-sdk 仓库。
优势
- 完全隔离
- 简易安全
- 易于扩展
模式 2:共享 CLI 服务器(资源高效)
适用于:内部工具、受信任环境、资源受限的部署。可视化图示请参阅 github/copilot-sdk 仓库。
要求
- 每用户唯一的会话 ID
- 应用层访问控制
- 操作前的会话 ID 验证
// Application-level access control for shared CLI
async function resumeSessionWithAuth(
client: CopilotClient,
sessionId: string,
currentUserId: string
): Promise<Session> {
// Parse user from session ID
const [sessionUserId] = sessionId.split("-");
if (sessionUserId !== currentUserId) {
throw new Error("Access denied: session belongs to another user");
}
return client.resumeSession(sessionId);
}
Azure 动态会话
对于容器可能重启或迁移的无服务器/容器部署,需要将会话状态目录挂载到持久存储
# Azure Container Instance example
containers:
- name: copilot-agent
image: my-agent:latest
volumeMounts:
- name: session-storage
mountPath: /home/app/.copilot/session-state
volumes:
- name: session-storage
azureFile:
shareName: copilot-sessions
storageAccountName: myaccount
关于容器重启持久化的可视化图示,请参阅 github/copilot-sdk 仓库。
长时间运行工作流的无限会话
对于可能超出上下文限制的工作流,请启用带自动压缩的无限会话
const session = await client.createSession({
sessionId: "long-workflow-123",
infiniteSessions: {
enabled: true,
backgroundCompactionThreshold: 0.80, // Start compaction at 80% context
bufferExhaustionThreshold: 0.95, // Block at 95% if needed
},
});
注意
阈值为上下文使用率比例(0.0–1.0),而非绝对 token 数量。
限制与注意事项
| 限制 | 描述 | 缓解措施 |
|---|---|---|
| BYOK 重新认证 | API 密钥不会被持久化 | 将密钥存储在机密管理器中;在恢复时提供 |
| 可写存储 | ~/.copilot/session-state/ 必须是可写的 | 在容器中挂载持久卷 |
| 无会话锁定 | 对同一会话的并发访问未定义 | 实现应用层锁或队列 |
| 工具状态未持久化 | 内存中的工具状态会丢失 | 设计工具为无状态或自行持久化状态 |
处理并发访问
SDK 未提供内置的会话锁定。如果多个客户端可能访问同一会话,您应确保对每个会话加锁,以防被劫持。
// Option 1: Application-level locking with Redis
import Redis from "ioredis";
const redis = new Redis();
async function withSessionLock<T>(
sessionId: string,
fn: () => Promise<T>
): Promise<T> {
const lockKey = `session-lock:${sessionId}`;
const acquired = await redis.set(lockKey, "locked", "NX", "EX", 300);
if (!acquired) {
throw new Error("Session is in use by another client");
}
try {
return await fn();
} finally {
await redis.del(lockKey);
}
}
// Usage
await withSessionLock("user-123-task-456", async () => {
const session = await client.resumeSession("user-123-task-456");
await session.sendAndWait({ prompt: "Continue the task" });
});
摘要
| 功能 | 使用方法 |
|---|---|
| 创建可恢复会话 | 提供您自己的 sessionId |
| 恢复会话 | client.resumeSession(sessionId) |
| BYOK 恢复 | 重新提供 provider 配置 |
| 列出会话 | client.listSessions(filter?) |
| 从活跃会话断开连接 | session.disconnect() — 释放内存资源;磁盘上的会话数据被保留以便恢复 |
| 永久删除会话 | client.deleteSession(sessionId) — 永久删除磁盘上所有会话数据;无法恢复 |
| 容器化部署 | 将 ~/.copilot/session-state/ 挂载到持久存储 |