会话的工作原理
创建会话时,Copilot CLI 会维护会话历史记录、工具状态和规划上下文。 默认情况下,此状态位于内存中,并在会话结束时消失。 启用持久性后,可以在重启、容器迁移甚至不同的客户端实例之间恢复会话。

| 州 | 发生的情况 |
|---|---|
| 创建 | session_id 分配 |
| 激活 | 发送提示、工具调用、响应 |
| 已暂停 | 保存到磁盘的状态 |
| Resume | 状态从磁盘加载 |
快速入门:创建可恢复会话
可恢复会话的关键在于提供你自己的 session_id。 如果没有 ID,SDK 将生成随机 ID,会话以后无法恢复。
TypeScript
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
from copilot import CopilotClient
from copilot.session import PermissionHandler
client = CopilotClient()
await client.start()
# Create a session with a meaningful ID
session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model="gpt-5.2-codex", session_id="user-123-task-456")
# Do some work...
await session.send_and_wait("Analyze my codebase")
# Session state is automatically persisted
Go
ctx := context.Background()
client := copilot.NewClient(nil)
// Create a session with a meaningful ID
session, _ := client.CreateSession(ctx, &copilot.SessionConfig{
SessionID: "user-123-task-456",
Model: "gpt-5.2-codex",
})
// Do some work...
session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "Analyze my codebase"})
// Session state is automatically persisted
C# (.NET)
using GitHub.Copilot;
var client = new CopilotClient();
// Create a session with a meaningful ID
var session = await client.CreateSessionAsync(new SessionConfig
{
SessionId = "user-123-task-456",
Model = "gpt-5.2-codex",
});
// Do some work...
await session.SendAndWaitAsync(new MessageOptions { Prompt = "Analyze my codebase" });
// Session state is automatically persisted
恢复会话
稍后(分钟、小时甚至几天)可以从离开位置恢复会话。
使用会话文件系统记住的权限
配置自定义 sessionFs 提供程序时,由运行时管理的持久权限选项使用提供程序存储,而不是运行时主机的配置。 这些文件位于提供程序 sessionStatePath 下,并保留其现有格式:
permissions.json:保留现有allowed_directories和locations字段的顶级tool_approvals映射settings.json:顶级sandbox,用于allowedUrlsURL 审批,approve-permanently用于已保存的沙盒首选项config.json:用于已记住的文件夹信任的顶层sandboxOnboardingShown以及用于首次启用沙盒提示消息的trustedFolders
位置键是规范化的提供程序目录路径,例如 /workspace,没有添加前缀。 运行时使用提供程序路径约定以词法解析它们,而无需检查主机文件系统或发现主机 Git 存储库。 当工作目录为/workspace时,不会自动选择为/workspace/sub保存的审批。
基于提供程序的文件夹信任也使用词法路径:受信任的文件夹涵盖其自身及其子项,而不包括位于其他路径上的链接 Git 工作树。 显式信任这些工作树路径。
这些文件内没有额外的会话 ID 分区。 访问相同后备文件的会话共享记住的选项。 当会话或租户不得共享授权时,请使用单独的提供程序命名空间。 使用每个会话的命名空间时,永久选择在恢复该会话时仍然有效,但不会自动延续到新会话。 若要在恢复时还原会话中持久化的选项,请将其重新连接到同一命名空间。
同意更新在一个运行时进程中按提供程序终结点和文件序列化。 单独的端点不会相互阻塞。 如果不同的提供程序终结点或运行时进程共享后备文件,应用程序必须协调并发更新;运行时无法推断这些文件是共享的。
这些操作从不导入、更新或回退到主机的permissions-config.json、settings.json或config.json,包括提供程序读取或写入失败时。 直接读取通过提供方提供的现有格式的文件。
与主机配置一样,URL 审批仅从 settings.json 读取。 在 config.json 中的旧 allowedUrls 字段会被忽略;config.json 仍是全局状态文件,用于记住的文件夹信任和沙盒引导标记。
存储路由不会更改权限生存期、URL 拒绝优先级或会话策略行为。 单次批准和本次会话批准不会变成永久授权。
保存的沙盒首选项在创建和恢复时还原。 以后的显式 SDK options.update 调用可以更改实时沙盒配置,而无需重写保存的首选项。
在没有 sessionFs 的情况下,SDK 应用程序在 empty 和 copilot-cli 两种模式下将保留现有的主机支持的持久性。 这包括永久 URL 同意保存主机设置并在实时会话中授予访问权限的现有行为,但新的 SDK 会话不会自动加载主机 URL 允许列表。
请参阅 多租户与服务器部署 了解提供程序隔离责任。
转录文本恢复
继续选项 allowTranscriptRecovery 控制运行时从存储加载转录内容时的恢复。 在所有模式下,它默认为 true。 使用 false 时,丢弃损坏记录或移动 session.start 的负载会失败,并出现 JSON-RPC 错误 -32075,而无需重写转录内容。 接受不带换行符的完整最终记录。
在检查持久顺序时,为向前兼容性而跳过的记录仍会被计入。
如果此类记录位于 session.start 之前,恢复必须先将开始记录移到它们之后。 仅包含跳过记录的转录并非空白,没有有效的 session.start 就无法还原。
允许恢复时,返回的会话会提供 transcriptRecovery,包括无效的行号、session.start 是否移动以及计划的字节精确备份路径。 仅执行加载操作不会写入该备份;下一个持久追加执行修复并写入该备份。
注意
此选项适用于新的转录文本加载,不适用于会话的生存期。 重新连接到已驻留在运行时的会话会重复使用其实时历史记录,而无需重新验证存储或拒绝由先前恢复操作授权的恢复。 恢复报告描述的是执行恢复的负载项,而不是之后每一次重新连接。

