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 文档明确列出了如下隔离手段,全部来自 script/agent/qa-sandbox.sh 所提供的沙箱能力: 这些环境变量与目录隔离共同构成了“hermetic(密闭)”场景:任何副作用都只会落在临时目录内,后续可以整体删除。 QA 使用了与社区报告完全一致的遗留配置片段作为输入: 这里出现了两个需要迁移的旧键: ,作为迁移的起点。 QA 文档定义的验证流程包含六个动作,覆盖“迁移 → 幂等 → 体检 → 运行时加载 → 数据隔离”全链路: 迁移执行结果如下: 两次运行退出码均为 ——重复执行不会产生差异,也不会反复改写用户文件。 幂等性在源码层面有双重保障: 第一次迁移后, 的内容为: 关键变化一目了然: 这个“模型链”语义在 doctor 的替换提示中也有明确说明: 映射表。 为什么 定义于第 190-198 行。其关键规则如下: 1. 遗留键归一化 )归一。 2. 模型链合并 当定义中同时存在 两个旧键。 3. 冲突诊断 若同一定义同时出现多个推理相关键(如 会生成一条诊断信息,指明保留了哪个键、丢弃了哪些键,例如: 这条诊断会写入迁移日志,测试 reasoning-unification.test.ts 精确断言了该输出。 4. OpenCode 块特例 在 OpenCode 语义下被放行回原值。这一行为由测试用例直接验证(见 reasoning-unification.test.ts)。 5. 类型化块与 profiles 递归 配置会递归归一,确保全配置文件的键风格一致。完整的输入/输出对照见仓库夹具 fixture-input.json 与 fixture-expected.json。 迁移完成后,QA 运行了 ,得到: 两条 pass 意味着:迁移后的配置通过了结构校验,且不再包含任何遗留 reasoning 键——这正是用户报告中的“警告刷屏”被消除的直接证明。 需要说明的是,本次 doctor 的整体退出码为 ,QA 文档明确指出这是有意的:隔离的 OpenCode 配置为空,插件未注册,属于该密闭场景下的无关系统检查失败,与本次配置迁移无关。这种“拆分看待检查项”的严谨态度,避免了把无关失败误判为迁移失败。 doctor 检查的实现细节值得展开:检查函数 警告并给出替换建议;当文件已有迁移标记时,fix 后缀会自动省略“或运行 config migrate”的提示,防止把用户带入重复迁移的循环(见 deprecated-reasoning-keys.ts)。 doctor 通过只代表“语法与键名正确”,QA 还进一步验证了运行时行为。 在隔离 HOME 的项目目录下返回: 这里的关键信息是:执行面读取到的字段是 ),没有退回到默认值。QA 文档特别强调:这证明了“迁移后的规范链真正到达执行面对应的字段,而不是静默回退到默认配置”。 QA 还对比了 OpenCode 会话数据库的前后状态: 迁移、doctor、插件校验全流程执行完毕后,会话记录数保持 。这证明整个 QA 没有向真实或隔离的 OpenCode 会话数据库写入任何数据,迁移本身是纯文件级别的操作,不会产生会话副作用。 QA 文档用五个要点总结了验证充分性: 这五条恰好覆盖了“输入 → 变换 → 输出 → 运行 → 副作用”五个维度,构成完整的证据闭环。 QA 收尾时移除了两个沙箱临时目录( ),并确认无服务器、端口、tmux 会话、浏览器标签、容器、socket 或 QA 专属环境残留。修正 harness 作用域后,受影响场景被重跑复验: 同时,QA 文档明确了保密边界:不包含 内容、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隔离环境:QA 沙箱的关键配置
CODEX_HOME;HOME(用于~/.omo/omo.jsonc的定位);OPENCODE_DISABLE_AUTOUPDATE=1(关闭自动更新,保证迁移过程不因自更新引入变量);OPENCODE_DISABLE_MODELS_FETCH=1(关闭模型元数据拉取,确保模型解析只依赖本地配置)。被测输入:legacy-input.jsonc
{ "[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验证动作:六步闭环
bun run packages/omo-opencode/src/cli/index.ts config migrate --json(真实 CLI 入口见 CLI 入口);~/.omo/omo.jsonc计算哈希;bun run packages/omo-opencode/src/cli/index.ts doctor --json --platform=opencode;HOME下的项目目录中对配置调用validatePluginConfig();幂等性验证:哈希相等即证据
first exit: 0 second exit: 0 first hash: 355e7fec9b8481c9f312576e636bf975ea1807588e037c386d9212165664381a second hash: 355e7fec9b8481c9f312576e636bf975ea1807588e037c386d9212165664381a0,且两次迁移后的文件哈希完全一致。这一证据链证明迁移具备幂等性_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。fallback_models的规范替换是models: [, ...fallbacks](首项成为主模型),见 deprecated-reasoning-keys.ts 中的CANONICAL_REPLACEMENT源码层面的变换规则:transformReasoningUnification
variant能正确地变成reasoning?核心实现在 reasoning-unification.ts,迁移 ID 常量定义于第 6 行,入口变换函数transformReasoningUnificationnormalizeDefinition会识别reasoning、variant、reasoningEffort、thinking、textVerbosity等键,其中variant与reasoningEffort统一归一为reasoning;thinking与textVerbosity这类 provider 原生键则被收进provider_options容器。模型条目统一经由normalizeLegacyModelEntry/normalizeLegacyModelFields(来自@oh-my-opencode/omo-config-corefallback_models,或 agent 同时声明了model与models时,变换会把主模型引用(primaryModelRef)、已存在的models列表与 fallback 列表按顺序拼接成新的models链,然后删除model与fallback_modelsreasoning+reasoningEffort+variant),conflictDiagnosticconflict: categories.conflict dropped variant="high" kept reasoningEffort="xhigh"[opencode]块走独立的normalizeOpenCodeBlock路径:只重写agents与categories下的已知键,而native等嵌套对象、provider等无关顶层字段保持原样;maxTokens、providerOptions、textVerbosity[senpi]、[codex]块与profilesdoctor 配置检查:规范产物被正式认可
doctor --json --platform=opencodeConfiguration: pass — Configuration is valid Configuration: pass — No deprecated reasoning keys found hasUnknownModels: false hasDeprecatedHarness: false1checkDeprecatedReasoningKeys扫描~/.omo/omo.jsonc与~/.omo/omo.json,对每个键比对CANONICAL_REPLACEMENT映射表,命中即产出Deprecated config key运行时加载验证:链真正到达执行面
validatePluginConfig(){ "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会话数据库隔离:零污染证据
sessions before: 0 sessions after: 00 → 0为什么这些证据足够:五条结论
variant、fallback_models)被原样传入真实迁移命令,没有使用简化替身;model、reasoning、fallback_models字段,而非回退默认值;清理收据与保密边界
/var/folders/.../omo-qa-sandbox.XXXXXX.S4qmb1Nm5K与...yuwTgRcO5bmigration 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.env小结:一条可复用的配置迁移验证方法论
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考