跳转至

第 1 章:总览 —— OpenCode 不是一个 Loop,而是一台 Agent 产品运行时

1. 三种看 OpenCode 的视角

打开仓库时很容易被 packages/apppackages/opencodepackages/core 和一大组 workspace package 分散注意力。先固定三个视角:

视角一:产品

OpenCode 是一个开源 coding agent。用户可以从 CLI 启动 TUI,可以直接 run 一次任务,也可以运行 Server,让 Web、Desktop、远程 SDK 或 ACP 连接进来。README 中的 buildplangeneral agent 只是产品层入口,真正的执行能力在服务层。

视角二:运行时

运行时由 Effect Layer 组装。packages/opencode/src/effect/app-runtime.tsAppLayer 把 Database、Config、Provider、Session、LLM、LSP、MCP、ToolRegistry、Project、Workspace 等服务组合起来,再由 ManagedRuntime 提供 runPromise 等执行出口。

视角三:可恢复系统

Session 不是一组内存消息,而是由数据库、事件、消息投影、输入箱和 Context Epoch 组成的长期对象。SessionRunner 只负责当前进程拥有的 drain;它不拥有 Session 的永久身份,也不把“正在运行”写成一条不可恢复的黑盒状态。

2. 顶层数据流

flowchart TB
  subgraph Hosts[宿主]
    CLI[packages/opencode CLI]
    TUI[packages/tui]
    APP[packages/app]
    DESKTOP[packages/desktop]
    ACP[ACP adapter]
  end
  subgraph Boundary[稳定边界]
    API[Effect HttpApi]
    CLIENT[client / sdk-next]
    EVENTS[Event V2 / Sync / SSE]
  end
  subgraph Runtime[OpenCode runtime]
    SERVER[packages/opencode server]
    CORE[packages/core services]
    LLM[packages/llm]
  end
  subgraph State[状态]
    DB[(SQLite)]
    FS[(project filesystem)]
    PROVIDER[Provider APIs]
  end
  CLI --> SERVER
  TUI --> CLIENT
  APP --> CLIENT
  DESKTOP --> CLIENT
  ACP --> SERVER
  CLIENT --> API
  API --> SERVER
  SERVER --> CORE
  CORE --> LLM
  CORE --> DB
  CORE --> FS
  LLM --> PROVIDER
  SERVER --> EVENTS
  EVENTS --> TUI
  EVENTS --> APP

3. 最值得先记住的五个边界

边界 责任 不应该做什么
Schema 定义 ID、消息、Part、Event、Prompt 的可编码形状 不放 UI 行为和 provider 具体调用
Core 领域服务、数据库、Session V2、工具和位置作用域 不依赖具体 UI 宿主
Server 启动 runtime、鉴权、路由、HTTP/WebSocket 不让客户端导入后端私有模块
LLM canonical request / event 与 provider wire format 不决定 Session 如何落盘
Client / SDK 把 HttpApi 变成调用者可消费的 API 不复制 server orchestration

这种分界让同一个 Session 能被 TUI 和 Web 同时观察;也让 provider 适配器可以替换,而不要求 TUI 知道 Anthropic 或 OpenAI 的请求格式。

4. OpenCode 的中心不是 prompt(),而是“事实 + 投影”

旧式 Agent 通常是:

const messages = [...history, userMessage]
const result = await model.generate(messages, tools)

OpenCode 的现实更接近:

durable input
  → promotion event
  → projected session history
  → canonical LLM request
  → streamed domain events
  → durable message / part projection
  → tool settlement
  → next provider turn

这里有两个重要推论:

  1. 模型请求是投影,不是事实本身。 需要重新请求时,系统可以从 durable history 和当前 Context Epoch 重建。
  2. 执行状态是局部的。 某个进程正在跑,并不意味着 Session 的全部语义只存在于这个进程的内存里。

5. 代码规模带来的阅读策略

OpenCode 的 packages/opencode/src 同时包含 CLI、V1 服务、V2 路由、插件、MCP、LSP、分享、安装和迁移代码。如果按目录顺序读,会把“产品功能”误认为“核心执行链”。建议先走这些入口:

  1. packages/opencode/src/index.ts:CLI 命令地图。
  2. packages/opencode/src/effect/app-runtime.ts:运行时依赖地图。
  3. packages/opencode/src/server/server.ts:HTTP listener 和 runtime 生命周期。
  4. packages/opencode/src/server/routes/instance/httpapi/api.ts:API 组合边界。
  5. packages/core/src/session/runner/llm.ts:Session V2 的真实 provider-turn。
  6. packages/core/src/system-context/*:上下文的稳定基线和更新机制。
  7. packages/opencode/src/tool/registry.ts / packages/core/src/tool/*:两代工具系统的连接处。

不要从 UI 开始

UI 文件很多,但它们主要告诉你“服务器暴露了什么”。要理解“为什么状态会这样变化”,先读 Schema、Session、Event 和 API,再回到 TUI / App。

6. 本章小结

  • OpenCode 是一个带 Server、数据库、SDK 和多端宿主的产品运行时。
  • Session V2 把 prompt admission、provider turn、tool settlement 和事件回放拆开。
  • Effect Layer 是依赖装配图,不只是异步语法。
  • API 和 Event 是客户端与后端之间的主边界。

源码锚点