internal/session是会话领域模型、SQLite 存储实现和资产持久化的唯一归属层。internal/runtime只决定何时创建会话、追加消息、更新会话头和替换 transcript,不关心底层表结构。internal/tui只消费 runtime 暴露的会话数据,不直接读取数据库或资产文件。
NeoCode 当前使用工作区级 SQLite 数据库持久化会话,不再使用 session.json 文件。
- 数据库路径:
~/.neocode/projects/<workspace-hash>/session.db - 资产目录:
~/.neocode/projects/<workspace-hash>/assets/<session-id>/<asset-id>.bin - 工作区哈希基于启动时确定的工作区根目录生成
session.Workdir记录该会话最近一次运行实际使用的目录,但不参与分桶- 开发阶段遗留的旧
sessions/JSON 目录不迁移、不回读、不兼容
SQLite 初始化固定使用以下 PRAGMA:
journal_mode = WALsynchronous = NORMALforeign_keys = ONbusy_timeout = 5000user_version = 1
会话头保存摘要和 durable 状态:
idtitlecreated_at_msupdated_at_msprovidermodelworkdirtask_state_jsontodos_jsonactivated_skills_jsontoken_input_totaltoken_output_totallast_seqmessage_count
消息正文按行存储,一条消息对应一行:
session_idseqroleparts_jsontool_calls_jsontool_call_idis_errortool_metadata_jsoncreated_at_ms
资产元数据入库,二进制内容落盘:
idsession_idmime_typesize_bytesrelative_pathcreated_at_ms
runtime 在新会话开始时调用 CreateSession,只写入一条空会话头,不写消息正文。
runtime 在以下时机调用 AppendMessages:
- 用户消息提交后
- assistant 完整回复后
- 每个 tool result 完成后
一次调用会在同一事务内完成两件事:
- 追加 1..N 条消息
- 更新会话头上的
updated_at、provider、model、workdir、token 增量和消息计数
因此常规写入不再与历史消息总量线性耦合。
runtime 在以下场景调用 UpdateSessionState:
- workdir 变更
- task_state 变更
- todo 列表变更
- skill 激活状态变更
- assistant 本轮没有正文,但 provider/model 或 token 统计发生变化
该操作不写消息,只覆盖会话头字段。
compact 成功后,runtime 调用 ReplaceTranscript,在单事务内:
- 删除该会话原有全部消息
- 按新顺序写回 compact 后的消息
- 同步更新
task_state、token 统计、provider/model/workdir 和消息计数
这是低频路径,允许重写整段 transcript。
ListSummaries只查询sessions表,并按updated_at倒序返回摘要LoadSession先读取会话头,再按seq顺序加载消息并组装完整Session
- runtime 在 assistant 调用完成后累计输入和输出 token
AppendMessages可以原子地追加消息并累加 tokenUpdateSessionState和ReplaceTranscript可以直接覆盖 token 总量- compact 成功后,runtime 会将 token 总量重置为 0 并持久化
TaskState是 compact 与多轮续航依赖的 durable summaryTodo是结构化任务状态,独立持久化在sessions.todos_json- 二者都属于会话头,不写入
messages表 - context 构建时优先读取
TaskState、Todo、最近消息和必要工具结果
- SQLite 负责单工作区数据库的一致性和事务边界
- runtime 继续通过会话锁串行化同一 session 的关键写入路径
- 不同 session 可以并行运行
- 新增持久化行为时,优先扩展
internal/session.Store的意图型接口 - 不要把 SQL、事务或表结构细节泄漏到
runtime、tui或其他上层模块 - 如需进一步优化读路径,应继续在
internal/session内演进,而不是重新引入文件级快照保存