oh-my-openagent 配置迁移实战:2026-08-reasoning-unification 的隔离化 OpenCode CLI QA 全记录

oh-my-openagent 配置迁移实战:2026-08-reasoning-unification 的隔离化 OpenCode CLI QA 全记录

【免费下载链接】oh-my-openagentOmO: Just type "mass ulw" keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent

导读

本文围绕 oh-my-openagent 仓库中针对 OpenCode CLI 的一次真实配置迁移验证(QA)展开,核心是2026-08-reasoning-unification迁移:它将分散的variant、reasoningEffort、thinking、textVerbosity与fallback_models等遗留键统一为规范化的reasoning字段与有序models链。读者将看到一条完整的隔离化 QA 路径——如何在沙箱环境中执行真实迁移命令、验证幂等性、通过doctor

配置检查、确认运行时配置加载结果,并确保不污染真实会话数据库。读完本文,你可以掌握这套“可复现、可清理、证据闭环”的配置迁移验证方法,以及该迁移在源码层的具体变换规则。

背景:来自 Discord 与 issue #6567 的遗留配置问题

本次 QA 的触发点是社区反馈:在 Discord 与 issue #6567 中,用户报告了 OpenCode 配置里旧式 reasoning 相关键(如variant、reasoningEffort、fallback_models)引发的警告刷屏问题。oh-my-openagent 的应对方案不是简单地打补丁,而是引入一次性配置迁移2026-08-reasoning-unification,把旧键统一转换为规范化结构,并在迁移完成后通过_migrations

标记位防止重复执行。

QA 文档记录的验证对象不是 mock,而是真实源码 CLI 与运行时配置加载器

(“task-owned worktree”中的真实实现),这保证了结论直接反映生产代码行为。

隔离环境:QA 沙箱的关键配置

要让配置迁移验证不污染真实环境,QA 文档明确列出了如下隔离手段,全部来自 script/agent/qa-sandbox.sh 所提供的沙箱能力:

  • 独立的 XDG data / config / cache / state 目录;
  • 独立的CODEX_HOME;
  • 独立的HOME(用于~/.omo/omo.jsonc的定位);
  • OPENCODE_DISABLE_AUTOUPDATE=1(关闭自动更新,保证迁移过程不因自更新引入变量);
  • OPENCODE_DISABLE_MODELS_FETCH=1(关闭模型元数据拉取,确保模型解析只依赖本地配置)。

这些环境变量与目录隔离共同构成了“hermetic(密闭)”场景:任何副作用都只会落在临时目录内,后续可以整体删除。

被测输入:legacy-input.jsonc

QA 使用了与社区报告完全一致的遗留配置片段作为输入:

{ "[opencode]": { "agents": { "explore": { "model": "anthropic/claude-fable-5", "variant": "high", "fallback_models": [ { "model": "openai/gpt-5.6-sol-fast", "variant": "medium" } ] } } } }

这里出现了两个需要迁移的旧键:variant(推理强度)与fallback_models(后备模型列表)。该输入被放进隔离HOME下的~/.omo/omo.jsonc

,作为迁移的起点。

验证动作:六步闭环

QA 文档定义的验证流程包含六个动作,覆盖“迁移 → 幂等 → 体检 → 运行时加载 → 数据隔离”全链路:

  1. 运行bun run packages/omo-opencode/src/cli/index.ts config migrate --json(真实 CLI 入口见 CLI 入口);
  2. 对迁移后的~/.omo/omo.jsonc计算哈希;
  3. 再次运行相同迁移,再次计算哈希;
  4. 运行bun run packages/omo-opencode/src/cli/index.ts doctor --json --platform=opencode;
  5. 在隔离HOME下的项目目录中对配置调用validatePluginConfig();
  6. 对比 OpenCode 会话数据库在验证前后的记录数。

幂等性验证:哈希相等即证据

迁移执行结果如下:

first exit: 0 second exit: 0 first hash: 355e7fec9b8481c9f312576e636bf975ea1807588e037c386d9212165664381a second hash: 355e7fec9b8481c9f312576e636bf975ea1807588e037c386d9212165664381a

两次运行退出码均为0,且两次迁移后的文件哈希完全一致。这一证据链证明迁移具备幂等性

——重复执行不会产生差异,也不会反复改写用户文件。

