Skip to content

Ta ​

基于 Cell 与 pi 的 coding agent。ta 就是改名为 Ta 的 pi:交互界面、-p、--mode json|rpc、斜杠命令、会话树、扩展、Skills、pi 包都与 pi 一致;另外多了这些:

  • 默认用 codemode:模型通过 codemode 写 JavaScript 脚本调用所有工具,可以并行调用、在脚本里过滤大输出,只有脚本的输出进上下文(见下文「pi 补丁」)。
  • 会话锁:同一个会话文件同时只能被一个 Ta 进程写(pi 没有锁,两个进程会交错写入)。
  • Ta 的外观与身份:终端界面启动时显示 Cell 的像素小恐龙、版本和常用按键(按展开键看全部按键;quietStartup: true 时不显示);system prompt、提示文字、MCP 客户端名都说 Ta;/bug 在浏览器里打开 Ta 的 GitHub issue(带版本、模型、平台,不带别的);去掉了依赖 pi 官方服务(Radius)的 /share;/changelog 显示 Ta 的更新记录。pi 面向 pi.dev 的版本检查和安装统计默认关闭(TA_SKIP_VERSION_CHECK=0、TA_TELEMETRY=1 可打开)。pi 的环境变量在 Ta 里叫 TA_OFFLINE、TA_SELF_UPDATE_COMMAND、TA_TELEMETRY,原来的 PI_* 名字也照样生效。
  • ta serve:把 pi 会话通过 WebSocket 提供给任意多个客户端(Web、桌面、手机),并自带 Web 客户端,见 @celljs/ta-host 与 @celljs/ta-web。

安装 ​

bash
npm i -g @celljs/ta     # Node.js >= 22.19
ta                      # 交互模式
ta -p "总结这个仓库"     # 一次性运行

与 pi 的对应 ​

piTa
全局目录~/.pi/agent/~/.ta/agent/(auth.json、models.json、settings.json、sessions/、extensions/ …,内容格式相同)
项目目录.pi/.ta/;项目说明仍是 AGENTS.md
环境变量PI_CODING_AGENT_DIRTA_CODING_AGENT_DIR、TA_CODING_AGENT_SESSION_DIR
子命令install remove update list mcp相同,另加 serve、exec-server、pair、relay

pi 的扩展和 pi 包可以直接用:ta install npm:<包名>。想复用项目里已有的 .pi/skills,在 .ta/settings.json 里写 "skills": ["../.pi/skills"]。

装了 Cua Driver 时,Ta 能在后台使用这台电脑上的桌面应用,见内置扩展 @celljs/ta-computer-use。

每轮回复改动了文件时,Web 客户端在输入框上方显示改动的文件和增删行数,点文件在工作台查看差异,也可以一键撤销这一轮的改动,见内置扩展 @celljs/ta-changes。

让 Ta 按时干活:/loop 30m <要做的事>、/remind in 45m <要做的事>,或者直接说"每天 9 点汇总昨天的提交"。Ta 服务到点在新对话里运行,Web 客户端的"定时任务"页列出任务和每次运行的总结,见内置扩展 @celljs/ta-cron。

Ta 和 pi 一样,默认不在工具调用前请求批准;需要的话安装可选包 @celljs/ta-permission-gate。

ta serve ​

bash
ta serve                      # 127.0.0.1,上次的端口(被占用时换一个空闲端口)
ta serve --host 0.0.0.0 --port 4100
ta serve --web                # 同时在浏览器里打开 Web 客户端(已带上 token)
ta serve --exec ws://box:4200/exec   # 工具在另一台机器的 ta exec-server 上执行(TA_EXEC_TOKEN)
ta exec-server --host 0.0.0.0 --port 4200 --cwd /workspace
ta pair                       # 配对手机等设备,经 Relay 连回这台电脑(默认 https://relay.cellbang.com)
ta relay --port 8080          # 自己运行一个 Relay

启动后把地址和访问 token 写进 ~/.ta/agent/serve.json(权限 0600)。Web 客户端就在同一地址的 /:页面文件不含数据,无需 token;调用(/api)都要 token。--web 把 token 放在 URL 的 # 片段里(不会发给服务器,也不进 Referer),页面读到后存进 localStorage 并从地址栏去掉。端口和 token 跨重启保持不变(记在同目录的 serve-state.json,权限 0600;删掉它就换新的 token 和端口),这样装成应用(PWA)的 Web 客户端下次打开还能找到 ta serve 并自动登录;--port 指定端口时以它为准。TA_SERVE_TOKEN 可指定 token(例如由桌面壳生成),这时不记录它。客户端用 @celljs/ta-client 连接。

