配置腐烂:改名、卸载插件、禁用平台之后,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   # 按提示把该启用的平台启用

三条实用判断:

  1. 看到 “disabled while its required credentials are configured”,先问自己是不是有意关的。 检查本身就承认这一点——配了凭据只是“值得提一句”的理由,禁用完全可能是故意的。想启用就照提示跑 hermes plugins enable。
  2. 看到工具集名字不再有效,别急着删。 先确认它是不是属于某个已卸载的插件;如果是想继续用,装回插件即可,删掉这个名字只会让你以后重新配一遍。
  3. 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。