幂等性在源码层面有双重保障:

  • 迁移完成后,配置文件中写入_migrations: ["2026-08-reasoning-unification"]标记。doctor 的检查逻辑通过hasMigrationMarker判断标记是否存在,决定是否继续提示用户执行迁移(见 deprecated-reasoning-keys.ts);
  • 迁移计划本身采用mode: "replace-target",由 migration-plans.ts 中的reasoningPlan定义,其transform直接调用transformReasoningUnification,规范化变换是纯函数式处理,同样的输入必然产出同样的输出。

迁移产物:规范化结构长什么样

第一次迁移后,~/.omo/omo.jsonc

的内容为:

{ "[opencode]": { "agents": { "explore": { "models": [ { "model": "anthropic/claude-fable-5", "reasoning": "high" }, { "model": "openai/gpt-5.6-sol-fast", "reasoning": "medium" } ] } } }, "_migrations": [ "2026-08-reasoning-unification" ] }

关键变化一目了然:

  • variant: "high"→reasoning: "high";
  • variant: "medium"(fallback 内)→reasoning: "medium";
  • 主模型与fallback_models合并为有序的models链,链首即主模型;
  • 顶层出现_migrations标记数组,记录已执行的迁移 ID2026-08-reasoning-unification。

这个“模型链”语义在 doctor 的替换提示中也有明确说明:fallback_models的规范替换是models: [, ...fallbacks](首项成为主模型),见 deprecated-reasoning-keys.ts 中的CANONICAL_REPLACEMENT

映射表。

源码层面的变换规则:transformReasoningUnification

为什么variant能正确地变成reasoning?核心实现在 reasoning-unification.ts,迁移 ID 常量定义于第 6 行,入口变换函数transformReasoningUnification

定义于第 190-198 行。其关键规则如下:

1. 遗留键归一化

normalizeDefinition会识别reasoning、variant、reasoningEffort、thinking、textVerbosity等键,其中variant与reasoningEffort统一归一为reasoning;thinking与textVerbosity这类 provider 原生键则被收进provider_options容器。模型条目统一经由normalizeLegacyModelEntry/normalizeLegacyModelFields(来自@oh-my-opencode/omo-config-core

)归一。

2. 模型链合并

当定义中同时存在fallback_models,或 agent 同时声明了model与models时,变换会把主模型引用(primaryModelRef)、已存在的models列表与 fallback 列表按顺序拼接成新的models链,然后删除model与fallback_models

两个旧键。

3. 冲突诊断

若同一定义同时出现多个推理相关键(如reasoning+reasoningEffort+variant),conflictDiagnostic

会生成一条诊断信息,指明保留了哪个键、丢弃了哪些键,例如:

conflict: categories.conflict dropped variant="high" kept reasoningEffort="xhigh"

这条诊断会写入迁移日志,测试 reasoning-unification.test.ts 精确断言了该输出。

4. OpenCode 块特例

[opencode]块走独立的normalizeOpenCodeBlock路径:只重写agents与categories下的已知键,而native等嵌套对象、provider等无关顶层字段保持原样;maxTokens、providerOptions、textVerbosity

在 OpenCode 语义下被放行回原值。这一行为由测试用例直接验证(见 reasoning-unification.test.ts)。

5. 类型化块与 profiles 递归

[senpi]、[codex]块与profiles

配置会递归归一,确保全配置文件的键风格一致。完整的输入/输出对照见仓库夹具 fixture-input.json 与 fixture-expected.json。

doctor 配置检查:规范产物被正式认可

迁移完成后,QA 运行了doctor --json --platform=opencode

,得到:

Configuration: pass — Configuration is valid Configuration: pass — No deprecated reasoning keys found hasUnknownModels: false hasDeprecatedHarness: false

两条 pass 意味着:迁移后的配置通过了结构校验,且不再包含任何遗留 reasoning 键——这正是用户报告中的“警告刷屏”被消除的直接证明。

需要说明的是,本次 doctor 的整体退出码为1

,QA 文档明确指出这是有意的:隔离的 OpenCode 配置为空,插件未注册,属于该密闭场景下的无关系统检查失败,与本次配置迁移无关。这种“拆分看待检查项”的严谨态度,避免了把无关失败误判为迁移失败。

