第 8 章 · 02 三前端实现与 ACP 编辑器集成


文档摘要

第 8 章 · 02 三前端实现与 ACP 编辑器集成 本节摘要:本节走进三个前端的真实实现——同一个 ,四种截然不同的前端形态。TUI 前端用 Charm 全家桶(bubbletea/lipgloss/bubbles)画终端,有 CLI 主题和图片折叠效果;HTTP/SSE serve 前端是 OpenAI 兼容的 HTTP 网关,远程客户端按 OpenAI 协议接入;Wails 桌面前端用 Go 后端 + React 19 前端,富交互桌面应用;此外还有 ACP(Agent Client Protocol)编辑器集成,internal/acp(13066 行)把 Controller 适配成 stdio JSON-RPC,VS Code 扩展通过 ACP 协议驱动 Reasonix。

第 8 章 · 02 三前端实现与 ACP 编辑器集成

本节摘要:本节走进三个前端的真实实现——同一个 control.Controller,四种截然不同的前端形态。TUI 前端用 Charm 全家桶(bubbletea/lipgloss/bubbles)画终端,有 CLI 主题和图片折叠效果;HTTP/SSE serve 前端是 OpenAI 兼容的 HTTP 网关,远程客户端按 OpenAI 协议接入;Wails 桌面前端用 Go 后端 + React 19 前端,富交互桌面应用;此外还有 ACP(Agent Client Protocol)编辑器集成,internal/acp(13066 行)把 Controller 适配成 stdio JSON-RPC,VS Code 扩展通过 ACP 协议驱动 Reasonix。三前端各有所长——TUI 轻量、SSE 远程、桌面富交互——但共享同一个 Controller,行为完全一致。本节末尾给出三前端对比表。

内容来源:原项目源码 internal/servedesktop/internal/acp/protocol.go,配图 images/cli-theme-effect.svgimages/paste-folding-effect.svgimages/desktop-v2-layout-preview.pngimages/desktop-v2-skills-preview.pngimages/desktop-theme-dark.jpgimages/slash-command-views.svgimages/project-topic-tabs-context.png,对照 docs/serve_protocol.md

⚠️ 注意:本节聚焦"前端如何适配 Controller",不深入 Charm/Wails/React 各自的 API 细节。读者可结合官方文档学习具体前端框架。

学习目标

阅读完本节,你应当能够:

  1. 说出 TUI 前端用了 Charm 哪三个核心库(bubbletea/lipgloss/bubbles)及其分工。
  2. 解释 HTTP/SSE serve 为什么做成 OpenAI 兼容网关——远程客户端零成本接入。
  3. 描述 Wails 桌面的技术栈(Go 后端 Wails + React 19 前端)和它如何桥接 Controller。
  4. 讲清 ACP(Agent Client Protocol)是什么、internal/acp 如何把 Controller 适配成 stdio JSON-RPC、VS Code 扩展如何接入。
  5. 用对比表说清三前端各自的定位(TUI 轻量 / SSE 远程 / 桌面富交互)。

一、TUI 前端:Charm 全家桶

TUI(Terminal User Interface)是 Reasonix 的默认前端——开箱即用、零依赖、SSH 友好。它用 Charm 生态的三个核心库搭建:

作用
bubbletea Elm 架构(Model-Update-View)的 TUI 框架,管理状态和事件循环
lipgloss 终端样式(颜色、边框、布局),声明式写终端 UI
bubbles 常用组件(文本框、列表、分页、spinner 等)

TUI 前端对 Controller 的适配是教科书式的"命令/事件双流"消费:

  • 命令方向:用户在终端按键 → bubbletea 把按键翻译成命令 → 调 Controller 的 Send/Cancel/Approve 等。
  • 事件方向:Controller 吐事件 → TUI 实现一个 event.Sink 把事件渲染成终端字符 → bubbletea 触发重绘。

1.1 CLI 主题效果

TUI 不是丑陋的纯文本,Reasonix 用 lipgloss 做了完整的 CLI 主题系统,效果见 images/cli-theme-effect.svg——配色、边框、状态栏、工具调用块都有视觉设计。主题让终端里的 agent 输出有结构感:推理段落一种颜色,工具调用一种颜色,审批请求一种颜色,用户一眼能分辨当前 agent 在干什么。

主题系统写在 Controller 之外(它是 TUI 专属的表现层,第 1 节讲过判断标准——UI 表现属于前端专属)。但这不影响行为一致性——主题只改颜色不改语义,TUI 用户和桌面用户看到的 agent 行为是同一套。

