跳到主要内容

oh-my-pi v15.10.1 发布 —— Auth 重构铺到底层,/tan 让 AI 分身干活,计划模式全屏重写

· 阅读需 7 分钟

oh-my-pi v15.10.1 封面

Auth 重试架构:从单点 key 到 a/b/c 三层轮换

v15.10.1 最深的改动藏在 API 调用链的最底层——认证层。

过去 oh-my-pi 的 API key 管理是平面的:一个 apiKey 走到底,401 报错就报错。这个版本引入了 ApiKeyResolverApiKey 的完整认证系统,配合 authStorage.resolver() 建出的 a/b/c 三层重试策略:

  • 第一次 401:尝试 forceRefresh 刷新当前凭据(针对短期 token)
  • 第二次 401:切换到 sibling credential(针对多账号轮转)
  • 超出限制/无 sibling:按最初配置的 apiKey 兜底

这不是某个 provider 的专属改动——它写进了全部调用路径的底层。非 agent 的 API 操作(标题生成、commit-message 生成、图片生成、web search、eval、记忆合并)全部换上了 session-aware 的 key 解析。图片生成(OpenAI-hosted、antigravity、xai-oauth)和 web search(anthropic、exa、tavily、parallel 等 7 个 provider)各自套上了 withAuth 包装。

说实话,做多 provider 的 agent 工具里,我很少看到对 auth 重试写得这么细致的。大部分项目只在用户首次配置 key 时管一次,后面出错就弹 401 了事。oh-my-pi 把这个塞进了重试循环里——登录失效后自动刷新,刷新失败自动切换账号,切换失败才报错。对于长期跑在后台的 agent 任务,这个差距是「自己知道要修 key」和「任务默默失败」之间的差别。

/tan 命令:在想主线任务的同时开一条副线

/tan <work> 是一个新命令——把当前会话分支成一个后台 agent,跑边角任务不阻塞主会话。

它的实现比想象中重:后台会话继承了父会话的 prompt 缓存 key 和 MCP 代理工具,有独立的 artifact 副本。dispatch 消息记录了非阻塞移交,主会话继续正常编辑,后台 agent 完成后再把结果送回来。现有的 /bg(挂起整个进程组)被移除了——/tan 才是更合理的后台模式。

这个功能的使用场景很明显:你在改代码的时候想到「顺便查一下这个 API 的文档」或「跑一下测试看看会不会炸」——过去要么等当前工具返回,要么开一个新终端。/tan 让这个并行发生在同一个 agent 的上下文里。

计划模式:从内嵌面板到独立全屏

计划模式(plan-mode)被整个翻了一遍。之前的版本是一个内联 transcript 块加一个底部选择器——交互空间小,导航僵硬。v15.10.1 把它换成了类似 /copy 的全屏 overlay,借用了终端的 alternate screen buffer:

  • ScrollView 导航:↑/↓ 逐行、Shift+↑/↓ 加速、PgUp/PgDn、g/G 跳转首尾
  • VS Code 风格侧边栏:终端宽度够 + 计划有 ≥2 个标题时自动显示,高亮跟踪滚动位置
  • 区域操作:Tab/Shift+Tab 在侧边栏和正文间切换焦点,d 删除区域(u 撤销),a 添加反馈标注
  • 鼠标支持:点击批准选项生效、点击侧边栏跳转、滚轮滚动计划页面
  • 走到底部自动进入批准选项:从最后一个 section 的底部往下走就落到 approve/refine/back

这个改动不只是界面美化——之前的内联版在 scrollback 中会散落 transcript 段落,全屏 overlay 让整个审批流程保持在一个独立的视图里,审批完了回到 transcript 时不会被中间步骤污染。我自己试了一下,在 long plan(>5个section)上导航速度快了不止一倍。

平滑流式输出和其他渲染改进

30FPS 逐字输出

assistant 的流式输出从「chunk-by-chunk 整个替换消息」改成「每秒 30 帧逐字增量揭示」,带 grapheme-safe 自适应追赶。更接近人类打字的效果——不是一下子弹出整段话,而是一个字一个字地出现,但追赶上之前的内容时加速不卡。

