OpenCode 将会话数据存储在一个 SQLite 关系型数据库中。与许多将每个会话存为独立文件的工具不同,这种设计让会话成为一个结构化的“一等公民”,具备了更强的可查询性和可管理性。
其数据库设计的核心精髓可以总结为以下三点:
- 以 SQLite 为存储核心:所有会话、消息等数据都集中存放在一个
opencode.db数据库文件中。 - 以 Drizzle ORM 为建模工具:使用 Drizzle ORM 在
session/session.sql.ts中定义数据表结构(Schema)。 - 以 JSON 为灵活载荷:消息和部件(Part)的具体内容以 JSON 格式存储在
data文本列中。
下面是其核心数据表的详细设计。
🏗️ 核心数据表设计
OpenCode 的数据库核心由几张相互关联的表组成,用于清晰地组织和查询会话数据。其主要表和字段如下:
project 表 (项目)
记录 OpenCode 打开过的每一个 Git 仓库。
id: 项目唯一标识。name: 项目名称。worktree: 工作树路径。vcs: 版本控制系统信息。
session 表 (会话)
存储每一次独立对话的元数据。
id: 会话唯一标识。project_id: 外键,关联到所属项目。parent_id: 外键,指向父会话,用于实现子代理(subagent)等场景。directory: 会话的工作目录。title: 会话标题。slug: 会话的简短标识符。time_created/time_updated: 创建和更新时间戳。time_archived: 归档时间戳。cost: 会话总成本。tokens_input/tokens_output: 输入和输出的 Token 数量统计。
message 表 (消息)
存储会话中的每一条消息。
id: 消息唯一标识。session_id: 外键,关联到所属会话。time_created/time_updated: 创建和更新时间戳。data: JSON 文本,存储消息的完整内容(如角色、模型、耗时、Token 详情等)。
part 表 (部件)
存储构成消息的各个部分,是 OpenCode 实现细粒度管理的核心。
id: 部件唯一标识。message_id: 外键,关联到所属消息。session_id: 外键,关联到所属会话。time_created/time_updated: 创建和更新时间戳。data: JSON 文本,存储部件的具体内容,如文本、推理过程、工具调用等。
此外,还有 todo 表用于追踪任务,permission 表用于管理权限。
📦 消息与部件的 JSON 结构
message 和 part 表的 data 列是 JSON 格式,这种设计提供了极大的灵活性。
-
message.data结构:以 Assistant 消息为例,其 JSON 包含了丰富的元数据:{ "role": "assistant", "mode": "build", "agent": "build", "modelID": "qwen2.5-coder:7b", "providerID": "ollama", "cost": 0, "tokens": { "total": 4117, "input": 4096, "output": 21, "reasoning": 0 }, "time": { "created": 1780398431744, "completed": 1780398480810 }, "finish": "stop" } -
part.data结构:data中的type字段定义了部件的类型,常见类型包括text,reasoning,tool等。- 文本部件 (
text):包含实际的对话文本。 - 工具调用部件 (
tool):结构如下:{ "type": "tool", "tool": "read", "callID": "call_...", "state": { "status": "completed", "input": { "filePath": "..." }, "output": "..." } }
- 文本部件 (
🚀 分片与扩展设计
随着会话增多,单个 SQLite 数据库可能成为性能瓶颈。为此,OpenCode 引入了 会话树分片(Session-tree Sharding) 的设计。
- 核心思想:每个“根会话”及其所有子会话(如子代理)的数据,会被独立存储到各自的 SQLite 数据库文件中。
- 实现方式:
- 在
session表中增加root_session_id字段来标识会话树。 - 会话的元数据(如标题、时间等)仍保留在全局的
opencode.db中。 - 而
message、part、todo等详细数据则写入该会话树专属的数据库文件。
- 在
这种设计有效减轻了单一数据库的写入压力,并为未来实现跨机器的会话同步与恢复提供了基础。
🔄 会话的生命周期管理
OpenCode 将会话视为活跃的系统组件,支持丰富的状态管理。
- 状态流转:会话可以处于活跃、归档(
time_archived)等状态。 - 版本控制与回滚:通过
version字段和revert元数据支持会话的版本管理和回滚功能。 - 数据压缩:支持对长会话进行压缩(compaction),以优化性能。
💡 补充设计考量
- 并发安全:OpenCode 以 WAL (Write-Ahead Logging) 模式打开数据库。外部工具应始终以只读方式连接,避免与 OpenCode 的写入操作冲突。
- 版本迁移:通过
__drizzle_migrations表和迁移文件管理数据库 Schema 的版本演进。 - 历史遗留:在 SQLite 方案之前,OpenCode 曾使用过按项目和消息 ID 分层的 JSON 文件存储方式。迁移工具会将旧数据导入 SQLite。
总而言之,OpenCode 的会话数据库设计通过 SQLite 的集中存储、Drizzle ORM 的清晰建模,以及 JSON 字段的灵活扩展,实现了一个强大、可查询且支持复杂工作流的会话管理系统。其引入的会话树分片机制,更是为大规模使用和未来的分布式扩展奠定了基础。