客户端没指定目录时,对话在 ta serve 的工作目录里打开:默认是启动它的目录,Web 客户端和桌面应用里可以改("打开工作目录…"),记在 agent 目录的 ta.json。模型服务可以在 Web 客户端里登录(齿轮菜单的"模型账号…",与终端的 /login 写同一个 auth.json)。对话也可以在另一台机器上工作,像 VS Code 的 Remote SSH:在目录选择器里选一台主机(~/.ssh/config 里的 Host,或 user@host),目录就是 ssh://<host>/<path>。Agent 和模型凭据留在 ta serve 这台机器,命令、文件、终端、git 在那台主机上;ta serve 用本机的 ssh 连过去(密钥、ssh-agent、ProxyJump 照常可用,要密码或确认新主机时页面会弹窗),第一次会把一个很小的服务器(和没有时的 Node.js 22)放到那台主机的 ~/.ta/server。那台主机上的开发服务器在内置浏览器里打开 localhost 地址即可,端口自动转发。见 ta-remote-ssh.md。

ta pair 配对的设备经 Relay 连到 ta serve,内容端到端加密;Web 客户端的"在手机上使用…"做同样的事,并显示二维码。

构建 ​

bun run build 先用 cell build --root serve 把 ta serve 的服务端打成 dist/serve/index.mjs、Web 客户端打成 dist/public/(serve 应用装了 @celljs/ta-web 就会构建前端,@celljs/serve-static 负责托管),再由 scripts/assemble.ts 把 ta 命令(ta-harness 的 TaCli)打成 dist/cli.mjs,并生成 dist/pi/:一个把 pi 改名为 Ta 的 package.json(piConfig),加上 pi 的主题、HTML 导出模板、docs 和 examples。ta 启动时让 pi 从这个目录读取品牌信息(PI_PACKAGE_DIR),和 pi 官方二进制的目录布局相同。Ta 自带的 pi 包(TaPackages.BUILTIN)构建后复制到 dist/pi/packages/<名字>,不含源码与测试,可在 Web 客户端的 设置 → 包 关闭。

ta 运行时用到的都在 dist/ 里,所以发布的包没有 dependencies,装 ta 不会再装 Cell 和 pi;构建用到的包都是 devDependencies。ta serve 的服务端是 serve/ 下单独的 Cell 应用(私有,不在 workspaces 里):Cell 只从 dependencies 收集组件,它的 serve/package.json 列出这些组件,@celljs/ta 自己就不必有 dependencies。给 ta serve 加组件时,两处都要加(serve/package.json 的 dependencies 决定打包内容,package.json 的 devDependencies 决定 turbo 的构建顺序)。

ta 命令本身不加载 Cell,启动时间和内存与 pi 相同;只有 ta serve 加载 Cell。

pi 补丁 ​

pi 里写死的品牌文字、/bug 和 /share 两个内置命令,以及 codemode 的默认值,用补丁改:

  • 补丁是仓库根目录的 patches/@earendil-works%2Fpi-coding-agent@<版本>.patch,由 bun run pi-patch(scripts/pi-patch.ts,见下)生成,登记在根 package.json 的 patchedDependencies,bun install 时自动打上。只改 pi 的打包产物 dist/bundle(Ta 只运行它)。
  • 包管理器的补丁只在本仓库生效,所以构建时 scripts/assemble.ts 把打过补丁的 dist/bundle 复制进 dist/pi/dist/bundle 随包发布(约 9 MB);ta 设置 PI_PACKAGE_DIR 指向 dist/pi,PiBundleUtil 就加载这一份。进程里只有这一份 pi,扩展通过它内置的模块表拿到同一个实例。没打补丁时构建直接失败。
  • 打包产物运行时从 node_modules 加载的 jiti(加载扩展)、@silvia-odwyer/photon-node(图片缩放)和 quickjs-wasi(codemode 的 WebAssembly)也由 scripts/assemble.ts 从 pi 旁边复制进 dist/pi/node_modules,版本与 pi 相同;扩展用到的 typebox 和 pi 自己的包走打包产物内置的模块表。构建时会扫描打包产物里按名字加载的包,出现不在这份清单(或可选清单)里的就失败,升级 pi 时照提示补上。

改了什么,以 scripts/pi-patch.ts 的 REPLACEMENTS 为准(按组列出每处原文和替换文字):

