跳到主要内容

oh-my-pi v15.12.4 发布 —— 同时开三个 omp session 会 crash?SQLite 并发修复来了

· 阅读需 7 分钟

SQLite 并发崩溃、Gemini 静默停摆、模型切换卡住 UI 好几秒、session 恢复等十秒、Ollama 上传 WebP 图片返回 400、Mermaid 中文标签画歪、Mnemopi graph voice 永远返回空……

每个问题单独看都不致命,可合起来就是「这个 agent 怎么又不动了」的累积挫败感。

oh-my-pi v15.12.4 封面

痛点:oomp——开了多个 session,然后全崩了

cmux 用户有个习惯:开多个 pane,每个 pane 跑一个 omp --session。一个 debug,一个 review PR,一个写文档。这很自然——omp 的 session 管理强就强在能同时维持多条独立对话线。

但问题是:当你电脑意外关机、重启后 cmux 自动恢复所有 pane,这几个 omp --session同时启动。它们都去打开 SQLite 数据库,争着做 WAL recovery,然后——SQLITE_BUSY_RECOVERY 一路 crash 过去。每次启动都撞到同一个锁,谁也抢不到。

这个 bug 藏了多久?从同时支持多个 session 的那天就存在了。不是 omp 的问题,是 SQLite 本身的 WAL recovery 机制——第一次写操作发生时必须加锁,多个进程同时复苏就会互锁。

