Skip to content

OpenCode Session & Runner

SessionV2

OpenCode 的 Session 是全事件溯源的 durable session。这是它和 Pi/Hermes 最大的架构差异。

text
packages/core/src/session.ts

核心模型

typescript
interface SessionV2 {
  id: string;
  input: SessionInput;   // 输入项(user messages, tool approvals)
  events: EventV2[];      // 事件流(完整执行历史)
  state: SessionState;    // 派生状态(从 events 投影)
}

EventV2 事件溯源

OpenCode 将每个操作建模为事件:

typescript
type EventV2 =
  | UserMessageEvent      // "用户发送了消息"
  | AssistantDeltaEvent   // "模型返回了 delta"
  | ToolCallStartedEvent  // "开始执行工具"
  | ToolCallCompletedEvent // "工具执行完成"
  | PermissionAskedEvent  // "请求权限"
  | SessionCompressedEvent // "会话被压缩"
  | StopEvent             // "停止信号"
  | ErrorEvent            // "错误"

所有事件写入 SQLite,状态可以被随时重放

SessionV2.prompt() 调用

typescript
class SessionV2 {
  prompt(input: string, options: PromptOptions): Effect<PromptResult> {
    // 1. 构建 session_input
    // 2. 确保 session 被唤醒(wake)
    // 3. 触发 SessionExecution.local().execute()
    // 4. 返回最终响应
  }
}

SessionRunner

text
packages/core/src/session/runner/

SessionRunner 是实际运行 agent 的引擎:

SessionRunner.run()

1. 准备 context(历史消息 + system prompt + 工具)
2. LLM.request()
3. 处理响应
   ├─ text delta → 追加到 stream
   └─ tool_calls → ToolRegistry.settle()
4. 事件持久化
5. 循环直到完成或达到限制

与 Hermes 的 Session 对比

维度OpenCodeHermes
存储SQLite (event-sourced)SQLite + FTS5 (message-centric)
投影状态从事件重放状态直接存储
压缩事件压缩 + 重放消息压缩 + 摘要
搜索事件查询FTS5 全文搜索
可恢复性完全(事件流完整)部分(消息历史完整)

为什么 Event Sourcing?

OpenCode 使用事件溯源的好处:

  1. 审计追踪:完整知道 agent 做了什么
  2. 调试:回放任何一个 session
  3. 断点续传:crash 后从最后事件恢复
  4. 多客户端:event stream 可以推送多个 TUI/web 客户端

代价是复杂度比 Hermes 的消息存储方式高不少。

Powered by VitePress