Session 是用户与 Agent 协作的基本单位。它绑定一个工作目录,并保存从用户消息到工具执行结果的完整时间线。
产品入口
每个 Workspace 下都有独立的 Session 列表。Session 支持创建、切换、重命名、置顶、排序和删除。
保存的内容
- 标题、工作目录和当前模型。
- 用户消息和 Assistant 消息。
- 工具调用、工具结果和 Approval 结果。
- 推理、图片和隐藏上下文。
- 分支根、直接父 Session、精确分叉点、Goal、Team、Schedule 和恢复点关联。
Session 消息使用追加写历史。模型输入、append、fork、rewind、compaction、export 和知识沉淀使用严格读取;JSONL 出现坏行时 fail closed,避免在残缺历史上继续写入。诊断视图可以保留已经解析的消息,但会明确记录坏行。meta 中的 message_revision 只在真实 append 或 rewrite 后单调推进,用于识别同一毫秒内的变化;完全相同的幂等 append 不推进 revision。
等待队列为每条消息分配稳定 ID 和创建时间。claim、append 和 acknowledge 分步持久化,崩溃重放不会重复追加同一条用户消息,也不会重新解析已经提交的文件、URL、Context 或 Image snapshot。
删除与恢复
删除 Session 使用持久 tombstone 阻止新 run、queue admission 和新的 Knowledge 写入,并取消活动 run,最多等待 3 秒。随后等待该 Session 的 consolidation lease 释放。选择删除并沉淀时,蒸馏、usage 结算或 revision 校验失败都会停止删除。
真正清理前,kxen 会建立 recovery bundle,包含 meta、messages、compaction、queue、artifacts、Team、Goal、Schedule 和 usage 关联状态。bundle stage 成功后才 purge 原数据,随后把 bundle 移入系统废纸篓。中间失败会精确回滚,或者保留 tombstone 供启动恢复,不会把部分删除报告为成功。
从系统废纸篓恢复 .kxen-session bundle 后,应用启动扫描可以重新导入。目标路径冲突或 bundle 损坏时 fail closed,并保留恢复证据。
存储一致性恢复
当消息 JSONL 或 pending queue 处于 blocked、尾部不完整或损坏状态时,Composer 上方会显示存储恢复面板。健康 Session 不显示该面板。
- 检查会分别报告消息日志和队列的完整性、写入阻塞和可证明恢复性。
- 仅缺少最后换行的完整 JSON 记录会保留记录并追加换行。不完整最后一段只有在可证明是尾部时才可移出工作副本。
- 修复 JSONL 前,kxen 会把原始字节完整备份到
sessions/.recovery/,权限为0600,并在界面显示证据路径。 - 中间坏行、重复 message ID、Session ID 不匹配或队列无法与期望快照对齐时不会自动修复。原文件保持不变,用户应先导出诊断包。
- 恢复不会在 active run 期间执行。只有 Session 与 Queue 两个 store 都可证明恢复时,后端才会解除写入阻塞。
时间线操作
用户可以编辑并重新发送消息,从指定消息创建分支,重新生成 Assistant 回合,以及导出当前 Session。每个分支本身都是完整 Session,独立拥有消息历史、模型覆盖、待发送队列、运行状态和 Composer 草稿。原 Session 和原回复保持不变,不会把两个后续执行混进同一条时间线。
创建分支
- 「从此消息分叉」复制到目标消息之后,创建手动分支并切入。
- 编辑 User 消息时,从目标消息之前创建编辑分支,再发送修改后的文本、原始图片和可逆 Context。第一条消息也使用相同谱系,不会变成无关的新 Session。
- 重新生成 Assistant 回合时,从关联 User 消息之前创建重新生成分支,再原样发送该消息。原 Assistant 回复永久保留在原分支。
每个新分支记录稳定分支根、直接父级、父级消息 ID、从 1 开始的消息序号、消息时间、before 或 after 位置,以及 manual、edit 或 rerun 来源。旧版分支缺少精确分叉点时仍可沿父链导航,并明确标记为存量数据。
导航和删除
Sidebar 在 Workspace 项目下按父子层级展示 Session。Session Header 的分支选择器用于切换同一分支族、返回直接父级,并显示当前分支位置和创建来源。
删除只作用于当前选择的 Session,不级联删除后代。父分支被删除后,后代继续可用,Sidebar 和 Header 会显示父级缺失;从系统废纸篓恢复父级后,既有 parent_id 会重新连通谱系。
文件状态边界
对话分支不是 Git branch,也不是文件快照。同一 Workspace 下的分支共享当前文件状态:一个分支中的工具修改可能被其他分支随后读取。Header 和 Markdown 导出都会标记这一边界。
只需独立探索对话时使用分支。需要隔离文件修改时,先创建独立 Worktree 再开始 Session;需要把当前 Session 和文件共同回退到恢复点时使用 Rewind。
状态边界
每个 run 必须结束为完成、取消或错误。界面停止流式更新不代表后端 run 已结束。活动状态、等待队列和 Approval 共同决定 Session 是否仍在运行。
Trajectory 检视视图
Session 页提供 Chat 和 Trajectory 两个标签。两者读同一份追加写事件流:Chat 负责阅读,Trajectory 负责检视。
- 记录表是三列结构(序号、事件类型、内容),事件类型为封闭集合:system、user、context(上下文注入)、compacted、message、tool、subtool。tool-call 与 tool-result 合并为一行,耗时取执行实测起止之差。
- 工具栏提供 Duration 列开关、Collapse turns(折叠轮次只保留首行和「N 步骤 · N 工具调用」计数)、Collapse calls(工具行只留名字)和覆盖已加载窗口全部记录的搜索。
- 记录表上方的 Overview 把有真实计时数据的记录按起止投影为时间条。Assistant 条以首个非空 token 为界区分 TTFT 与解码两段配色;计时不完整的记录退化为单一颜色或不投影,不会虚构耗时。支持左键拖选聚焦(记录表随之只显示与闭区间重叠的记录)、滚轮缩放、右键拖动平移、右键单击清除选区,悬停 500ms 显示精确起止、总耗时和 TTFT/解码拆分。
- 点击任意记录在侧栏打开检查器。消息类记录给内容、来源和 provider/模型字段;工具类记录给 Summary、Payload、Result、Schema 和 Timing。图片按媒体渲染。
- 长会话按尾部优先分页并做行虚拟化:打开定位到最新记录,记录表只挂载可视窗附近的行;滚到顶部自动加载更早一页(顶部按钮是同语义的显式入口),加载完成后视口内容原位不动。视图跟随尾部,用户上滚后暂停跟随,新记录到达只增加底部占位,不打断检视。
- Chat 中每条工具行悬停露出「Inspect」入口,点击切到 Trajectory 并定位展开对应记录;切回 Chat 恢复原阅读位置。工具行展开后分 IN(调用参数)和 OUT(执行结果)两区;参数带文件路径时路径可点击,桌面端直接用系统方式打开,web 端复制路径。
- Chat 中来源消息(teammate 来信、task notification)和 @/# 上下文注入默认折叠为带来源标题的卡片,展开查看全文;普通用户口信保持气泡直出。
- Composer 右侧显示上下文占用圆环和估算百分比,点击展开系统提示词、工具定义、对话消息三段组成明细。三段为 chars/4 粗估(标记 ~),与最近一次 run 的 provider 实测输入并列展示但不对账;尚无实测时实测项显示未知。
未持久化的字段(例如调用发生时的 schema 快照、存量会话缺省的工具起止时间)一律显示为未知或留空,不会用当前配置回填历史。token 用量只出现在 run 收尾消息的统计快照里;计量不完整时界面标注 token 数为已知下限。
进入 Session 或手动重试时,界面会把请求开始时的 baseline、后端 snapshot 和加载期间收到的 live 事件按 message ID 与 Approval occurrence 对账。已经落盘的记录接管对应 optimistic 或 live 前缀,但只存在于 live 流中的新记录不会被旧 snapshot 抹掉。切换 Session、存储恢复或新的 queue 更新会使旧加载 generation 失效,迟到结果不能复活上一 Session 的时间线或队列。
时间线和 queue 分别保留错误来源,可以单独重试。存储恢复成功后,界面取消旧 generation、清除旧加载错误并重新读取两者的后端真相。