doctor 检查的实现细节值得展开:检查函数checkDeprecatedReasoningKeys扫描~/.omo/omo.jsonc与~/.omo/omo.json,对每个键比对CANONICAL_REPLACEMENT映射表,命中即产出Deprecated config key

警告并给出替换建议;当文件已有迁移标记时,fix 后缀会自动省略“或运行 config migrate”的提示,防止把用户带入重复迁移的循环(见 deprecated-reasoning-keys.ts)。

运行时加载验证:链真正到达执行面

doctor 通过只代表“语法与键名正确”,QA 还进一步验证了运行时行为。validatePluginConfig()

在隔离 HOME 的项目目录下返回:

{ "valid": true, "messages": [], "explore": { "model": "anthropic/claude-fable-5", "reasoning": "high", "fallback_models": [ { "model": "openai/gpt-5.6-sol-fast", "reasoning": "medium" } ] } }

这里的关键信息是:执行面读取到的字段是model、reasoning、fallback_models,而不是落盘文件中的models链。这说明运行时配置加载器正确地把规范化的models链重新展开为执行所需的模型选择结构,且reasoning值被完整保留(high/medium

),没有退回到默认值。QA 文档特别强调:这证明了“迁移后的规范链真正到达执行面对应的字段,而不是静默回退到默认配置”。

会话数据库隔离:零污染证据

QA 还对比了 OpenCode 会话数据库的前后状态:

sessions before: 0 sessions after: 0

迁移、doctor、插件校验全流程执行完毕后,会话记录数保持0 → 0

。这证明整个 QA 没有向真实或隔离的 OpenCode 会话数据库写入任何数据,迁移本身是纯文件级别的操作,不会产生会话副作用。

为什么这些证据足够:五条结论

QA 文档用五个要点总结了验证充分性:

  1. 输入真实:Discord 与 issue #6567 报告的精确遗留键(variant、fallback_models)被原样传入真实迁移命令,没有使用简化替身;
  2. 幂等成立:两次迁移哈希相等,重复执行安全;
  3. 产物被认可:真实 doctor 配置检查确认规范输出合法且不再产生社区报告的警告刷屏;
  4. 运行时贯通:迁移后的规范链确实到达执行面的model、reasoning、fallback_models字段,而非回退默认值;
  5. 零污染:会话计数前后一致,QA 未污染真实或隔离的会话数据库。

这五条恰好覆盖了“输入 → 变换 → 输出 → 运行 → 副作用”五个维度,构成完整的证据闭环。

清理收据与保密边界

QA 收尾时移除了两个沙箱临时目录(/var/folders/.../omo-qa-sandbox.XXXXXX.S4qmb1Nm5K与...yuwTgRcO5b

),并确认无服务器、端口、tmux 会话、浏览器标签、容器、socket 或 QA 专属环境残留。修正 harness 作用域后,受影响场景被重跑复验:

migration exit: 0 Configuration: pass — Configuration is valid Configuration: pass — No deprecated reasoning keys found hasUnknownModels: false hasDeprecatedHarness: false sessions: 0 → 0 QA root removed: verified

同时,QA 文档明确了保密边界:不包含.env

内容、provider 凭据、auth 头、token 与私有模型缓存数据;与插件注册/模型缓存缺失无关的 doctor 输出只以摘要形式说明;首次使用 dummy-model 的试运行因未知模型 ID 正确回退到默认值,不作为运行时选择证据保留,仅出现在清理收据中。这种“证据与噪声分离”的记录方式,保证了结论的可信度不因无关细节稀释。

小结:一条可复用的配置迁移验证方法论

从本次 QA 可以提炼出一套通用方法:隔离环境 → 真实输入 → 迁移执行 → 哈希幂等 → doctor 校验 → 运行时加载 → 副作用核对 → 清理确认

。它既适用于后续其他一次性配置迁移的验收,也为任何“配置升级类功能”提供了可复制的证据标准——尤其是“文件级哈希 + 会话级计数”的双重零副作用检查,值得在同类任务中直接复用。对配置迁移实现本身感兴趣的读者,可继续深入 config-migration 目录 的源码与测试,其中 migration-plans.ts 展示了迁移计划的发现、备份与执行编排,reasoning-unification.test.ts 则提供了完整的规则级验收用例。

【免费下载链接】oh-my-openagentOmO: Just type "mass ulw" keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考