Skip to content

Technology Selection Archive

zuohaisu edited this page Oct 6, 2026 · 1 revision

Technology Selection Archive(2026-09-27)

Status: Historical / non-authoritative · 现行技术结论唯一来源:ADR-0011(Rust 宿主与终端 TUI,已交付)

Provenance — Merged 2026-10-06 from docs/research/archive/technology-selection/2026-09-27/(README + 3 份快照全文,原文未删改)@ zuohaisu/viva@871a00a。这些文件保留多轮研究的原文和资料来源,阶段性推荐的变化属于研究过程;后续 Agent 应以 ADR-0011 的裁决与实施状态为准,不将旧 Ticket Autopilot/单控制器推导套回当前 Viva 产品。


快照索引(原 archive README)


快照一:技术选型的一手资料核查

核查日期:2026-09-27。范围为选型讨论,不构成迁移决定。

后续证据修正: 用户进一步明确开发复杂度不参与选型,真实任务完成速度是核心指标。Pi 的 TypeScript、自有 TUI 与可复用 Agent 核心表明,不能仅依据 Rust 无 GC 就把它定为整体速度首选。最新核查见下方快照二;应优先验证 Pi 能力的复用,并以同负载数据比较资源和端到端速度。下文 Rust 首选是此前资源约束分析的阶段性判断,尚未经过此验证。

讨论前提已更新: 用户明确要求忽略迁移成本,首版做终端 TUI,在较小内存的 Intel Mac 上支持 16 个并发 Agent;桌面与 Windows 只保留合理接口边界。本节下方原有 Web/现有代码成本判断保留作资料背景,已不适合作为本轮推荐理由。以新增分析为准。

TUI 与 16 并发的新判断

推荐倾向(工程推论,非基准结果):Rust + Tokio + Ratatui + Crossterm;Go + Bubble Tea 是接近的第二候选。 Rust 更贴近显式资源生命周期与避免 tracing GC 开销的优先级;Go 可以用更简洁的并发模型提供单一可执行文件与成熟 TUI。16 路主要为 I/O 的任务本身并不超过 TypeScript/Node 或 Python 的能力,也不足以证明 Rust 一定使用更少的实测内存。Rust 所有权机制、Bubble Tea

新增核实事实与限制:

  • Rust 官方目前把 Intel Mac 的 x86_64-apple-darwin 列为 Tier 2,仍经 rustup 分发;官方记录 x86 最低 macOS 10.12。不能沿用"Intel Mac Tier 1"旧说法。目标可用不代表每个三方 crate 已在目标老机器完成验收。Rust macOS 平台文档
  • Tokio mpsc::channel 有限容量并提供背压;容量限制的是消息数量,因此还必须约束单条消息大小,才能形成字节预算。不能让非当前可见的 15 个 Agent 日志无限堆积。Tokio mpsc
  • Tokio 子进程句柄丢弃默认不杀进程;kill_on_drop 默认 false,即使打开也只有尽力回收保证。需要显式 wait().await 或 kill().await;Unix process_group(0) 可为子进程建立独立组,但发送组信号、拒绝误杀与退出确认仍需 Controller 实现。Tokio Command
  • Ratatui 默认支持 Crossterm backend,同时有 TestBackend;终端绘制和键鼠事件由 backend 提供。应保持单一渲染者,16 个 Agent 向它提交状态与事件,而非 16 个 TUI 或 Controller 实例。Ratatui backends
  • Go GC 可以用 GOGC 权衡 CPU 与堆占用,也支持 GOMEMLIMIT。后者是软限制,运行时可能超过;不是进程树或整机内存硬限制。官方也提示对输入与环境不受控的 CLI/桌面程序,不宜盲目内置该限制。Go GC guide
