配置腐烂:改名、卸载插件、禁用平台之后,hermes config check 现在会开口了

你换了一台机器,把旧的 config.yaml 带了过来;或者几周前卸掉了某个插件、改过工具集的名字。Hermes 照常启动、照常聊天,看起来一切正常——直到某天你发现某个平台的机器人不回消息了,或者某类工具干脆不见了。你翻配置文件,那些名字明明还在里面。
这就是配置腐烂:platform_toolsets 里保存的工具集名字,是当初 Hermes 在“保存那一刻”认为存在的;插件卸载、工具集改名之后,这些名字就成了指向虚空的引用。而运行时只是安静地忽略它们。2026-09-29 合并的补丁(PR #127782,收编 #127392 并保留原作者提交)让 hermes config check 把这些失效选择报出来,并让判定逻辑与运行时保持一致。
一个判定器,三处共用
补丁最核心的结构性改动,是把“这个名字还算不算有效工具集”的判断收敛成一个函数:
# hermes_cli/toolset_validation.py
def saved_toolset_resolver(config: dict) -> Callable[[str], bool]:
"""is_valid_toolset for a saved platform_toolsets list, mirroring what
tools_config._get_platform_tools lets through."""
hermes config check 与 hermes config migrate 现在都走它。为什么这件事重要?因为在修复之前,migrate 会对已经配置好的 MCP 服务器名字和插件平台 bundle 发出警告——警告到什么程度呢:它会建议你把 'hermes-teams' 改成 'hermes-teams'。一个自己给自己提建议的迁移检查,基本等于噪音。
新的判定规则有几条值得记住,因为它们解释了“为什么我的配置现在不再报警了”:
- 配置过的 MCP 服务器算已知,即使它写着
enabled: false。它是被停用了,不是拼错了。旧实现把“停用”当成“不认识”,于是给出一条毫无意义的“你是不是想用 hermes-cli”。 known_plugin_toolsets不再作为工具集存在的证据。 它记录的是“保存那天这个平台被提供了哪些工具集”,所以已卸载插件留下的名字恰好被它掩盖——而那正是这个检查存在的意义。- 插件查找与平台清单扫描只在便宜的检查定位不到时才执行。 也就是说,一份干净的配置永远不会触发插件发现流程——这个检查本身不会拖慢任何东西。
禁用的平台:按运行时看到的方式判断
第二类误报来自 plugins.disabled。运行时代码读这个键时对形态是宽容的:它只认列表。但旧检查会照着 YAML 字面值判断,于是这样一行:
plugins:
disabled: platforms/telegram # 字符串,运行时其实忽略
会被报成“平台已禁用”,可运行时照样加载它。现在检查走运行时自己的读取器(_get_disabled_plugins()),非列表值不再被当作“禁用了平台”。
而且报出来时也不再只凭猜测——它会去查这个平台必需的凭据是否已经配好:
platform plugin 'platforms/telegram' is disabled while its required credentials are configured.
Run `hermes plugins enable platforms/telegram` if you want it active.
注意“必需”两个字:判定来自 _platform_manifest_env_entries(optional=False),可选变量不算数。一个没有配 token 的禁用平台不会烦你——API 里那些可选环境变量也不会被误当成“你已经配好了,只是想自找麻烦”。
顺手修掉的崩溃,以及一个被删掉的检查
这轮还处理了两个“看起来毫无关系”的问题:
- 格式错掉的
mcp_servers不再让命令崩掉。 比如你不小心把它写成了列表(mcp_servers: [a]),旧实现会直接抛AttributeError回溯;现在它照常跑完,把问题当成普通诊断报出来。诊断命令本身死掉是最没用的失败方式。 - 顶层
toolsets键的检查被删掉了。 原先那个 PR 还检查顶层toolsets键,但 CLI 解析工具集时只看--toolsets命令行参数或platform_toolsets,顶层键只在遗留的 kanban 场景里被读一次。检查一个运行时根本不读的键,只会制造虚假的“你需要修一下”。
下面这张表来自补丁自带的验证记录(用真实的 hermes config check 加临时 HERMES_HOME 跑出来的),左边是旧行为、右边是新行为:
| 场景 | 修复前 | 现在 |
|---|---|---|
platform_toolsets.cli 里列了已删除的名字 |
报出 | 报出 |
已卸载插件的工具集,被记在 known_plugin_toolsets 里 |
静默 | 报出 |
platform_toolsets 里列了 enabled: false 的 MCP 服务器 |
报“unknown toolset,你是不是想用 hermes-cli” | 静默 |
mcp_servers: [a](形态写错) |
AttributeError 回溯 | 正常运行 |
plugins.disabled: platforms/telegram(字符串)且已配 token |
报“已禁用”(运行时其实照常加载) | 静默 |
plugins.disabled: [platforms/telegram] 且已配 token |
报出 | 报出 |
老配置为什么还能读出来
还有一个容易被忽略的历史包袱:早期版本的 hermes config set 会把一个裸的 JSON 数组参数存成字符串,所以配置里可能出现:
platform_toolsets:
cli: '["browser", "terminal"]' # 字符串,不是列表
现在运行时、hermes doctor 和 hermes plugins enable 都通过同一个解析函数读这个区段,所以它们对“你究竟配了什么”的看法一致;任何一个读取方单独做兼容,都会让另外两个看到不同的世界。
你该什么时候跑它
建议很简单:在换机器、卸插件、改工具集名字、或者从一个旧版本升级上来之后跑一次。
hermes config check # 报告保存下来的失效选择
hermes config migrate # 按同一判定器做迁移与修正
hermes tools # 交互式重新挑选工具集
hermes plugins enable platforms/telegram # 按提示把该启用的平台启用
三条实用判断:
- 看到 “disabled while its required credentials are configured”,先问自己是不是有意关的。 检查本身就承认这一点——配了凭据只是“值得提一句”的理由,禁用完全可能是故意的。想启用就照提示跑
hermes plugins enable。 - 看到工具集名字不再有效,别急着删。 先确认它是不是属于某个已卸载的插件;如果是想继续用,装回插件即可,删掉这个名字只会让你以后重新配一遍。
config check干净不等于配置完美。 它只判断“保存的选择能不能被运行时兑现”,不判断你的模型选得对不对、密钥有没有过期。那类问题交给hermes doctor。
想让这个检查更有意义,前提是配置本身别乱:我们的 MCP 配置与上下文变量 和 插件目录指南 里都强调过,插件与 MCP 的增删要跟着配置文件一起清理。现在这轮补丁做的,正是把“一起清理”这件事从你的记忆力,交给命令。
总结
hermes config check现在会报出保存下来但已失效的platform_toolsets名字,以及“平台被禁用、必需凭据却配着”的情况。- 它与
hermes config migrate共用同一判定器,不再出现'hermes-teams'建议改成'hermes-teams'这类自相矛盾的警告。 - 规则与运行时对齐:停用的 MCP 服务器算已知、
known_plugin_toolsets不再当作证据、非列表形态的plugins.disabled不再误报、可选环境变量不计入必需凭据。 - 插件发现只在必要时执行,干净配置零开销;格式错误的
mcp_servers不再让命令崩溃。 - 顶层
toolsets键的检查被移除,因为 CLI 从不读它(仅在遗留 kanban 场景)。 - 换机器、卸插件、升级之后跑一次,配合
hermes config migrate与hermes tools修掉它报出的每一条。
命令的完整用法见 hermes config 与 hermes plugins。