1.2 图片折叠效果

images/paste-folding-effect.svg 展示了 TUI 的图片折叠技巧——当 agent 输出大段图片(比如粘贴截图、生成图表)时,TUI 默认折叠只显示一行摘要,用户按键展开看全图。这是终端场景的工程优化:终端宽高有限,大图片会刷屏,折叠让会话流保持紧凑。

这个折叠行为是 TUI 专属的(桌面对话框直接显示,SSE 用 URL 引用),所以写在 TUI 前端里而不是 Controller 里。Controller 只负责吐出"这里有一张图"的事件,怎么显示由各前端决定。

💡 契约要点:TUI 前端是"命令/事件双流"最纯粹的消费者。bubbletea 管状态机和重绘,lipgloss 管样式,bubbles 提供组件。主题和图片折叠是 TUI 专属表现层,不进 Controller——这是"判断行为是否跨前端共享"的实操案例。

二、HTTP/SSE serve 前端:OpenAI 兼容网关

internal/serve 实现了 HTTP/SSE serve 前端。它的定位很特别——它是一个 OpenAI 兼容的 HTTP 网关

2.1 为什么做成 OpenAI 兼容

OpenAI 的 Chat Completions API 是事实上的行业标准(/v1/chat/completions、SSE 流式响应、tool calling)。Reasonix 把 serve 前端做成 OpenAI 兼容,意味着:

  • 任何 OpenAI 兼容客户端(Cursor、Continue、openai-python、各种聊天 UI)都能直接接入 Reasonix。
  • 远程用户不需要装 Reasonix,只要会调 OpenAI API 就能用。
  • 集成到现有工具链零成本——把 base URL 从 api.openai.com 改成本地 reasonix serve 的地址即可。

这是"传输无关 Controller"的远程延伸——serve 前端把 Controller 的事件流翻译成 OpenAI 风格的 SSE 数据帧(data: {...}\n\n),把 HTTP POST 的 chat completion 请求翻译成 Controller 的 Send 命令。协议层是 OpenAI 兼容的,但底层执行是完整的 Reasonix agent(工具、权限、沙箱、缓存全都在)。

docs/serve_protocol.md 详细描述了这个协议——支持的端点、SSE 事件格式、鉴权、会话管理。serve 还提供了 index.html/login.html/provider_setup.html 等内置网页,用户开浏览器就能用。

2.2 serve 的文件构成

internal/serve/ serve.go 主入口 auth.go 鉴权 broadcaster.go SSE 广播(把一个事件流扇出给多个订阅者) provider_setup.go 模型配置页面 index.html 内置聊天网页 login.html 登录页 ...

broadcaster.go 是个有意思的组件——一个 Controller 的事件流,可能要同时推给网页 UI、日志、计费等多个订阅者。broadcaster 做"一进多出"的扇出,让多个订阅者各自收到完整事件流。

serve 前端的存在证明了 transport-agnostic 的威力——HTTP/SSE 是和终端完全不同的传输层,但接的是同一个 Controller,跑的是同一套 agent 行为。远程用户和本地 TUI 用户得到的体验在语义上完全一致。

💡 契约要点:serve 前端是 transport-agnostic 的远程证明。OpenAI 兼容协议让 Reasonix 能被任何标准客户端调用,把"本地 coding agent"延伸成"远程 agent 服务"。底层 Controller 不变,只换了传输层和协议适配层。

三、Wails 桌面前端:Go 后端 + React 19 前端

desktop/ 是 Reasonix 的桌面前端,技术栈是 Wails + React 19。

3.1 Wails 是什么

Wails 是 Go 的桌面应用框架,定位类似 Electron 但用 Go 代替 Node.js 做后端——Go 编译成原生二进制,前端用 Web 技术(React/Vue 等)渲染。相比 Electron,Wails 的优势是:

  • 二进制小:Go 静态编译,不捆绑整个 Chromium 和 Node 运行时。
  • 内存省:Go 后端比 Node 后端省内存。
  • 原生体验:用系统 webview 而不是自带 Chromium。

这和 Reasonix 的"薄 harness + 单静态二进制"哲学(第 1 章)完全契合——Wails 让桌面应用也是一个相对轻量的二进制,而不是动辄几百 MB 的 Electron 包。

3.2 技术栈分层

桌面前端的分层:

React 19 前端(UI 层) - 状态管理:Zustand - 终端组件:xterm.js - 数学公式:KaTeX - 图表:Mermaid ↓ Wails 桥(双向调用) Go 后端(Wails 绑定) - 调 control.Controller(命令) - 实现 event.Sink(事件) - 持有桌面专属逻辑(主题、窗口、文件拖拽)

React 19 前端用了几个值得注意的库:

  • Zustand:轻量状态管理,比 Redux 简洁,适合中等复杂度应用。
  • xterm.js:在浏览器/webview 里渲染真终端,桌面应用可以内嵌一个完整终端跑命令。
  • KaTeX:渲染数学公式,让 agent 输出的 LaTeX 公式美观显示。
  • Mermaid:渲染流程图/时序图,agent 输出的图表直接可视化。

这些都是桌面专属的富交互能力——TUI 画不了数学公式和流程图,SSE 客户端通常也不渲染 Mermaid。桌面用 React 把这些做好,但底层的 agent 推理、工具调用、审批流还是走 Controller。

3.3 桌面布局与主题

images/desktop-v2-layout-preview.png 展示了桌面 v2 的整体布局——侧边栏(会话列表/Bots)、主区域(对话)、底部(输入框)、可能还有 Skills 面板(images/desktop-v2-skills-preview.png)。这是富交互桌面应用的标配。

images/desktop-theme-dark.jpg 是暗色主题的截图。Reasonix 桌面自带 8 套官方主题(第 10 章第 2 节详述 desktop/themes/official/),用户可以切换。主题是桌面专属的(终端有 CLI 主题、桌面有桌面主题),但都只是表现层,不影响 agent 行为。

桌面 Go 后端还做了一件重要的事——它同时承载 bot 运行时(bot_bridge.go/bot_runtime_app.go 等)。也就是说,桌面应用除了是 Reasonix 的 UI,还是 IM 机器人(第 10 章第 1 节)的运行宿主。这是桌面相对 TUI/SSE 的独特定位——它不只是前端,还是集成枢纽。

⚠️ 注意:桌面是体量最大的前端(Go 后端 11.1 万行 + React 前端 12.6 万行),但它依然只是 Controller 的一个消费者。bot_bridge 这些桥接代码把 IM 网关接进来,但不重新实现 agent 逻辑。判断一个功能该不该写进桌面后端的标准还是那条——是否跨前端共享。

四、ACP:Agent Client Protocol 编辑器集成

第四个"前端"严格说是编辑器集成——internal/acp(13066 行)实现了 ACP(Agent Client Protocol)。

4.1 ACP 是什么

ACP 是一个开放协议(agentclientprotocol.com),让编辑器(VS Code、Neovim、Zed 等)能标准化地驱动 AI coding agent。可以理解为"AI agent 的 LSP"——LSP 让编辑器和语言服务器对话,ACP 让编辑器和 agent 对话。

internal/acp/protocol.go 的包注释说得很清楚:

// Package acp implements the Agent Client Protocol // (https://agentclientprotocol.com) transport: a stdio JSON-RPC 2.0 agent // that editors and other host clients speak to drive Reasonix. ... // The package is an adapter layer over the v2 kernel and depends only on // stable contracts: it maps the agent's typed event.Event stream onto // session/update notifications, bridges permission.Approver onto // session/request_permission round-trips, and exposes the whole thing over // NDJSON JSON-RPC.

关键信息:

  • stdio JSON-RPC 2.0:ACP 用标准输入输出传 JSON-RPC 消息,这是编辑器集成的事实标准(LSP 也用 stdio)。
  • adapter layer(适配层):ACP 包是"适配器",它不实现 agent 逻辑,只做协议翻译。
  • maps event onto notifications:把 Controller 的事件流映射成 ACP 的 session/update 通知。
  • bridges permission.Approver onto request_permission:把 Reasonix 的权限审批桥接成 ACP 的 session/request_permission 往返请求。

4.2 ACP 的协议版本契约

// ProtocolVersion is the ACP version this agent implements. Matches main. const ProtocolVersion = 1

ACP 包刻意保持协议版本号和主线分支一致——因为很多工具是基于 v1 ACP 协议集成的,Reasonix v2 必须保持 wire contract(线路协议)完全一致,否则这些工具就废了。这是协议适配层的核心契约——协议是公共承诺,实现可以变,协议不能变

4.3 VS Code 扩展集成