候选 在新前提下的判断
Rust + Tokio + Ratatui/Crossterm 资源管理优先的首选;没有 GC 不等于不会泄漏/无限缓存,异步生命周期与进程回收要显式验收
Go + Bubble Tea 并发、单二进制、TUI 与开发复杂度的强平衡;有 GC,但不能未经实测断言老 Mac 上不合格
TypeScript/Node + Ink React 交互迭代便利,16 路 I/O 可实现;当前没有必须复用 React 的需求,不能拿未来桌面界面作为首版引入理由
Python + Textual 可以实现,异步 Worker 与 TUI 具备现成能力;当低控制器开销优先且不计迁移成本时,优先级下降;不是因 GIL 就无法同时等待 16 个子进程

验收应同时量 Viva 本身与 16 个真实 Agent 及其后代总量:常驻/峰值物理内存、整机 memory pressure/swap、CPU、输入响应、输出丢失、Stop 回收结果。不能写一个 Rust Controller 就承诺老 Mac 能跑 16 个真实 Claude/Codex CLI;大头可能来自外部 CLI,与 Controller 语言不同。

最小实现边界:一个 Controller,一个 TUI,16 个受预算约束的 Agent 会话;日志落盘、可见窗口保留有界缓存,状态更新合并,队列与消息大小有上限。只隔离核心状态/命令/事件、Agent adapter、终端 UI、平台进程控制四处职责,不为未来桌面端新增服务或跨进程协议。

问题边界

当时的 IDEA.md 定义的是 Ticket 驱动的自动软件交付;docs/closed-loop-workflow.md 当前定义的是 Plane-first、localhost Web 服务,调用外部 Developer/QA CLI,保存检查与审计证据。应分别选 Controller 语言、用户界面、持久化与外部 Agent 协议,不能拿一个终端产品的 UI 技术决定所有层。

已核实事实

  • Ink 是终端 React renderer。 官方 README 将其定义为 interactive command-line apps;它有组件测试工具,并区分 CI 渲染行为。它能复用 React 的编程模型,不意味着终端组件可以原样成为浏览器 DOM 组件。对于当前 Web 产品,Ink 本身没有直接贡献。Ink 官方仓库
  • Claude Code 的发布方式不能简单归为 Node 工具。 当前官方 setup 推荐 Native Install;明确说明 npm 从 v2.1.198 起安装与独立安装器相同的 native binary,运行的 claude binary 不调用 Node。该文档没有证明其全部源码语言、UI 内部实现;本次没有找到足以独立确认完整 TypeScript + React + Ink 架构的官方材料,因此将用户给出的源码栈视作待核实前提,而非本项目决策依据。Claude Code 官方 setup
  • Python 能处理异步子进程,但没有自动解决进程生命周期。 Python 3.11 提供 asyncio.create_subprocess_exec、stdout/stderr 流、terminate/kill;wait 本身没有 timeout 参数,需配合 wait_for。只等待不消费管道可死锁,communicate 将输出缓存在内存,不适合无限输出。POSIX 与 Windows 的终止语义不同。Python 3.11 subprocess 文档
  • Node 能处理异步子进程,取消也不等于清理进程树。 spawn 不阻塞事件循环,支持 AbortSignal;输出管道容量有限。官方明确指出 Linux 下 kill 父进程不会终止其子进程;killed 仅表示信号成功发出。detached 的平台行为也不同。Node child_process 官方文档
  • Go 可编译为可执行文件,可把 Web 静态资源嵌入。 go build 生成 executable,embed 可以在编译时纳入文件。由此可以设计成一个 Viva 可执行文件携带浏览器界面;这是方案推论,仍需按平台构建、签名、发布,仍依赖 Git 与外部 Agent CLI,也不能保证所有 cgo/原生依赖都消失。Go 编译教程、embed 官方文档
  • Go 取消语义仍需自己设计。 CommandContext 默认 Cancel 调用该 Process 的 Kill;默认没有设置 WaitDelay。可以定制 Cancel,设置 WaitDelay 来限制未退出进程或未关闭管道的等待。官方没有承诺默认清理整个进程树;平台专属配置仍是 Controller 的职责。Go os/exec 官方文档
  • 静态类型与外部证据校验是两件事。 Python 的注解不会被运行时强制执行,需配置类型检查器。TypeScript 类型注解在编译后被擦除;其 discriminated unions 可以帮助表达状态与穷尽分支,但不能自动校验来自 Plane、Agent CLI、磁盘文件的 JSON。Python typing、TypeScript Basics、TypeScript Narrowing
  • Python 与 Go 也有完整 TUI 方案。 Textual 提供异步/线程 Worker,与 UI 生命周期协调;Bubble Tea 使用 Model/Update/View 的 Elm 式事件模型。因此"想要 TUI"不足以推出必须改成 TypeScript。Textual Workers、Bubble Tea 官方仓库
  • Rust 有相关行业例子,但理由不能直接移植。 OpenAI 的 2025 年 Codex CLI 作者说明从 TypeScript/Ink 改到 Rust 的诉求是免 Node 安装、原生 sandbox bindings、内存/性能和可扩展 wire protocol。这证明 UI 和核心可以分层选择;Viva 当前委托现成 Agent 执行任务,尚不能推导出需要重建原生安全 harness。OpenAI 原作者公告