对应的,TUI 动画帧率从 60fps 降到 30fps(工作状态、待处理边框、主题 loading 动画)。显示上其实看不出差别,但 CPU 负载减半——在复杂的 TUI 会话中,每个 tick 都少算一倍的渲染周期。

ChatBlock 原语

新引入的 ChatBlock transcript 原语和统一的 ctx.present() sink,把之前零散分布在各个 controller 里的 chatContainer.addChild() + ui.requestRender() 模式收归一处。ChatBlock 带 React/Svelte 风格的生命周期——onMount 启动效果、onCleanup 注销清理、finish() 冻结内容、dispose() 完全销毁。MCP 的「Connecting…」spinner 现在就是一个 ChatBlock。

这意味着 transcript 重建时(session replay)不会再有泄漏的 setInterval/requestRender——所有动画块自己管理自己的资源。

Tool 输出框架统一化

多个 tool 的渲染被梳理了一遍:

  • edit/apply_patch:流式进行中也有框架
  • bash/eval:框架 title bar 不再重复「Bash」行,优化最小化 artifact 链接的位置
  • search 家族(find/search/ast_grep):多级目录树折叠,从单层 # dir/ 变成 # pkg/src/ → ## nested/ → ### child.ts
  • read 连续调用:跨 completion 聚合(不再每个 tool call 单独一行)
  • todo 阶段性渲染:多阶段列表默认只渲染有更新的阶段,其他折叠为一行摘要
  • completion.notify 前台也触发:桌面 toast 不再只在后台模式亮起
  • tool 间垂直间距统一:所有 block 的空白由 TranscriptContainer 统一管理,不再依赖各组件自己的 Spacer

这些改动单独看都很小——但每次修一条,agent 的输出就少一分「AI 感」多一分「控制台感」。

值得关注的修复

llama.cpp 并行 tool call 修复。llama.cpp 的 OpenAI Responses endpoint(/v1/responses)在发出多个 function_call 时,只有最后一个的 arguments 是正确的,前面的全是 {}。根因是 llama.cpp 的 stream 事件中 output_item.added 只带 item.call_id 没有 item.id,而 function_call_arguments.deltaitem_id: "fc_<call_id>" 匹配。oh-my-pi 加了 item.call_id 作为次级查找 key,让 identifier 不标准的 host 也能正确路由。(#2015)

dlv 调试 Go 包debug 工具之前拒绝任何 dlv 对目录的启动——validateLaunchProgram 在 adapter 选择之前就 reject 了。现在 adapter 解析在验证之前执行,dlv 标记了 acceptsDirectoryProgram,目录和 .go 文件启动为 mode=debug,其他文件为 mode=exec。(#2020)

多字节 UTF-8 bash 命令损坏修复。当命令中包含 /× 等多字节字符且在尾部有 | head/| tail 时,brush-parser 报告的是 Unicode scalar 偏移量,但 pi_shell::fixup 按字节偏移量切割——多字节每个 char 的偏移量多了一个字节,导致切除的位置正好落在多字节序列中间,丢掉末尾的闭合引号。

OMP dry-balance --bench 修复。解决了两类问题:401 token 失败后自动重续 OAuth 凭据;raw 模式(ONLCR 关闭)下的进度行不再阶梯式重复渲染。

URL 二进制读取智能降级。read/web-fetch 读取远程 URL 时,根据 payload 类型差异化处理:压缩存档列出根目录条目、SQLite 数据库显示表概览、notebook 渲染为可编辑单元格、二进制文件返回元数据提示而不是解码乱码。

升级

curl -fsSL https://omp.sh/install | sh
# 或用 Bun
bun install -g @oh-my-pi/pi-coding-agent

完整更新日志:GitHub Release

📢 关注我,获取最新开源更新日志和开发者工具动态。

#oh-my-pi #AI编程 #Auth重构 #开源 #计划模式 #开发者工具