Hermes Update 冲突排查:本地 Xiaomi MIMO 补丁的保全与重放
背景
hermes update 拉取了 1150 个新 commit 之后,本地针对 Xiaomi MIMO 的两处兼容补丁产生冲突,需要手动处理。
这不是一次偶然——只要维护了任何本地 hack,每次大版本 update 就可能触发。本文记录根因、解法,以及如何让补丁在下次更新后不再丢失。
冲突根因
本地有两处 MIMO 兼容改动:
| 文件 | 本地改动 | 上游动作 | 结果 |
|---|---|---|---|
hermes_cli/models.py | 在 _PROVIDER_MODELS["xiaomi"] 加入 mimo-v2.5-pro、mimo-v2.5、mimo-v2.5-flash | 上游同位置合并了 mimo-v2.5-pro、mimo-v2.5(缺 flash) | 冲突 |
run_agent.py | 修复 _swap_credential 的 base_url 覆盖 bug | 上游未触碰此行 | 自动合并成功,但 reset 时丢弃 |
hermes update 内部的冲突处理机制:
sequenceDiagram
participant U as hermes update
participant S as git stash
participant R as git pull (upstream)
participant A as stash apply
U->>S: stash save(保存本地改动)
S-->>U: stash 入栈
U->>R: git pull 1150 commits
R-->>U: 拉取成功
U->>A: stash apply
A-->>U: ❌ 冲突(models.py 同区域改动)
Note over U,A: apply 失败 → git reset --hard<br/>staging 全清,stash 原样保留
apply 失败时会 git reset --hard,staging 清空,stash 保留——但不会自动提示你哪里出了问题。
两处补丁的具体内容
补丁一:hermes_cli/models.py — 补入 mimo-v2.5-flash
上游已合并了 mimo-v2.5-pro 和 mimo-v2.5,但遗漏了 flash 变体。手动插入:
# 上游合并后的状态: "xiaomi": [ "mimo-v2.5-pro", "mimo-v2.5", "mimo-v2-pro", ... ] # 手动补入(插在 v2.5 之后、v2-pro 之前): "xiaomi": [ "mimo-v2.5-pro", "mimo-v2.5", "mimo-v2.5-flash", # ← 新增 "mimo-v2-pro", ... ] 补丁二:run_agent.py — _swap_credential base_url 覆盖修复
问题根因:credential rotation 时,如果 entry 的 base_url 恰好等于 provider 的默认 inference_base_url,会错误地覆盖 self.base_url。Xiaomi MIMO 的多 token 轮换场景会稳定触发。
# 原始代码(一行 or 链): runtime_base = getattr(entry, "runtime_base_url", None) \ or getattr(entry, "base_url", None) \ or self.base_url # 修复后:先拿到 entry_base,再判断是否与 provider 默认值重复 entry_base = getattr(entry, "runtime_base_url", None) or getattr(entry, "base_url", None) or "" if entry_base and self.base_url and entry_base.rstrip("/") != self.base_url.rstrip("/"): try: from hermes_cli.auth import PROVIDER_REGISTRY pconfig = PROVIDER_REGISTRY.get(self.provider) if pconfig and entry_base.rstrip("/") == pconfig.inference_base_url.rstrip("/"): entry_base = "" # entry 的 base_url 就是 provider 默认值,不应覆盖 except Exception: pass runtime_base = entry_base or self.base_url 核心逻辑:当 entry 携带的 base_url 与 provider 全局默认值相同时,不应覆盖当前实例的 self.base_url。
解决步骤
不要重新 git stash apply(会再次冲突),直接手动应用:
# 1. 确认 reset 后状态是干净的 git -C ~/.hermes/hermes-agent status # 2. 手动编辑 models.py,在 "xiaomi" list 中补入 mimo-v2.5-flash vim ~/.hermes/hermes-agent/hermes_cli/models.py # 3. 手动编辑 run_agent.py,应用 _swap_credential 修复 vim ~/.hermes/hermes-agent/run_agent.py # 4. 验证两处补丁均已应用 grep "mimo-v2.5-flash" ~/.hermes/hermes-agent/hermes_cli/models.py grep "entry_base" ~/.hermes/hermes-agent/run_agent.py # 5. 清理已失效的旧 stash git -C ~/.hermes/hermes-agent stash drop stash@{1} # 冲突时的 auto-stash 每次 hermes update 后的检查清单
# 快速验证两处本地补丁是否仍然存在 grep "mimo-v2.5-flash" ~/.hermes/hermes-agent/hermes_cli/models.py \ && echo "✅ models.py OK" || echo "❌ models.py 缺 flash" grep "entry_base" ~/.hermes/hermes-agent/run_agent.py \ && echo "✅ run_agent.py OK" || echo "❌ run_agent.py 缺修复" 两行都有输出则正常,否则重新应用本文的补丁。
让补丁不再手动重放:patch 文件方案
维护一个 .patch 文件,每次 update 后自动应用:
第一步:在补丁应用完毕后生成 patch
git -C ~/.hermes/hermes-agent diff > \ ~/CodexSpace/Tooling/2026-0430-hermes-mimo-update-conflict/mimo-local.patch 第二步:每次 hermes update 后执行
git -C ~/.hermes/hermes-agent apply \ ~/CodexSpace/Tooling/2026-0430-hermes-mimo-update-conflict/mimo-local.patch 如果 apply 失败(说明上游部分合并了本地改动),检查 grep 输出,只手动补剩余未合入的部分。
graph LR
UPD["hermes update"] --> CHK["grep 快速检查两处补丁"]
CHK --> OK["两行均有输出\n✅ 无需操作"]
CHK --> MISS["有行缺失\n❌ 补丁丢失"]
MISS --> TRY["git apply mimo-local.patch"]
TRY --> SUCC["apply 成功\n✅ 完成"]
TRY --> FAIL["apply 失败\n(上游已部分合入)"]
FAIL --> MANUAL["grep 确认哪行缺失\n手动补剩余差异"]
MANUAL --> REGEN["重新生成 mimo-local.patch"]
Stash 残留说明
解决冲突后清理了已失效的 stash:
git -C ~/.hermes/hermes-agent stash list # stash@{0}: hermes-update-autostash-20260430-101237 — 仅含 ui-tui/package-lock.json # stash@{1}: 90caa28... — 包含 MIMO 补丁的旧 stash(已失效,手动处理后可删) git -C ~/.hermes/hermes-agent stash drop stash@{1} 残留的 stash@{0} 只含 ui-tui/package-lock.json,是 update 过程自动产生的 auto-stash,与 MIMO 无关,可忽略。
2026-04-30