由事实得到的选型判断(推论)

候选 最有价值的适用条件 当前不能由其解决的问题
Python Controller + 浏览器 UI 已有代码与验证资产;核心工作是集成、检查、证据处理;先把一张真实 Ticket 闭环 类型纪律、重启恢复、授权校验、持久化原子性与进程树控制仍要明确设计
TypeScript/Node + React 浏览器 UI 产品主要复杂度在交互;希望前后端共享 schema/事件定义;团队熟悉 TS 或深度依赖 JS SDK 不能靠静态类型校验外部 JSON;不自带可靠任务队列或进程树终止;Ink 对 Web 无帮助
Go Controller + TypeScript 浏览器 UI 目标是面向多人分发的本地控制器;安装摩擦、长驻进程、取消与并发可维护性成为可测量瓶颈 需要承担双语言契约与发布链成本;外部 Agent CLI 的安装与鉴权不会消失
Rust Controller + 浏览器 UI 确认需要原生沙箱/系统级隔离、严格资源上限或原生核心被多个客户端复用 当前没有证明这些是 Viva 最紧迫的缺口;重写风险不能由 Codex 的选择抵消

这不是语言性能排名。当前 Controller 的主要等待发生在网络、Git、检查和外部 Agent,是否有语言运行时瓶颈必须以测量证明。

更值得作为淘汰标准的验证

  1. 外部 CLI 大量输出、stdout/stderr 同时写入时 UI 仍响应,证据不丢失且内存受限。
  2. Stop 在子进程树、忽略 TERM、管道被后代保持打开时都有明确结果,并不会信号误发到其他运行。
  3. Controller 在 QA 或 Commit 边界崩溃后,恢复的是可信证据状态,不重复执行不可幂等操作,也不假造 QA PASS。
  4. 外部非法 JSON、状态与 attempt 不匹配、重复 Owner action 均被运行时契约拒绝。
  5. 在声明支持的操作系统上,从安装到一张真实低风险 Ticket 的完整运行有可复现证据。

这些标准同时适用于四种语言。迁移只有在修复现有实现比迁移更昂贵,或产品分发/系统约束明确变化时才有充分理由。


快照二:Pi 的资源相关设计核查

日期:2026-09-27。检查 canonical earendil-works/pi 的 main;所读 package manifest 标记 0.87.1。未安装、运行 Agent 或调用模型。这里是源代码证据,不是 Intel Mac 性能验收。

实际栈

Pi TUI 是 TypeScript 自有 pi-tui,不是 React/Ink。tsc 构建,Node 要求 >=22.19.0;TUI manifest 只有 get-east-asian-width 与 marked 两个运行依赖,并分发 macOS Objective-C、Linux/Windows C 原生辅助代码。不能把 TUI 两个依赖误说成整个 Agent 仅有两个依赖。TUI package manifest、Agent package manifest

