作者:张大鹏 发布时间:2026-04-23 字数:5634 预计阅读时间:9 分钟
引言
昨天刚研究完 Hermes Agent 的传输层重构,今天上游又双叒叕更新了。
这次的画风不太一样------不是大架构改动,而是安全加固 + 生态扩展。200+ commit 里面,我挑了跟日常使用最相关的几个点来研究:
- Agent 创建的 skill 终于不再被关键词扫描误杀了
- Session split-brain 问题被彻底修掉
- MCP toolset 继承默认开启
- xAI Grok STT 和 OpenAI Codex 图像插件来了
- 开发工具链终于加上 ruff + mypy
本文是我的研究笔记。
1. 安全机制终于不扰民了
1.1 之前的痛点
之前的 skills_guard 扫描逻辑比较死板:agent 创建的 skill 内容如果包含 rm -rf、curl | bash 这类关键词,直接被 block。
但问题是------正常写 skill 文档经常要引用这些危险命令 。比如写个「如何安全地清理临时文件」的 skill,里面提到 rm -rf /tmp/* 再正常不过了,结果被扫描拦下。
1.2 新增配置开关
这次新增了 config.skills.guard_agent_created 配置项,默认关闭:
yaml
# config.yaml
skills:
guard_agent_created: false # 默认关闭,agent 创建的 skill 不扫描
核心逻辑变更:
python
# tools/skills_guard.py
def should_scan(action: str, source: str) -> bool:
if action in ('create', 'edit', 'patch'):
if source == 'agent_created':
return config.get('skills.guard_agent_created', False)
return True # 其他情况继续扫描
Rationale :如果 agent 本身已经被攻陷,它完全可以通过 terminal() 直接执行危险命令,扫描 skill 内容没有额外的安全价值,只是徒增误杀。
1.3 SSRF 防护可配置
之前 tirith 安全扫描默认禁止访问私有/内网 IP,这次新增了全局开关:
yaml
security:
allow_private_url_resolution: true # 默认 false,开启需谨慎
2. Gateway Session 并发安全
2.1 那个让你头疼的 split-brain
Session split-brain 是 Hermes Agent gateway 的老问题了:并发场景下多个请求操作同一个 session,导致状态不一致。
这次一口气修了三个相关 bug:
| Commit | 修复内容 |
|---|---|
d72985b7 |
序列化 reset 命令的 hand-off,修复竞争条件 |
b7bdf32d |
stop/reset 后保护 session slot 所有权 |
5651a733 |
finally-block 中 guard _active_sessions 删除 |
2.2 修复细节
核心改进是 reset 命令的 hand-off 序列化:
python
# gateway/session.py
async def reset_session(self, session_id: str):
async with self._session_lock(session_id):
# 1. 先标记为 resetting
await self._mark_resetting(session_id)
# 2. 等待当前请求完成
await self._drain_pending_requests(session_id)
# 3. 最后才执行真正的 reset
await self._do_reset(session_id)
之前的问题是 reset 和正常请求并发执行,导致状态机混乱。现在 reset 必须等所有 pending 请求完成才能执行。
2.3 新增回归测试
这次还专门写了 #11016 split-brain session locks 的回归测试,确保这个问题不会复发:
python
async def test_split_brain_resession_locks():
"""并发 reset + 正常请求不应该死锁"""
session = await gateway.create_session()
async def concurrent_reset():
await asyncio.gather(*[session.reset() for _ in range(5)])
async def concurrent_send():
await asyncio.gather(*[session.send("ping") for _ in range(10)])
await asyncio.gather(concurrent_reset(), concurrent_send())
# 不应该死锁,不应该抛出异常
3. Terminal 环境变量修复
3.1 nvm/n 用户的天坑
之前在 Docker 或远程 SSH 环境里用 Hermes Agent,nvm/n 管理的 Node.js 版本经常找不到。原因是 ~/.profile 和 ~/.bash_profile 没有被 source。
这次修了:
python
# tools/environments/local.py
async def _build_env(self) -> dict:
env = os.environ.copy()
# 自动 source 登录 shell 配置文件
for rc_file in ['~/.bash_profile', '~/.profile', '~/.bashrc']:
rc_path = Path(rc_file).expanduser()
if rc_path.exists():
result = await self._run_shell(f'source {rc_path} && env')
# 解析输出,更新 env
...
return env
现在 nvm/n 的 PATH 在 terminal tool 中也能保持了。
4. MCP Toolset 继承默认开启
4.1 之前的问题
之前的 delegate_task 默认 不继承 父 agent 的 MCP toolsets,导致子 agent 经常找不到父 agent 配置好的 MCP 服务器。
4.2 新行为
python
# tools/delegate_tool.py
DEFAULT_CONFIG = {
'inherit_mcp_toolsets': True, # 默认开启
}
子 agent 自动继承父 agent 的 MCP 配置:
yaml
# config.yaml
tools:
delegate:
inherit_mcp_toolsets: true # 默认 true
# 或者在调用时指定
# { "task": "分析代码", "inherit_mcp_toolsets": false }
5. 图片生成生态扩展
5.1 OpenAI Codex 插件
之前 Hermes Agent 只支持 fal 的图片生成,这次新增了 OpenAI Codex 的 gpt-image-2 支持:
yaml
# config.yaml
image_gen:
provider: openai-codex
# 需要配置 Codex OAuth
codex_client_id: your_client_id
codex_client_secret: your_secret
python
# plugins/image_gen/openai-codex/__init__.py
class OpenAICodexProvider(ImageGenProvider):
"""OpenAI Codex 图片生成(通过 OAuth)"""
async def generate(self, prompt: str, aspect_ratio: str = "1:1", **kwargs) -> str:
# 使用 Codex OAuth 获取 access token
token = await self._get_oauth_token()
# 调用 Codex Images API
response = await self._call_codex_api(prompt, token)
return response.data[0].url
5.2 长生命周期 Session 插件刷新
之前一个 session 运行几小时后,图片生成插件的 provider 配置可能过期。这次加了强制刷新逻辑:
python
# tools/image_generation_tool.py
async def generate(self, prompt: str, ...):
# 检测 provider 是否需要刷新
if self._provider.should_refresh():
await self._provider.refresh()
return await self._provider.generate(prompt, ...)
6. 消息平台新成员
6.1 xAI Grok STT
新增 xAI Grok 的语音转文字 provider:
yaml
# config.yaml
stt:
provider: xai-grok
api_key: xai-your-api-key
python
# agent/transcription.py
class XAIGrokSTTProvider(BaseSTTProvider):
async def transcribe(self, audio_data: bytes) -> str:
response = await self.client.audio.transcriptions.create(
model="grok-stt",
file=("audio.wav", audio_data, "audio/wav")
)
return response.text
6.2 MiniMax-AI/cli Skill
新增 MiniMax-AI/cli 到默认 skill tap:
bash
# 使用方式
/hermes skill install MiniMax-AI/cli
7. 开发工具链完善
7.1 ruff + mypy 加入 dev 依赖
之前项目的 linting 和 type checking 比较松散,这次终于规范化了:
toml
# pyproject.toml
[tool.ruff]
line-length = 100
target-version = "py310"
[tool.mypy]
python_version = "3.10"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
现在开发流程:
bash
# lint
ruff check .
# type check
mypy hermes_agent/
# 或者一键
make check
7.2 Windows 兼容性改进
os.kill(pid, 0) 在 Windows 上会抛出 OSError,这次加了兼容处理:
python
import platform
def is_process_running(pid: int) -> bool:
if platform.system() == 'Windows':
# Windows 用 signal 0 不可靠
import ctypes
return ctypes.windll.kernel32.OpenProcess(1, False, pid) != 0
else:
try:
os.kill(pid, 0)
return True
except OSError:
return False
总结
本次更新要点
| 类别 | 改动 |
|---|---|
| 安全 | skills-guard 默认不扫描 agent 创建的 skill;SSRF 防护可配置 |
| Gateway | Session split-brain 彻底修复;reset hand-off 序列化 |
| Terminal | 自动 source ~/.profile,nvm/n PATH 保持 |
| MCP | inherit_mcp_toolsets 默认开启 |
| 图像 | OpenAI Codex 插件;长生命周期 session 插件刷新 |
| 语音 | xAI Grok STT provider |
| Skill | MiniMax-AI/cli 加入默认 tap |
| DevOps | ruff + mypy 加入 dev 依赖;Windows 兼容修复 |
评价
这次更新没有大架构改动,但刀法精准------全是日常使用中的痛点。Session split-brain 修了好几个版本终于修干净了,skills-guard 的误杀问题也算是还开发者一个清净。
唯一要提醒的是 SSRF 防护可配置 这个开关------开启前请确认你的使用场景真的需要解析内网 URL,否则相当于把门拆了。
相关资料:
- GitHub:github.com/NousResearc...
- 项目主站:hermesagent.ai