Session 检查点与分支
wesgine 支持在 Session 中创建快照(检查点)并从中分支,实现对话的"时间旅行"与并行探索。
检查点
检查点是 Session 在某一时刻的完整快照。
创建检查点
POST /cells/{id}/sessions/{sid}/checkpoints
在当前 Session 状态上创建快照。
回滚
POST /cells/{id}/sessions/{sid}/checkpoints/{cpid}/restore
将 Session 恢复到检查点时的状态。后续消息被丢弃。
列出检查点
GET /cells/{id}/sessions/{sid}/checkpoints
删除检查点
DELETE /cells/{id}/sessions/{sid}/checkpoints/{cpid}
分支
从检查点创建一个新的对话分支,原始 Session 不受影响。
Fork
POST /cells/{id}/sessions/{sid}/checkpoints/{cpid}/fork
基于检查点创建一个新的 Session 分支。
列出分支
GET /cells/{id}/sessions/{sid}/branches
删除分支
DELETE /cells/{id}/sessions/{sid}/branches/{bid}
使用场景
| 场景 | 操作 |
|---|---|
| 尝试不同方案 | Fork → 在分支中尝试 → 不满意则切回 |
| 保存关键节点 | 重要阶段创建 Checkpoint |
| 回退错误决策 | Restore 到之前的 Checkpoint |
| 并行探索 | Fork 多个分支同时探索 |
Actor 边界(INV-SESS-03)
检查点和分支操作遵循严格的 Actor 边界:
行身份
checkpoint / branch 的行身份是 (session_id, id):
- SQL 必须写
WHERE id = ? AND session_id = ? - 不能只用
WHERE id = ?
跨 Session 安全
DELETE /sessions/我的/checkpoints/受害者的
↑ 归属门检查通过 ↑ id 由调用方给
如果只检查 session 归属不检查行身份,就能跨 actor 删除。
错误处理
| 操作 | 不是你的 | 不存在 |
|---|---|---|
| 删除 | 幂等成功(不泄露存在性) | 幂等成功 |
| Restore | 404 ErrCheckpointNotInSession | 404 |
| Fork | 404 ErrCheckpointNotInSession | 404 |
删除幂等是因为区分"不存在"与"不是你的"本身就是存在性预言机。
Fork 的特殊风险
把别人的 checkpoint fork 进自己的 session:
- 别人的消息经由你自己那条正确设门的 session 变得可读
- 效果是绕过归属门泄漏对话历史
Cell Boot 自动清理(INV-CKPT-04)
Cell 启动时自动执行:
MarkInterruptedSessions()— 标记崩溃中断的 sessionListOrphanedRuns()→MarkRunTerminated()— 清理孤儿 Run
消费方不必在 PostBoot 手动调用。
POST /cells/{id}/sessions/mark-interrupted 保留给运维手动触发。
与 TaskMemory 的关系
| Session Checkpoint | TaskMemory Checkpoint | |
|---|---|---|
| 内容 | 完整 Session 快照 | 任务进度标记 |
| 可回滚 | ✅ Restore | ❌ 只是记录 |
| 可分支 | ✅ Fork | ❌ |
| 生命周期 | 与 Session 绑定 | 与 Session 绑定 |
相关文档
- Session 管理 →
session-management.md - Actor 边界 →
actor-boundary.md - Cell 生命周期 →
cell-lifecycle.md - Task Memory →
task-memory.md