能解释响应与开销的机制

  • 合并与节流 UI 更新。 TuiBase.requestRender 对已有待渲染请求直接返回;普通更新最小间隔 16 ms。键盘事件使用 immediate 路径,抢占已调度的节流帧。源码称其为 differential rendering;这些机制可以减少重复绘制,不能据此声称实测低于其他语言。TUI 源码
  • 缓存不变内容。 Markdown 组件按文本与宽度缓存输出;变更调用 invalidate。Bash 折叠显示默认 5 个 visual lines,按宽度缓存,流式输出更新以 100 ms 节流,避免每个输出 chunk 都重建预览。Markdown 源码、Bash renderer、Bash 工具
  • 展示与完整输出分离。 工具输出默认上限是 2,000 行或 50 KiB,先达到者生效。OutputAccumulator 保留 rolling tail、流式 UTF-8 解码;超限后保存原始输出到临时文件并清掉此前 raw chunks。这限制了展示与模型上下文的单次输出,不代表整个会话、所有扩展、磁盘队列都受同一上限。截断工具、OutputAccumulator
  • 仍有资源边界要核验。 上述 accumulator 的 WriteStream.write(data) 没有利用返回值等待 drain;源码中的 rolling-tail 上限不等于磁盘缓慢或大突发输出时进程总内存的硬上限。必须在目标工作负载测试背压,而不能只引用其"bounded memory"注释。OutputAccumulator
  • 不能归因于全面 lazy startup。 当前 main.ts 有大量静态导入,未找到其入口普遍按需动态加载的证据。Bash renderer 确实与执行/schema 模块分开,让纯显示消费者不用加载执行路径;这只是局部模块隔离。入口源码、Bash renderer

Benchmark 的证据等级

不能说完全没有性能数据:官方仓库的 issue #7739 收录跨项目启动/内存对照以及低端机器扩展加载测量。但 issue 正文引用竞争项目的历史 benchmark,评论是用户在 Linux/Windows 的特定版本和扩展配置测量;不是 Pi maintainers 对当前 main、Intel Mac、16 并发的官方验收。它还提醒扩展加载可能主导启动开销,不能把用户感到流畅推广为所有安装配置都快。

本次没有获得足以给 Rust/Go/TS/Python 排名的同机同负载数据,也未对用户实际使用的 Pi 版本做 profiling。

作者的 2025-11-30 原文 说明了小 harness、可见上下文、少工具与分层 TUI 设计,并给出历史 Terminal-Bench 测试。这可以支持"harness 设计值得研究",不能证明当前 main 在 Intel Mac 上的 16 并发内存或真实任务墙钟时间优于另一语言。

对 Viva 的结论

Pi 提供了实质反例:TypeScript 不是终端产品必然笨重的原因,React/Ink 也不是 TypeScript TUI 的必选项。可以复用轻量 TUI,或在任意语言实现其合帧、差异绘制、缓存、输出落盘与有界窗口机制。

选型不能只依据"Rust 无 GC"或"Pi 用起来快"。若资源优先,应对候选原型使用相同的 16 路数据源、输出量、可见窗口、日志保留和 Agent 拓扑,分别测 Controller 本身和子进程树。若编程复杂度不进入用户目标函数,应将其从比较标准移除,保留资源表现、安全边界和可验证性。

用户补充实际任务完成速度最重要且 Pi 体验明显更快后,优先核查复用 TypeScript 的 pi-tui / pi-agent-core 比直接自建 Rust harness 更符合 reuse-first。此处理由是复用已存在的执行语义与速度相关设计,不是迁移成本或编程复杂度。Rust 继续作为资源与系统约束候选,不能未经同负载验证就授予整体速度优势。模型、推理预算、提示上下文、工具调用与并发策略均会影响完成速度;TUI 重绘效率只覆盖其中一部分。