组改动
codemode by default默认工具加上 codemode,codemode.mode 默认 only:模型只看到 codemode 一个工具,read / bash / edit / write、扩展工具和 MCP 工具都在脚本里用 tools.<name>() 调用。pi 没有给宿主的默认设置层,只能改这里。改回 pi 的行为:settings.json 写 "codemode": { "mode": "on" }(其他工具也直接提供)或 "defaultTools": ["-codemode"](不用 codemode),单次运行用 --tools -codemode
built-in commands去掉 /share(上传到 Radius)和 pi 的 /bug(发给 pi 的开发者);/bug 由 Ta 的扩展提供;崩溃后的 /bug 提示随之改写
system prompt开头改为 Ta;pi 文档一节说明 pi 的 ~/.pi/agent、.pi/、pi 命令在 Ta 里是什么
help of tata -h、ta update -h、ta auth -h 里的 pi → Ta;环境变量列为 TA_*(由 TaBrand.activate 转给 pi 的 PI_*),去掉 Ta 自己设置的 PI_PACKAGE_DIR 和随 /share 去掉的 PI_SHARE_VIEWER_URL;示例里的 MCP 服务 radius 换成 github;ta update ta 与 ta update self 同义
update of tata update(self、ta)向 npm 查询 @celljs/ta 的最新版本,而不是向 pi.dev 查询(那里返回的是 pi 的包名,会把 Ta 换成 pi);不提示运行 pi 的安装脚本(Ta 是单文件打包,没有要固定的依赖)
messagestmux 设置提示、项目信任提示、ChatGPT 登录端口占用提示:pi → Ta;MCP 客户端名 pi → ta

只改 pi 没有设置、参数或扩展点可用的地方;能用 piConfig、环境变量(TaBrand.activate)或 Ta 的扩展做到的,不进补丁。补丁不手改:pi 的打包产物按哈希命名分块、压缩成长行,手改的补丁在 pi 升级后必然失效。

升级 pi 时:改 ai-packages/ai-coding-agent 等处的 pi 版本并 bun install,然后在 apps/ta 下 bun run pi-patch。脚本从 Bun 缓存里取未打补丁的 pi,按 REPLACEMENTS 逐条替换(不管文件名,每条原文在整个 dist/bundle 里须恰好出现约定的次数),再用 bun patch --commit 生成新版本的补丁、去掉 .bun-tag-* 段并删除旧版本的补丁文件;最后把根 package.json 的 patchedDependencies 里旧版本那一行删掉,跑 bun run test。某条原文在新版 pi 里变了,脚本会列出它找到的次数并停下,改那一条的 from 再跑。bun run pi-patch --check 只检查不生成;test/pi-patch.spec.ts 也会检查当前安装的 pi。

没有改的:pi 文档正文(system prompt 已告诉模型如何对应)、Radius 登录选项的介绍(那是 pi 官方的服务,文字属实)、设置页"Pi's drawn cursor"和包管理器的一条错误信息(在几十 KB 的长行里,补丁代价大于收益)。

性能基准 ​

bash
bun run bench               # 除长时间场景外全部运行,约 3 分钟,输出 Markdown 表格
bun run bench streaming     # 指定场景;--help 列出全部场景

基准用本机构建产物(先 bun run build),模型是独立进程里的假 OpenAI 兼容服务(bench/fake-model.ts:rate 首 token 200 ms、每秒 100 个 token;burst 尽快输出 5000 个 token)。对照组是 pi --mode rpc:pi 要服务多个会话只能每个会话一个进程。内存与 CPU 从进程外用 ps(Linux 读 /proc)采样,不干扰被测进程。

参考结果(Apple M4 Pro,Node.js 24):

场景piTa
--version / -p0.12 s 112 MB / 0.18 s 127 MB0.12 s 114 MB / 0.19 s 128 MB
ta serve 空载—66 MB,空闲 CPU 0
32 个会话每会话一个进程,约 127 MB × 32181 MB(每会话约 1.6 MB)
单会话流式(rate)首 token / CPU209 ms / 5%209 ms / 5–6%
10 个会话同时流式1693 MB,4.57 s CPU191 MB,1.92 s CPU
50 个客户端看同一会话—每客户端每 delta 约 35 µs

endurance(长时间场景,需显式指定)在 64 MB 堆上限下连续 60 轮突发输出,检查内存是否收敛。

测试 ​

bun run test 是集成测试:真实构建产物 + 本地假的 OpenAI 兼容模型服务,覆盖 print / JSON 模式、会话锁、安装 pi 包与权限拦截,以及 ta serve 的多客户端广播、断线补发、审批先到先得、幂等回执、会话锁、空闲回收和限流。