TypeScript
// 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
# Resume from a different client instance (or after restart)
session = await client.resume_session("user-123-task-456", on_permission_request=PermissionHandler.approve_all)
# Continue where you left off
await session.send_and_wait("What did we discuss earlier?")
Go
ctx := context.Background()
// Resume from a different client instance (or after restart)
session, _ := client.ResumeSession(ctx, "user-123-task-456", nil)
// Continue where you left off
session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "What did we discuss earlier?"})
C# (.NET)
// Resume from a different client instance (or after restart)
var session = await client.ResumeSessionAsync("user-123-task-456");
// Continue where you left off
await session.SendAndWaitAsync(new MessageOptions { Prompt = "What did we discuss earlier?" });
恢复选项
恢复会话时,可以选择重新配置许多设置。 如果需要更改模型、更新工具配置或修改行为,这非常有用。
| 选项 | Description |
|---|---|
model | 更改已恢复的会话的模型 |
systemMessage | 覆盖或扩展系统提示 |
availableTools | 限制可用的工具 |
excludedTools | 禁用特定工具 |
provider | 重新提供 BYOK 凭据(这是 BYOK 会话所需的) |
capi.autoTier | 覆盖已保存的自动路由偏好设置 |
capi.enable | 为已恢复的会话选择 Responses API 传输方式 |
reasoningEffort | 调整推理工作量级别 |
streaming | 启用/禁用流式处理响应 |
workingDirectory | 更改工作目录 |
configDir | 覆盖配置目录 |
mcpServers | 配置 MCP 服务器 |
customAgents | 配置自定义代理 |
agent | 按名称预先选择自定义代理 |
skillDirectories | 要从中加载技能的目录 |
disabledSkills | 禁用技能 |
infiniteSessions | 配置无限会话模式 |
自动层暂留
使用 model: "auto",可选 capi.autoTier 设置选择自动路由首选项: efficiency、 balance、 intelligence或 fast。 在 Python 中,使用 capi={"auto_tier": "balance"}。 此设置适用于 V2 自动路由;V1 自动请求保持不变。
启用运行时的默认关闭DYNAMIC_AUTO_TIERS功能后,会话的 model.list RPC 还会从提供程序的auto终结点返回可选/meta元数据。 使用启用的描述符结合 type: "auto" 来发现其他受支持的层标识符、显示名称、说明和排序。 现有的选择方法和 JSON 字段接受这些标识符。 发现失败不会回退到 /models,没有 auto 元数据的成功响应不提供可选择的自动层。
若要在尚无任何会话时填充模型选取器,可在运行时的环境中启用 DYNAMIC_AUTO_TIERS(例如 env 客户端选项)。 服务器级 models.list RPC(Node.js 中的 client.rpc.models.list())随后会从同一 /meta 响应中返回相同的 auto 元数据,并具有相同的无回退行为。 服务器级列表读取运行时在启动时解析的标志,而不是每个会话的功能标志或实验分配,因此请在启动运行时的位置设置该标志。 禁用标志后, models.list 未更改并省略 auto。
将层标识符视为可扩展值,而不是封闭枚举。 现有的命名值仍然可用;对于附加标识符,请在 Node.js 和 Python 中使用字符串,在 Go 中使用 AutoTier("premium-v2"),在 .NET 中使用 new AutoTier("premium-v2"),在 Rust 中使用 AutoTier::Custom,在 Java 中使用 AutoTier.fromValue。 提供程序的 defaultTier 配置描述其默认路由,而无需创建已提交的 SDK 首选项。
如果删除或禁用持久化层级,则继续会保留显式首选项,而不是将其替换为提供程序的默认值。 激活自动路由之前,请选择可用的替换项。
CLI 还会在启动期间保留设置派生的首选项,即使层不可用或动态发现被禁用也是如此。 然后,可以在模型选取器中选择替代项。 在操作成功之前,仍会验证显式 SDK 创建和恢复首选项,并且自动激活始终根据解析的发现模式验证可用性。
创建或恢复请求包括 expAssignments时,运行时会在验证显式自动首选项之前应用这些分配。 验证、发现和激活使用相同的已解析的功能判定结果。
fast是仅集成商延迟预设,不是第一方GitHub Copilot产品首选项。 配置会话时,不会根据 /meta 层目录对 Fast 进行验证。 SDK 不会决定是否符合 Fast 条件、检查客户端身份、将 Fast 设为默认选项,或在运行时不支持 Fast 时回退到其他层级——较旧的运行时会原样返回其原生错误。
运行时会保留所选层,因此应用程序无需在每次恢复时重新发送它:
- 创建会话时省略层使用运行时的默认路由行为。
- 冷恢复会还原暂留的层。 显式指定层级会覆盖新激活时恢复的值。
- 恢复已驻留在运行时中的会话时,省略该层级会保留当前选择,而指定相同的层级则不会执行任何操作。 提供不同的层会请求一次安全切换,运行时会在恢复成功后应用该切换;它无法更改已在进行中的轮次。
- 没有持久层的旧会话会保留默认路由行为。
层选择不是实时模型切换操作。 SDK 转发首选项;运行时拥有持久性和验证。
session.start 和 session.resume 事件会在其可选的 data.autoTier 字段中提供所选层级(在 Python 中为 data.auto_tier)。 如果未选择任何层,则省略该字段。
在会话期间更改自动层级
调用 setAutoTier 以在不更改所选模型的情况下更改实时会话上的路由首选项。 传入 null(Python None,Go nil)即可恢复为提供商默认的 Auto 路由。
const result = await session.setAutoTier("intelligence");
if (result.status === "pending") {
// Accepted, but not yet in effect.
}
运行时不会立即应用首选项。 仅当以后用户使用 auto 模型成功从提供程序获取可用模型时,它才会记录请求并提交该请求。 因此,状态 pending 确认请求已接受,而不是它生效。 只有最新的请求会被保留:新请求会替换此前任何尚未被任何轮次认领的请求。
如果较旧的请求在较新的首选项请求或重置到达时仍在验证,则较旧的调用将失败,并出现“请求已被取代”错误,而不是替换较新的意图。
通过以下事件监视结果:
session.model_change在首选项提交时。session.auto_tier_switch_failed未能执行时。 此事件是短暂的,因此运行时在恢复运行时既不会将其持久化,也不会重放该事件。 其reason字段的值为policy_rejected、setup_failed、request_failed或unsupported之一,且先前生效的首选项将继续生效。
还可以通过会话的 model.getCurrent RPC 方法随时读取权威状态;该方法会返回已提交的 autoTier、任何未被认领的 pendingAutoTier,以及正在进行的激活当前已认领的 activatingAutoTier。
| SDK | 更改级别 | 返回到提供程序默认路由 |
|---|---|---|
| Node.js | session.set | session.set |
| Python | session.set_auto_tier("balance") | session.set_auto_tier(None) |
| Go | session.Set | session.Set |
| .NET | session.Set | session.Set |
| Rust | session.set_auto_tier(Some(Auto | session.set_auto_tier(None) |
| Java | session.set | session.set |
若要在一次调用中同时选择 auto 模型及其路由偏好,请改为在模型切换器上设置层级。 当模型不是 auto 时,运行时会拒绝此选项。
| SDK | 通过切换暂存一个层 | 重置为提供程序默认路由 |
|---|---|---|
| Node.js | setModel("auto", { autoTier: "balance" }) | setModel("auto", { autoTier: null }) |
| Python | set_model("auto", auto_tier="balance") | set_model("auto", auto_tier=None) |
| Go | Set | Set |
| .NET | new SetModelOptions { AutoTier = AutoTier.Balance } | new SetModelOptions { ResetAutoTier = true } |
| Rust | Set | Set |
| Java | new Set | new Set |
Node.js、Python和 Rust 以单个值表示所有三种状态:Node.js 和Python,因为null/None与省略的参数区分开来,Rust 是AutoTierPreference::Reset同一选项的不同变体。 Go、.NET 和 Java 无法在单个值中区分“重置”和“未设置”,因此它们会额外使用一个单独的重置标志。 省略两者始终意味着“仅保留当前首选项”。
恢复时传输响应
可选的 capi.enableWebSocketResponses 设置项用于为 CAPI 响应 API 选择传输方式。 它的默认值为 true,因此当所选模型声明了 ws:/responses 端点时,就会使用 WebSocket 传输。 将其设置为 false 将回退到 HTTP 传输。 在 Python 中,使用 capi={"enable_web_socket_responses": False}。
需要时,在恢复调用中提供它。 当 WebSocket 连接在代理后发生失败时,以及恢复的会话报告 400 input item ID does not belong to this connection(这是 WebSocket 传输特有的)时,建议设置此项。
const session = await client.resumeSession("user-123-task-456", {
capi: { enableWebSocketResponses: false },
});
将其设置为 false 等效于 COPILOT_CLI_DISABLE_WEBSOCKET_RESPONSES 具有相反极性的环境变量。
示例:恢复时更改模型。
// 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
| Data | 持久化? | 笔记 |
|---|---|---|
| 对话历史记录 | ||
| ✅ 是的 | 完整消息线程 | |
| 工具调用结果 | ||
| ✅ 是的 | 为提供上下文而缓存 | |
| 代理规划状态 | ||
| ✅ 是的 | ||
plan.md 文件 | ||
| 会话项目 | ||
| ✅ 是的 | 在 files/ 目录中 | |
| 提供者/API 密钥 | ||
| ❌ 否 | 安全性:必须重新提供 | |
| 内存中工具状态 | ||
| ❌ 否 | 工具应为无状态 |
会话 ID 最佳实践
选择能编码拥有者和用途的会话 ID。 这使得审核和清理更加容易。
| Pattern | 示例 | 用例 |
|---|---|---|
❌abc123 | 随机 ID | 难以审核,没有所有权信息 |
✅user-{user | user-alice-pr-review-42 | 多用户应用 |
✅tenant-{tenant | tenant-acme-onboarding | 多租户软件即服务 |
✅{user | 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"
import time
def create_session_id(user_id: str, task_type: str) -> str:
timestamp = int(time.time())
return f"{user_id}-{task_type}-{timestamp}"
session_id = create_session_id("alice", "code-review")
# → "alice-code-review-1706932800"
管理会话生命周期
列出活动会话
// 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);
断开会话连接(disconnect)
任务完成后,显式断开会话连接,而非等待超时。 这会释放内存中资源,但 会保留磁盘上的会话数据,以便以后仍可以恢复会话:
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 还提供惯用的自动清理模式:
| 语言 | Pattern | 示例 |
|---|---|---|
| TypeScript | Symbol.async | await using session = await client.create |
| Python | async with 上下文管理器 | async with await client.create_session(on_ |
| C# | IAsyncDisposable | await using var session = await client.Create |
| Go | defer | defer session.Disconnect() |
注意
destroy() 已弃用,改用 disconnect()。 现有使用destroy()的代码将继续工作,但应迁移。
永久删除会话 (deleteSession)
若要永久删除会话及其所有数据(会话历史记录、规划状态、项目),请使用 deleteSession。 这是不可逆转的 — 删除后 无法 恢复会话:
// Permanently remove session data
await client.deleteSession("user-123-task-456");
disconnect()vsdeleteSession():disconnect()释放内存中资源,但保留磁盘上的会话数据以供以后恢复。deleteSession()永久删除所有内容,包括磁盘上的文件。
自动清理:空闲超时
默认情况下,会话没有空闲超时限制,并且会无限期持续存在,直到被显式断开连接或删除。 您可以选择通过 CopilotClientOptions.sessionIdleTimeoutSeconds 配置服务器级空闲超时:
const client = new CopilotClient({
sessionIdleTimeoutSeconds: 30 * 60, // 30 minutes
});
配置了超时时间后,在该时长内无活动的会话会被自动清理。 设置为 0 或省略以禁用。
注意
此选项仅适用于 SDK 生成运行时进程时。 通过 cliUrl 连接到现有服务器时,将采用服务器自身的超时配置。

具有活动工作(正在运行的命令、后台智能体)的会话始终受到空闲清理保护,无论超时设置如何。
监听空闲事件以响应会话不活动:
session.on("session.idle", (event) => {
console.log(`Session idle for ${event.idleDurationMs}ms`);
});
部署模式
模式 1:每个用户一台 CLI 服务器(建议)
最适合:强隔离、多租户环境、Azure动态会话。

**好处:**✅ 完全隔离 | ✅ 简单安全性 | ✅ 轻松缩放
模式 2:共享 CLI 服务器(资源高效)
最适用于:内部工具、可信环境、资源受限的部署环境。

要求:
- ⚠️ 每个用户的唯一会话 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

会话在容器重启后仍然存在!
长时间运行的工作流的无限会话
如果工作流可能超出上下文限制,请启用自动压缩以支持无限会话:
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),而不是绝对令牌计数。 有关详细信息,请参阅 SDK 和 CLI 兼容性 。
限制和注意事项
| Limitation | Description | 缓解措施 |
|---|---|---|
| BYOK 重新身份验证 | API 密钥不会持久化 | 将密钥存储在机密管理器中;在恢复时提供 |
| 可写存储 | ~/ 必须可写 | 在容器中装载永久性卷 |
| 无会话锁定 | 对同一会话的并发访问未定义 | 实现应用程序级锁定或队列 |
| 工具状态未持久化 | 内存中的工具状态已丢失 | 将工具设计为无状态或保留其自己的状态 |
处理并发访问
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.resume |
| BYOK 简历 | 重新提供 provider 配置 |
| 列表会话 | client.list |
| 断开与活动会话的连接 | session.disconnect()- 释放内存中资源;保留磁盘上的会话数据以恢复 |
| 永久删除会话 | client.delete— 永久删除磁盘中的所有会话数据;无法恢复 |
| 容器化部署 | 装载 ~/ 到永久性存储 |
后续步骤
- 会话挂钩 - 使用挂钩自定义会话行为
- SDK 和 CLI 兼容性 - SDK 与 CLI 功能比较
- 调试指南 - 排查会话问题