快照三:计算机控制对选型的影响

日期:2026-09-27。一手 API/绑定文档核查;未实现或操控机器。只讨论既定 TUI、16 Agent 与未来系统控制需求,不设计新的通用平台。

结论

Rust 作为受控执行核心的理由增强,但它不自动提高模型决策质量、任务完成速度或操作权限。 可让 Rust 核心负责资源、动作校验、进程与桌面访问协调,复用现成 Agent 与浏览器能力。Pi 已核实的合帧、缓存、输出分流是实际机制,用户感到更快是有价值的工作负载证据;将其归因于语言并推广到 Viva 尚缺同任务测量。

平台事实

  • macOS 的 AXUIElement/Accessibility 与 CGEvent 是原生接口;CGEventPost 把事件加入 Quartz event stream。Rust 可经 FFI/现成绑定调用,并非必须用 Swift。objc2-application-services 记录了 AX 绑定,但当前部分 AX 符号标记 deprecated,故此处只证实可接入,不定具体 crate/API 版本;实现前要核实对应系统支持与弃用原因。Apple CGEventPost、Rust ApplicationServices 绑定
  • 截屏/流式捕获可以复用 ScreenCaptureKit,Rust 已有 objc2-screen-capture-kit 绑定;也可以保留小型 Swift/ObjC helper。两条路最终使用相同 OS 框架,不能未经 profiling 声称纯 Rust 截屏更快。Apple ScreenCaptureKit、Rust 框架绑定
  • Accessibility 信任与 Screen Recording 许可由 macOS 判断。AXIsProcessTrustedWithOptions 查询可信状态,异步提示不会改变当次返回值。语言不能绕过授权或凭类型安全阻止合法 API 误点;动作权限、目标校验和用户审批是产品政策。Apple Accessibility 信任检查、Apple 屏幕捕获示例
  • Windows 可复用 Microsoft windows-rs 的 COM/Win32 bindings,官方生成文档含 Win32::UI::Accessibility。Microsoft UI Automation 的 client API 可读取和操作其他应用暴露的控件。首版仅保留平台 adapter 边界,无需现在实现 Windows。windows-rs、Accessibility 绑定、Microsoft UI Automation
  • 浏览器操作先复用 Playwright;其 BrowserContext 隔离 cookies/storage,并可在单个 browser 中创建多个 context。Rust 主控可以通过 adapter 调用现成实现,无须重写整个浏览器自动化;context 隔离不是 OS 安全沙箱,也不承诺 16 个页面没有内存负担。Playwright isolation

16 并发的关键限制(工程推论)

16 个 Agent 可以同时推理、调用彼此隔离的 API、执行受控命令或使用独立浏览器 context。不能让 16 个 Agent 同时争抢一台电脑的前台焦点、全局鼠标与键盘。 全局事件进入共享桌面;即使每次动作的 API 调用线程安全,不同任务的"定位—点击—输入—验证"仍会相互破坏。

因此,对共享前台桌面应串行分配操作权,保护整个需要稳定焦点的动作序列;在执行前确认目标窗口/元素仍匹配,结束后验证结果,允许用户输入打断。可以定向操作 AX/UIA 元素的动作应优先于坐标点击,但仍需按目标应用/资源处理冲突。需要真正并行的全桌面操作时,须有隔离会话/机器;不能由语言选择解决。

最小选型含义

Rust + Tokio + Ratatui/Crossterm 仍是资源与原生控制优先的合理选择。复用 Pi 的 Agent 设计或直接复用其模块是独立选择,不强制整个系统都用 TypeScript,也不强制为了 Rust 全部重写。语言无关的硬要求是:有界数据流、真实退出确认、明确 OS 权限、动作目标验证、审计证据和共享桌面的互斥操作权。

最终速度应测同模型同任务下成功完成的墙钟时间,同时记录内存、重试与错误动作;原生内核的低开销不是整体最快的证明。

Clone this wiki locally