Hermes Agent v0.21.5
概览
v0.21.5 —— 又一个为下游而生的补丁 tag。 发布于 2026 年 9 月 24 日。自 v0.21.4 以来:1,610 个非合并提交 · 4,828 个改动文件(+164,132 / −149,440)· 460 个已合并 PR · 475 个已关闭 issue,测量于提交 f97608f178d1ffeca59860195ab7da295f7c8e5f。
这个 tag 存在的理由和 v0.21.4 一样:Docker 镜像、Hermes Cloud 和托管部署都从最新的 release tag 构建,所以窗口里修好的东西必须先落进一个稳定版本,云上的用户才拿得到。发版正文写得很直白——完整整理的发版说明推迟到 v0.22.0,那一版会把 v0.21.0 以来的所有内容补齐:亮点、功能分区和完整的贡献者名单,窗口里的东西一件都不会漏。
在那之前,这个页面记录这个 tag 是给谁的,以及窗口里已经跑在你机器上的那些变化。
亮点
1. 桌面端补齐法语、德语、西班牙语目录,并新增文字方向设置
桌面端现在有三套完整的界面目录(fr / de / es),在 Settings → Appearance → Language 里可选。三套目录覆盖了 en.ts 里的每一个 key,包括 defineFieldCopy 的设置项标题与说明,以及只在介绍页轮播用的 intro-{fr,de,es}.ts。它们按 defineLocale() 覆盖层注册(和 ja / ar / ru 一样),所以英文以后新增 key 会回落到英文,不会让每个贡献者的类型检查一起变红。后端本来就有 locales/{fr,de,es}.yaml;现在 display.language: fr|de|es、以及 fr-CA、de-AT、es-419 这类地区别名,都会解析到对应目录,而不是回落英文。法语用 vous,德语用 Sie,西班牙语用中性祈使的 tú。产品名和标识符(Hermes、MCP、API、OAuth、模型 ID、环境变量、文件名)保持原文。PRs #120829。
顺带一个 Appearance → Chat display → Text direction,三选一:Auto / Right-to-left / Left-to-right。此前每个聊天正文块和输入框都按“第一个强方向字符”判断方向(UAX#9 的 plaintext 规则),问题是它分不清“以拉丁人名开头的阿拉伯语段落”和“引用了阿拉伯语的英语段落”。Auto 就是今天的行为(不加属性、不写存储键);选 RTL/LTR 会给聊天正文和两个输入框统一加一个 dir,多行草稿的每一行都跟着走。代码块永远 LTR(围栏代码、行内代码、KaTeX 保持隔离),界面外壳(侧边栏、工具栏、按钮)不翻转。它只是阅读偏好,不会往草稿、已发消息或复制出来的文本里塞双向控制字符。这是一个渲染端持有的偏好,不是 config.yaml 里的键。PRs #120822。
2. Webhook 投递可以“镜像进会话”:你能直接回复那条告警了
默认情况下 webhook 投递是发完就走的:每个事件跑在自己的会话里,所以你在那个聊天里回复“他真走了?”,agent 只会回你“你指的是谁?”。现在路由可以显式开启 mirror_to_session: true(或 hermes webhook subscribe 加 --mirror-to-session),投递成功后把 [Webhook delivery: <route>] 加正文,作为一个带 user 权限的 user 轮次写进目标聊天的会话——和可续跑的 cron brief 走同一条 gateway.mirror.mirror_to_session 路径、同一个角色约定。默认关闭,只有真正的布尔 true 才开启;镜像在 _profile_scope(profile) 里跑,所以 /p/<profile>/ 路由只会写进那个 profile 的 state.db。它是尽力而为的:失败不会让投递失败,目标聊天还没有 gateway 会话(没人跟它说过话)时直接跳过。deliver_only 路由镜像进去的是渲染后的原始载荷,所以只对你自己信任的来源开。PRs #120825。
3. Bot Screen 通过 -desktop 镜像标签登上托管部署
托管和不可变部署现在靠拉 -desktop 镜像标签拿到 Bot Screen。发布出来的镜像不带 Xvnc/Xfce,运行时也装不了(非特权 hermes 用户、没有 sudo、/opt/hermes 是密封的),所以镜像层是唯一的交付路径。:latest / :main / :v* 还是今天那个镜像;:latest-desktop / :main-desktop / :v*-desktop 额外带上相关软件包和 Playwright 的有头 Chromium。每个变体一个 manifest,所以 desktop 发版失败不会拖累 slim 的 :latest。容器里没有 logind,XDG_RUNTIME_DIR=/tmp/hermes-runtime 在启动时以 0700 建好(以前的 $HOME/.cache 回退落在共享的 /opt/data 卷上,两个实例会抢同一个显示锁),非本用户所有或是符号链接的目录会被拒绝,而不是 chown 过去。PRs #120914;功能文档在 website/docs/user-guide/features/bot-screen.md。
4. 每一处模型选择器都能按 slug 添加自定义模型
模型菜单、切换模型对话框、Settings → Model、以及“编辑模型”列表,现在都能直接敲一个模型 slug 把它加进来:菜单底部多了一行 Add custom model…,点了之后搜索框变成 slug 输入,边打边按已配置的 provider 给出选项;加过的 slug 会作为一个普通条目留在列表里,带一个移除 ×。PRs #120693。
5. 本地语音不再每喊一次就重新加载
tts.keep_warm_seconds(默认 60)是新的配置项:最后一个持有点释放后,卸载会等这么久再执行,窗口内任何一次重新开启都会取消这次卸载,直接复用已加载的模型。0 表示立刻卸载。这一条对“唤醒词式”的语音对话尤其重要——那种对话在 ~2 秒的 Piper 预热后就结束,原来语音会在加载完几毫秒后被驱逐,于是每次唤醒都从头加载一遍。PRs #121080。
6. 桌面端语音循环开始读你的配置
**朗读(Read Aloud)**不再念“code block omitted”和“link”这类英文占位词,也不再默默丢掉 Markdown 表格:代码块和 URL 直接静默,MEDIA: 文件链接令牌不会进语音(行内的标点保留),代码块后面悬着的行尾冒号会变成句号,表格改念表头行(“Item, Value, Notes.”)而跳过数据行。PRs #120752。口头停止现在读 voice.stop_phrases(默认 ["stop"])——以前只认一份写死的英文列表,所以一个俄语用户按提示说“отбой”会被当成 prompt 发给 agent;同时整个说话内容要等于某个短语才算停止,[] 表示禁用口头停止。**打断(barge-in)**播放阈值不再写死 0.14,改用已有的 voice.barge_in_threshold_multiplier(默认 3.0)——旧的硬编码值高于蓝牙 HFP 耳机在播放时的说话电平,所以对着回复说话永远打断不了。PRs #120751。
7. 功能键语音快捷键可以重新绑定
一键口述(dictation)变成了一个未绑定的 composer.dictate 键盘动作,和语音对话分开;它复用了桌面端已有的 F 键 / Caps Lock / Delete / Space 及组合键捕获路径。桌面端那个过时的 voice.record_key 字段被移除并说明该配置只对 CLI/TUI 有效。Electron 侧加了仲裁:被指派给渲染进程的 F12 能收到按键,没被指派的 F12 保留 DevTools 行为。PRs #120928。同一个窗口里,macOS 上的功能键工作流也修好了:TUI 解析器保留 F1–F12 终端序列(含带修饰键的协议路径),并且给 TUI 和经典 CLI 的实时工作坞(live-work dock)加了 Ctrl+R 作为可移植的 F7 备选。PRs #120666。
8. 一批只在本地化 Windows 上出现的故障被修掉
四条互相独立的 Windows 专属问题:
- 时区名崩溃。 Windows 用 ANSI 代码页给出时区名(
Paris, Madrid (heure d'été)是 cp1252 字节)。当LC_CTYPE是 UTF-8 时,这些字节会以surrogateescape解码,tzname()里就留下了单独的代理字符;datetime.strftime把tzname()以 UTF-8 插进格式串,于是%Z会在strftime内部抛UnicodeEncodeError——在任何字符串存在之前,所以已有的_sanitize_surrogates清理根本没机会跑。系统提示在每次会话开始和每次压缩时都会重建,故障因此反复出现。新的hermes_time.safe_strftime()在健康 locale 下输出与strftime完全一致(前缀缓存的不变式因此成立),在带代理字符时按 ANSI 代码页还原字节。PRs #120748。 - 中文 Windows 上的子进程输出解码。
subprocess.communicate()在 Windows 上起的_readerthread在读子进程输出时,若捕获只传了text=True而没有encoding=,就会用subprocess._text_encoding(),也就是locale.getencoding()——中文 Windows 上是 cp936/GBK。被读的子进程写的是 UTF-8,任何在 GBK 里非法的字节都会在那个线程里抛UnicodeDecodeError,然后被 serve 进程的threading.excepthook打成一行[gateway-crash]。hermes_cli/web_routers/files.py的_fs_git_branch就是这种写法(它的 kwargs 放在字典字面量里,所以按行匹配text=True的规则一直没抓到它),而桌面端会不停轮询它。PRs #120749。 - Windows 绝对路径的标记与预览。
C:\...\report.html和 UNC 路径\\server\share\...以前既不会被识别成路径(所以产物标签不出现),在渲染端回退里还会被当成相对路径拼到 cwd 上,产生/repo/C:\...这种路径;预览标题也会把C:解析成 URL scheme。新的isWindowsAbsolutePath覆盖盘符(正反斜杠都算)和 UNC 前缀。PRs #121074。 - 冷启动的启动探针。 Windows 冷启动时本地后端先能应答 HTTP,随后事件循环会因为持着 GIL 导入 gateway 平台模块而停住 12–28 秒;启动时的 WebSocket 探针固定 10 秒就放弃,于是把一次正常冷启动锁死成启动失败,拆掉子进程并落进“Ignoring stale Hermes backend exit (1)“的级联。现在由本应用拉起的后端,只要子进程还活着,探针就会越过 10 秒基础预算继续等,上限 90 秒(和端口公告步骤对冷启动给出的预算是同一个)。判断依据是存活而不是输出新鲜度,因为这段停顿是无声的。远端 gateway、“Test remote”按钮和 host 后端附着仍保持固定 10 秒。PRs #120750。
改进
- 桌面端插件 SDK 这一波(composer 草稿 API、会话列表与行装饰插槽、侧边栏导航偏好、模型药丸标签、类型化的 settings/skills/toolsets/profiles 桥、沙箱化嵌入原语、外观设置插槽、插件后端的公共事件桥)都在这个窗口里,规划中的完整说明同样留到 v0.22.0。
- Connectors 页面取代了 MCP 标签页,新装插件的 MCP server 有“Connect now”,已装插件的工具与技能会在每个打开的聊天里实时生效;引导流程会把目录插件和连接器并列推荐。
- Kanban 做了一轮设计打磨:两列的工单弹窗,任务正文支持 Markdown。
- 这个窗口里还有一长串热路径性能工作,覆盖配置加载、工具注册表、gateway 消息处理和模型选择器。
升级
hermes update # git 安装
# 或者重跑一次安装脚本一行命令
Docker / Hermes Cloud:镜像从本 tag 构建,nousresearch/hermes-agent:v2026.9.24。
完整变更对比:v2026.9.21…v2026.9.24
← Hermes Agent Changelog版本号对应关系:tag 是日期式的
v2026.9.24,语义版本是v0.21.5,两者是同一个发布。