跳至主要内容

Copilot SDK 中的会话持久化

在重启和部署期间暂停、恢复并管理 Copilot SDK 会话。

谁可以使用此功能?

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

注意

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用于上下文的缓存
代理规划状态✅ Yesplan.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 都提供惯用的自动清理模式

语言模式示例
TypeScriptSymbol.asyncDisposeawait using session = await client.createSession(config);
Pythonasync with context managerasync with await client.create_session(config) as session
C#IAsyncDisposableawait using var session = await client.CreateSessionAsync(config);
Godeferdefer session.Disconnect()
Javatry-with-resourcestry (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`);
});

部署模式

适用于:强隔离、多租户环境、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/ 挂载到持久存储
© . This site is unofficial and not affiliated with GitHub, Inc.