Skip to main content

Copilot SDK 中的会话持久性

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

谁可以使用此功能?

GitHub Copilot SDK 适用于所有 Copilot 计划。

注意

          Copilot SDK 当前处于 技术预览版. 功能和可用性可能会发生更改。

创建会话时, Copilot SDK 维护会话历史记录、工具状态和规划上下文。 默认情况下,此状态位于内存中,并在会话结束时消失。 启用持久性后,可以在重启、容器迁移甚至不同的客户端实例之间恢复会话。 有关会话状态生命周期的直观概述,请参阅 github/copilot-sdk 存储库

发生的情况
          **创建** | 
          `sessionId` 分配 |

| 启用 | 发送提示、工具调用、响应 | | 已暂停 | 保存到磁盘的状态 | | 简历 | 状态从磁盘加载 |

快速入门:创建可恢复会话

可恢复会话的关键是提供你自己的 sessionId (其他 SDK 可以使用 session_id)。 如果没有 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存储库

恢复会话

你可以从会话结束的位置(分钟、小时甚至几天后)恢复会话。 有关跨客户端会话恢复的直观概述,请参阅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 存储库

继续选项

恢复会话时,可以选择重新配置许多设置。 如果需要更改模型、更新工具配置或修改行为,这非常有用。

选项说明
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
数据持久化?备注
对话历史记录
          ✅ 是 | 完整消息线程 |

| 工具调用结果 | ✅ 是 | 为提供上下文而缓存 | | 代理规划状态 | ✅ 是 | plan.md 文件 | | 会话产物 | ✅ 是 | 在 files/ 目录中 | | 提供者/API 密钥 | ❌ 否 | 安全性:必须重新提供 | | 内存中工具状态 | ❌ 否 | 工具应为无状态 |

会话 ID 最佳实践

选择能编码拥有者和用途的会话 ID。 这使得审核和清理更加容易。

图案示例用例
          ❌
          `abc123`
         | 随机 ID | 难以审核,没有所有权信息 |

| ✅ user-{userId}-{taskId} | user-alice-pr-review-42 | 多用户应用 | | ✅ tenant-{tenantId}-{workflow} | tenant-acme-onboarding | 多租户软件即服务 | | ✅ {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 存储库

管理会话生命周期

列出活动会话

// 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 上下文管理器 | async with await client.create_session(config) as session: | | C# | IAsyncDisposable | await using var session = await client.CreateSessionAsync(config); | | 去吧 | defer | defer session.Disconnect() |

注意

          `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),而不是绝对令牌计数。

限制和注意事项

限度说明缓解措施
          **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/ 到永久性存储 |