会话管理
概述
Session 是 wesgine 中同一 Actor 的对话容器。每个 Session 包含一组有序的消息(用户输入、AI 回复、工具调用结果),持久化在 Cell 的 sessions.db 中。Session 是 Actor 边界的第二个面——每个 Session 有明确的 Actor 归属。
核心概念
Session 与 Actor
- 每个 Session 在创建时绑定一个 Actor(
wes_sessions.actor列) - 普通用户只能访问自己的 Session;管理员可查看 Cell 内全部 Session
- Session 的变更操作需要
cell:chatscope(不是cell:read)
消息持久化
消息存储在 wes_messages 表中,支持 FTS5 全文搜索:
- 每条消息包含:角色(system/user/assistant/tool)、内容、轮次号、时间戳
- assistant 消息如果内容为空(thinking-only,无 text/tool_use),不写入数据库
- 所有写入路径统一剥离 base64 图片,防止数据库膨胀
Run 与 Session
一个 Session 可以包含多次 Run。每次 cell.Runtime().Run() 在指定 Session 中执行一轮对话。Run 结束时,引擎写入一条 role=system 的摘要消息。
Session 操作
列表与查询
GET /cells/{id}/sessions # 列出会话
GET /cells/{id}/sessions/{sid}/messages # 消息列表(?before=&limit=)
删除
DELETE /cells/{id}/sessions/{sid} # 删除会话
DELETE /cells/{id}/sessions/delete-by-prefix?prefix= # 按前缀批量删除
中断
POST /cells/{id}/sessions/{sid}/interrupt # 中断当前 Run
POST /cells/{id}/sessions/interrupt-all # 中断 Cell 内所有 Run(需 admin)
POST /cells/{id}/sessions/mark-interrupted # 崩溃后批量标记 interrupted(需 admin)
Checkpoint 与 Branch
Session 支持会话快照功能,可以在对话的任意时刻创建检查点,并从检查点回滚或分叉:
| 操作 | 端点 | 说明 |
|---|---|---|
| 创建快照 | POST /sessions/{sid}/checkpoints | 保存当前对话状态 |
| 回滚 | POST /sessions/{sid}/checkpoints/{cpid}/restore | 恢复到指定快照 |
| 分叉 | POST /sessions/{sid}/checkpoints/{cpid}/fork | 从快照创建新分支 |
| 分支列表 | GET /sessions/{sid}/branches | 查看所有分支 |
Checkpoint 的行身份是
(session_id, id)复合键。跨 Session 的操作会被拒绝。
认知结算(CognitiveSettlement)
每次 Run 结束时,引擎执行认知结算——由主对话模型将本轮对话压缩为 SessionState:
- SessionState 是下一轮上下文的唯一历史来源
- System Prompt 的历史信息仅从 SessionState 注入,不从旧消息推断
- Settlement 产出对用户不可见(不通过 SSE 推送到前端)
- Settlement 失败时执行机械压缩 fallback(提取工具证据后丢弃旧消息)
认知结算是 Run 生命周期的强制阶段,不可跳过(唯一例外:进程级崩溃 panic_stop)。
Cell Boot 时的自动恢复
Cell 启动时自动执行:
MarkInterruptedSessions():标记上次崩溃时未完成的 SessionListOrphanedRuns()→MarkRunTerminated():清理孤儿 Run
消费方不需要在启动后手动调用 MarkInterrupted——引擎层已覆盖。
使用示例
// 发起对话
events, err := cell.Runtime().Run(ctx, wesgine.AppRunRequest{
Actor: "alice",
SessionID: "session-001",
AgentID: "assistant",
Messages: []Message{{Role: "user", Content: "帮我查一下合同条款"}},
})
// 列出 alice 的会话
sessions, err := cell.Sessions().List(ctx, SessionListOptions{
Actor: "alice",
Limit: 20,
})
// 中断正在进行的 Run
err := cell.Sessions().Interrupt(ctx, "session-001")