v15.12.4 的修法很务实:在所有 SQLite 打开路径之前先执行 PRAGMA busy_timeout = 5000,然后 retry SQLITE_BUSYSQLITE_BUSY_RECOVERYSQLITE_BUSY_SNAPSHOTSQLITE_BUSY_TIMEOUT 四种 busy 状态,带指数退避。修复覆盖了 auth credential store、AgentStorage、history、memories、github cache、auto-QA、catalog model cache、stats 全部 SQLite 路径(#2421)。

这是个挺隐蔽但用久了大概率会碰到的问题。如果你的经验里从来没遇到过,可能是还没经历过异常关机后恢复 session 的场景——遇到了就回不去了。

Gemini agent 悄悄不说话的问题

如果你用 Gemini 模型跑 omp,可能遇到过这种场景:agent 突然不回复了,没有错误提示,没有网络超时,session 安静得像什么都没发生。

原因是 Gemini 有时返回 finishReason: STOP 但附带一个空文本(只有空格或空字符串),也没有 tool call。omp 之前把这种情况当作"正常结束"——agent 收到空回复,无事可做,停止。这就是那个著名的"Gemini 静默"bug。

这个版本修了所有 Google 后端(public Generative Language、Vertex、Cloud Code Assist)的空响应处理。现在统一的 hasMeaningfulGoogleContent 检查把空文本视为"无效回复",自动重试到 MAX_EMPTY_STREAM_RETRIES 次后才报错。Cloud Code Assist 路径之前虽然有一个空流重试,但它用 hasContent 判断——空字符串也算"有内容"——所以从来没真正触发过重试。

类似的问题还有 Gemini/Antigravity 返回纯思考块(reasoning/thinking only)没有最后文本或 tool call 的 STOMP 响应:现在也自动重试了,不会静默停摆。

session 恢复等十秒、模型切换卡半分钟

这两个问题同根。无论是 pi -c 恢复 session 还是 Ctrl+P 切换模型,底层都会调用 modelRegistry.getApiKey(model)。可 getApiKey 做的事远不止"取 key"——它会同步执行命令式 key 程序(apiKey: "!cmd"execSync 带 10 秒超时),还会在 token 过期时去刷新 OAuth token。一个模型切换触发一次网络请求+子进程执行,偶尔卡几秒也就算了——但 restoreSessionModel 对每个候选模型都做一次,session 恢复就能卡十秒。

修法:switching 和 restore 改用同步的 hasConfiguredAuth 探测,不做任何有副作用的操作。真正的 key 解析延迟到第一次请求时才执行。改动很小,效果很明显——model switch 从 "fine for a few switches, then a multi-second stall" 变成瞬间切换。

Provider 流式全方位的补丁

v15.12.4 对 OpenAI-compatible 流式做了系统性加固:

  • SSE 直接解析:不再依赖 OpenAI SDK,改用内部的 postOpenAIStream JSON/SSE transport,自己解析 wire-level JSON frames 和 [DONE] 终结符
  • HTTP 408/429/5xx 自动重试:这些在 Provider 层面不是致命错误,之前却直接抛给了用户。现在带 Retry-After/quota-hint aware backoff
  • OpenRouter finish_reason: error 映射:OpenRouter 报告上游失败(如 Gemini MALFORMED_FUNCTION_CALL)时返回 finish_reason: "error"。omp 之前把它当作不可重试的错误,session 卡死。现在映射为 Provider returned error finish_reason,被 session retry classifier 识别为瞬态错误,自动重试
  • 客户端中断释放上游连接:用户打断 stream 时,之前只停了本地 reader,上游 request body 还在继续跑。现在 abortable stream 包装会真正 cancel 上游请求
  • MiniMax M3 推理去重:同一个 chunk 携带 <think>…</think> 和结构化 reasoning_content 时,structured reasoning 优先,累计的 MiniMax 推理快照 collapse 为 delta

这些修的不算"用户可见的功能",但如果你在用任何 OpenAI-compatible 后端(OpenRouter、Together、Fireworks 等等),session 卡死、流断掉、超频错误的场景会大幅减少。

Fireworks 新模型自动出现,不用等 catalog 更新

Fireworks 的用户之前有个隐藏痛点:他们在 model picker 里看不到 kimi-k2.7-codedeepseek-v4-flash 这些新模型——不是因为 omp 不支持,而是因为 omp 的 bundled catalog 还没更新。Fireworks 每周发新模型,而 bundled catalog 的更新滞后几天到一周。

修复:Fireworks 模型发现从 inference API(/v1/models,返回 account-specific 稀疏子集)切换到 control-plane List Models API。control-plane 枚举所有 serverless 模型,附带 capability metadata(supportsServerlesssupportsToolssupportsImageInputcontextLengthdisplayName)。新发布的 serverless 模型现在自动出现在 picker 里,不需要等 catalog 编辑。

此外 contextWindowmaxTokensnull 代替了之前硬编码的 222222/8888 哨兵值。模型列表里未知限制显示为 - 而不是伪造的 222K/8.9K

其他值得关注的修复

Mnemopi graph voice 终于能用了sleep/sleepAllSessions 背后的 consolidateToEpisodic 之前"运行了但什么都没写"——gistsgraph_edges 表永远是 0 行,Polyphonic Recall 的 graph voice 永远返回空。现在 consolidation 会实际 ingest episodic memory 进入 EpisodicGraph(#2435)。用了 3 个月 rerank voice 的人可以试试切回 graph 了。

Mermaid 中文标签不再画歪:ASCII 渲染时 CJK/emoji 标签的边框宽度用 UTF-16 code units 计算,但终端渲染东亚字符是 2 列宽。一个 patchedDependencies 入口把 beautiful-mermaid 的渲染器改成 grapheme-cluster aware wcwidth-style 测量(#2442)。这个 bug 影响所有在 agent 对话中用中文编写 Mermaid 流程图的人。

Mnemopi bank 不再被 .git 位置意外改变:之前 per-project/per-project-tagged bank 的 ID 从 git.repo.resolveSync(cwd)?.repoRoot || path.resolve(cwd) 哈希生成。如果你在 /home/x/projects/repo 下工作,然后在上层目录加了一个 .git,bank 的哈希值变了——所有之前的记忆都"消失"了(实际还在旧 bank 里,但找不到了)。现在直接哈希 path.resolve(cwd),启动时还会扫描兄弟 bank 找回那些"丢失"的记忆(#2412)。

Windows 粘贴修复:Ctrl+V 在 PowerShell 下走原生 clipboard reader;之前 reader 报 "no image" 后不会 fall back 到 PowerShell clipboard bridge。现在是 fallback 路径了(#2429)。

升级

# 已安装用户
omp update

# macOS/Linux 一键安装
curl -fsSL https://omp.sh/install | sh

# Homebrew
brew install can1357/tap/omp

# Bun(推荐)
bun install -g @oh-my-pi/pi-coding-agent

# Windows (PowerShell)
irm https://omp.sh/install.ps1 | iex

完整更新日志:GitHub Release

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

#oh-my-pi #SQLite #AI-agent #bugfix