第 3 讲:Session 会话核心

OpenCode 源码解析 · 第 3 讲

OpenCode 源码解析 第 3 讲:Session 会话核心 基于 dev 分支源码 · 2026-07-09 📖 开篇导读 第 1 讲我们俯瞰了 OpenCode 的 Monorepo 全景,第 2 讲拆解了 CLI 入口与命令路由。今天深入 Session 会话核心 ——这是整个系统的"心脏"。Session 负责管理一次完整的 AI 对话生命周期:从用户输入、LLM 推理、工具执行到上下文压缩和持久化。Session 层横跨 packages/core/src/session/ (25 个文件,3657 行)和 packages/opencode/src/session/ (24 个文件,8034 行),总计约 11700 行源码 。 一、Session 的三层架构 OpenCode 的 Session 设计遵循"Schema → Core → Application"的三层分离: packages/schema/src/session*.ts Schema 层:类型定义与事件清单 ⬇️ 依赖 packages/core/src/session/ Core 层:Effect 服务、SQLite 持久化、执行编排 ⬇️ 依赖 packages/opencode/src/session/ 应用层:LLM 流式处理、上下文溢出、V1 兼容 二、Schema 层:会话的类型骨架 packages/schema/ 定义了 Session 相关的所有类型,共 64 个文件 ,其中直接关联 Session 的核心文件包括: Schema 文件 职责 session.ts Session ID、Info 结构体、版本字段 session-message.ts V2 消息类型(user/assistant/system/tool) session-input.ts 用户输入准入(Admitted)与投递模式 session-event.ts 会话事件定义(PromptAdmitted、MessageUpdated 等) session-compaction-event.ts 上下文压缩事件 session-todo.ts Todo 列表信息结构 prompt.ts / prompt-input.ts Prompt 结构与附件类型 Session ID 使用 ulid 库生成时间排序的唯一标识符。V2 消息系统引入了序列号( seq )机制,每条消息在 SQLite 中按序列号严格排序,确保事件溯源的一致性。 三、Core 层:Effect 驱动的会话引擎 packages/core/src/session/ 是 Session 的核心实现,基于 Effect 函数式编程范式构建。以下是关键模块: 3.1 SessionStore — 会话数据存取 packages/core/src/session/store.ts 定义了 SessionStore.Service ,提供四个核心接口: interface Interface { get(sessionID: ID) → SessionSchema.Info | undefined context(sessionID: ID) → SessionMessage.Message[] runnerContext(sessionID: ID, baselineSeq: number) → Message[] message(messageID: ID) → { sessionID, message } | undefined } context() 通过 SessionHistory.load() 加载完整会话历史; runnerContext() 则加载从指定基线序列号之后的消息,用于 V2 Runner 增量加载。两者都考虑了压缩(compaction)边界——压缩后的历史只保留最新压缩点之后的消息。 3.2 SessionExecution — 执行路由 packages/core/src/session/execution.ts 定义了 Session 执行的抽象接口: interface Interface { active() → ReadonlySet<SessionID> // 当前…

阅读全文:OpenCode 源码解析 第 3 讲