全部文章
NINTHLESS / NOTE

Tau:为什么编码 Agent 需要一层桌面工作台

我没有在 Tau-gui 中重写 Pi,而是在 RPC 与 SDK 之上处理会话、上下文和桌面交互。

我喜欢终端执行命令的直接,但它不天然适合展示一段持续数小时、包含多个会话分支、工具调用、权限请求和上下文压缩的 Agent 工作。

因此我做了 Tau-gui,一个基于 Electron/React 的 Pi Coding Agent 桌面工作台。我认为自己最正确的架构决定,是没有重写 Agent 内核:会话循环使用 Pi 的 RPC,包管理使用 Pi SDK,我只在 Tau 中负责桌面交互、状态协调和可见性。

项目时间线

2026-05-19:建立桌面工作区

我先把 Pi 会话接入 Electron,并提供聊天、侧栏和设置界面。

2026-05-20:界面重建与会话连续性

我把项目迁移到 shadcn/ui,重写聊天区、侧栏和设置,同时加入 --continue 以减少无意创建新会话。随后我又压缩界面密度,使工具输出与长对话更适合持续阅读。

2026-05-22:从“能聊天”转向“能管理 Agent 状态”

我用一次集中修复处理了错误 RPC 命令、会话树、HTML 导出、扩展错误、自动重试、设置同步、并发启动竞争和会话切换不刷新等问题,并加入上下文用量条和乐观会话切换。

同一天后续提交处理 EPIPE,防止父子进程管道断开时桌面应用崩溃,并进一步调整阅读间距。

这几天的提交说明:Agent GUI 的复杂度主要来自异步状态,而不是消息气泡。

为什么选择 RPC + SDK

Pi RPC 模式 通过 stdin/stdout 使用严格 JSONL:命令按行输入,响应带关联 ID,Agent 事件持续流式输出。它适合嵌入 IDE 或自定义界面。

Tau 可以通过 RPC 处理提示、流式消息、工具事件、会话和设置;而 Pi RPC 尚未暴露的包安装、更新和移除,则通过 Pi SDK 完成。

这种混合并不漂亮,但边界诚实:

Pi Runtime:模型、工具、会话与协议
Tau Main:子进程、RPC、凭证桥接、包操作
Tau Renderer:聊天、侧栏、设置、状态反馈

重写运行时会带来短期控制感,却要永久追赶模型提供商、会话格式、扩展协议和工具行为。复用公开接口把维护成本留在正确的所有者处。

严格 JSONL 为什么会成为产品问题

RPC 文档明确要求只按 \n 分隔记录,允许输入端去除 \r,并警告某些通用行读取器会把合法的 Unicode 分隔符误当换行。

这类协议细节一旦处理错误,用户看到的不是“解析器不合规”,而是消息随机断裂、事件丢失或会话卡住。GUI 层必须把协议错误转换成可理解状态,而不能静默吞掉。

同时,stdout 是协议通道,普通日志不能随意写入;子进程退出、EPIPE、第一条输出超时和并发重启都要有明确生命周期。

会话切换不是换一个数组

Agent 会话通常包含消息、分支、模型、思考级别、压缩状态、工作目录、扩展状态和上下文统计。切换会话时,界面至少经历:

  1. 用户选择目标会话。
  2. 侧栏立即反馈选择,避免点击无响应。
  3. 后台向 Runtime 请求切换。
  4. 清理或隔离旧流式事件。
  5. 加载新消息与状态。
  6. 失败时恢复原选择并解释原因。

Tau 后期加入“乐观高亮 + 加载状态”,本质上是在处理感知延迟。但乐观更新必须有回滚,否则界面会显示一个并未真正激活的会话。

上下文用量应该可见

编码 Agent 的上下文窗口不是无限内存。长对话、工具输出和大文件读取会逐渐逼近限制,随后触发压缩或丢失早期细节。

Tau 把 context usage 放在标题栏,并用颜色提示占用程度。这不是装饰性指标,它帮助用户决定何时:

  • 开新会话而不是继续追加。
  • 把稳定规则写入项目文件或 Skill。
  • 压缩当前分支。
  • 删除无关输出,重新提供关键上下文。

一个好的 Agent UI 不只展示 Agent 说了什么,还要展示 Agent 当前还能可靠记住多少。

工具调用需要自己的交互语法

文本聊天只需要发送与接收。编码 Agent 还会发起选择、确认、输入、编辑器、权限和工具结果。每一种请求都可能阻塞 Runtime。

界面必须明确区分:

  • 正在生成文本。
  • 正在运行工具。
  • 等待用户批准。
  • 工具失败但 Agent 可继续。
  • Runtime 已断开,输入不会被处理。

如果全部压成一个旋转图标,用户就无法判断应该等待、批准还是重启。

桌面 Agent 工作台的质量标准

一个 Agent GUI 至少要通过这些场景:

场景 期望行为
流式文本中切换会话 旧事件不会污染新会话
子进程意外退出 明确显示断开并允许恢复
工具请求等待确认 输入区与阻塞状态清晰
上下文接近上限 提前提示压缩或新会话
包安装失败 保留原状态并显示原因
快速连续切换 不产生并发重启竞态

Agent UI 的核心不是“把终端变好看”,而是让隐形状态变得可观察、可操作、可恢复。

相关链接