通过 ACP,VS Code 扩展(以及任何支持 ACP 的编辑器)可以把 Reasonix 当成一个后端 agent 来驱动。images/slash-command-views.svg 展示了 slash 命令在编辑器里的视图——用户在 VS Code 里输入 /reviewer/doc-rewriter 这些 slash 命令(第 9 章 SUBAGENT_PROFILES),命令通过 ACP 传给 Reasonix,Reasonix 启动子代理执行,结果通过 ACP 事件流回传给 VS Code 渲染。

ACP 包的结构印证了它是纯适配层:

internal/acp/ protocol.go ACP 协议类型(wire types) server.go stdio JSON-RPC 服务器 dispatch.go 事件 → session/update 通知 service.go 会话工厂(组合 root 提供) status.go 状态报告 ...

它 import 了 agent/event/permission 这些内核包,但不 import 任何前端包。它自己就是"前端"(对编辑器来说),但实现方式是协议适配而不是 UI 渲染。

💡 契约要点:ACP 是"新前端零成本接入"的最佳实证(第 1 节讲的第三个收益)。Reasonix 没有 为 VS Code 重写 agent,只是写了一个 13066 行的协议适配层,把 Controller 的命令/事件映射到 ACP 的 JSON-RPC。任何支持 ACP 的编辑器都能零成本接入 Reasonix,这正是 transport-agnostic Controller 的长期红利。

五、三前端对比

最后用一张表把三前端(加 ACP)的定位对比清楚。配图 images/project-topic-tabs-context.png 展示了多前端共享同一会话上下文的效果。

维度 TUI HTTP/SSE serve Wails 桌面 ACP 编辑器
传输 终端 stdin/stdout HTTP + SSE Wails IPC + webview stdio JSON-RPC
技术 Charm(bubbletea/lipgloss/bubbles) Go net/http + broadcaster Go Wails + React 19 internal/acp 协议适配
定位 轻量本地、SSH 友好 远程访问、OpenAI 兼容客户端接入 富交互、集成枢纽(IM bot 宿主) 编辑器内嵌(VS Code 等)
富渲染 CLI 主题、图片折叠 网页 + URL 引用 KaTeX/Mermaid/xterm、8 套主题 编辑器原生 UI
共享 同一个 control.Controller,同一套 agent 行为 同上 同上 同上

最后一行是这张表的灵魂——不管前端形态差多大,底层 Controller 和 agent 行为完全一致。TUI 用户的 /approve、桌面用户的按钮点击、SSE 客户端的 HTTP 调用、VS Code 用户的 ACP 请求,最终都走同一段 Controller 审批逻辑,跑同一个 agent,用同一套工具和权限规则。这就是 REASONIX.md 那句"One transport-agnostic control.Controller sits behind every frontend"在工程上的兑现。

本节要点回顾

  1. TUI 前端:Charm 全家桶——bubbletea(Elm 架构状态机)、lipgloss(终端样式)、bubbles(组件);命令/事件双流最纯粹的消费者;CLI 主题(images/cli-theme-effect.svg)和图片折叠(images/paste-folding-effect.svg)是 TUI 专属表现层不进 Controller。
  2. HTTP/SSE serve:OpenAI 兼容网关,任何标准客户端零成本接入;broadcaster.go 做事件流一进多出;docs/serve_protocol.md 定义协议;内置 index.html 等网页;是 transport-agnostic 的远程证明。
  3. Wails 桌面:Go 后端 Wails + React 19 前端,二进制小内存省符合薄 harness 哲学;前端用 Zustand/xterm/KaTeX/Mermaid 做富交互;images/desktop-v2-layout-preview.png 展示布局、images/desktop-v2-skills-preview.png 展示 Skills;桌面同时是 IM bot 运行宿主(bot_bridge.go)。
  4. ACP 编辑器集成:Agent Client Protocol(agentclientprotocol.com)是 AI agent 的 LSP;internal/acp 13066 行是纯适配层,把 Controller 事件映射成 session/update 通知、把权限审批桥接成 request_permission 往返;ProtocolVersion = 1 保持 wire contract 稳定;VS Code 扩展通过 ACP 接入(images/slash-command-views.svg)。
  5. 三前端对比:TUI 轻量本地、SSE 远程访问、桌面富交互+集成枢纽、ACP 编辑器内嵌;底层共享同一个 Controller 和同一套 agent 行为——REASONIX.md"One Controller behind every frontend"的工程兑现。

下一章我们钻进 Controller 编排的一个特殊场景——多 agent 协作。internal/agent 的 fleet/coordinator 实现子代理编排(主代理委派子代理并行处理),SUBAGENT_PROFILES.md 定义子代理配置,把"一个 agent 干所有事"升级成"多个子代理分工协作"。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U