欢迎光临
我们一直在努力

【hermes-agent】Hermes-Agent v0.21.2 系统级架构分析

Hermes-Agent 系统级架构分析

分析对象:github.com/hermes-agent(hermes-agent v0.21.2,分支 main)
分析日期:2026-09-12 · 分析方式:只读分析,所有结论附「文件:行号」证据
代码规模:6056 个 Python 文件;核心目录 LOC:hermes_cli 204,498 / agent 111,118 / tools 102,568 / plugins 86,639 / gateway 83,865 / 根级 30,076


执行摘要

Hermes-Agent 是一个自我改进的个人 AI 代理:同一套 agent 内核横跨 CLI、消息网关(Telegram/Discord/Slack 等 ~34 个平台)、TUI、Electron 桌面端、ACP 协议五种界面运行,支持跨会话学习(memory + skills)、子代理委派、定时任务、真实终端与浏览器驱动,并通过插件与技能而非膨胀内核来扩展能力(AGENTS.md:12-16)。

整体架构受两条不变量约束(AGENTS.md:18-29):

  • 每会话 prompt 缓存神圣不可侵犯——长对话每轮复用缓存前缀,任何中途篡改历史上下文/切换工具集/重载记忆/重建 system prompt 都会使缓存失效并倍增成本;唯一例外是上下文压缩(agent/AGENTS.md:55-81)。
  • 内核是窄腰,能力在边缘——每个 model tool 在每次 API 调用都下发,新增核心工具门槛极高;新能力应按「Footprint Ladder」(扩展现有 → CLI+skill → service-gated 工具 → plugin → MCP → 新核心工具,最后手段)在边缘落地(AGENTS.md:27-29、AGENTS.md:56-58)。
  • 架构骨架:AIAgent 窄腰内核(run_agent.py:211,14 个 Mixin 组合)+ 11 阶段同步 turn 状态机(agent/conversation_loop.py:1423,每阶段拆为 turn_*.py 兄弟文件)+ ToolRegistry 单例(tools/registry.py:368,进程级唯一,import 时自注册)+ 4 大可扩展子系统(tools / plugins / providers / gateway 平台适配器)。

    整体设计思路是一个窄腰 + 厚边缘的分层架构:内核只做「跑一个 turn 循环 + 调一组工具」,所有平台、模型、记忆、上下文引擎、图像生成均以插件/ABC 形式挂载在边缘;通过 DEFAULT_CONFIG 单一 schema 源(hermes_cli/config_defaults.py:21)与三套加载器(hermes_cli/AGENTS.md:69-72)统一配置。

    整体运行流程:用户消息从界面(CLI REPL / gateway 平台适配器 / TUI / desktop)进入 → 经 run_conversation(agent/conversation_loop.py:1573)→ _run_conversation_turn(:1423)进入 11 阶段同步循环(构建请求 → 预检门 → API 调用 → 响应归一化 → 工具轮/收尾)→ 工具调用经 model_tools.handle_function_call(model_tools.py:855)→ ToolRegistry.dispatch(tools/registry.py:810)→ handler 执行 → 结果回灌为 tool 消息 → 下一轮迭代,直到模型不再请求工具(finish)或预算耗尽 → finalize_turn(agent/turn_finalizer.py:435)落库并返回。

    最大风险:① 4 个「上帝文件」——hermes_cli/gateway.py(6390 行/288KB,名实不符的进程管理巨石)、gateway/run.py(285KB 门面)、cli.py(4635 行/212KB REPL)、gateway/run_turn.py(221KB);② agent/ 三大压缩/辅助 god 文件(auxiliary_client.py 379KB、context_compressor.py 277KB、conversation_compression.py 216KB);③ 平台适配器自身是 god-adapter(telegram 382KB、discord 352KB、slack 339KB);④ agent↔hermes_cli 双向依赖:18 个 agent 文件反向 import hermes_cli(占 218 个的 ~8%),模块边界事实上被穿透。

    重构主线:P0 拆 hermes_cli/gateway.py(按进程后端)与 cli.py↔mixin 循环回引;P1 拆 agent 三大压缩 god 文件并补模块边界 CI;P2 将根级 hermes_state_* 15 文件包化、AIAgent.__init__ 的 ~60 参数分组。


    一、项目全貌

    1.1 技术栈

    维度内容证据
    项目名/版本 hermes-agent v0.21.2 pyproject.toml:4-5
    描述 “The self-improving AI agent — creates skills from experience, improves them during use, and runs anywhere” pyproject.toml:6
    语言 Python >=3.11,<3.14(上限是 load-bearing:避免 3.14 的 Rust 依赖回退源码编译) pyproject.toml:15
    构建后端 setuptools(setup.py 设 _GuardedSdist/_GuardedBdistWheel,禁止非 Nix 构建产物) setup.py:21-46、pyproject.toml:388-389
    入口脚本 hermes = hermes_cli.main:main;hermes-agent = run_agent:main;hermes-acp = acp_adapter.entry:main pyproject.toml:391-394
    核心依赖 精确钉版(exact pin,反供应链攻击;Mini Shai-Hulud 蠕虫教训):openai 2.24.0、httpx 0.28.1、pydantic 2.13.4、rich、tenacity、pyyaml、jinja2、croniter、snowballstemmer、packaging 26.0 等 pyproject.toml:19-90
    依赖策略 核心仅含「每个 session 都用」的包;provider 特定的(anthropic、firecrawl-py、exa-py 等)放 extra,经 tools/lazy_deps.py 按用户选择后端时懒装 pyproject.toml:34-39
    依赖上限 全部带上限(litellm 投毒 #2796/#2810 教训);exclude-newer = 14 days + CVE 例外白名单 pyproject.toml:292-298、:411
    前端栈 React + TS(web web/、TUI ui-tui/、Electron 桌面 apps/desktop/);package.json + eslint 共享配置 package.json、eslint.config.shared.mjs、apps/desktop/
    部署 shell 安装器 / Docker 镜像 / Nix(pip/PyPI/Homebrew 已不支持,因 wheel 缺 bundled assets) setup.py:5-19、Dockerfile、docker-compose.yml、nix/
    测试 scripts/run_tests.sh(强制 CI parity:凭据 unset、TZ=UTC、HERMES_HOME→temp、per-file 子进程隔离) AGENTS.md:313-329

    1.2 目录结构与规模

    #mermaid-svg-WUNXd9afHSUBObQp{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WUNXd9afHSUBObQp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WUNXd9afHSUBObQp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WUNXd9afHSUBObQp .error-icon{fill:#10b981;}#mermaid-svg-WUNXd9afHSUBObQp .error-text{fill:#ef467e;stroke:#ef467e;}#mermaid-svg-WUNXd9afHSUBObQp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WUNXd9afHSUBObQp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WUNXd9afHSUBObQp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WUNXd9afHSUBObQp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WUNXd9afHSUBObQp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WUNXd9afHSUBObQp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WUNXd9afHSUBObQp .marker{fill:#6b7280;stroke:#6b7280;}#mermaid-svg-WUNXd9afHSUBObQp .marker.cross{stroke:#6b7280;}#mermaid-svg-WUNXd9afHSUBObQp svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WUNXd9afHSUBObQp p{margin:0;}#mermaid-svg-WUNXd9afHSUBObQp .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-WUNXd9afHSUBObQp .cluster-label text{fill:#ef467e;}#mermaid-svg-WUNXd9afHSUBObQp .cluster-label span{color:#ef467e;}#mermaid-svg-WUNXd9afHSUBObQp .cluster-label span p{background-color:transparent;}#mermaid-svg-WUNXd9afHSUBObQp .label text,#mermaid-svg-WUNXd9afHSUBObQp span{fill:#fff;color:#fff;}#mermaid-svg-WUNXd9afHSUBObQp .node rect,#mermaid-svg-WUNXd9afHSUBObQp .node circle,#mermaid-svg-WUNXd9afHSUBObQp .node ellipse,#mermaid-svg-WUNXd9afHSUBObQp .node polygon,#mermaid-svg-WUNXd9afHSUBObQp .node path{fill:#4a90d9;stroke:#2c5f8a;stroke-width:1px;}#mermaid-svg-WUNXd9afHSUBObQp .rough-node .label text,#mermaid-svg-WUNXd9afHSUBObQp .node .label text,#mermaid-svg-WUNXd9afHSUBObQp .image-shape .label,#mermaid-svg-WUNXd9afHSUBObQp .icon-shape .label{text-anchor:middle;}#mermaid-svg-WUNXd9afHSUBObQp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-WUNXd9afHSUBObQp .rough-node .label,#mermaid-svg-WUNXd9afHSUBObQp .node .label,#mermaid-svg-WUNXd9afHSUBObQp .image-shape .label,#mermaid-svg-WUNXd9afHSUBObQp .icon-shape .label{text-align:center;}#mermaid-svg-WUNXd9afHSUBObQp .node.clickable{cursor:pointer;}#mermaid-svg-WUNXd9afHSUBObQp .root .anchor path{fill:#6b7280!important;stroke-width:0;stroke:#6b7280;}#mermaid-svg-WUNXd9afHSUBObQp .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-WUNXd9afHSUBObQp .edgePath .path{stroke:#6b7280;stroke-width:2.0px;}#mermaid-svg-WUNXd9afHSUBObQp .flowchart-link{stroke:#6b7280;fill:none;}#mermaid-svg-WUNXd9afHSUBObQp .edgeLabel{background-color:#f59e0b;text-align:center;}#mermaid-svg-WUNXd9afHSUBObQp .edgeLabel p{background-color:#f59e0b;}#mermaid-svg-WUNXd9afHSUBObQp .edgeLabel rect{opacity:0.5;background-color:#f59e0b;fill:#f59e0b;}#mermaid-svg-WUNXd9afHSUBObQp .labelBkg{background-color:rgba(245, 158, 11, 0.5);}#mermaid-svg-WUNXd9afHSUBObQp .cluster rect{fill:#10b981;stroke:hsl(160.1183431953, 44.07960199%, 29.4117647059%);stroke-width:1px;}#mermaid-svg-WUNXd9afHSUBObQp .cluster text{fill:#ef467e;}#mermaid-svg-WUNXd9afHSUBObQp .cluster span{color:#ef467e;}#mermaid-svg-WUNXd9afHSUBObQp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:#10b981;border:1px solid hsl(160.1183431953, 44.07960199%, 29.4117647059%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-WUNXd9afHSUBObQp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#fff;}#mermaid-svg-WUNXd9afHSUBObQp rect.text{fill:none;stroke-width:0;}#mermaid-svg-WUNXd9afHSUBObQp .icon-shape,#mermaid-svg-WUNXd9afHSUBObQp .image-shape{background-color:#f59e0b;text-align:center;}#mermaid-svg-WUNXd9afHSUBObQp .icon-shape p,#mermaid-svg-WUNXd9afHSUBObQp .image-shape p{background-color:#f59e0b;padding:2px;}#mermaid-svg-WUNXd9afHSUBObQp .icon-shape .label rect,#mermaid-svg-WUNXd9afHSUBObQp .image-shape .label rect{opacity:0.5;background-color:#f59e0b;fill:#f59e0b;}#mermaid-svg-WUNXd9afHSUBObQp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WUNXd9afHSUBObQp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WUNXd9afHSUBObQp :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-WUNXd9afHSUBObQp .core>*{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-WUNXd9afHSUBObQp .core span{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-WUNXd9afHSUBObQp .core tspan{fill:#fff!important;}#mermaid-svg-WUNXd9afHSUBObQp .tool>*{fill:#10b981!important;stroke:#047857!important;color:#fff!important;}#mermaid-svg-WUNXd9afHSUBObQp .tool span{fill:#10b981!important;stroke:#047857!important;color:#fff!important;}#mermaid-svg-WUNXd9afHSUBObQp .tool tspan{fill:#fff!important;}#mermaid-svg-WUNXd9afHSUBObQp .surface>*{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-WUNXd9afHSUBObQp .surface span{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-WUNXd9afHSUBObQp .surface tspan{fill:#fff!important;}#mermaid-svg-WUNXd9afHSUBObQp .edge>*{fill:#8b5cf6!important;stroke:#6d28d9!important;color:#fff!important;}#mermaid-svg-WUNXd9afHSUBObQp .edge span{fill:#8b5cf6!important;stroke:#6d28d9!important;color:#fff!important;}#mermaid-svg-WUNXd9afHSUBObQp .edge tspan{fill:#fff!important;}#mermaid-svg-WUNXd9afHSUBObQp .state>*{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-WUNXd9afHSUBObQp .state span{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-WUNXd9afHSUBObQp .state tspan{fill:#fff!important;}

    驱动的

    调用的

    扩展于

    落库于

    状态层

    hermes_state*.py15 文件 / 30K LOC会话持久化(SQLite)

    扩展层(厚边缘)

    plugins/241 文件 / 86K LOC22 平台/39 模型 provider/记忆/看板

    skills/13 目录技能包

    providers/ProviderProfile ABC

    cron/scheduler.py 177KB

    界面层(厚边缘)

    cli.py + hermes_cli/478 文件 / 204K LOC

    gateway/151 文件 / 83K LOC消息网关

    tui_gateway/ + ui-tui/

    web/ + hermes_cli/web_server.py

    apps/desktop/ (Electron)

    acp_adapter/ (ACP 协议)

    工具层(窄腰)

    tools/299 文件 / 102K LOC256 个工具文件

    toolsets.py / model_tools.py

    tools/registry.pyToolRegistry 单例

    内核层(窄腰)

    run_agent.pyAIAgent 门面

    agent/279 文件 / 111K LOCturn 循环/压缩/prompt

    hermes-agent 根目录

    顶级目录文件数LOC核心职责代表证据
    agent/ 279 111,118 AIAgent 内核、turn 循环、压缩、prompt 构建 run_agent.py:211、agent/conversation_loop.py:1423
    hermes_cli/ + cli.py 478+1 204,498 CLI 子命令 + 交互 REPL + 配置系统 + 插件运行时 hermes_cli/main.py:3351、cli.py:2530
    tools/ 299 102,568 窄腰工具集:256 个工具文件 + ToolRegistry 单例 tools/registry.py:368、model_tools.py:855
    plugins/ 241 86,639 厚边缘:22 平台适配器 + 39 模型 provider + 记忆/看板/图像 plugins/platforms/、plugins/model-providers/
    gateway/ 151 83,865 消息网关:17 个 run_*.py 生命周期阶段 + 12 内置平台适配器 gateway/run.py、gateway/platforms/base.py:1797
    skills/ 50 11,565 13 目录技能包(创作/研发/邮件/笔记/媒体等) skills/
    cron/ 定时调度器(scheduler.py 177KB) cron/scheduler.py
    根级 *.py 40 30,076 hermes_state_* 15 文件会话持久化 + hermes_constants + trajectory_compressor hermes_state.py、hermes_state_sessions.py
    providers/ 2 781 ProviderProfile ABC(模型 provider 基类) providers/base.py:39

    1.3 构建方式与成熟度

    • 构建:PEP 517 setuptools 后端(pyproject.toml:388);setup.py 主动拦截 bdist_wheel/sdist,仅 Nix 构建(HERMES_NIX_BUILD=1)可产出 wheel,editable 安装走 build_editable 不受影响(setup.py:21-46)。根级单文件模块(run_agent、hermes_state、toolsets 等)从源树动态派生 py_modules(setup.py:71-76)。
    • 成熟度标志:424 行根级 AGENTS.md + 每区域 AGENTS.md 路由表(AGENTS.md:405-419);完整多语言 README(en/es/ur-pk/zh-CN);3869 行临时插件兼容清单(COMPAT_MANIFEST.md,2026-09 拆分 PR #102117 的回退垫片,2026-09-14 移除);严格的反供应链攻击依赖钉版策略;标记化 OS 测试(@pytest.mark.linux_only 等,AGENTS.md:349-373);Windows 实时进程拓扑 E2E lane(AGENTS.md:367-373)。这是一个高度成熟、工程纪律严格的大型项目。

    二、模块划分与职责

    按「内核窄腰 / 工具窄腰 / 界面层 / 扩展层 / 状态层」五大层划分,共 9 个一级模块。

    2.1 模块总览图

    #mermaid-svg-xuti72qc2pK0l1h7{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xuti72qc2pK0l1h7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xuti72qc2pK0l1h7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xuti72qc2pK0l1h7 .error-icon{fill:hsl(30.6293706294, 65.296803653%, 62.0588235294%);}#mermaid-svg-xuti72qc2pK0l1h7 .error-text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);stroke:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-xuti72qc2pK0l1h7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xuti72qc2pK0l1h7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xuti72qc2pK0l1h7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xuti72qc2pK0l1h7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xuti72qc2pK0l1h7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xuti72qc2pK0l1h7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xuti72qc2pK0l1h7 .marker{fill:#6b7280;stroke:#6b7280;}#mermaid-svg-xuti72qc2pK0l1h7 .marker.cross{stroke:#6b7280;}#mermaid-svg-xuti72qc2pK0l1h7 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xuti72qc2pK0l1h7 p{margin:0;}#mermaid-svg-xuti72qc2pK0l1h7 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-xuti72qc2pK0l1h7 .cluster-label text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-xuti72qc2pK0l1h7 .cluster-label span{color:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-xuti72qc2pK0l1h7 .cluster-label span p{background-color:transparent;}#mermaid-svg-xuti72qc2pK0l1h7 .label text,#mermaid-svg-xuti72qc2pK0l1h7 span{fill:#fff;color:#fff;}#mermaid-svg-xuti72qc2pK0l1h7 .node rect,#mermaid-svg-xuti72qc2pK0l1h7 .node circle,#mermaid-svg-xuti72qc2pK0l1h7 .node ellipse,#mermaid-svg-xuti72qc2pK0l1h7 .node polygon,#mermaid-svg-xuti72qc2pK0l1h7 .node path{fill:#4a90d9;stroke:hsl(210.6293706294, 25.296803653%, 47.0588235294%);stroke-width:1px;}#mermaid-svg-xuti72qc2pK0l1h7 .rough-node .label text,#mermaid-svg-xuti72qc2pK0l1h7 .node .label text,#mermaid-svg-xuti72qc2pK0l1h7 .image-shape .label,#mermaid-svg-xuti72qc2pK0l1h7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-xuti72qc2pK0l1h7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xuti72qc2pK0l1h7 .rough-node .label,#mermaid-svg-xuti72qc2pK0l1h7 .node .label,#mermaid-svg-xuti72qc2pK0l1h7 .image-shape .label,#mermaid-svg-xuti72qc2pK0l1h7 .icon-shape .label{text-align:center;}#mermaid-svg-xuti72qc2pK0l1h7 .node.clickable{cursor:pointer;}#mermaid-svg-xuti72qc2pK0l1h7 .root .anchor path{fill:#6b7280!important;stroke-width:0;stroke:#6b7280;}#mermaid-svg-xuti72qc2pK0l1h7 .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-xuti72qc2pK0l1h7 .edgePath .path{stroke:#6b7280;stroke-width:2.0px;}#mermaid-svg-xuti72qc2pK0l1h7 .flowchart-link{stroke:#6b7280;fill:none;}#mermaid-svg-xuti72qc2pK0l1h7 .edgeLabel{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);text-align:center;}#mermaid-svg-xuti72qc2pK0l1h7 .edgeLabel p{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-xuti72qc2pK0l1h7 .edgeLabel rect{opacity:0.5;background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);fill:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-xuti72qc2pK0l1h7 .labelBkg{background-color:rgba(143.9999999999, 217, 73.9999999999, 0.5);}#mermaid-svg-xuti72qc2pK0l1h7 .cluster rect{fill:hsl(30.6293706294, 65.296803653%, 62.0588235294%);stroke:hsl(30.6293706294, 25.296803653%, 52.0588235294%);stroke-width:1px;}#mermaid-svg-xuti72qc2pK0l1h7 .cluster text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-xuti72qc2pK0l1h7 .cluster span{color:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-xuti72qc2pK0l1h7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(30.6293706294, 65.296803653%, 62.0588235294%);border:1px solid hsl(30.6293706294, 25.296803653%, 52.0588235294%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xuti72qc2pK0l1h7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#fff;}#mermaid-svg-xuti72qc2pK0l1h7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-xuti72qc2pK0l1h7 .icon-shape,#mermaid-svg-xuti72qc2pK0l1h7 .image-shape{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);text-align:center;}#mermaid-svg-xuti72qc2pK0l1h7 .icon-shape p,#mermaid-svg-xuti72qc2pK0l1h7 .image-shape p{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);padding:2px;}#mermaid-svg-xuti72qc2pK0l1h7 .icon-shape .label rect,#mermaid-svg-xuti72qc2pK0l1h7 .image-shape .label rect{opacity:0.5;background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);fill:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-xuti72qc2pK0l1h7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xuti72qc2pK0l1h7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xuti72qc2pK0l1h7 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-xuti72qc2pK0l1h7 .l1>*{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-xuti72qc2pK0l1h7 .l1 span{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-xuti72qc2pK0l1h7 .l1 tspan{fill:#fff!important;}#mermaid-svg-xuti72qc2pK0l1h7 .l2>*{fill:#10b981!important;stroke:#047857!important;color:#fff!important;}#mermaid-svg-xuti72qc2pK0l1h7 .l2 span{fill:#10b981!important;stroke:#047857!important;color:#fff!important;}#mermaid-svg-xuti72qc2pK0l1h7 .l2 tspan{fill:#fff!important;}#mermaid-svg-xuti72qc2pK0l1h7 .l3>*{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-xuti72qc2pK0l1h7 .l3 span{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-xuti72qc2pK0l1h7 .l3 tspan{fill:#fff!important;}#mermaid-svg-xuti72qc2pK0l1h7 .l4>*{fill:#8b5cf6!important;stroke:#6d28d9!important;color:#fff!important;}#mermaid-svg-xuti72qc2pK0l1h7 .l4 span{fill:#8b5cf6!important;stroke:#6d28d9!important;color:#fff!important;}#mermaid-svg-xuti72qc2pK0l1h7 .l4 tspan{fill:#fff!important;}#mermaid-svg-xuti72qc2pK0l1h7 .l5>*{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-xuti72qc2pK0l1h7 .l5 span{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-xuti72qc2pK0l1h7 .l5 tspan{fill:#fff!important;}

    ⑤ 状态层

    ④ 扩展层(厚边缘)

    ③ 界面层

    ② 工具窄腰 — ToolRegistry

    ① 内核窄腰 — AIAgent

    构造 AIAgent

    调用 run_conversation

    tool_call

    挂载于

    挂载于

    挂载于

    AIAgent 门面14 Mixin

    init_agent 初始化链~30 有序阶段

    turn 状态机11 阶段 + 29 turn_*.py

    压缩子系统3 文件 788KB

    辅助客户端auxiliary_client 379KB

    ToolRegistry 单例import 时自注册

    toolsets 分组~30 命名组

    model_tools 每调用组装+ dispatch

    256 工具文件14 类别

    hermes_cli 子命令argparse func= 派发

    cli.py REPLHermesCLI 14 mixin

    gateway 消息网关17 生命周期阶段

    TUI / Web / Desktop / ACP

    plugins/ 22 平台适配器+ 39 模型 provider

    plugins/ 记忆/看板/图像ABC + orchestrator

    skills/ 13 技能包

    providers/ ProviderProfile

    hermes_state_* 15 文件SQLite 会话持久化

    2.2 模块①:内核窄腰 —— AIAgent(run_agent.py + agent/)

    核心作用:实现同步、带工具调用的 turn 循环——接收用户消息,组装 API 请求(system prompt + 历史 + 工具 schema),调用 LLM,若有 tool_calls 则执行工具并回灌结果继续迭代,否则返回最终响应。它是所有五种界面共享的唯一内核。

    关键类/函数:

    符号位置职责
    AIAgent run_agent.py:211-215 门面类,14 个 Mixin 组合;__init__(:233-272)是 ~60 参数的转发器,转发到 init_agent
    init_agent agent/agent_init.py:2172 真正的初始化器,~30 步有序编排(_install_safe_stdio :2221 → _build_client :2278 → _load_tools :2280 → _init_session_state :2281 → … → _snapshot_primary_runtime :2307);文档明言「phase ORDER is load-bearing」(agent_init.py:1-8)
    run_conversation agent/conversation_loop.py:1573 公开入口,转发到 _run_conversation_turn
    _run_conversation_turn agent/conversation_loop.py:1423 turn 状态机主体(详见 §2.2.2)
    _LoopState agent/conversation_loop.py:1276 贯穿各阶段的 turn 局部状态 dataclass(~60 字段)
    _run_phase agent/conversation_loop.py:1370 阶段调度器:按函数签名注入 state 字段、回写 verdict 字段
    ContextCompressor agent/context_compressor.py:1678 上下文压缩引擎(god-class,组合 3 个 Mixin)
    _resolve_auto_route agent/auxiliary_client.py:4278 辅助侧 LLM(curator/vision/embed/title/压缩)路由解析
    build_api_kwargs agent/chat_completion_helpers.py:1362 API kwargs 构建
    interruptible_api_call agent/chat_completion_helpers.py:1145 可中断的 API 调用 + 流解析
    CredentialPool agent/credential_pool.py:922 轮转凭据池(耗尽/TTL)
    build_context_files_prompt agent/prompt_builder.py:1581 上下文文件/技能/记忆提示构建
    execute_tool_calls_concurrent agent/tool_executor.py:1404 并发工具执行
    2.2.1 AIAgent 的 14 个 Mixin

    #mermaid-svg-OfSkBUvfiziWLQzk{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-OfSkBUvfiziWLQzk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-OfSkBUvfiziWLQzk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-OfSkBUvfiziWLQzk .error-icon{fill:hsl(30.6293706294, 65.296803653%, 62.0588235294%);}#mermaid-svg-OfSkBUvfiziWLQzk .error-text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);stroke:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-OfSkBUvfiziWLQzk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-OfSkBUvfiziWLQzk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-OfSkBUvfiziWLQzk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-OfSkBUvfiziWLQzk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-OfSkBUvfiziWLQzk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-OfSkBUvfiziWLQzk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-OfSkBUvfiziWLQzk .marker{fill:#374151;stroke:#374151;}#mermaid-svg-OfSkBUvfiziWLQzk .marker.cross{stroke:#374151;}#mermaid-svg-OfSkBUvfiziWLQzk svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-OfSkBUvfiziWLQzk p{margin:0;}#mermaid-svg-OfSkBUvfiziWLQzk .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-OfSkBUvfiziWLQzk .cluster-label text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-OfSkBUvfiziWLQzk .cluster-label span{color:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-OfSkBUvfiziWLQzk .cluster-label span p{background-color:transparent;}#mermaid-svg-OfSkBUvfiziWLQzk .label text,#mermaid-svg-OfSkBUvfiziWLQzk span{fill:#fff;color:#fff;}#mermaid-svg-OfSkBUvfiziWLQzk .node rect,#mermaid-svg-OfSkBUvfiziWLQzk .node circle,#mermaid-svg-OfSkBUvfiziWLQzk .node ellipse,#mermaid-svg-OfSkBUvfiziWLQzk .node polygon,#mermaid-svg-OfSkBUvfiziWLQzk .node path{fill:#4a90d9;stroke:hsl(210.6293706294, 25.296803653%, 47.0588235294%);stroke-width:1px;}#mermaid-svg-OfSkBUvfiziWLQzk .rough-node .label text,#mermaid-svg-OfSkBUvfiziWLQzk .node .label text,#mermaid-svg-OfSkBUvfiziWLQzk .image-shape .label,#mermaid-svg-OfSkBUvfiziWLQzk .icon-shape .label{text-anchor:middle;}#mermaid-svg-OfSkBUvfiziWLQzk .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-OfSkBUvfiziWLQzk .rough-node .label,#mermaid-svg-OfSkBUvfiziWLQzk .node .label,#mermaid-svg-OfSkBUvfiziWLQzk .image-shape .label,#mermaid-svg-OfSkBUvfiziWLQzk .icon-shape .label{text-align:center;}#mermaid-svg-OfSkBUvfiziWLQzk .node.clickable{cursor:pointer;}#mermaid-svg-OfSkBUvfiziWLQzk .root .anchor path{fill:#374151!important;stroke-width:0;stroke:#374151;}#mermaid-svg-OfSkBUvfiziWLQzk .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-OfSkBUvfiziWLQzk .edgePath .path{stroke:#374151;stroke-width:2.0px;}#mermaid-svg-OfSkBUvfiziWLQzk .flowchart-link{stroke:#374151;fill:none;}#mermaid-svg-OfSkBUvfiziWLQzk .edgeLabel{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);text-align:center;}#mermaid-svg-OfSkBUvfiziWLQzk .edgeLabel p{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-OfSkBUvfiziWLQzk .edgeLabel rect{opacity:0.5;background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);fill:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-OfSkBUvfiziWLQzk .labelBkg{background-color:rgba(143.9999999999, 217, 73.9999999999, 0.5);}#mermaid-svg-OfSkBUvfiziWLQzk .cluster rect{fill:hsl(30.6293706294, 65.296803653%, 62.0588235294%);stroke:hsl(30.6293706294, 25.296803653%, 52.0588235294%);stroke-width:1px;}#mermaid-svg-OfSkBUvfiziWLQzk .cluster text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-OfSkBUvfiziWLQzk .cluster span{color:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-OfSkBUvfiziWLQzk div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(30.6293706294, 65.296803653%, 62.0588235294%);border:1px solid hsl(30.6293706294, 25.296803653%, 52.0588235294%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-OfSkBUvfiziWLQzk .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#fff;}#mermaid-svg-OfSkBUvfiziWLQzk rect.text{fill:none;stroke-width:0;}#mermaid-svg-OfSkBUvfiziWLQzk .icon-shape,#mermaid-svg-OfSkBUvfiziWLQzk .image-shape{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);text-align:center;}#mermaid-svg-OfSkBUvfiziWLQzk .icon-shape p,#mermaid-svg-OfSkBUvfiziWLQzk .image-shape p{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);padding:2px;}#mermaid-svg-OfSkBUvfiziWLQzk .icon-shape .label rect,#mermaid-svg-OfSkBUvfiziWLQzk .image-shape .label rect{opacity:0.5;background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);fill:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-OfSkBUvfiziWLQzk .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-OfSkBUvfiziWLQzk .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-OfSkBUvfiziWLQzk :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-OfSkBUvfiziWLQzk .base>*{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-OfSkBUvfiziWLQzk .base span{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-OfSkBUvfiziWLQzk .base tspan{fill:#fff!important;}#mermaid-svg-OfSkBUvfiziWLQzk .mixin>*{fill:#60a5fa!important;stroke:#2563eb!important;color:#fff!important;}#mermaid-svg-OfSkBUvfiziWLQzk .mixin span{fill:#60a5fa!important;stroke:#2563eb!important;color:#fff!important;}#mermaid-svg-OfSkBUvfiziWLQzk .mixin tspan{fill:#fff!important;}

    AIAgentrun_agent.py:211

    ClientLifecycleMixinclient_lifecycle.py:106API client 构建/刷新

    StreamDeliveryMixinstream_delivery.py:19流式 delta 下发

    StatusOutputMixinstatus_output.py:16状态行/通知渲染

    ApiRequestHooksMixinapi_request_hooks.py:32API 请求前后置钩子

    ApiErrorSummaryMixinapi_error_summary.py:47错误摘要

    InterruptControlMixininterrupt_control.py:90中断标志检查/中断

    TurnExplainersMixinturn_explainers.py:209轮级用户解释

    ActivityTrackingMixinactivity_tracking.py:28活动溯源

    RateLimitCreditsMixinrate_limit_credits.py:32限流/额度

    SessionPersistenceMixinsession_persistence.py:273SessionDB 追加/恢复

    CompressionFacadeMixincompression_facade.py:186压缩子系统门面

    TurnFacadeMixinturn_facade.py:19run_conversation 租约+转发

    VisionMessagePrepMixinvision_message_prep.py:60视觉/图像消息准备

    ReasoningParamsMixinreasoning_params.py:47reasoning_effort/echo 配置

    2.2.2 Turn 状态机(11 阶段)

    主循环 while (api_call_count < max_iterations and iteration_budget.remaining > 0) or _budget_grace_call(conversation_loop.py:1514),每轮迭代按下序执行阶段,每阶段是 turn_*.py 中的独立兄弟函数(共 29 个 turn_*.py 文件):

    #mermaid-svg-TaZNmYVwBLF0d4EX{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TaZNmYVwBLF0d4EX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TaZNmYVwBLF0d4EX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TaZNmYVwBLF0d4EX .error-icon{fill:hsl(30.6293706294, 65.296803653%, 62.0588235294%);}#mermaid-svg-TaZNmYVwBLF0d4EX .error-text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);stroke:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-TaZNmYVwBLF0d4EX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TaZNmYVwBLF0d4EX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TaZNmYVwBLF0d4EX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TaZNmYVwBLF0d4EX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TaZNmYVwBLF0d4EX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TaZNmYVwBLF0d4EX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TaZNmYVwBLF0d4EX .marker{fill:#374151;stroke:#374151;}#mermaid-svg-TaZNmYVwBLF0d4EX .marker.cross{stroke:#374151;}#mermaid-svg-TaZNmYVwBLF0d4EX svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TaZNmYVwBLF0d4EX p{margin:0;}#mermaid-svg-TaZNmYVwBLF0d4EX .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-TaZNmYVwBLF0d4EX .cluster-label text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-TaZNmYVwBLF0d4EX .cluster-label span{color:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-TaZNmYVwBLF0d4EX .cluster-label span p{background-color:transparent;}#mermaid-svg-TaZNmYVwBLF0d4EX .label text,#mermaid-svg-TaZNmYVwBLF0d4EX span{fill:#fff;color:#fff;}#mermaid-svg-TaZNmYVwBLF0d4EX .node rect,#mermaid-svg-TaZNmYVwBLF0d4EX .node circle,#mermaid-svg-TaZNmYVwBLF0d4EX .node ellipse,#mermaid-svg-TaZNmYVwBLF0d4EX .node polygon,#mermaid-svg-TaZNmYVwBLF0d4EX .node path{fill:#4a90d9;stroke:hsl(210.6293706294, 25.296803653%, 47.0588235294%);stroke-width:1px;}#mermaid-svg-TaZNmYVwBLF0d4EX .rough-node .label text,#mermaid-svg-TaZNmYVwBLF0d4EX .node .label text,#mermaid-svg-TaZNmYVwBLF0d4EX .image-shape .label,#mermaid-svg-TaZNmYVwBLF0d4EX .icon-shape .label{text-anchor:middle;}#mermaid-svg-TaZNmYVwBLF0d4EX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-TaZNmYVwBLF0d4EX .rough-node .label,#mermaid-svg-TaZNmYVwBLF0d4EX .node .label,#mermaid-svg-TaZNmYVwBLF0d4EX .image-shape .label,#mermaid-svg-TaZNmYVwBLF0d4EX .icon-shape .label{text-align:center;}#mermaid-svg-TaZNmYVwBLF0d4EX .node.clickable{cursor:pointer;}#mermaid-svg-TaZNmYVwBLF0d4EX .root .anchor path{fill:#374151!important;stroke-width:0;stroke:#374151;}#mermaid-svg-TaZNmYVwBLF0d4EX .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-TaZNmYVwBLF0d4EX .edgePath .path{stroke:#374151;stroke-width:2.0px;}#mermaid-svg-TaZNmYVwBLF0d4EX .flowchart-link{stroke:#374151;fill:none;}#mermaid-svg-TaZNmYVwBLF0d4EX .edgeLabel{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);text-align:center;}#mermaid-svg-TaZNmYVwBLF0d4EX .edgeLabel p{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-TaZNmYVwBLF0d4EX .edgeLabel rect{opacity:0.5;background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);fill:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-TaZNmYVwBLF0d4EX .labelBkg{background-color:rgba(143.9999999999, 217, 73.9999999999, 0.5);}#mermaid-svg-TaZNmYVwBLF0d4EX .cluster rect{fill:hsl(30.6293706294, 65.296803653%, 62.0588235294%);stroke:hsl(30.6293706294, 25.296803653%, 52.0588235294%);stroke-width:1px;}#mermaid-svg-TaZNmYVwBLF0d4EX .cluster text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-TaZNmYVwBLF0d4EX .cluster span{color:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-TaZNmYVwBLF0d4EX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(30.6293706294, 65.296803653%, 62.0588235294%);border:1px solid hsl(30.6293706294, 25.296803653%, 52.0588235294%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-TaZNmYVwBLF0d4EX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#fff;}#mermaid-svg-TaZNmYVwBLF0d4EX rect.text{fill:none;stroke-width:0;}#mermaid-svg-TaZNmYVwBLF0d4EX .icon-shape,#mermaid-svg-TaZNmYVwBLF0d4EX .image-shape{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);text-align:center;}#mermaid-svg-TaZNmYVwBLF0d4EX .icon-shape p,#mermaid-svg-TaZNmYVwBLF0d4EX .image-shape p{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);padding:2px;}#mermaid-svg-TaZNmYVwBLF0d4EX .icon-shape .label rect,#mermaid-svg-TaZNmYVwBLF0d4EX .image-shape .label rect{opacity:0.5;background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);fill:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-TaZNmYVwBLF0d4EX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-TaZNmYVwBLF0d4EX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-TaZNmYVwBLF0d4EX :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-TaZNmYVwBLF0d4EX .phase>*{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-TaZNmYVwBLF0d4EX .phase span{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-TaZNmYVwBLF0d4EX .phase tspan{fill:#fff!important;}#mermaid-svg-TaZNmYVwBLF0d4EX .sub>*{fill:#60a5fa!important;stroke:#2563eb!important;color:#fff!important;}#mermaid-svg-TaZNmYVwBLF0d4EX .sub span{fill:#60a5fa!important;stroke:#2563eb!important;color:#fff!important;}#mermaid-svg-TaZNmYVwBLF0d4EX .sub tspan{fill:#fff!important;}#mermaid-svg-TaZNmYVwBLF0d4EX .decision>*{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-TaZNmYVwBLF0d4EX .decision span{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-TaZNmYVwBLF0d4EX .decision tspan{fill:#fff!important;}#mermaid-svg-TaZNmYVwBLF0d4EX .term>*{fill:#10b981!important;stroke:#047857!important;color:#fff!important;}#mermaid-svg-TaZNmYVwBLF0d4EX .term span{fill:#10b981!important;stroke:#047857!important;color:#fff!important;}#mermaid-svg-TaZNmYVwBLF0d4EX .term tspan{fill:#fff!important;}

    异常

    异常

    有工具调用

    无工具调用

    继续迭代

    结束

    用户消息进入run_conversation:1573

    _run_conversation_turn:1423build_turn_context → _LoopState:1276

    while api_call_count < max_iterand budget.remaining > 0:1514

    ① begin_iterationturn_iteration_prep.py:300:1515

    ② prepare_iterationturn_iteration_prep.py:95:1517

    ③ assemble_api_requestturn_request_assembly.py:106:1518

    ④ run_preflight_gateturn_preflight_gate.py:20:1519

    ⑤ announce_api_callturn_iteration_prep.py:255:1526

    _run_api_retry_loop:1391内含 6 子阶段

    nous_rate_limit_guard:1397

    build_api_request:1403

    perform_api_call:1404

    check_api_response:1406

    handle_api_interrupt:1412

    handle_api_error:1415

    ⑥ apply_retry_restartsturn_iteration_prep.py:384:1536

    ⑦ normalize_model_responseturn_response_intake.py:115:1543

    assistant_message.tool_calls?:1549

    ⑧ run_tool_roundturn_tool_round.py:45:1548

    ⑧ finish_text_responseturn_final_response.py:46:1549

    ⑨ handle_outer_loop_errorturn_loop_errors.py:34:1558 (仅异常)

    finish_reason / budget?

    ⑩ finalize_turnturn_finalizer.py:435:1562

    返回 result dict

    2.2.3 消息流不变量(每处改动须据此评审)
    不变量证据含义
    Prompt 缓存不可破坏 agent/AGENTS.md:55-56 永不中途改历史/换工具集/重载记忆/重建 system prompt
    System prompt 全程 byte-stable agent/AGENTS.md:57 唯一上下文变更 = 压缩
    中途注入走 user/tool 消息 agent/AGENTS.md:58-60 skill slash 注入为 user 消息;子目录 hints 追加到 tool 结果
    严格角色轮替 agent/AGENTS.md:61-65 永不连续两同角色;/steer 是 tool 结果后的独立 user 行
    上下文文件仅启动时从 CWD 加载 agent/AGENTS.md:66-69 带 cap;安装树 AGENTS.md 永不作为项目上下文
    压缩双阈值 agent/AGENTS.md:76-77 gateway session 卫生 85%;agent ContextCompressor 50%(可配,per-model 覆盖,溢出后冷却)
    压缩算法 agent/AGENTS.md:78-80 先剪旧 tool 结果(无 LLM 调用)→ 选边界 → 辅助模型生成结构化摘要;原地压缩保持稳定 session id
    2.2.4 模块①架构图

    #mermaid-svg-AtVxcEW5ejMwSpu2{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-AtVxcEW5ejMwSpu2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-AtVxcEW5ejMwSpu2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-AtVxcEW5ejMwSpu2 .error-icon{fill:hsl(30.6293706294, 65.296803653%, 62.0588235294%);}#mermaid-svg-AtVxcEW5ejMwSpu2 .error-text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);stroke:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-AtVxcEW5ejMwSpu2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-AtVxcEW5ejMwSpu2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-AtVxcEW5ejMwSpu2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-AtVxcEW5ejMwSpu2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-AtVxcEW5ejMwSpu2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-AtVxcEW5ejMwSpu2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-AtVxcEW5ejMwSpu2 .marker{fill:#6b7280;stroke:#6b7280;}#mermaid-svg-AtVxcEW5ejMwSpu2 .marker.cross{stroke:#6b7280;}#mermaid-svg-AtVxcEW5ejMwSpu2 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-AtVxcEW5ejMwSpu2 p{margin:0;}#mermaid-svg-AtVxcEW5ejMwSpu2 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-AtVxcEW5ejMwSpu2 .cluster-label text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-AtVxcEW5ejMwSpu2 .cluster-label span{color:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-AtVxcEW5ejMwSpu2 .cluster-label span p{background-color:transparent;}#mermaid-svg-AtVxcEW5ejMwSpu2 .label text,#mermaid-svg-AtVxcEW5ejMwSpu2 span{fill:#fff;color:#fff;}#mermaid-svg-AtVxcEW5ejMwSpu2 .node rect,#mermaid-svg-AtVxcEW5ejMwSpu2 .node circle,#mermaid-svg-AtVxcEW5ejMwSpu2 .node ellipse,#mermaid-svg-AtVxcEW5ejMwSpu2 .node polygon,#mermaid-svg-AtVxcEW5ejMwSpu2 .node path{fill:#4a90d9;stroke:hsl(210.6293706294, 25.296803653%, 47.0588235294%);stroke-width:1px;}#mermaid-svg-AtVxcEW5ejMwSpu2 .rough-node .label text,#mermaid-svg-AtVxcEW5ejMwSpu2 .node .label text,#mermaid-svg-AtVxcEW5ejMwSpu2 .image-shape .label,#mermaid-svg-AtVxcEW5ejMwSpu2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-AtVxcEW5ejMwSpu2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-AtVxcEW5ejMwSpu2 .rough-node .label,#mermaid-svg-AtVxcEW5ejMwSpu2 .node .label,#mermaid-svg-AtVxcEW5ejMwSpu2 .image-shape .label,#mermaid-svg-AtVxcEW5ejMwSpu2 .icon-shape .label{text-align:center;}#mermaid-svg-AtVxcEW5ejMwSpu2 .node.clickable{cursor:pointer;}#mermaid-svg-AtVxcEW5ejMwSpu2 .root .anchor path{fill:#6b7280!important;stroke-width:0;stroke:#6b7280;}#mermaid-svg-AtVxcEW5ejMwSpu2 .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-AtVxcEW5ejMwSpu2 .edgePath .path{stroke:#6b7280;stroke-width:2.0px;}#mermaid-svg-AtVxcEW5ejMwSpu2 .flowchart-link{stroke:#6b7280;fill:none;}#mermaid-svg-AtVxcEW5ejMwSpu2 .edgeLabel{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);text-align:center;}#mermaid-svg-AtVxcEW5ejMwSpu2 .edgeLabel p{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-AtVxcEW5ejMwSpu2 .edgeLabel rect{opacity:0.5;background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);fill:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-AtVxcEW5ejMwSpu2 .labelBkg{background-color:rgba(143.9999999999, 217, 73.9999999999, 0.5);}#mermaid-svg-AtVxcEW5ejMwSpu2 .cluster rect{fill:hsl(30.6293706294, 65.296803653%, 62.0588235294%);stroke:hsl(30.6293706294, 25.296803653%, 52.0588235294%);stroke-width:1px;}#mermaid-svg-AtVxcEW5ejMwSpu2 .cluster text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-AtVxcEW5ejMwSpu2 .cluster span{color:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-AtVxcEW5ejMwSpu2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(30.6293706294, 65.296803653%, 62.0588235294%);border:1px solid hsl(30.6293706294, 25.296803653%, 52.0588235294%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-AtVxcEW5ejMwSpu2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#fff;}#mermaid-svg-AtVxcEW5ejMwSpu2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-AtVxcEW5ejMwSpu2 .icon-shape,#mermaid-svg-AtVxcEW5ejMwSpu2 .image-shape{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);text-align:center;}#mermaid-svg-AtVxcEW5ejMwSpu2 .icon-shape p,#mermaid-svg-AtVxcEW5ejMwSpu2 .image-shape p{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);padding:2px;}#mermaid-svg-AtVxcEW5ejMwSpu2 .icon-shape .label rect,#mermaid-svg-AtVxcEW5ejMwSpu2 .image-shape .label rect{opacity:0.5;background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);fill:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-AtVxcEW5ejMwSpu2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-AtVxcEW5ejMwSpu2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-AtVxcEW5ejMwSpu2 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-AtVxcEW5ejMwSpu2 .main>*{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-AtVxcEW5ejMwSpu2 .main span{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-AtVxcEW5ejMwSpu2 .main tspan{fill:#fff!important;}#mermaid-svg-AtVxcEW5ejMwSpu2 .god>*{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-AtVxcEW5ejMwSpu2 .god span{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-AtVxcEW5ejMwSpu2 .god tspan{fill:#fff!important;}#mermaid-svg-AtVxcEW5ejMwSpu2 .support>*{fill:#60a5fa!important;stroke:#2563eb!important;color:#fff!important;}#mermaid-svg-AtVxcEW5ejMwSpu2 .support span{fill:#60a5fa!important;stroke:#2563eb!important;color:#fff!important;}#mermaid-svg-AtVxcEW5ejMwSpu2 .support tspan{fill:#fff!important;}

    agent/ 内核包

    继承

    run_agent.pyAIAgent 门面:211

    agent_init.pyinit_agent:2172 (~30 阶段)

    14 个 Mixinclient_lifecycle/stream_delivery/…

    conversation_loop.pyturn 状态机:1423

    turn_*.py29 个阶段兄弟文件

    tool_executor.py:1404并发工具执行

    chat_completion_helpers.pyAPI kwargs:1362 / 可中断调用:1145

    context_compressor.py:1678277KB god-class

    conversation_compression.py:3558216KB 编排+提交栅栏

    auxiliary_client.py:4278379KB 辅助侧 LLM 路由

    prompt_builder.py:1581上下文/技能/记忆提示

    credential_pool.py:922凭据轮转

    model_metadata.py上下文长度/能力

    agent_runtime_helpers.py轨迹/清洗


    2.3 模块②:工具窄腰 —— ToolRegistry(tools/ + toolsets.py + model_tools.py)

    核心作用:构成 Hermes 的「窄腰」——「每个 model tool 在每次 API 调用都下发」(AGENTS.md:27-29)。一个无依赖的 ToolRegistry 在 import 时收集所有工具的 schema + handler;model_tools.py 触发发现并组装每调用的工具列表;toolsets.py 把工具分组为命名、可按平台开关的集合。能力应在边缘(skill/plugin/MCP)扩展,而非膨胀窄腰(tools/AGENTS.md:3)。

    关键类/函数:

    符号位置职责
    ToolRegistry tools/registry.py:368 单例(docstring「Singleton registry」:369;实例 registry = ToolRegistry() :928);_tools 全局注册 + _scoped_tools 按 HERMES_HOME 的插件覆盖层
    register tools/registry.py:596 注册工具(name/toolset/schema/handler/check_fn/override/scope);跨工具集 shadow 默认拒绝(:618-648);mutation bump _generation(:661)使 get_tool_definitions 失效缓存
    dispatch tools/registry.py:810 派发工具调用到 handler
    get_definitions tools/registry.py:760 取通过 check_fn 过滤的工具 schema
    TOOLSETS toolsets.py:72 ~30 个命名工具集;_HERMES_CORE_TOOLS(:11-40)= 每平台继承的默认集
    get_tool_definitions model_tools.py:212 每调用组装:选名 → registry.get_definitions(check_fn 过滤)→ 动态 schema 重写器 → Tool Search 折叠;按 generation+config mtime+profile scope 做 LRU 缓存
    handle_function_call model_tools.py:855 派发入口:请求中间件 → 前置钩子 → _execute_tool(:804)→ registry.dispatch(:810)→ handler
    INLINE_TOOL_EXECUTORS agent/inline_tool_executors.py:154 agent 循环级工具(todo/memory/session_search/delegate_task)在 dispatch 前拦截
    2.3.1 工具执行路径

    渲染错误: Mermaid 渲染失败: Parse error on line 25:
    …lt string TE–>>Loop: 回灌 tool 消息 → 下
    ———————-^
    Expecting '+', '-', '()', 'ACTOR', got 'loop'

    2.3.2 工具类别(256 文件,14 类别)
    类别代表文件用途
    文件/FS tools/file_tools.py、tools/path_security.py 读/写/patch/搜索
    终端 tools/terminal_tool.py、tools/terminal_tool_backends.py shell + 进程管理,可插拔后端
    浏览器 tools/browser_tool.py、tools/browser_tool_cdp.py、tools/browser_supervisor.py 自动化(cdp/cloud/lightpanda)
    审批/安全 tools/approval.py、tools/approval_floors.py、tools/url_safety.py 安全护栏
    委派 tools/delegate_tool.py:410、tools/async_delegation.py 子代理 spawn/批量/异步
    看板 tools/kanban_tools.py、tools/kanban_tools_schemas.py 多代理协调
    MCP 客户端 tools/mcp_tool_*.py(20+) 外部 MCP server 工具
    技能 tools/skills_tool.py、tools/skills_hub_*.py 技能 CRUD + hub
    消息 tools/send_message_tool.py、tools/discord_tool.py 平台外发(无 agent 可调 send_message,toolsets.py:185-186)
    记忆/todo tools/memory_tool.py、tools/todo_tool.py:280 会话/代理状态(内联派发)
    视觉/媒体 tools/vision_tools.py、tools/image_generation_tool.py、tools/tts_tool_*.py 图像/视频/音频
    Web tools/web_tools.py、tools/x_search_tool.py 搜索 + 抽取
    代码执行 tools/code_execution_tool.py、tools/code_kernel.py 沙箱 Python
    服务连接器 tools/connections_tool.py、tools/homeassistant_tool.py service-gated 集成
    2.3.3 Footprint Ladder(能力扩展阶梯)

    #mermaid-svg-Lu6JNTSYZlF3foiv{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Lu6JNTSYZlF3foiv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Lu6JNTSYZlF3foiv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Lu6JNTSYZlF3foiv .error-icon{fill:hsl(340.1183431953, 84.07960199%, 44.4117647059%);}#mermaid-svg-Lu6JNTSYZlF3foiv .error-text{fill:rgb(46.5298507462, 236.9701492537, 173.8656716418);stroke:rgb(46.5298507462, 236.9701492537, 173.8656716418);}#mermaid-svg-Lu6JNTSYZlF3foiv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Lu6JNTSYZlF3foiv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Lu6JNTSYZlF3foiv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Lu6JNTSYZlF3foiv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Lu6JNTSYZlF3foiv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Lu6JNTSYZlF3foiv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Lu6JNTSYZlF3foiv .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-Lu6JNTSYZlF3foiv .marker.cross{stroke:#0b0b0b;}#mermaid-svg-Lu6JNTSYZlF3foiv svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Lu6JNTSYZlF3foiv p{margin:0;}#mermaid-svg-Lu6JNTSYZlF3foiv .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-Lu6JNTSYZlF3foiv .cluster-label text{fill:rgb(46.5298507462, 236.9701492537, 173.8656716418);}#mermaid-svg-Lu6JNTSYZlF3foiv .cluster-label span{color:rgb(46.5298507462, 236.9701492537, 173.8656716418);}#mermaid-svg-Lu6JNTSYZlF3foiv .cluster-label span p{background-color:transparent;}#mermaid-svg-Lu6JNTSYZlF3foiv .label text,#mermaid-svg-Lu6JNTSYZlF3foiv span{fill:#fff;color:#fff;}#mermaid-svg-Lu6JNTSYZlF3foiv .node rect,#mermaid-svg-Lu6JNTSYZlF3foiv .node circle,#mermaid-svg-Lu6JNTSYZlF3foiv .node ellipse,#mermaid-svg-Lu6JNTSYZlF3foiv .node polygon,#mermaid-svg-Lu6JNTSYZlF3foiv .node path{fill:#10b981;stroke:hsl(160.1183431953, 44.07960199%, 29.4117647059%);stroke-width:1px;}#mermaid-svg-Lu6JNTSYZlF3foiv .rough-node .label text,#mermaid-svg-Lu6JNTSYZlF3foiv .node .label text,#mermaid-svg-Lu6JNTSYZlF3foiv .image-shape .label,#mermaid-svg-Lu6JNTSYZlF3foiv .icon-shape .label{text-anchor:middle;}#mermaid-svg-Lu6JNTSYZlF3foiv .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Lu6JNTSYZlF3foiv .rough-node .label,#mermaid-svg-Lu6JNTSYZlF3foiv .node .label,#mermaid-svg-Lu6JNTSYZlF3foiv .image-shape .label,#mermaid-svg-Lu6JNTSYZlF3foiv .icon-shape .label{text-align:center;}#mermaid-svg-Lu6JNTSYZlF3foiv .node.clickable{cursor:pointer;}#mermaid-svg-Lu6JNTSYZlF3foiv .root .anchor path{fill:#0b0b0b!important;stroke-width:0;stroke:#0b0b0b;}#mermaid-svg-Lu6JNTSYZlF3foiv .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-Lu6JNTSYZlF3foiv .edgePath .path{stroke:#0b0b0b;stroke-width:2.0px;}#mermaid-svg-Lu6JNTSYZlF3foiv .flowchart-link{stroke:#0b0b0b;fill:none;}#mermaid-svg-Lu6JNTSYZlF3foiv .edgeLabel{background-color:hsl(40.1183431953, 84.07960199%, 39.4117647059%);text-align:center;}#mermaid-svg-Lu6JNTSYZlF3foiv .edgeLabel p{background-color:hsl(40.1183431953, 84.07960199%, 39.4117647059%);}#mermaid-svg-Lu6JNTSYZlF3foiv .edgeLabel rect{opacity:0.5;background-color:hsl(40.1183431953, 84.07960199%, 39.4117647059%);fill:hsl(40.1183431953, 84.07960199%, 39.4117647059%);}#mermaid-svg-Lu6JNTSYZlF3foiv .labelBkg{background-color:rgba(185, 129.0000000001, 16.0000000001, 0.5);}#mermaid-svg-Lu6JNTSYZlF3foiv .cluster rect{fill:hsl(340.1183431953, 84.07960199%, 44.4117647059%);stroke:hsl(340.1183431953, 44.07960199%, 34.4117647059%);stroke-width:1px;}#mermaid-svg-Lu6JNTSYZlF3foiv .cluster text{fill:rgb(46.5298507462, 236.9701492537, 173.8656716418);}#mermaid-svg-Lu6JNTSYZlF3foiv .cluster span{color:rgb(46.5298507462, 236.9701492537, 173.8656716418);}#mermaid-svg-Lu6JNTSYZlF3foiv div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(340.1183431953, 84.07960199%, 44.4117647059%);border:1px solid hsl(340.1183431953, 44.07960199%, 34.4117647059%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Lu6JNTSYZlF3foiv .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#fff;}#mermaid-svg-Lu6JNTSYZlF3foiv rect.text{fill:none;stroke-width:0;}#mermaid-svg-Lu6JNTSYZlF3foiv .icon-shape,#mermaid-svg-Lu6JNTSYZlF3foiv .image-shape{background-color:hsl(40.1183431953, 84.07960199%, 39.4117647059%);text-align:center;}#mermaid-svg-Lu6JNTSYZlF3foiv .icon-shape p,#mermaid-svg-Lu6JNTSYZlF3foiv .image-shape p{background-color:hsl(40.1183431953, 84.07960199%, 39.4117647059%);padding:2px;}#mermaid-svg-Lu6JNTSYZlF3foiv .icon-shape .label rect,#mermaid-svg-Lu6JNTSYZlF3foiv .image-shape .label rect{opacity:0.5;background-color:hsl(40.1183431953, 84.07960199%, 39.4117647059%);fill:hsl(40.1183431953, 84.07960199%, 39.4117647059%);}#mermaid-svg-Lu6JNTSYZlF3foiv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Lu6JNTSYZlF3foiv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Lu6JNTSYZlF3foiv :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-Lu6JNTSYZlF3foiv .rung>*{fill:#10b981!important;stroke:#047857!important;color:#fff!important;}#mermaid-svg-Lu6JNTSYZlF3foiv .rung span{fill:#10b981!important;stroke:#047857!important;color:#fff!important;}#mermaid-svg-Lu6JNTSYZlF3foiv .rung tspan{fill:#fff!important;}#mermaid-svg-Lu6JNTSYZlF3foiv .note>*{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-Lu6JNTSYZlF3foiv .note span{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-Lu6JNTSYZlF3foiv .note tspan{fill:#fff!important;}

    ① 扩展现有代码(首选)

    ② CLI 命令 + skill

    ③ service-gated 工具check_fn (TTL 缓存)

    ④ plugin

    ⑤ MCP server (catalog)

    ⑥ 新核心工具(最后手段)

    check_fn 只回答可达性/可选入永不回答 surfacetools/registry.py:300-340

    证据:AGENTS.md:56-58、AGENTS.md:132-148;check_fn TTL 缓存实现 tools/registry.py:300-340(~30s TTL);GUI-only 工具必须放命名工具集按会话折叠(tools/AGENTS.md:47-49);multiplex/浏览器控制经 check_fn_cache_scope() 绕过缓存(tools/registry.py:244-267)。

    2.3.4 模块②架构图

    #mermaid-svg-S3blTaqIxhtcDk3A{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-S3blTaqIxhtcDk3A .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-S3blTaqIxhtcDk3A .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-S3blTaqIxhtcDk3A .error-icon{fill:hsl(340.1183431953, 84.07960199%, 44.4117647059%);}#mermaid-svg-S3blTaqIxhtcDk3A .error-text{fill:rgb(46.5298507462, 236.9701492537, 173.8656716418);stroke:rgb(46.5298507462, 236.9701492537, 173.8656716418);}#mermaid-svg-S3blTaqIxhtcDk3A .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-S3blTaqIxhtcDk3A .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-S3blTaqIxhtcDk3A .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-S3blTaqIxhtcDk3A .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-S3blTaqIxhtcDk3A .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-S3blTaqIxhtcDk3A .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-S3blTaqIxhtcDk3A .marker{fill:#6b7280;stroke:#6b7280;}#mermaid-svg-S3blTaqIxhtcDk3A .marker.cross{stroke:#6b7280;}#mermaid-svg-S3blTaqIxhtcDk3A svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-S3blTaqIxhtcDk3A p{margin:0;}#mermaid-svg-S3blTaqIxhtcDk3A .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-S3blTaqIxhtcDk3A .cluster-label text{fill:rgb(46.5298507462, 236.9701492537, 173.8656716418);}#mermaid-svg-S3blTaqIxhtcDk3A .cluster-label span{color:rgb(46.5298507462, 236.9701492537, 173.8656716418);}#mermaid-svg-S3blTaqIxhtcDk3A .cluster-label span p{background-color:transparent;}#mermaid-svg-S3blTaqIxhtcDk3A .label text,#mermaid-svg-S3blTaqIxhtcDk3A span{fill:#fff;color:#fff;}#mermaid-svg-S3blTaqIxhtcDk3A .node rect,#mermaid-svg-S3blTaqIxhtcDk3A .node circle,#mermaid-svg-S3blTaqIxhtcDk3A .node ellipse,#mermaid-svg-S3blTaqIxhtcDk3A .node polygon,#mermaid-svg-S3blTaqIxhtcDk3A .node path{fill:#10b981;stroke:hsl(160.1183431953, 44.07960199%, 29.4117647059%);stroke-width:1px;}#mermaid-svg-S3blTaqIxhtcDk3A .rough-node .label text,#mermaid-svg-S3blTaqIxhtcDk3A .node .label text,#mermaid-svg-S3blTaqIxhtcDk3A .image-shape .label,#mermaid-svg-S3blTaqIxhtcDk3A .icon-shape .label{text-anchor:middle;}#mermaid-svg-S3blTaqIxhtcDk3A .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-S3blTaqIxhtcDk3A .rough-node .label,#mermaid-svg-S3blTaqIxhtcDk3A .node .label,#mermaid-svg-S3blTaqIxhtcDk3A .image-shape .label,#mermaid-svg-S3blTaqIxhtcDk3A .icon-shape .label{text-align:center;}#mermaid-svg-S3blTaqIxhtcDk3A .node.clickable{cursor:pointer;}#mermaid-svg-S3blTaqIxhtcDk3A .root .anchor path{fill:#6b7280!important;stroke-width:0;stroke:#6b7280;}#mermaid-svg-S3blTaqIxhtcDk3A .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-S3blTaqIxhtcDk3A .edgePath .path{stroke:#6b7280;stroke-width:2.0px;}#mermaid-svg-S3blTaqIxhtcDk3A .flowchart-link{stroke:#6b7280;fill:none;}#mermaid-svg-S3blTaqIxhtcDk3A .edgeLabel{background-color:hsl(40.1183431953, 84.07960199%, 39.4117647059%);text-align:center;}#mermaid-svg-S3blTaqIxhtcDk3A .edgeLabel p{background-color:hsl(40.1183431953, 84.07960199%, 39.4117647059%);}#mermaid-svg-S3blTaqIxhtcDk3A .edgeLabel rect{opacity:0.5;background-color:hsl(40.1183431953, 84.07960199%, 39.4117647059%);fill:hsl(40.1183431953, 84.07960199%, 39.4117647059%);}#mermaid-svg-S3blTaqIxhtcDk3A .labelBkg{background-color:rgba(185, 129.0000000001, 16.0000000001, 0.5);}#mermaid-svg-S3blTaqIxhtcDk3A .cluster rect{fill:hsl(340.1183431953, 84.07960199%, 44.4117647059%);stroke:hsl(340.1183431953, 44.07960199%, 34.4117647059%);stroke-width:1px;}#mermaid-svg-S3blTaqIxhtcDk3A .cluster text{fill:rgb(46.5298507462, 236.9701492537, 173.8656716418);}#mermaid-svg-S3blTaqIxhtcDk3A .cluster span{color:rgb(46.5298507462, 236.9701492537, 173.8656716418);}#mermaid-svg-S3blTaqIxhtcDk3A div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(340.1183431953, 84.07960199%, 44.4117647059%);border:1px solid hsl(340.1183431953, 44.07960199%, 34.4117647059%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-S3blTaqIxhtcDk3A .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#fff;}#mermaid-svg-S3blTaqIxhtcDk3A rect.text{fill:none;stroke-width:0;}#mermaid-svg-S3blTaqIxhtcDk3A .icon-shape,#mermaid-svg-S3blTaqIxhtcDk3A .image-shape{background-color:hsl(40.1183431953, 84.07960199%, 39.4117647059%);text-align:center;}#mermaid-svg-S3blTaqIxhtcDk3A .icon-shape p,#mermaid-svg-S3blTaqIxhtcDk3A .image-shape p{background-color:hsl(40.1183431953, 84.07960199%, 39.4117647059%);padding:2px;}#mermaid-svg-S3blTaqIxhtcDk3A .icon-shape .label rect,#mermaid-svg-S3blTaqIxhtcDk3A .image-shape .label rect{opacity:0.5;background-color:hsl(40.1183431953, 84.07960199%, 39.4117647059%);fill:hsl(40.1183431953, 84.07960199%, 39.4117647059%);}#mermaid-svg-S3blTaqIxhtcDk3A .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-S3blTaqIxhtcDk3A .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-S3blTaqIxhtcDk3A :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-S3blTaqIxhtcDk3A .core>*{fill:#10b981!important;stroke:#047857!important;color:#fff!important;}#mermaid-svg-S3blTaqIxhtcDk3A .core span{fill:#10b981!important;stroke:#047857!important;color:#fff!important;}#mermaid-svg-S3blTaqIxhtcDk3A .core tspan{fill:#fff!important;}#mermaid-svg-S3blTaqIxhtcDk3A .data>*{fill:#34d399!important;stroke:#059669!important;color:#fff!important;}#mermaid-svg-S3blTaqIxhtcDk3A .data span{fill:#34d399!important;stroke:#059669!important;color:#fff!important;}#mermaid-svg-S3blTaqIxhtcDk3A .data tspan{fill:#fff!important;}#mermaid-svg-S3blTaqIxhtcDk3A .support>*{fill:#60a5fa!important;stroke:#2563eb!important;color:#fff!important;}#mermaid-svg-S3blTaqIxhtcDk3A .support span{fill:#60a5fa!important;stroke:#2563eb!important;color:#fff!important;}#mermaid-svg-S3blTaqIxhtcDk3A .support tspan{fill:#fff!important;}

    工具窄腰

    import 时自注册

    ToolRegistry 单例registry.py:368 / 实例:928

    256 工具文件tools/*.py (import 时 registry.register)

    _scoped_tools 插件覆盖层按 HERMES_HOME

    threading.RLock:383

    _generation 计数:661 失效缓存

    toolsets.py:72~30 命名工具集

    _HERMES_CORE_TOOLS:11默认集

    model_tools.pyget_tool_definitions:212handle_function_call:855

    inline_tool_executors.py:154todo/memory/session_search/delegate

    tool_executor.py:1404并发/顺序/分段执行


    2.4 模块③:界面层 —— CLI(cli.py + hermes_cli/)

    核心作用:提供两条入口——hermes <cmd> 子命令调度(hermes_cli/main.py)与交互式 REPL(cli.py 的 HermesCLI),并承载配置系统、插件运行时、模型目录、认证、Web 后端、goals、backup、kanban 持久层等横切设施。

    关键类/函数:

    符号位置职责
    main() hermes_cli/main.py:3351 hermes 可执行入口:进程设置 + 自愈 + 快速路径 + _build_cli_parser(:3194)+ argparse func= 绑定 + args.func(args)
    _forward_command hermes_cli/main.py:1789 惰性转发:调用时才 importlib.import_module,避免快速路径付 import 代价
    HermesCLI cli.py:2530 交互 REPL 主体类,组合 14 个 mixin
    process_command cli.py:3206 slash 命令派发入口
    _SLASH_DISPATCH cli.py:3175 canonical -> (method_name, pass_arg) 显式映射字典
    COMMAND_REGISTRY hermes_cli/commands.py:49 slash 命令单一注册源;resolve_command(:333)解析别名→规范名
    DEFAULT_CONFIG hermes_cli/config_defaults.py:21 配置 schema 单一源(纯数据,无类)
    PluginManager hermes_cli/plugins.py:1117 插件运行时,组合 PluginLoaderMixin/PluginDispatchMixin/PluginLedgerMixin
    gateway_command hermes_cli/gateway.py:5826 名实不符:是 gateway 进程管理(PID/systemd/launchd/重启),非网络网关;6390 行/282 函数 god-file
    2.4.1 CLI 调度流程

    #mermaid-svg-AtKAoDA0aFKAc943{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-AtKAoDA0aFKAc943 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-AtKAoDA0aFKAc943 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-AtKAoDA0aFKAc943 .error-icon{fill:hsl(217.6923076923, 92.125984252%, 55.1960784314%);}#mermaid-svg-AtKAoDA0aFKAc943 .error-text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);stroke:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-AtKAoDA0aFKAc943 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-AtKAoDA0aFKAc943 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-AtKAoDA0aFKAc943 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-AtKAoDA0aFKAc943 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-AtKAoDA0aFKAc943 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-AtKAoDA0aFKAc943 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-AtKAoDA0aFKAc943 .marker{fill:#374151;stroke:#374151;}#mermaid-svg-AtKAoDA0aFKAc943 .marker.cross{stroke:#374151;}#mermaid-svg-AtKAoDA0aFKAc943 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-AtKAoDA0aFKAc943 p{margin:0;}#mermaid-svg-AtKAoDA0aFKAc943 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-AtKAoDA0aFKAc943 .cluster-label text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-AtKAoDA0aFKAc943 .cluster-label span{color:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-AtKAoDA0aFKAc943 .cluster-label span p{background-color:transparent;}#mermaid-svg-AtKAoDA0aFKAc943 .label text,#mermaid-svg-AtKAoDA0aFKAc943 span{fill:#fff;color:#fff;}#mermaid-svg-AtKAoDA0aFKAc943 .node rect,#mermaid-svg-AtKAoDA0aFKAc943 .node circle,#mermaid-svg-AtKAoDA0aFKAc943 .node ellipse,#mermaid-svg-AtKAoDA0aFKAc943 .node polygon,#mermaid-svg-AtKAoDA0aFKAc943 .node path{fill:#f59e0b;stroke:hsl(37.6923076923, 52.125984252%, 40.1960784314%);stroke-width:1px;}#mermaid-svg-AtKAoDA0aFKAc943 .rough-node .label text,#mermaid-svg-AtKAoDA0aFKAc943 .node .label text,#mermaid-svg-AtKAoDA0aFKAc943 .image-shape .label,#mermaid-svg-AtKAoDA0aFKAc943 .icon-shape .label{text-anchor:middle;}#mermaid-svg-AtKAoDA0aFKAc943 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-AtKAoDA0aFKAc943 .rough-node .label,#mermaid-svg-AtKAoDA0aFKAc943 .node .label,#mermaid-svg-AtKAoDA0aFKAc943 .image-shape .label,#mermaid-svg-AtKAoDA0aFKAc943 .icon-shape .label{text-align:center;}#mermaid-svg-AtKAoDA0aFKAc943 .node.clickable{cursor:pointer;}#mermaid-svg-AtKAoDA0aFKAc943 .root .anchor path{fill:#374151!important;stroke-width:0;stroke:#374151;}#mermaid-svg-AtKAoDA0aFKAc943 .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-AtKAoDA0aFKAc943 .edgePath .path{stroke:#374151;stroke-width:2.0px;}#mermaid-svg-AtKAoDA0aFKAc943 .flowchart-link{stroke:#374151;fill:none;}#mermaid-svg-AtKAoDA0aFKAc943 .edgeLabel{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);text-align:center;}#mermaid-svg-AtKAoDA0aFKAc943 .edgeLabel p{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-AtKAoDA0aFKAc943 .edgeLabel rect{opacity:0.5;background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);fill:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-AtKAoDA0aFKAc943 .labelBkg{background-color:rgba(158, 11.0000000001, 245, 0.5);}#mermaid-svg-AtKAoDA0aFKAc943 .cluster rect{fill:hsl(217.6923076923, 92.125984252%, 55.1960784314%);stroke:hsl(217.6923076923, 52.125984252%, 45.1960784314%);stroke-width:1px;}#mermaid-svg-AtKAoDA0aFKAc943 .cluster text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-AtKAoDA0aFKAc943 .cluster span{color:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-AtKAoDA0aFKAc943 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(217.6923076923, 92.125984252%, 55.1960784314%);border:1px solid hsl(217.6923076923, 52.125984252%, 45.1960784314%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-AtKAoDA0aFKAc943 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#fff;}#mermaid-svg-AtKAoDA0aFKAc943 rect.text{fill:none;stroke-width:0;}#mermaid-svg-AtKAoDA0aFKAc943 .icon-shape,#mermaid-svg-AtKAoDA0aFKAc943 .image-shape{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);text-align:center;}#mermaid-svg-AtKAoDA0aFKAc943 .icon-shape p,#mermaid-svg-AtKAoDA0aFKAc943 .image-shape p{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);padding:2px;}#mermaid-svg-AtKAoDA0aFKAc943 .icon-shape .label rect,#mermaid-svg-AtKAoDA0aFKAc943 .image-shape .label rect{opacity:0.5;background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);fill:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-AtKAoDA0aFKAc943 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-AtKAoDA0aFKAc943 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-AtKAoDA0aFKAc943 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-AtKAoDA0aFKAc943 .entry>*{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-AtKAoDA0aFKAc943 .entry span{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-AtKAoDA0aFKAc943 .entry tspan{fill:#fff!important;}#mermaid-svg-AtKAoDA0aFKAc943 .step>*{fill:#fbbf24!important;stroke:#d97706!important;color:#fff!important;}#mermaid-svg-AtKAoDA0aFKAc943 .step span{fill:#fbbf24!important;stroke:#d97706!important;color:#fff!important;}#mermaid-svg-AtKAoDA0aFKAc943 .step tspan{fill:#fff!important;}#mermaid-svg-AtKAoDA0aFKAc943 .decision>*{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-AtKAoDA0aFKAc943 .decision span{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-AtKAoDA0aFKAc943 .decision tspan{fill:#fff!important;}

    Slash 调度 (REPL 内 /cmd)

    命中

    未命中

    未注册

    REPL 输入

    process_commandcli.py:3206

    resolve_commandcommands.py:333COMMAND_REGISTRY:49

    _slash_handlercli.py:3199

    查 _SLASH_DISPATCHcli.py:3175

    调用 mapped method

    命名约定反射_handle__commandcli.py:3201-3204

    handler()

    _process_unregistered_slashcli.py:3254quick→plugins→bundles→skills→prefix

    子命令调度 (hermes )

    hermes 可执行

    main()main.py:3351

    早期自愈venv 恢复/字节码清理main.py:3371-3395

    快速路径termux/serve/chatmain.py:3418-3424

    _build_cli_parsermain.py:3194

    set_defaults func=cmd_xxxmain.py:2938/3204

    args.func(args)

    直接定义cmd_chat:1684cmd_gateway:1770cmd_model:1833

    惰性转发 _forward_commandmain.py:1789cmd_setup/login/doctor/plugins/kanban

    铁律:无 elif 阶梯(hermes_cli/AGENTS.md:14)。

    2.4.2 HermesCLI 的 14 个 Mixin
    Mixin定义位置职责
    CLIProcessNotificationsMixin cli_process_notifications.py:4 进程通知
    CLIAgentSetupMixin cli_agent_setup_mixin.py:174 agent 启动准备
    CLICommandsMixin cli_commands_mixin.py:607 slash 处理器主库(56 个 _handle_/_cmd_/_show_)
    CLIBillingMixin cli_billing_mixin.py:70 计费/订阅展示
    CLITuiMixin cli_tui_mixin.py:94 prompt_toolkit TUI/键绑定/覆盖层
    CLIStatusBarMixin cli_status_bar_mixin.py:41 状态栏渲染
    CLIVoiceMixin cli_voice_mixin.py:54 语音输入/STT
    CLIModelSwitchMixin cli_model_switch_mixin.py:233 模型/provider 切换
    CLISessionMixin cli_session_mixin.py:135 会话管理
    CLIStreamMixin cli_stream_mixin.py:45 流式输出渲染
    CLIModalMixin cli_modal_mixin.py:80 模态确认面板
    CLITerminalMixin cli_terminal_mixin.py:50 终端能力/尺寸
    CLIInfoMixin cli_info_mixin.py:73 /tools//whoami 等信息展示
    CLILoopsMixin cli_loops_mixin.py:30 REPL 循环骨架
    2.4.3 配置系统(三套加载器)

    #mermaid-svg-SpanioQpQz6cR1b5{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-SpanioQpQz6cR1b5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-SpanioQpQz6cR1b5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-SpanioQpQz6cR1b5 .error-icon{fill:hsl(217.6923076923, 92.125984252%, 55.1960784314%);}#mermaid-svg-SpanioQpQz6cR1b5 .error-text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);stroke:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-SpanioQpQz6cR1b5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-SpanioQpQz6cR1b5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-SpanioQpQz6cR1b5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-SpanioQpQz6cR1b5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-SpanioQpQz6cR1b5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-SpanioQpQz6cR1b5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-SpanioQpQz6cR1b5 .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-SpanioQpQz6cR1b5 .marker.cross{stroke:#0b0b0b;}#mermaid-svg-SpanioQpQz6cR1b5 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-SpanioQpQz6cR1b5 p{margin:0;}#mermaid-svg-SpanioQpQz6cR1b5 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-SpanioQpQz6cR1b5 .cluster-label text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-SpanioQpQz6cR1b5 .cluster-label span{color:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-SpanioQpQz6cR1b5 .cluster-label span p{background-color:transparent;}#mermaid-svg-SpanioQpQz6cR1b5 .label text,#mermaid-svg-SpanioQpQz6cR1b5 span{fill:#fff;color:#fff;}#mermaid-svg-SpanioQpQz6cR1b5 .node rect,#mermaid-svg-SpanioQpQz6cR1b5 .node circle,#mermaid-svg-SpanioQpQz6cR1b5 .node ellipse,#mermaid-svg-SpanioQpQz6cR1b5 .node polygon,#mermaid-svg-SpanioQpQz6cR1b5 .node path{fill:#f59e0b;stroke:hsl(37.6923076923, 52.125984252%, 40.1960784314%);stroke-width:1px;}#mermaid-svg-SpanioQpQz6cR1b5 .rough-node .label text,#mermaid-svg-SpanioQpQz6cR1b5 .node .label text,#mermaid-svg-SpanioQpQz6cR1b5 .image-shape .label,#mermaid-svg-SpanioQpQz6cR1b5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-SpanioQpQz6cR1b5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-SpanioQpQz6cR1b5 .rough-node .label,#mermaid-svg-SpanioQpQz6cR1b5 .node .label,#mermaid-svg-SpanioQpQz6cR1b5 .image-shape .label,#mermaid-svg-SpanioQpQz6cR1b5 .icon-shape .label{text-align:center;}#mermaid-svg-SpanioQpQz6cR1b5 .node.clickable{cursor:pointer;}#mermaid-svg-SpanioQpQz6cR1b5 .root .anchor path{fill:#0b0b0b!important;stroke-width:0;stroke:#0b0b0b;}#mermaid-svg-SpanioQpQz6cR1b5 .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-SpanioQpQz6cR1b5 .edgePath .path{stroke:#0b0b0b;stroke-width:2.0px;}#mermaid-svg-SpanioQpQz6cR1b5 .flowchart-link{stroke:#0b0b0b;fill:none;}#mermaid-svg-SpanioQpQz6cR1b5 .edgeLabel{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);text-align:center;}#mermaid-svg-SpanioQpQz6cR1b5 .edgeLabel p{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-SpanioQpQz6cR1b5 .edgeLabel rect{opacity:0.5;background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);fill:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-SpanioQpQz6cR1b5 .labelBkg{background-color:rgba(158, 11.0000000001, 245, 0.5);}#mermaid-svg-SpanioQpQz6cR1b5 .cluster rect{fill:hsl(217.6923076923, 92.125984252%, 55.1960784314%);stroke:hsl(217.6923076923, 52.125984252%, 45.1960784314%);stroke-width:1px;}#mermaid-svg-SpanioQpQz6cR1b5 .cluster text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-SpanioQpQz6cR1b5 .cluster span{color:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-SpanioQpQz6cR1b5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(217.6923076923, 92.125984252%, 55.1960784314%);border:1px solid hsl(217.6923076923, 52.125984252%, 45.1960784314%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-SpanioQpQz6cR1b5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#fff;}#mermaid-svg-SpanioQpQz6cR1b5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-SpanioQpQz6cR1b5 .icon-shape,#mermaid-svg-SpanioQpQz6cR1b5 .image-shape{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);text-align:center;}#mermaid-svg-SpanioQpQz6cR1b5 .icon-shape p,#mermaid-svg-SpanioQpQz6cR1b5 .image-shape p{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);padding:2px;}#mermaid-svg-SpanioQpQz6cR1b5 .icon-shape .label rect,#mermaid-svg-SpanioQpQz6cR1b5 .image-shape .label rect{opacity:0.5;background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);fill:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-SpanioQpQz6cR1b5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-SpanioQpQz6cR1b5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-SpanioQpQz6cR1b5 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-SpanioQpQz6cR1b5 .src>*{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-SpanioQpQz6cR1b5 .src span{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-SpanioQpQz6cR1b5 .src tspan{fill:#fff!important;}#mermaid-svg-SpanioQpQz6cR1b5 .loader>*{fill:#fbbf24!important;stroke:#d97706!important;color:#fff!important;}#mermaid-svg-SpanioQpQz6cR1b5 .loader span{fill:#fbbf24!important;stroke:#d97706!important;color:#fff!important;}#mermaid-svg-SpanioQpQz6cR1b5 .loader tspan{fill:#fff!important;}#mermaid-svg-SpanioQpQz6cR1b5 .warn>*{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-SpanioQpQz6cR1b5 .warn span{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-SpanioQpQz6cR1b5 .warn tspan{fill:#fff!important;}

    不合并 DEFAULT_CONFIG

    DEFAULT_CONFIGconfig_defaults.py:21(单一 schema 源, 纯数据)

    .env 仅密钥OPTIONAL_ENV_VARS:2429

    config_migrations.py_migrate_to_N:110 起(仅主动迁移才 bump _config_version)

    ① load_cli_configcli.py:458(CLI: 默认+用户YAML)

    ② load_confighermes_cli/config.py(tools/setup/多数子命令合并 DEFAULT_CONFIG)

    ③ 原始 YAMLgateway/run.py + gateway/config.py(gateway 运行时)

    校验require_parseable_user_config:468InvalidUserConfigError:48 / ConfigIssue:1059

    ⚠ 若 CLI 见到 key 而 gateway 不见= 用错加载器AGENTS.md:69-72

    2.4.4 模块③架构图

    #mermaid-svg-MrfcwQWLUWnk5TSO{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MrfcwQWLUWnk5TSO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MrfcwQWLUWnk5TSO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MrfcwQWLUWnk5TSO .error-icon{fill:hsl(217.6923076923, 92.125984252%, 55.1960784314%);}#mermaid-svg-MrfcwQWLUWnk5TSO .error-text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);stroke:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-MrfcwQWLUWnk5TSO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MrfcwQWLUWnk5TSO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MrfcwQWLUWnk5TSO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MrfcwQWLUWnk5TSO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MrfcwQWLUWnk5TSO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MrfcwQWLUWnk5TSO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MrfcwQWLUWnk5TSO .marker{fill:#6b7280;stroke:#6b7280;}#mermaid-svg-MrfcwQWLUWnk5TSO .marker.cross{stroke:#6b7280;}#mermaid-svg-MrfcwQWLUWnk5TSO svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MrfcwQWLUWnk5TSO p{margin:0;}#mermaid-svg-MrfcwQWLUWnk5TSO .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-MrfcwQWLUWnk5TSO .cluster-label text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-MrfcwQWLUWnk5TSO .cluster-label span{color:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-MrfcwQWLUWnk5TSO .cluster-label span p{background-color:transparent;}#mermaid-svg-MrfcwQWLUWnk5TSO .label text,#mermaid-svg-MrfcwQWLUWnk5TSO span{fill:#fff;color:#fff;}#mermaid-svg-MrfcwQWLUWnk5TSO .node rect,#mermaid-svg-MrfcwQWLUWnk5TSO .node circle,#mermaid-svg-MrfcwQWLUWnk5TSO .node ellipse,#mermaid-svg-MrfcwQWLUWnk5TSO .node polygon,#mermaid-svg-MrfcwQWLUWnk5TSO .node path{fill:#f59e0b;stroke:hsl(37.6923076923, 52.125984252%, 40.1960784314%);stroke-width:1px;}#mermaid-svg-MrfcwQWLUWnk5TSO .rough-node .label text,#mermaid-svg-MrfcwQWLUWnk5TSO .node .label text,#mermaid-svg-MrfcwQWLUWnk5TSO .image-shape .label,#mermaid-svg-MrfcwQWLUWnk5TSO .icon-shape .label{text-anchor:middle;}#mermaid-svg-MrfcwQWLUWnk5TSO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MrfcwQWLUWnk5TSO .rough-node .label,#mermaid-svg-MrfcwQWLUWnk5TSO .node .label,#mermaid-svg-MrfcwQWLUWnk5TSO .image-shape .label,#mermaid-svg-MrfcwQWLUWnk5TSO .icon-shape .label{text-align:center;}#mermaid-svg-MrfcwQWLUWnk5TSO .node.clickable{cursor:pointer;}#mermaid-svg-MrfcwQWLUWnk5TSO .root .anchor path{fill:#6b7280!important;stroke-width:0;stroke:#6b7280;}#mermaid-svg-MrfcwQWLUWnk5TSO .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-MrfcwQWLUWnk5TSO .edgePath .path{stroke:#6b7280;stroke-width:2.0px;}#mermaid-svg-MrfcwQWLUWnk5TSO .flowchart-link{stroke:#6b7280;fill:none;}#mermaid-svg-MrfcwQWLUWnk5TSO .edgeLabel{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);text-align:center;}#mermaid-svg-MrfcwQWLUWnk5TSO .edgeLabel p{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-MrfcwQWLUWnk5TSO .edgeLabel rect{opacity:0.5;background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);fill:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-MrfcwQWLUWnk5TSO .labelBkg{background-color:rgba(158, 11.0000000001, 245, 0.5);}#mermaid-svg-MrfcwQWLUWnk5TSO .cluster rect{fill:hsl(217.6923076923, 92.125984252%, 55.1960784314%);stroke:hsl(217.6923076923, 52.125984252%, 45.1960784314%);stroke-width:1px;}#mermaid-svg-MrfcwQWLUWnk5TSO .cluster text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-MrfcwQWLUWnk5TSO .cluster span{color:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-MrfcwQWLUWnk5TSO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(217.6923076923, 92.125984252%, 55.1960784314%);border:1px solid hsl(217.6923076923, 52.125984252%, 45.1960784314%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MrfcwQWLUWnk5TSO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#fff;}#mermaid-svg-MrfcwQWLUWnk5TSO rect.text{fill:none;stroke-width:0;}#mermaid-svg-MrfcwQWLUWnk5TSO .icon-shape,#mermaid-svg-MrfcwQWLUWnk5TSO .image-shape{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);text-align:center;}#mermaid-svg-MrfcwQWLUWnk5TSO .icon-shape p,#mermaid-svg-MrfcwQWLUWnk5TSO .image-shape p{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);padding:2px;}#mermaid-svg-MrfcwQWLUWnk5TSO .icon-shape .label rect,#mermaid-svg-MrfcwQWLUWnk5TSO .image-shape .label rect{opacity:0.5;background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);fill:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-MrfcwQWLUWnk5TSO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MrfcwQWLUWnk5TSO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MrfcwQWLUWnk5TSO :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-MrfcwQWLUWnk5TSO .god>*{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-MrfcwQWLUWnk5TSO .god span{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-MrfcwQWLUWnk5TSO .god tspan{fill:#fff!important;}#mermaid-svg-MrfcwQWLUWnk5TSO .main>*{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-MrfcwQWLUWnk5TSO .main span{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-MrfcwQWLUWnk5TSO .main tspan{fill:#fff!important;}#mermaid-svg-MrfcwQWLUWnk5TSO .support>*{fill:#fbbf24!important;stroke:#d97706!important;color:#fff!important;}#mermaid-svg-MrfcwQWLUWnk5TSO .support span{fill:#fbbf24!important;stroke:#d97706!important;color:#fff!important;}#mermaid-svg-MrfcwQWLUWnk5TSO .support tspan{fill:#fff!important;}

    CLI 界面层

    hermes_cli/main.py:3351子命令入口

    cli.py:2530HermesCLI REPL (14 mixin)

    cli_*_mixin.py14 个行为 mixin

    commands.py:49COMMAND_REGISTRY 单一源

    hermes_cli/gateway.py:5826gateway 进程管理(288KB god-file)

    config.py + config_defaults.py:21配置系统 (三加载器)

    plugins.py:1117PluginManager (3 mixin)

    models.py / auth.py:149模型目录 / 认证

    web_server.py:138FastAPI 后端

    goals.py:281GoalContract/Gate/State

    kanban_db.py178KB 持久层

    backup.py:118


    2.5 模块④:界面层 —— 消息网关(gateway/)

    核心作用:消息网关——把 agent 内核暴露到 ~34 个消息平台(Telegram/Discord/Slack 等)。gateway/run.py 是门面,生命周期阶段在 run_*.py(startup/adapters/inbound/turn/busy/notifications/shutdown…),会话在 session*.py,slash 处理在 slash_commands_*.py,适配器在 platforms/<name>.py 之上基于 platforms/base.py 的 BasePlatformAdapter。

    关键类/函数:

    符号位置职责
    GatewayRunner gateway/run.py:3332-3337 god-object:组合 16 个 Mixin(GatewayAuthorizationMixin、GatewayTurnMixin、GatewayShutdownMixin、GatewayBusySessionMixin、GatewayStartupMixin、GatewayInboundMixin、GatewayNotificationsMixin、GatewayAdapterLifecycleMixin、GatewayAgentCacheMixin 等);隐式共享可变状态属性面庞大(run.py:3364-3384)
    start_gateway gateway/run.py:5249 异步入口;__main__ 调 asyncio.run(start_gateway(…))(run.py:5474)
    BasePlatformAdapter(ABC) gateway/platforms/base.py:1797 平台适配器 ABC;抽象方法 connect/disconnect/send/edit_message/delete_message(:2414/:2420/:2424/:2437/:2445);_active_sessions(:1863)+ _pending_messages(:1864)实现消息守卫①
    PlatformRegistry gateway/platform_registry.py:102 适配器延迟/惰性注册与工厂;create_adapter(:349)、register(:271)、register_deferred(:156),无 if/elif 链
    TurnRunner gateway/run_turn_runner.py:48 每轮 turn 协作者;_build_fresh_agent(:1011)构造/复用 AIAgent
    _run_agent_inner gateway/run_turn.py:3819 驱动一个 turn;同步路径在 executor 内调 agent.run_conversation(run_turn.py:2192/:2196)
    GatewayAgentCacheMixin gateway/run_agent_cache.py:43 跨 turn 缓存 AIAgent(_AGENT_CACHE_MAX_SIZE=128、_AGENT_CACHE_IDLE_TTL_SECS=3600,run.py:46-47)
    acquire_scoped_lock / release_scoped_lock gateway/status.py:1094 / :1142 token 锁:唯一凭据的适配器在 connect/stop 时获取/释放,防两个 profile 共享一个凭据(gateway/AGENTS.md:129-132)
    AIAgent( 调用点 gateway/run_turn.py:1146,2163、gateway/run_turn_runner.py:1017-1039 gateway 构造 AIAgent 实例(model/session_id/platform/user_id/chat_id/gateway_session_key/session_db…)

    循环分层警示:run_turn_runner.py:1013 反向 from gateway.run import _checkpoint_agent_kwargs——turn 协作者回引门面,形成 facade↔collaborator 的近似循环依赖。

    2.5.1 网关生命周期阶段(17 个 run_*.py)

    #mermaid-svg-rwgL2QoZftNNZgcz{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-rwgL2QoZftNNZgcz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rwgL2QoZftNNZgcz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rwgL2QoZftNNZgcz .error-icon{fill:hsl(217.6923076923, 92.125984252%, 55.1960784314%);}#mermaid-svg-rwgL2QoZftNNZgcz .error-text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);stroke:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-rwgL2QoZftNNZgcz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rwgL2QoZftNNZgcz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rwgL2QoZftNNZgcz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rwgL2QoZftNNZgcz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rwgL2QoZftNNZgcz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rwgL2QoZftNNZgcz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rwgL2QoZftNNZgcz .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-rwgL2QoZftNNZgcz .marker.cross{stroke:#0b0b0b;}#mermaid-svg-rwgL2QoZftNNZgcz svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rwgL2QoZftNNZgcz p{margin:0;}#mermaid-svg-rwgL2QoZftNNZgcz .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-rwgL2QoZftNNZgcz .cluster-label text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-rwgL2QoZftNNZgcz .cluster-label span{color:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-rwgL2QoZftNNZgcz .cluster-label span p{background-color:transparent;}#mermaid-svg-rwgL2QoZftNNZgcz .label text,#mermaid-svg-rwgL2QoZftNNZgcz span{fill:#fff;color:#fff;}#mermaid-svg-rwgL2QoZftNNZgcz .node rect,#mermaid-svg-rwgL2QoZftNNZgcz .node circle,#mermaid-svg-rwgL2QoZftNNZgcz .node ellipse,#mermaid-svg-rwgL2QoZftNNZgcz .node polygon,#mermaid-svg-rwgL2QoZftNNZgcz .node path{fill:#f59e0b;stroke:hsl(37.6923076923, 52.125984252%, 40.1960784314%);stroke-width:1px;}#mermaid-svg-rwgL2QoZftNNZgcz .rough-node .label text,#mermaid-svg-rwgL2QoZftNNZgcz .node .label text,#mermaid-svg-rwgL2QoZftNNZgcz .image-shape .label,#mermaid-svg-rwgL2QoZftNNZgcz .icon-shape .label{text-anchor:middle;}#mermaid-svg-rwgL2QoZftNNZgcz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-rwgL2QoZftNNZgcz .rough-node .label,#mermaid-svg-rwgL2QoZftNNZgcz .node .label,#mermaid-svg-rwgL2QoZftNNZgcz .image-shape .label,#mermaid-svg-rwgL2QoZftNNZgcz .icon-shape .label{text-align:center;}#mermaid-svg-rwgL2QoZftNNZgcz .node.clickable{cursor:pointer;}#mermaid-svg-rwgL2QoZftNNZgcz .root .anchor path{fill:#0b0b0b!important;stroke-width:0;stroke:#0b0b0b;}#mermaid-svg-rwgL2QoZftNNZgcz .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-rwgL2QoZftNNZgcz .edgePath .path{stroke:#0b0b0b;stroke-width:2.0px;}#mermaid-svg-rwgL2QoZftNNZgcz .flowchart-link{stroke:#0b0b0b;fill:none;}#mermaid-svg-rwgL2QoZftNNZgcz .edgeLabel{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);text-align:center;}#mermaid-svg-rwgL2QoZftNNZgcz .edgeLabel p{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-rwgL2QoZftNNZgcz .edgeLabel rect{opacity:0.5;background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);fill:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-rwgL2QoZftNNZgcz .labelBkg{background-color:rgba(158, 11.0000000001, 245, 0.5);}#mermaid-svg-rwgL2QoZftNNZgcz .cluster rect{fill:hsl(217.6923076923, 92.125984252%, 55.1960784314%);stroke:hsl(217.6923076923, 52.125984252%, 45.1960784314%);stroke-width:1px;}#mermaid-svg-rwgL2QoZftNNZgcz .cluster text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-rwgL2QoZftNNZgcz .cluster span{color:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-rwgL2QoZftNNZgcz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(217.6923076923, 92.125984252%, 55.1960784314%);border:1px solid hsl(217.6923076923, 52.125984252%, 45.1960784314%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-rwgL2QoZftNNZgcz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#fff;}#mermaid-svg-rwgL2QoZftNNZgcz rect.text{fill:none;stroke-width:0;}#mermaid-svg-rwgL2QoZftNNZgcz .icon-shape,#mermaid-svg-rwgL2QoZftNNZgcz .image-shape{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);text-align:center;}#mermaid-svg-rwgL2QoZftNNZgcz .icon-shape p,#mermaid-svg-rwgL2QoZftNNZgcz .image-shape p{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);padding:2px;}#mermaid-svg-rwgL2QoZftNNZgcz .icon-shape .label rect,#mermaid-svg-rwgL2QoZftNNZgcz .image-shape .label rect{opacity:0.5;background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);fill:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-rwgL2QoZftNNZgcz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-rwgL2QoZftNNZgcz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-rwgL2QoZftNNZgcz :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-rwgL2QoZftNNZgcz .phase>*{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-rwgL2QoZftNNZgcz .phase span{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-rwgL2QoZftNNZgcz .phase tspan{fill:#fff!important;}

    关闭

    侧路

    执行

    入站

    启动

    缓存

    拦截 slash

    run_startup.py进程初始化

    run_adapters.py连接平台适配器

    run_inbound.py接收消息过两道消息守卫

    run_turn.py:1146构造 AIAgent + 跑 turn

    run_turn_runner.py:1017turn 运行器

    run_agent_cache.py跨 turn 缓存 agent

    run_busy.py运行中 slash 拦截守卫②

    run_notifications.py后台进程通知

    run_goals.py

    run_watchers.py

    run_voice.py

    run_shutdown.py优雅关闭

    2.5.2 两道消息守卫 + 流式契约 + token 锁

    #mermaid-svg-XGShp7SHhagYEphX{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XGShp7SHhagYEphX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XGShp7SHhagYEphX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XGShp7SHhagYEphX .error-icon{fill:hsl(217.6923076923, 92.125984252%, 55.1960784314%);}#mermaid-svg-XGShp7SHhagYEphX .error-text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);stroke:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-XGShp7SHhagYEphX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XGShp7SHhagYEphX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XGShp7SHhagYEphX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XGShp7SHhagYEphX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XGShp7SHhagYEphX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XGShp7SHhagYEphX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XGShp7SHhagYEphX .marker{fill:#374151;stroke:#374151;}#mermaid-svg-XGShp7SHhagYEphX .marker.cross{stroke:#374151;}#mermaid-svg-XGShp7SHhagYEphX svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XGShp7SHhagYEphX p{margin:0;}#mermaid-svg-XGShp7SHhagYEphX .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-XGShp7SHhagYEphX .cluster-label text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-XGShp7SHhagYEphX .cluster-label span{color:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-XGShp7SHhagYEphX .cluster-label span p{background-color:transparent;}#mermaid-svg-XGShp7SHhagYEphX .label text,#mermaid-svg-XGShp7SHhagYEphX span{fill:#fff;color:#fff;}#mermaid-svg-XGShp7SHhagYEphX .node rect,#mermaid-svg-XGShp7SHhagYEphX .node circle,#mermaid-svg-XGShp7SHhagYEphX .node ellipse,#mermaid-svg-XGShp7SHhagYEphX .node polygon,#mermaid-svg-XGShp7SHhagYEphX .node path{fill:#f59e0b;stroke:hsl(37.6923076923, 52.125984252%, 40.1960784314%);stroke-width:1px;}#mermaid-svg-XGShp7SHhagYEphX .rough-node .label text,#mermaid-svg-XGShp7SHhagYEphX .node .label text,#mermaid-svg-XGShp7SHhagYEphX .image-shape .label,#mermaid-svg-XGShp7SHhagYEphX .icon-shape .label{text-anchor:middle;}#mermaid-svg-XGShp7SHhagYEphX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XGShp7SHhagYEphX .rough-node .label,#mermaid-svg-XGShp7SHhagYEphX .node .label,#mermaid-svg-XGShp7SHhagYEphX .image-shape .label,#mermaid-svg-XGShp7SHhagYEphX .icon-shape .label{text-align:center;}#mermaid-svg-XGShp7SHhagYEphX .node.clickable{cursor:pointer;}#mermaid-svg-XGShp7SHhagYEphX .root .anchor path{fill:#374151!important;stroke-width:0;stroke:#374151;}#mermaid-svg-XGShp7SHhagYEphX .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-XGShp7SHhagYEphX .edgePath .path{stroke:#374151;stroke-width:2.0px;}#mermaid-svg-XGShp7SHhagYEphX .flowchart-link{stroke:#374151;fill:none;}#mermaid-svg-XGShp7SHhagYEphX .edgeLabel{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);text-align:center;}#mermaid-svg-XGShp7SHhagYEphX .edgeLabel p{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-XGShp7SHhagYEphX .edgeLabel rect{opacity:0.5;background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);fill:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-XGShp7SHhagYEphX .labelBkg{background-color:rgba(158, 11.0000000001, 245, 0.5);}#mermaid-svg-XGShp7SHhagYEphX .cluster rect{fill:hsl(217.6923076923, 92.125984252%, 55.1960784314%);stroke:hsl(217.6923076923, 52.125984252%, 45.1960784314%);stroke-width:1px;}#mermaid-svg-XGShp7SHhagYEphX .cluster text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-XGShp7SHhagYEphX .cluster span{color:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-XGShp7SHhagYEphX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(217.6923076923, 92.125984252%, 55.1960784314%);border:1px solid hsl(217.6923076923, 52.125984252%, 45.1960784314%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-XGShp7SHhagYEphX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#fff;}#mermaid-svg-XGShp7SHhagYEphX rect.text{fill:none;stroke-width:0;}#mermaid-svg-XGShp7SHhagYEphX .icon-shape,#mermaid-svg-XGShp7SHhagYEphX .image-shape{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);text-align:center;}#mermaid-svg-XGShp7SHhagYEphX .icon-shape p,#mermaid-svg-XGShp7SHhagYEphX .image-shape p{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);padding:2px;}#mermaid-svg-XGShp7SHhagYEphX .icon-shape .label rect,#mermaid-svg-XGShp7SHhagYEphX .image-shape .label rect{opacity:0.5;background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);fill:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-XGShp7SHhagYEphX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XGShp7SHhagYEphX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XGShp7SHhagYEphX :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-XGShp7SHhagYEphX .guard>*{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-XGShp7SHhagYEphX .guard span{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-XGShp7SHhagYEphX .guard tspan{fill:#fff!important;}#mermaid-svg-XGShp7SHhagYEphX .stream>*{fill:#10b981!important;stroke:#047857!important;color:#fff!important;}#mermaid-svg-XGShp7SHhagYEphX .stream span{fill:#10b981!important;stroke:#047857!important;color:#fff!important;}#mermaid-svg-XGShp7SHhagYEphX .stream tspan{fill:#fff!important;}#mermaid-svg-XGShp7SHhagYEphX .lock>*{fill:#8b5cf6!important;stroke:#6d28d9!important;color:#fff!important;}#mermaid-svg-XGShp7SHhagYEphX .lock span{fill:#8b5cf6!important;stroke:#6d28d9!important;color:#fff!important;}#mermaid-svg-XGShp7SHhagYEphX .lock tspan{fill:#fff!important;}#mermaid-svg-XGShp7SHhagYEphX .bypass>*{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-XGShp7SHhagYEphX .bypass span{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-XGShp7SHhagYEphX .bypass tspan{fill:#fff!important;}

    守卫② — Runner

    守卫① — 基础适配器

    控制命令绕过

    控制命令绕过

    token 锁

    acquire_scoped_lockstatus.py:1094 (connect)

    release_scoped_lockstatus.py:1142 (stop)

    流式契约 (draft_stream_is_message=True)

    ① draft 帧 prefix-stable

    ② 消费者声明 finaladapter 永不猜

    ③ interim 带 _interim_send=True

    ④ edit 对账, 非 plain send

    入站消息 (agent 运行中)

    platforms/base.pysession_key in _active_sessions→ 排队 _pending_messages:1864

    run.py / run_busy.py拦截 /stop /new /queue /status/approve /deny→ running_agent.interrupt()

    必须绕过两道守卫的命令inline 派发永不走 _process_message_backgroundgateway/AGENTS.md:20-28

    证据:两道守卫 gateway/AGENTS.md:20-28;流式契约四不变量 gateway/AGENTS.md:30-52(每条来自一次重复最终事故 NS-658 / #85796);token 锁 gateway/AGENTS.md:129-132。

    2.5.3 平台适配器(34 个 = 12 内置 + 22 插件)
    类型数量位置代表
    内置适配器 12 gateway/platforms/*.py signal、whatsapp_cloud、weixin、yuanbao、webhook、api_server 等
    插件适配器 22 plugins/platforms/*/ telegram(382KB)、discord(352KB)、slack(339KB)、feishu、matrix、teams、line、irc、ntfy、wecom、simplex…
    基类 1 gateway/platforms/base.py:1797 BasePlatformAdapter(ABC),4263 行
    2.5.4 模块④架构图

    #mermaid-svg-tCddFpkGqfFjl0AT{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tCddFpkGqfFjl0AT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tCddFpkGqfFjl0AT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tCddFpkGqfFjl0AT .error-icon{fill:hsl(217.6923076923, 92.125984252%, 55.1960784314%);}#mermaid-svg-tCddFpkGqfFjl0AT .error-text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);stroke:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-tCddFpkGqfFjl0AT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tCddFpkGqfFjl0AT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tCddFpkGqfFjl0AT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tCddFpkGqfFjl0AT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tCddFpkGqfFjl0AT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tCddFpkGqfFjl0AT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tCddFpkGqfFjl0AT .marker{fill:#6b7280;stroke:#6b7280;}#mermaid-svg-tCddFpkGqfFjl0AT .marker.cross{stroke:#6b7280;}#mermaid-svg-tCddFpkGqfFjl0AT svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tCddFpkGqfFjl0AT p{margin:0;}#mermaid-svg-tCddFpkGqfFjl0AT .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-tCddFpkGqfFjl0AT .cluster-label text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-tCddFpkGqfFjl0AT .cluster-label span{color:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-tCddFpkGqfFjl0AT .cluster-label span p{background-color:transparent;}#mermaid-svg-tCddFpkGqfFjl0AT .label text,#mermaid-svg-tCddFpkGqfFjl0AT span{fill:#fff;color:#fff;}#mermaid-svg-tCddFpkGqfFjl0AT .node rect,#mermaid-svg-tCddFpkGqfFjl0AT .node circle,#mermaid-svg-tCddFpkGqfFjl0AT .node ellipse,#mermaid-svg-tCddFpkGqfFjl0AT .node polygon,#mermaid-svg-tCddFpkGqfFjl0AT .node path{fill:#f59e0b;stroke:hsl(37.6923076923, 52.125984252%, 40.1960784314%);stroke-width:1px;}#mermaid-svg-tCddFpkGqfFjl0AT .rough-node .label text,#mermaid-svg-tCddFpkGqfFjl0AT .node .label text,#mermaid-svg-tCddFpkGqfFjl0AT .image-shape .label,#mermaid-svg-tCddFpkGqfFjl0AT .icon-shape .label{text-anchor:middle;}#mermaid-svg-tCddFpkGqfFjl0AT .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-tCddFpkGqfFjl0AT .rough-node .label,#mermaid-svg-tCddFpkGqfFjl0AT .node .label,#mermaid-svg-tCddFpkGqfFjl0AT .image-shape .label,#mermaid-svg-tCddFpkGqfFjl0AT .icon-shape .label{text-align:center;}#mermaid-svg-tCddFpkGqfFjl0AT .node.clickable{cursor:pointer;}#mermaid-svg-tCddFpkGqfFjl0AT .root .anchor path{fill:#6b7280!important;stroke-width:0;stroke:#6b7280;}#mermaid-svg-tCddFpkGqfFjl0AT .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-tCddFpkGqfFjl0AT .edgePath .path{stroke:#6b7280;stroke-width:2.0px;}#mermaid-svg-tCddFpkGqfFjl0AT .flowchart-link{stroke:#6b7280;fill:none;}#mermaid-svg-tCddFpkGqfFjl0AT .edgeLabel{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);text-align:center;}#mermaid-svg-tCddFpkGqfFjl0AT .edgeLabel p{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-tCddFpkGqfFjl0AT .edgeLabel rect{opacity:0.5;background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);fill:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-tCddFpkGqfFjl0AT .labelBkg{background-color:rgba(158, 11.0000000001, 245, 0.5);}#mermaid-svg-tCddFpkGqfFjl0AT .cluster rect{fill:hsl(217.6923076923, 92.125984252%, 55.1960784314%);stroke:hsl(217.6923076923, 52.125984252%, 45.1960784314%);stroke-width:1px;}#mermaid-svg-tCddFpkGqfFjl0AT .cluster text{fill:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-tCddFpkGqfFjl0AT .cluster span{color:rgb(219.5039370078, 141.2381889763, 8.9960629921);}#mermaid-svg-tCddFpkGqfFjl0AT div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(217.6923076923, 92.125984252%, 55.1960784314%);border:1px solid hsl(217.6923076923, 52.125984252%, 45.1960784314%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-tCddFpkGqfFjl0AT .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#fff;}#mermaid-svg-tCddFpkGqfFjl0AT rect.text{fill:none;stroke-width:0;}#mermaid-svg-tCddFpkGqfFjl0AT .icon-shape,#mermaid-svg-tCddFpkGqfFjl0AT .image-shape{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);text-align:center;}#mermaid-svg-tCddFpkGqfFjl0AT .icon-shape p,#mermaid-svg-tCddFpkGqfFjl0AT .image-shape p{background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);padding:2px;}#mermaid-svg-tCddFpkGqfFjl0AT .icon-shape .label rect,#mermaid-svg-tCddFpkGqfFjl0AT .image-shape .label rect{opacity:0.5;background-color:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);fill:hsl(-82.3076923077, 92.125984252%, 50.1960784314%);}#mermaid-svg-tCddFpkGqfFjl0AT .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-tCddFpkGqfFjl0AT .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-tCddFpkGqfFjl0AT :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-tCddFpkGqfFjl0AT .god>*{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-tCddFpkGqfFjl0AT .god span{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-tCddFpkGqfFjl0AT .god tspan{fill:#fff!important;}#mermaid-svg-tCddFpkGqfFjl0AT .main>*{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-tCddFpkGqfFjl0AT .main span{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-tCddFpkGqfFjl0AT .main tspan{fill:#fff!important;}#mermaid-svg-tCddFpkGqfFjl0AT .plugin>*{fill:#8b5cf6!important;stroke:#6d28d9!important;color:#fff!important;}#mermaid-svg-tCddFpkGqfFjl0AT .plugin span{fill:#8b5cf6!important;stroke:#6d28d9!important;color:#fff!important;}#mermaid-svg-tCddFpkGqfFjl0AT .plugin tspan{fill:#fff!important;}

    gateway/ 消息网关

    挂载

    plugins/platforms/ (22 适配器)

    telegram382KB

    discord352KB

    slack339KB

    feishu/matrix/teams/line/irc/…

    run.py285KB 门面

    17 个 run_*.py生命周期阶段

    session*.py会话管理

    slash_commands_*.pygateway slash (mixin)

    authz_mixin.py授权

    platforms/base.py:1797BasePlatformAdapter ABC(4263 行)

    12 内置适配器platforms/*.py

    builtin_hooks/扩展点 (无内置)


    2.6 模块⑤:扩展层 —— 插件 / 技能 / Provider / Cron

    核心作用:实现「能力在边缘」——所有平台适配器、模型 provider、记忆后端、上下文引擎、图像生成、看板、定时调度均以插件/ABC/技能形式挂载,内核不感知具体实现。

    关键 ABC 与编排器:

    ABC / 编排器位置职责
    ProviderProfile providers/base.py:39 模型 provider 基类;插件目录 plugins/model-providers/<name>/(39 个)
    MemoryProvider(ABC) agent/memory_provider.py:58 记忆后端 ABC;agent/memory_manager.py 编排
    ContextEngine(ABC) agent/context_engine.py:47 上下文引擎 ABC
    ImageGenProvider agent/image_gen_provider.py:30 图像生成 provider(继承 CatalogProviderBase)
    PluginManager hermes_cli/plugins.py:1117 插件运行时:PluginLoaderMixin(plugins_loader.py:81)+ PluginDispatchMixin(plugins_dispatch.py:150)+ PluginLedgerMixin(plugins_ledger.py:62)
    LoadedPlugin / PluginContext hermes_cli/plugins.py:205 / :220 已加载插件 / 插件上下文
    Cron scheduler cron/scheduler.py(177KB) 定时任务调度;cron 会话默认 skip_memory=True(agent/AGENTS.md:100-101)

    插件发现三处来源(providers/__init__.py:1-20):① 内置 plugins/<kind>/<name>/;② 用户 $HERMES_HOME/plugins/<kind>/<name>/;③ pip 安装的 hermes_agent.plugins entry point。用户插件同名覆盖内置(last-writer-wins)。

    插件种类(plugins/ 18 目录):browser、context_engine、cron_providers、dashboard_auth、disk-cleanup、google_meet、hermes-achievements、image_gen、kanban、memory、model-providers、observability、platforms、security-guidance、spotify、teams_pipeline、video_gen、web。

    2.6.1 模块⑤架构图

    #mermaid-svg-WwaUmodRixUF8vfM{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WwaUmodRixUF8vfM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WwaUmodRixUF8vfM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WwaUmodRixUF8vfM .error-icon{fill:hsl(78.3116883117, 89.5348837209%, 71.2745098039%);}#mermaid-svg-WwaUmodRixUF8vfM .error-text{fill:rgb(47.6976744187, 7.6656976744, 138.8343023257);stroke:rgb(47.6976744187, 7.6656976744, 138.8343023257);}#mermaid-svg-WwaUmodRixUF8vfM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WwaUmodRixUF8vfM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WwaUmodRixUF8vfM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WwaUmodRixUF8vfM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WwaUmodRixUF8vfM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WwaUmodRixUF8vfM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WwaUmodRixUF8vfM .marker{fill:#6b7280;stroke:#6b7280;}#mermaid-svg-WwaUmodRixUF8vfM .marker.cross{stroke:#6b7280;}#mermaid-svg-WwaUmodRixUF8vfM svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WwaUmodRixUF8vfM p{margin:0;}#mermaid-svg-WwaUmodRixUF8vfM .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-WwaUmodRixUF8vfM .cluster-label text{fill:rgb(47.6976744187, 7.6656976744, 138.8343023257);}#mermaid-svg-WwaUmodRixUF8vfM .cluster-label span{color:rgb(47.6976744187, 7.6656976744, 138.8343023257);}#mermaid-svg-WwaUmodRixUF8vfM .cluster-label span p{background-color:transparent;}#mermaid-svg-WwaUmodRixUF8vfM .label text,#mermaid-svg-WwaUmodRixUF8vfM span{fill:#fff;color:#fff;}#mermaid-svg-WwaUmodRixUF8vfM .node rect,#mermaid-svg-WwaUmodRixUF8vfM .node circle,#mermaid-svg-WwaUmodRixUF8vfM .node ellipse,#mermaid-svg-WwaUmodRixUF8vfM .node polygon,#mermaid-svg-WwaUmodRixUF8vfM .node path{fill:#8b5cf6;stroke:hsl(258.3116883117, 49.5348837209%, 56.2745098039%);stroke-width:1px;}#mermaid-svg-WwaUmodRixUF8vfM .rough-node .label text,#mermaid-svg-WwaUmodRixUF8vfM .node .label text,#mermaid-svg-WwaUmodRixUF8vfM .image-shape .label,#mermaid-svg-WwaUmodRixUF8vfM .icon-shape .label{text-anchor:middle;}#mermaid-svg-WwaUmodRixUF8vfM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-WwaUmodRixUF8vfM .rough-node .label,#mermaid-svg-WwaUmodRixUF8vfM .node .label,#mermaid-svg-WwaUmodRixUF8vfM .image-shape .label,#mermaid-svg-WwaUmodRixUF8vfM .icon-shape .label{text-align:center;}#mermaid-svg-WwaUmodRixUF8vfM .node.clickable{cursor:pointer;}#mermaid-svg-WwaUmodRixUF8vfM .root .anchor path{fill:#6b7280!important;stroke-width:0;stroke:#6b7280;}#mermaid-svg-WwaUmodRixUF8vfM .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-WwaUmodRixUF8vfM .edgePath .path{stroke:#6b7280;stroke-width:2.0px;}#mermaid-svg-WwaUmodRixUF8vfM .flowchart-link{stroke:#6b7280;fill:none;}#mermaid-svg-WwaUmodRixUF8vfM .edgeLabel{background-color:hsl(138.3116883117, 89.5348837209%, 66.2745098039%);text-align:center;}#mermaid-svg-WwaUmodRixUF8vfM .edgeLabel p{background-color:hsl(138.3116883117, 89.5348837209%, 66.2745098039%);}#mermaid-svg-WwaUmodRixUF8vfM .edgeLabel rect{opacity:0.5;background-color:hsl(138.3116883117, 89.5348837209%, 66.2745098039%);fill:hsl(138.3116883117, 89.5348837209%, 66.2745098039%);}#mermaid-svg-WwaUmodRixUF8vfM .labelBkg{background-color:rgba(91.9999999999, 246, 139, 0.5);}#mermaid-svg-WwaUmodRixUF8vfM .cluster rect{fill:hsl(78.3116883117, 89.5348837209%, 71.2745098039%);stroke:hsl(78.3116883117, 49.5348837209%, 61.2745098039%);stroke-width:1px;}#mermaid-svg-WwaUmodRixUF8vfM .cluster text{fill:rgb(47.6976744187, 7.6656976744, 138.8343023257);}#mermaid-svg-WwaUmodRixUF8vfM .cluster span{color:rgb(47.6976744187, 7.6656976744, 138.8343023257);}#mermaid-svg-WwaUmodRixUF8vfM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(78.3116883117, 89.5348837209%, 71.2745098039%);border:1px solid hsl(78.3116883117, 49.5348837209%, 61.2745098039%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-WwaUmodRixUF8vfM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#fff;}#mermaid-svg-WwaUmodRixUF8vfM rect.text{fill:none;stroke-width:0;}#mermaid-svg-WwaUmodRixUF8vfM .icon-shape,#mermaid-svg-WwaUmodRixUF8vfM .image-shape{background-color:hsl(138.3116883117, 89.5348837209%, 66.2745098039%);text-align:center;}#mermaid-svg-WwaUmodRixUF8vfM .icon-shape p,#mermaid-svg-WwaUmodRixUF8vfM .image-shape p{background-color:hsl(138.3116883117, 89.5348837209%, 66.2745098039%);padding:2px;}#mermaid-svg-WwaUmodRixUF8vfM .icon-shape .label rect,#mermaid-svg-WwaUmodRixUF8vfM .image-shape .label rect{opacity:0.5;background-color:hsl(138.3116883117, 89.5348837209%, 66.2745098039%);fill:hsl(138.3116883117, 89.5348837209%, 66.2745098039%);}#mermaid-svg-WwaUmodRixUF8vfM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WwaUmodRixUF8vfM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WwaUmodRixUF8vfM :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-WwaUmodRixUF8vfM .abc>*{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-WwaUmodRixUF8vfM .abc span{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-WwaUmodRixUF8vfM .abc tspan{fill:#fff!important;}#mermaid-svg-WwaUmodRixUF8vfM .rt>*{fill:#8b5cf6!important;stroke:#6d28d9!important;color:#fff!important;}#mermaid-svg-WwaUmodRixUF8vfM .rt span{fill:#8b5cf6!important;stroke:#6d28d9!important;color:#fff!important;}#mermaid-svg-WwaUmodRixUF8vfM .rt tspan{fill:#fff!important;}#mermaid-svg-WwaUmodRixUF8vfM .plugin>*{fill:#a78bfa!important;stroke:#7c3aed!important;color:#fff!important;}#mermaid-svg-WwaUmodRixUF8vfM .plugin span{fill:#a78bfa!important;stroke:#7c3aed!important;color:#fff!important;}#mermaid-svg-WwaUmodRixUF8vfM .plugin tspan{fill:#fff!important;}#mermaid-svg-WwaUmodRixUF8vfM .skill>*{fill:#f472b6!important;stroke:#db2777!important;color:#fff!important;}#mermaid-svg-WwaUmodRixUF8vfM .skill span{fill:#f472b6!important;stroke:#db2777!important;color:#fff!important;}#mermaid-svg-WwaUmodRixUF8vfM .skill tspan{fill:#fff!important;}#mermaid-svg-WwaUmodRixUF8vfM .cron>*{fill:#10b981!important;stroke:#047857!important;color:#fff!important;}#mermaid-svg-WwaUmodRixUF8vfM .cron span{fill:#10b981!important;stroke:#047857!important;color:#fff!important;}#mermaid-svg-WwaUmodRixUF8vfM .cron tspan{fill:#fff!important;}

    cron/

    plugins/ (18 目录)

    插件运行时

    内核扩展点 (ABC)

    实现

    实现

    实现

    实现

    实现

    加载

    skills/ (13 目录)

    creative / devops / emailnote-taking / productivityresearch / social-mediasoftware-development / web

    ProviderProfileproviders/base.py:39

    MemoryProvider(ABC)agent/memory_provider.py:58

    ContextEngine(ABC)agent/context_engine.py:47

    ImageGenProvideragent/image_gen_provider.py:30

    BasePlatformAdaptergateway/platforms/base.py:1797

    PluginManagerplugins.py:1117

    PluginLoaderMixinplugins_loader.py:81

    PluginDispatchMixinplugins_dispatch.py:150

    PluginLedgerMixinplugins_ledger.py:62

    model-providers/ (39)

    platforms/ (22 适配器)

    memory/

    kanban/

    image_gen/

    context_engine/

    browser/cron_providers/dashboard_auth/…

    scheduler.py (177KB)


    2.7 模块⑥:状态层 —— hermes_state(根级 15 文件)

    核心作用:会话持久化——SQLite 存储会话消息、元数据、schema、搜索(FTS)、压缩、WAL、可移植性、修复、网关态、用量等。15 个扁平文件位于仓库根级,是 P2 包化目标。

    关键文件:

    文件大小主符号证据
    hermes_state.py 84KB SessionResumeTooLargeError:98、_compression_lock_holder_process_is_dead:119 hermes_state.py:98
    hermes_state_sessions.py 84KB workspace_key:27、_where_sql:86 hermes_state_sessions.py:27
    hermes_state_messages.py 84KB _parse_tool_calls:69、_scrub_surrogates:89 hermes_state_messages.py:69
    hermes_state_schema.py 76KB SessionSchemaMixin:174、reconcile_state_schema:1257 hermes_state_schema.py:174
    hermes_state_search.py 72KB 会话搜索
    hermes_state_repair.py 68KB 状态修复
    hermes_state_common.py 60KB 共享工具
    hermes_state_gateway.py 40KB 网关态
    hermes_state_compression.py 40KB 压缩落库
    hermes_state_dbfile.py 36KB DB 文件管理
    hermes_state_wal.py 32KB WAL
    hermes_state_portability.py 32KB 导入/导出
    hermes_state_fts.py 24KB 全文搜索
    hermes_state_usage.py 24KB 用量
    hermes_state_maintenance.py 28KB 维护

    三、模块调用关系与数据传递

    3.1 跨模块依赖矩阵

    #mermaid-svg-a6s3fON6gZx2JZS6{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-a6s3fON6gZx2JZS6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-a6s3fON6gZx2JZS6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-a6s3fON6gZx2JZS6 .error-icon{fill:hsl(30.6293706294, 65.296803653%, 62.0588235294%);}#mermaid-svg-a6s3fON6gZx2JZS6 .error-text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);stroke:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-a6s3fON6gZx2JZS6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-a6s3fON6gZx2JZS6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-a6s3fON6gZx2JZS6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-a6s3fON6gZx2JZS6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-a6s3fON6gZx2JZS6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-a6s3fON6gZx2JZS6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-a6s3fON6gZx2JZS6 .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-a6s3fON6gZx2JZS6 .marker.cross{stroke:#0b0b0b;}#mermaid-svg-a6s3fON6gZx2JZS6 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-a6s3fON6gZx2JZS6 p{margin:0;}#mermaid-svg-a6s3fON6gZx2JZS6 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-a6s3fON6gZx2JZS6 .cluster-label text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-a6s3fON6gZx2JZS6 .cluster-label span{color:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-a6s3fON6gZx2JZS6 .cluster-label span p{background-color:transparent;}#mermaid-svg-a6s3fON6gZx2JZS6 .label text,#mermaid-svg-a6s3fON6gZx2JZS6 span{fill:#fff;color:#fff;}#mermaid-svg-a6s3fON6gZx2JZS6 .node rect,#mermaid-svg-a6s3fON6gZx2JZS6 .node circle,#mermaid-svg-a6s3fON6gZx2JZS6 .node ellipse,#mermaid-svg-a6s3fON6gZx2JZS6 .node polygon,#mermaid-svg-a6s3fON6gZx2JZS6 .node path{fill:#4a90d9;stroke:hsl(210.6293706294, 25.296803653%, 47.0588235294%);stroke-width:1px;}#mermaid-svg-a6s3fON6gZx2JZS6 .rough-node .label text,#mermaid-svg-a6s3fON6gZx2JZS6 .node .label text,#mermaid-svg-a6s3fON6gZx2JZS6 .image-shape .label,#mermaid-svg-a6s3fON6gZx2JZS6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-a6s3fON6gZx2JZS6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-a6s3fON6gZx2JZS6 .rough-node .label,#mermaid-svg-a6s3fON6gZx2JZS6 .node .label,#mermaid-svg-a6s3fON6gZx2JZS6 .image-shape .label,#mermaid-svg-a6s3fON6gZx2JZS6 .icon-shape .label{text-align:center;}#mermaid-svg-a6s3fON6gZx2JZS6 .node.clickable{cursor:pointer;}#mermaid-svg-a6s3fON6gZx2JZS6 .root .anchor path{fill:#0b0b0b!important;stroke-width:0;stroke:#0b0b0b;}#mermaid-svg-a6s3fON6gZx2JZS6 .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-a6s3fON6gZx2JZS6 .edgePath .path{stroke:#0b0b0b;stroke-width:2.0px;}#mermaid-svg-a6s3fON6gZx2JZS6 .flowchart-link{stroke:#0b0b0b;fill:none;}#mermaid-svg-a6s3fON6gZx2JZS6 .edgeLabel{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);text-align:center;}#mermaid-svg-a6s3fON6gZx2JZS6 .edgeLabel p{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-a6s3fON6gZx2JZS6 .edgeLabel rect{opacity:0.5;background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);fill:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-a6s3fON6gZx2JZS6 .labelBkg{background-color:rgba(143.9999999999, 217, 73.9999999999, 0.5);}#mermaid-svg-a6s3fON6gZx2JZS6 .cluster rect{fill:hsl(30.6293706294, 65.296803653%, 62.0588235294%);stroke:hsl(30.6293706294, 25.296803653%, 52.0588235294%);stroke-width:1px;}#mermaid-svg-a6s3fON6gZx2JZS6 .cluster text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-a6s3fON6gZx2JZS6 .cluster span{color:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-a6s3fON6gZx2JZS6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(30.6293706294, 65.296803653%, 62.0588235294%);border:1px solid hsl(30.6293706294, 25.296803653%, 52.0588235294%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-a6s3fON6gZx2JZS6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#fff;}#mermaid-svg-a6s3fON6gZx2JZS6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-a6s3fON6gZx2JZS6 .icon-shape,#mermaid-svg-a6s3fON6gZx2JZS6 .image-shape{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);text-align:center;}#mermaid-svg-a6s3fON6gZx2JZS6 .icon-shape p,#mermaid-svg-a6s3fON6gZx2JZS6 .image-shape p{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);padding:2px;}#mermaid-svg-a6s3fON6gZx2JZS6 .icon-shape .label rect,#mermaid-svg-a6s3fON6gZx2JZS6 .image-shape .label rect{opacity:0.5;background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);fill:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-a6s3fON6gZx2JZS6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-a6s3fON6gZx2JZS6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-a6s3fON6gZx2JZS6 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-a6s3fON6gZx2JZS6 .layer>*{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-a6s3fON6gZx2JZS6 .layer span{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-a6s3fON6gZx2JZS6 .layer tspan{fill:#fff!important;}#mermaid-svg-a6s3fON6gZx2JZS6 .risk>*{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-a6s3fON6gZx2JZS6 .risk span{fill:#ef4444!important;stroke:#b91c1c!important;color:#fff!important;}#mermaid-svg-a6s3fON6gZx2JZS6 .risk tspan{fill:#fff!important;}

    378 处 / 21 文件

    146 处 / 2 文件

    载插件

    构造 AIAgent16 文件

    16 文件

    18 文件 反向!

    调工具

    落库

    载 provider/memory/ctx 插件

    载平台适配器插件

    0 文件 (干净!)

    hermes_cli/ + cli.py(界面层)

    gateway/(界面层)

    agent/ + run_agent.py(内核)

    tools/(工具)

    plugins/ + providers/(扩展)

    hermes_state*(状态)

    精确导入计数(grep ^(from|import) X):

    方向文件数说明
    hermes_cli/+cli.py → agent/ 21 文件 / 378 处 界面层重度向下依赖内核
    hermes_cli/+cli.py → gateway/ 2 文件 / 146 处 主要在 hermes_cli/gateway.py(41 处,它管理 gateway 进程)
    gateway/ → agent/+run_agent 16 文件 gateway 构造并运行 AIAgent(gateway/run_turn.py:1146,2163、run_turn_runner.py:1017)
    gateway/ → hermes_cli/ 16 文件 gateway 复用 CLI 设施
    agent/ → hermes_cli/ 18 文件(反向!) 内核反向依赖界面层设施(auth/config/nous_account 等),模块边界事实上被穿透
    agent/ → gateway/ 0 文件 干净——内核不依赖网关

    证据样本:agent/account_usage.py:12-13(from hermes_cli.auth import …)、agent/agent_init.py:40(from hermes_cli.config import cfg_get)。

    3.2 主流程(端到端数据传递)

    LLM Providerhermes_state (SQLite)tool handlerToolRegistry.dispatch:810model_toolshandle_function_call:85511 阶段 turn_*.py_run_conversation_turn:1423AIAgentrun_conversation:1573gateway run_turn.py:1146两道消息守卫gateway run_inbound平台适配器(CLI / Telegram / …)LLM Providerhermes_state (SQLite)tool handlerToolRegistry.dispatch:810model_toolshandle_function_call:85511 阶段 turn_*.py_run_conversation_turn:1423AIAgentrun_conversation:1573gateway run_turn.py:1146两道消息守卫gateway run_inbound平台适配器(CLI / Telegram / …)#mermaid-svg-JR0NwNhzavuv0Srp{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JR0NwNhzavuv0Srp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JR0NwNhzavuv0Srp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JR0NwNhzavuv0Srp .error-icon{fill:hsl(30.6293706294, 65.296803653%, 62.0588235294%);}#mermaid-svg-JR0NwNhzavuv0Srp .error-text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);stroke:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-JR0NwNhzavuv0Srp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JR0NwNhzavuv0Srp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JR0NwNhzavuv0Srp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JR0NwNhzavuv0Srp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JR0NwNhzavuv0Srp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JR0NwNhzavuv0Srp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JR0NwNhzavuv0Srp .marker{fill:#374151;stroke:#374151;}#mermaid-svg-JR0NwNhzavuv0Srp .marker.cross{stroke:#374151;}#mermaid-svg-JR0NwNhzavuv0Srp svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JR0NwNhzavuv0Srp p{margin:0;}#mermaid-svg-JR0NwNhzavuv0Srp .actor{stroke:hsl(210.6293706294, 25.296803653%, 47.0588235294%);fill:#4a90d9;}#mermaid-svg-JR0NwNhzavuv0Srp text.actor>tspan{fill:#fff;stroke:none;}#mermaid-svg-JR0NwNhzavuv0Srp .actor-line{stroke:hsl(210.6293706294, 25.296803653%, 47.0588235294%);}#mermaid-svg-JR0NwNhzavuv0Srp .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-JR0NwNhzavuv0Srp .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#fff;}#mermaid-svg-JR0NwNhzavuv0Srp .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#fff;}#mermaid-svg-JR0NwNhzavuv0Srp #arrowhead path{fill:#fff;stroke:#fff;}#mermaid-svg-JR0NwNhzavuv0Srp .sequenceNumber{fill:#c8beae;}#mermaid-svg-JR0NwNhzavuv0Srp #sequencenumber{fill:#fff;}#mermaid-svg-JR0NwNhzavuv0Srp #crosshead path{fill:#fff;stroke:#fff;}#mermaid-svg-JR0NwNhzavuv0Srp .messageText{fill:#fff;stroke:none;}#mermaid-svg-JR0NwNhzavuv0Srp .labelBox{stroke:hsl(210.6293706294, 25.296803653%, 47.0588235294%);fill:#4a90d9;}#mermaid-svg-JR0NwNhzavuv0Srp .labelText,#mermaid-svg-JR0NwNhzavuv0Srp .labelText>tspan{fill:#fff;stroke:none;}#mermaid-svg-JR0NwNhzavuv0Srp .loopText,#mermaid-svg-JR0NwNhzavuv0Srp .loopText>tspan{fill:#fff;stroke:none;}#mermaid-svg-JR0NwNhzavuv0Srp .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(210.6293706294, 25.296803653%, 47.0588235294%);fill:hsl(210.6293706294, 25.296803653%, 47.0588235294%);}#mermaid-svg-JR0NwNhzavuv0Srp .note{stroke:hsl(52.6829268293, 60%, 73.9215686275%);fill:#fff5ad;}#mermaid-svg-JR0NwNhzavuv0Srp .noteText,#mermaid-svg-JR0NwNhzavuv0Srp .noteText>tspan{fill:#333;stroke:none;}#mermaid-svg-JR0NwNhzavuv0Srp .activation0{fill:hsl(90.6293706294, 65.296803653%, 57.0588235294%);stroke:hsl(90.6293706294, 65.296803653%, 47.0588235294%);}#mermaid-svg-JR0NwNhzavuv0Srp .activation1{fill:hsl(90.6293706294, 65.296803653%, 57.0588235294%);stroke:hsl(90.6293706294, 65.296803653%, 47.0588235294%);}#mermaid-svg-JR0NwNhzavuv0Srp .activation2{fill:hsl(90.6293706294, 65.296803653%, 57.0588235294%);stroke:hsl(90.6293706294, 65.296803653%, 47.0588235294%);}#mermaid-svg-JR0NwNhzavuv0Srp .actorPopupMenu{position:absolute;}#mermaid-svg-JR0NwNhzavuv0Srp .actorPopupMenuPanel{position:absolute;fill:#4a90d9;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-JR0NwNhzavuv0Srp .actor-man line{stroke:hsl(210.6293706294, 25.296803653%, 47.0588235294%);fill:#4a90d9;}#mermaid-svg-JR0NwNhzavuv0Srp .actor-man circle,#mermaid-svg-JR0NwNhzavuv0Srp line{stroke:hsl(210.6293706294, 25.296803653%, 47.0588235294%);fill:#4a90d9;stroke-width:2px;}#mermaid-svg-JR0NwNhzavuv0Srp :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}alt[内联工具 (todo/memory)][注册工具]alt[有 tool_calls][无 tool_calls (finish)]loop[11 阶段循环 (每轮迭代)]上下文压缩 (50% 阈值) 时ContextCompressor 剪旧 tool 结果+ 辅助模型摘要= 唯一缓存破坏点用户发消息1MessageEvent2守卫①(base 队列) + 守卫②(runner 拦截 /stop)3放行 (非控制命令)4AIAgent(…).run_conversation(user_message, history, …)5_run_conversation_turn6begin→prepare→assemble→preflight→announce7perform_api_call (system_prompt + history + tools_schema)8response (tool_calls? 或 final)9handle_function_call(name, args)10内联结果11dispatch12handler(name, args)13结果 string14归一化结果15tool result16追加 tool 消息 (SessionDB)17继续迭代18final_response19finalize_turn:156220落库 final + messages21result dict {final_response, messages}22result23流式/最终消息24回复25用户

    3.3 关键数据结构传递

    数据形态传递路径证据
    用户消息 user_message (str / multimodal) 界面 → run_conversation → _run_conversation_turn → _LoopState.user_message conversation_loop.py:1423-1437
    API 消息 OpenAI 格式 {"role":"system|user|assistant|tool", …} _LoopState.messages → build_api_kwargs → client.chat.completions.create agent/AGENTS.md:46-47、chat_completion_helpers.py:1362
    工具 schema [{"type":"function","function":{…}}] model_tools.get_tool_definitions → 注入 api_kwargs["tools"] model_tools.py:212
    工具调用 tool_calls: [{name, args}] model response → tool_executor → handle_function_call → registry.dispatch → handler model_tools.py:855、tools/registry.py:810
    工具结果 JSON string (或 multimodal) handler → registry 归一化 → 回灌为 {"role":"tool",…} 消息 tools/registry.py:792-808
    turn 结果 dict {final_response, messages, …} finalize_turn → 返回调用方 turn_finalizer.py:435、conversation_loop.py:1562
    会话历史 SQLite 行 → List[Dict] hermes_state_sessions → run_conversation(conversation_history=…) hermes_state_sessions.py
    推理内容 assistant_msg["reasoning"] model response → 存于消息 agent/AGENTS.md:47

    四、入口与运行方式

    4.1 三个入口脚本(pyproject.toml:391-394)

    命令入口用途
    hermes hermes_cli.main:main(main.py:3351) 主 CLI:子命令调度(chat/gateway/setup/login/doctor/plugins/…)
    hermes-agent run_agent:main(run_agent.py:1434) 直接 agent 入口
    hermes-acp acp_adapter.entry:main(acp_adapter/entry.py) ACP(Agent Client Protocol)适配器,stdout 走 JSON-RPC

    交互式 REPL 另有 cli.py:main(cli.py:4439),由 hermes 的 chat 子命令或直接调用触发。

    4.2 初始化流程

    #mermaid-svg-ntqg7XG5BpONWtTx{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ntqg7XG5BpONWtTx .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ntqg7XG5BpONWtTx .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ntqg7XG5BpONWtTx .error-icon{fill:hsl(30.6293706294, 65.296803653%, 62.0588235294%);}#mermaid-svg-ntqg7XG5BpONWtTx .error-text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);stroke:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-ntqg7XG5BpONWtTx .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ntqg7XG5BpONWtTx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ntqg7XG5BpONWtTx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ntqg7XG5BpONWtTx .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ntqg7XG5BpONWtTx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ntqg7XG5BpONWtTx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ntqg7XG5BpONWtTx .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-ntqg7XG5BpONWtTx .marker.cross{stroke:#0b0b0b;}#mermaid-svg-ntqg7XG5BpONWtTx svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ntqg7XG5BpONWtTx p{margin:0;}#mermaid-svg-ntqg7XG5BpONWtTx .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-ntqg7XG5BpONWtTx .cluster-label text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-ntqg7XG5BpONWtTx .cluster-label span{color:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-ntqg7XG5BpONWtTx .cluster-label span p{background-color:transparent;}#mermaid-svg-ntqg7XG5BpONWtTx .label text,#mermaid-svg-ntqg7XG5BpONWtTx span{fill:#fff;color:#fff;}#mermaid-svg-ntqg7XG5BpONWtTx .node rect,#mermaid-svg-ntqg7XG5BpONWtTx .node circle,#mermaid-svg-ntqg7XG5BpONWtTx .node ellipse,#mermaid-svg-ntqg7XG5BpONWtTx .node polygon,#mermaid-svg-ntqg7XG5BpONWtTx .node path{fill:#4a90d9;stroke:hsl(210.6293706294, 25.296803653%, 47.0588235294%);stroke-width:1px;}#mermaid-svg-ntqg7XG5BpONWtTx .rough-node .label text,#mermaid-svg-ntqg7XG5BpONWtTx .node .label text,#mermaid-svg-ntqg7XG5BpONWtTx .image-shape .label,#mermaid-svg-ntqg7XG5BpONWtTx .icon-shape .label{text-anchor:middle;}#mermaid-svg-ntqg7XG5BpONWtTx .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ntqg7XG5BpONWtTx .rough-node .label,#mermaid-svg-ntqg7XG5BpONWtTx .node .label,#mermaid-svg-ntqg7XG5BpONWtTx .image-shape .label,#mermaid-svg-ntqg7XG5BpONWtTx .icon-shape .label{text-align:center;}#mermaid-svg-ntqg7XG5BpONWtTx .node.clickable{cursor:pointer;}#mermaid-svg-ntqg7XG5BpONWtTx .root .anchor path{fill:#0b0b0b!important;stroke-width:0;stroke:#0b0b0b;}#mermaid-svg-ntqg7XG5BpONWtTx .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-ntqg7XG5BpONWtTx .edgePath .path{stroke:#0b0b0b;stroke-width:2.0px;}#mermaid-svg-ntqg7XG5BpONWtTx .flowchart-link{stroke:#0b0b0b;fill:none;}#mermaid-svg-ntqg7XG5BpONWtTx .edgeLabel{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);text-align:center;}#mermaid-svg-ntqg7XG5BpONWtTx .edgeLabel p{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-ntqg7XG5BpONWtTx .edgeLabel rect{opacity:0.5;background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);fill:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-ntqg7XG5BpONWtTx .labelBkg{background-color:rgba(143.9999999999, 217, 73.9999999999, 0.5);}#mermaid-svg-ntqg7XG5BpONWtTx .cluster rect{fill:hsl(30.6293706294, 65.296803653%, 62.0588235294%);stroke:hsl(30.6293706294, 25.296803653%, 52.0588235294%);stroke-width:1px;}#mermaid-svg-ntqg7XG5BpONWtTx .cluster text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-ntqg7XG5BpONWtTx .cluster span{color:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-ntqg7XG5BpONWtTx div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(30.6293706294, 65.296803653%, 62.0588235294%);border:1px solid hsl(30.6293706294, 25.296803653%, 52.0588235294%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ntqg7XG5BpONWtTx .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#fff;}#mermaid-svg-ntqg7XG5BpONWtTx rect.text{fill:none;stroke-width:0;}#mermaid-svg-ntqg7XG5BpONWtTx .icon-shape,#mermaid-svg-ntqg7XG5BpONWtTx .image-shape{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);text-align:center;}#mermaid-svg-ntqg7XG5BpONWtTx .icon-shape p,#mermaid-svg-ntqg7XG5BpONWtTx .image-shape p{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);padding:2px;}#mermaid-svg-ntqg7XG5BpONWtTx .icon-shape .label rect,#mermaid-svg-ntqg7XG5BpONWtTx .image-shape .label rect{opacity:0.5;background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);fill:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-ntqg7XG5BpONWtTx .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ntqg7XG5BpONWtTx .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ntqg7XG5BpONWtTx :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-ntqg7XG5BpONWtTx .entry>*{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-ntqg7XG5BpONWtTx .entry span{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-ntqg7XG5BpONWtTx .entry tspan{fill:#fff!important;}#mermaid-svg-ntqg7XG5BpONWtTx .init>*{fill:#60a5fa!important;stroke:#2563eb!important;color:#fff!important;}#mermaid-svg-ntqg7XG5BpONWtTx .init span{fill:#60a5fa!important;stroke:#2563eb!important;color:#fff!important;}#mermaid-svg-ntqg7XG5BpONWtTx .init tspan{fill:#fff!important;}#mermaid-svg-ntqg7XG5BpONWtTx .decision>*{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-ntqg7XG5BpONWtTx .decision span{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-ntqg7XG5BpONWtTx .decision tspan{fill:#fff!important;}

    hermes

    hermes chat

    gateway run

    hermes-acp

    构造 agent

    进程启动

    哪个入口?

    main():3351进程设置 + 自愈 + 快速路径

    cli.py:main:4439HermesCLI REPL

    gateway/run.pyrun_startup.py

    acp_adapter/entry:main

    _build_cli_parser:3194argparse + set_defaults func=

    args.func(args)

    cmd_chat / cmd_gateway / _forward_command

    AIAgent(…)run_agent.py:233转发到 init_agent

    init_agentagent_init.py:2172~30 有序阶段

    _install_safe_stdio:2221

    _resolve_api_mode:2258_finalize_routing:2259

    _build_client:2278_init_fallback_chain:2279

    _load_tools:2280(触发 ToolRegistry 发现)

    _init_session_state:2281加载 config:2288

    _init_memory:2294_parse_compression_config:2296

    _resolve_context_length:2297_build_context_engine:2300

    _snapshot_primary_runtime:2307

    agent 就绪

    agent.run_conversation()→ turn 状态机

    4.3 运行时拓扑

    #mermaid-svg-sRzpfwoPVocPjQgk{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-sRzpfwoPVocPjQgk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-sRzpfwoPVocPjQgk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-sRzpfwoPVocPjQgk .error-icon{fill:hsl(30.6293706294, 65.296803653%, 62.0588235294%);}#mermaid-svg-sRzpfwoPVocPjQgk .error-text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);stroke:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-sRzpfwoPVocPjQgk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-sRzpfwoPVocPjQgk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sRzpfwoPVocPjQgk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sRzpfwoPVocPjQgk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-sRzpfwoPVocPjQgk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sRzpfwoPVocPjQgk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sRzpfwoPVocPjQgk .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-sRzpfwoPVocPjQgk .marker.cross{stroke:#0b0b0b;}#mermaid-svg-sRzpfwoPVocPjQgk svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sRzpfwoPVocPjQgk p{margin:0;}#mermaid-svg-sRzpfwoPVocPjQgk .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#fff;}#mermaid-svg-sRzpfwoPVocPjQgk .cluster-label text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-sRzpfwoPVocPjQgk .cluster-label span{color:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-sRzpfwoPVocPjQgk .cluster-label span p{background-color:transparent;}#mermaid-svg-sRzpfwoPVocPjQgk .label text,#mermaid-svg-sRzpfwoPVocPjQgk span{fill:#fff;color:#fff;}#mermaid-svg-sRzpfwoPVocPjQgk .node rect,#mermaid-svg-sRzpfwoPVocPjQgk .node circle,#mermaid-svg-sRzpfwoPVocPjQgk .node ellipse,#mermaid-svg-sRzpfwoPVocPjQgk .node polygon,#mermaid-svg-sRzpfwoPVocPjQgk .node path{fill:#4a90d9;stroke:hsl(210.6293706294, 25.296803653%, 47.0588235294%);stroke-width:1px;}#mermaid-svg-sRzpfwoPVocPjQgk .rough-node .label text,#mermaid-svg-sRzpfwoPVocPjQgk .node .label text,#mermaid-svg-sRzpfwoPVocPjQgk .image-shape .label,#mermaid-svg-sRzpfwoPVocPjQgk .icon-shape .label{text-anchor:middle;}#mermaid-svg-sRzpfwoPVocPjQgk .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-sRzpfwoPVocPjQgk .rough-node .label,#mermaid-svg-sRzpfwoPVocPjQgk .node .label,#mermaid-svg-sRzpfwoPVocPjQgk .image-shape .label,#mermaid-svg-sRzpfwoPVocPjQgk .icon-shape .label{text-align:center;}#mermaid-svg-sRzpfwoPVocPjQgk .node.clickable{cursor:pointer;}#mermaid-svg-sRzpfwoPVocPjQgk .root .anchor path{fill:#0b0b0b!important;stroke-width:0;stroke:#0b0b0b;}#mermaid-svg-sRzpfwoPVocPjQgk .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-sRzpfwoPVocPjQgk .edgePath .path{stroke:#0b0b0b;stroke-width:2.0px;}#mermaid-svg-sRzpfwoPVocPjQgk .flowchart-link{stroke:#0b0b0b;fill:none;}#mermaid-svg-sRzpfwoPVocPjQgk .edgeLabel{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);text-align:center;}#mermaid-svg-sRzpfwoPVocPjQgk .edgeLabel p{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-sRzpfwoPVocPjQgk .edgeLabel rect{opacity:0.5;background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);fill:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-sRzpfwoPVocPjQgk .labelBkg{background-color:rgba(143.9999999999, 217, 73.9999999999, 0.5);}#mermaid-svg-sRzpfwoPVocPjQgk .cluster rect{fill:hsl(30.6293706294, 65.296803653%, 62.0588235294%);stroke:hsl(30.6293706294, 25.296803653%, 52.0588235294%);stroke-width:1px;}#mermaid-svg-sRzpfwoPVocPjQgk .cluster text{fill:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-sRzpfwoPVocPjQgk .cluster span{color:rgb(33.5753424657, 95.4246575342, 159.9246575343);}#mermaid-svg-sRzpfwoPVocPjQgk div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(30.6293706294, 65.296803653%, 62.0588235294%);border:1px solid hsl(30.6293706294, 25.296803653%, 52.0588235294%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-sRzpfwoPVocPjQgk .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#fff;}#mermaid-svg-sRzpfwoPVocPjQgk rect.text{fill:none;stroke-width:0;}#mermaid-svg-sRzpfwoPVocPjQgk .icon-shape,#mermaid-svg-sRzpfwoPVocPjQgk .image-shape{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);text-align:center;}#mermaid-svg-sRzpfwoPVocPjQgk .icon-shape p,#mermaid-svg-sRzpfwoPVocPjQgk .image-shape p{background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);padding:2px;}#mermaid-svg-sRzpfwoPVocPjQgk .icon-shape .label rect,#mermaid-svg-sRzpfwoPVocPjQgk .image-shape .label rect{opacity:0.5;background-color:hsl(90.6293706294, 65.296803653%, 57.0588235294%);fill:hsl(90.6293706294, 65.296803653%, 57.0588235294%);}#mermaid-svg-sRzpfwoPVocPjQgk .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-sRzpfwoPVocPjQgk .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-sRzpfwoPVocPjQgk :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-sRzpfwoPVocPjQgk .surface>*{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-sRzpfwoPVocPjQgk .surface span{fill:#f59e0b!important;stroke:#b45309!important;color:#fff!important;}#mermaid-svg-sRzpfwoPVocPjQgk .surface tspan{fill:#fff!important;}#mermaid-svg-sRzpfwoPVocPjQgk .core>*{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-sRzpfwoPVocPjQgk .core span{fill:#4a90d9!important;stroke:#2c5f8a!important;color:#fff!important;}#mermaid-svg-sRzpfwoPVocPjQgk .core tspan{fill:#fff!important;}#mermaid-svg-sRzpfwoPVocPjQgk .note>*{fill:#10b981!important;stroke:#047857!important;color:#fff!important;}#mermaid-svg-sRzpfwoPVocPjQgk .note span{fill:#10b981!important;stroke:#047857!important;color:#fff!important;}#mermaid-svg-sRzpfwoPVocPjQgk .note tspan{fill:#fff!important;}

    共享内核

    CLI

    ACP

    定时任务

    消息网关 (gateway run)

    Electron 桌面端 (apps/desktop/)

    spawn detached

    Electron app

    hermes serve (control plane)随 app 退出而死

    gateway 进程SURVIVES 桌面退出detached spawn

    ~34 平台 bot(Telegram/Discord/Slack/…)

    cron scheduler独立会话skip_memory=True

    hermes-acpJSON-RPC on stdout

    hermes chat REPL

    hermes 子命令

    AIAgent (per-session 实例)gateway 跨 turn 缓存 (run_agent_cache.py)

    ToolRegistry 单例(进程级)

    SQLite 会话库(HERMES_HOME)

    gateway vs desktop 生命周期gateway SURVIVES 桌面退出不可「修」为随 app 死gateway/AGENTS.md:116-125

    关键生命周期不变量:hermes serve(控制面,桌面派生子进程)随 app 退出而死;消息网关 gateway run 故意存活于桌面退出(detached spawn,start_new_session/DETACHED_PROCESS,before-quit 的 SIGTERM 到不了它),保证 bot 持续运行(gateway/AGENTS.md:116-125)。Gateway 在 gateway_state.json 盖 code_sha/code_version(status.py)以便 updater 校验整个 fleet。

    4.4 配置加载与 HERMES_HOME

    • HERMES_HOME(默认 ~/.hermes)是所有状态的锚点;代码须用 get_hermes_home(),禁止硬编码 ~/.hermes(5 个 bug 在 PR #3575,AGENTS.md:267-272)。
    • Profile(多实例)是独立岛:_apply_profile_override()(main.py:508)在任何 import 前设 HERMES_HOME;profile 间无 live 继承,–clone 覆盖「从我的默认起步」(AGENTS.md:127-138)。
    • .env 仅放密钥;行为设置入 config.yaml(AGENTS.md:79-82)。

    五、架构风险 / 坏味道

    #风险条目证据(文件:行号)影响优先级
    R1 上帝文件 hermes_cli/gateway.py(6390 行/288KB/282 函数/5 类),名实不符(进程管理而非网络网关) hermes_cli/gateway.py:1-4、:5826、:82、:99、:107 难维护/难测试/高合并冲突
    R2 上帝文件 gateway/run.py(285KB 门面,承担过多协调) gateway/run.py(facade,phases 在 run_*.py) 门面过厚,单点改动风险
    R3 上帝文件 cli.py(4635 行/212KB REPL + 模块级 helper 混入) cli.py:2530、:807-1313 REPL 与关闭/ANSI/终端检测混杂
    R4 上帝文件 gateway/run_turn.py(221KB turn 编排) gateway/run_turn.py:1146,2163、:3819 turn 逻辑过度集中
    R4b god-object GatewayRunner 组合 16 个 Mixin,隐式共享可变状态属性面庞大 gateway/run.py:3332-3337、:3364-3384 mixin 间隐式状态耦合,难追溯属性来源
    R4c facade↔collaborator 近似循环:run_turn_runner.py 反向 import gateway.run gateway/run_turn_runner.py:1013 分层破坏,导入脆弱
    R5 god-class ContextCompressor(277KB,组合 3 Mixin:SummaryDispatch+MicroCompaction+ContextEngine) agent/context_compressor.py:1678 单类混合 3 个关注点
    R6 god-module auxiliary_client.py(379KB/7601 行,路由+取消+client 工厂+进度钩子混杂) agent/auxiliary_client.py:4278、:204、:167 低内聚,难测
    R7 god-module conversation_compression.py(216KB,编排+提交栅栏+超时执行器+fallback 链+状态模板) agent/conversation_compression.py:3558、:366、:661 多职责同居
    R8 god-adapter:telegram(382KB)/discord(352KB)/slack(339KB) 平台适配器单文件过大 plugins/platforms/telegram/adapter.py、discord/adapter.py、slack/adapter.py 每平台单文件巨石
    R9 循环依赖 cli.py ↔ mixin:mixin 普遍 from cli import _looks_like_slash_command 等 cli_info_mixin.py:434、cli_tui_mixin.py:1348、cli_loops_mixin.py:525、cli_modal_mixin.py:122、cli_model_switch_mixin.py:787 导入顺序脆弱、难独立测试
    R10 模块边界穿透:agent/ → hermes_cli/ 反向 18 文件(内核依赖界面层 auth/config) agent/account_usage.py:12-13、agent/agent_init.py:40 分层被破坏,内核非自洽
    R11 AIAgent.__init__ ~60 参数(凭据/路由/回调/会话/预算/凭据池…)巨参列表 run_agent.py:233-272 难用/难扩展/易误传
    R12 进程全局可变状态 _last_resolved_tool_names,子代理执行期间读到的值可能 stale model_tools.py:248、tools/AGENTS.md:52-53 子代理工具桥看到父代理集
    R13 check_fn TTL 缓存进程级,多 session 答案泄漏;multiplex/浏览器须显式绕过 tools/registry.py:244-267、:300-340 需谨慎 bypass
    R14 三套配置加载器并存,key 覆盖不一致风险 hermes_cli/AGENTS.md:69-72 CLI 见到 gateway 不见的 key
    R15 根级 hermes_state_* 15 扁平文件未包化 hermes_state.py 等(仓库根级) 命名空间污染、难定位
    R16 hermes_cli/config.py 3849 行仅 2 类,加载/校验/路径/容器/安装检测混杂 hermes_cli/config.py:48、:1059、:463 函数式巨石
    R17 gateway/platforms/base.py 4263 行,BasePlatformAdapter ABC 过厚 gateway/platforms/base.py:1797 基类承载过多
    R18 256 文件扁平 tools/ 目录,仅 5 子包 tools/ 目录列举 可导航性成本
    R19 动态 schema 跨工具引用注入,rewriter 顺序敏感 model_tools.py:337-467 顺序错则模型幻觉不存在工具
    R20 cron/scheduler.py 177KB god-file cron/scheduler.py 调度逻辑过度集中

    六、技术债

    #技术债项证据(文件:行号)影响优先级
    D1 临时插件兼容垫片未回迁:2026-09 拆分 PR #102117 的 COMPAT_MANIFEST.md(3869 行)/compat_manifest.json(12551 行)仍待回退移除(2026-09-14 到期) COMPAT_MANIFEST.md:1-4、compat_manifest.json:1-5 外部插件依赖旧路径;到期未回退则双套路径并存
    D2 2026-09 拆分的 turn_*.py 已完成,但 agent 压缩三件套(auxiliary_client/context_compressor/conversation_compression)未跟进拆分 agent/turn_*.py(29 文件已拆)vs agent/auxiliary_client.py:1(379KB 未拆) turn 循环已治理,压缩子系统仍是 god-file
    D3 hermes_cli/gateway.py 进程管理未按后端拆分(已有 gateway_windows.py 先例可循) hermes_cli/gateway.py:5826、hermes_cli/gateway_windows.py 最大单文件债务
    D4 cli.py↔mixin 循环回引未抽公共模块 cli_info_mixin.py:434 等 5 处 导入脆弱,阻断独立测试
    D5 AIAgent.__init__ ~60 参数未分组为配置对象 run_agent.py:233-272 接口臃肿,易误用
    D6 hermes_state_* 根级扁平未包化为 hermes_state/ 包 仓库根级 15 文件 命名空间污染
    D7 三套配置加载器无 CI 校验 key 集合差 hermes_cli/AGENTS.md:69-72 配置漂移风险
    D8 平台适配器 god-adapter(telegram/discord/slack 300KB+)未按关注点拆 plugins/platforms/telegram/adapter.py 平台维护成本高
    D9 ToolRegistry 单例 + 进程全局可变状态(_last_resolved_tool_names、check_fn 缓存)在多 profile/多 session 下的正确性依赖 scope-key 纪律 tools/registry.py:373-385、model_tools.py:248 multiplex 场景需谨慎
    D10 依赖钉版维护成本:精确 pin + exclude-newer=14 days + CVE 例外白名单需持续手工维护 pyproject.toml:411-417 供应链防御的持续开销
    D11 gateway/platforms/base.py ABC 过厚(4263 行),新适配器继承面过大 gateway/platforms/base.py:1797 适配器作者认知负担

    七、重构建议

    指导原则(沿用 AGENTS.md:53-55):「Refactor god-files into clean modules」是被鼓励的工作;大型机械式 +N/-N 抽取 PR 是「wanted work」,每个抽出行都能追溯到抽取请求本身。重构顺序遵循 turn_*.py 已验证的「门面 + 兄弟阶段文件」模式。

    7.1 P0(立即,解除最大风险)

    #建议针对风险/债落地步骤证据参考
    P0-1 拆 hermes_cli/gateway.py 按进程后端分模块 R1/D3 抽出 gateway_proc_pid.py(PID 扫描)、gateway_proc_systemd.py、gateway_proc_launchd.py、gateway_proc_s6.py、gateway_proc_windows.py(已有先例)、gateway_restart.py、gateway_snapshot.py(GatewayRuntimeSnapshot:82);门面 gateway_command:5826 仅做派发 hermes_cli/gateway.py:1-4、hermes_cli/gateway_windows.py
    P0-2 断 cli.py↔mixin 循环回引 R9/D4 抽 hermes_cli/_slash_util.py 收纳被回引的模块级符号(_looks_like_slash_command、_DIM、_cprint、_panel_box_width);mixin 改从该模块 import,禁止 from cli import … cli_info_mixin.py:434、cli_tui_mixin.py:1348、cli_loops_mixin.py:525、cli_modal_mixin.py:122、cli_model_switch_mixin.py:787
    P0-3 回迁 COMPAT 垫片(按计划 2026-09-14 回退 PR #102117 的兼容 commit) D1 revert 添加 compat 的 commit;scripts/check_compat_pointers.py 已禁止树内使用,回退后外部插件须已迁移 COMPAT_MANIFEST.md:1-4

    7.2 P1(短期,建立边界与拆 god 文件)

    #建议针对风险/债落地步骤证据参考
    P1-1 拆 agent 压缩三件套 R5/R6/R7/D2 (a) auxiliary_client.py 按关注点拆:auxiliary_routing.py(_resolve_auto_route:4278)、auxiliary_cancellation.py(:204)、auxiliary_client_factory.py(:167)、auxiliary_progress.py(:305);(b) ContextCompressor god-class 沿 3 Mixin 轴拆为独立策略类;© conversation_compression.py 抽出 commit-fence/timeout/fallback 为协调模块 agent/auxiliary_client.py:4278、agent/context_compressor.py:1678、agent/conversation_compression.py:3558
    P1-2 拆 cli.py 模块级 helper 下沉 R3 _arm_exit_watchdog:682、_run_cleanup:807、_detect_light_mode 等下沉到 hermes_cli/cli_lifecycle.py / cli_terminal_detect.py;HermesCLI:2530 仅留 REPL 骨架 cli.py:2530、:682、:807-1313
    P1-3 补模块边界 CI:禁止 agent/ import hermes_cli/ R10 加 scripts/ci/check_layering.py(仿 check_compat_pointers.py)拦截 agent/*.py 中的 from hermes_cli / import hermes_cli;将 auth/config 等被反向依赖的设施下沉到 hermes_core 中立包或反转依赖 agent/account_usage.py:12-13、agent/agent_init.py:40
    P1-4 拆 gateway/run_turn.py R4 按 turn 子阶段(agent 构造 :1146、hygiene turn、turn runner 派发 :2163)拆兄弟文件,门面仅协调 gateway/run_turn.py:1146,2163

    7.3 P2(中期,结构优化)

    #建议针对风险/债落地步骤证据参考
    P2-1 hermes_state_* 包化 R15/D6 15 根级文件迁入 hermes_state/ 包,加 __init__.py 重导出保持外部 import 兼容 根级 hermes_state*.py
    P2-2 AIAgent.__init__ 参数分组 R11/D5 引入 AgentCredentials、AgentRouting、AgentCallbacks、AgentSessionContext、AgentBudget 等配置对象,__init__ 接收分组对象而非 60 散参 run_agent.py:233-272
    P2-3 配置加载器 key 一致性 CI R14/D7 加 CI 比对 load_cli_config / load_config / 原始 YAML 的 key 集合差,差异即失败 hermes_cli/AGENTS.md:69-72
    P2-4 平台适配器 god-adapter 拆分 R8/D8 telegram/discord/slack 按消息收发/媒体/命令/格式化拆兄弟文件,沿用 signal_format.py/yuanbao_media.py 先例 plugins/platforms/telegram/adapter.py、gateway/platforms/signal_format.py
    P2-5 check_fn 缓存 scope 化 R13/D9 默认 per-session 而非进程级;multiplex/浏览器无需显式 bypass tools/registry.py:244-267、:300-340
    P2-6 gateway/platforms/base.py ABC 瘦身 R17/D11 把非通用能力下沉为可选 Mixin,BasePlatformAdapter 仅留契约 gateway/platforms/base.py:1797
    P2-7 cron/scheduler.py 拆分 R20 按调度/失败处理/交付/事件拆兄弟文件 cron/scheduler.py

    7.4 重构路线图

    #mermaid-svg-3ieQYFHNAR8EzhN6{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#fff;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-3ieQYFHNAR8EzhN6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-3ieQYFHNAR8EzhN6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-3ieQYFHNAR8EzhN6 .error-icon{fill:hsl(340.1183431953, 84.07960199%, 44.4117647059%);}#mermaid-svg-3ieQYFHNAR8EzhN6 .error-text{fill:rgb(46.5298507462, 236.9701492537, 173.8656716418);stroke:rgb(46.5298507462, 236.9701492537, 173.8656716418);}#mermaid-svg-3ieQYFHNAR8EzhN6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-3ieQYFHNAR8EzhN6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3ieQYFHNAR8EzhN6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3ieQYFHNAR8EzhN6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-3ieQYFHNAR8EzhN6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3ieQYFHNAR8EzhN6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3ieQYFHNAR8EzhN6 .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-3ieQYFHNAR8EzhN6 .marker.cross{stroke:#0b0b0b;}#mermaid-svg-3ieQYFHNAR8EzhN6 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3ieQYFHNAR8EzhN6 p{margin:0;}#mermaid-svg-3ieQYFHNAR8EzhN6 .mermaid-main-font{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-3ieQYFHNAR8EzhN6 .exclude-range{fill:#eeeeee;}#mermaid-svg-3ieQYFHNAR8EzhN6 .section{stroke:none;opacity:0.2;}#mermaid-svg-3ieQYFHNAR8EzhN6 .section0{fill:hsl(340.1183431953, 84.07960199%, 44.4117647059%);}#mermaid-svg-3ieQYFHNAR8EzhN6 .section2{fill:#10b981;}#mermaid-svg-3ieQYFHNAR8EzhN6 .section1,#mermaid-svg-3ieQYFHNAR8EzhN6 .section3{fill:white;opacity:0.2;}#mermaid-svg-3ieQYFHNAR8EzhN6 .sectionTitle0{fill:rgb(46.5298507462, 236.9701492537, 173.8656716418);}#mermaid-svg-3ieQYFHNAR8EzhN6 .sectionTitle1{fill:rgb(46.5298507462, 236.9701492537, 173.8656716418);}#mermaid-svg-3ieQYFHNAR8EzhN6 .sectionTitle2{fill:rgb(46.5298507462, 236.9701492537, 173.8656716418);}#mermaid-svg-3ieQYFHNAR8EzhN6 .sectionTitle3{fill:rgb(46.5298507462, 236.9701492537, 173.8656716418);}#mermaid-svg-3ieQYFHNAR8EzhN6 .sectionTitle{text-anchor:start;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-3ieQYFHNAR8EzhN6 .grid .tick{stroke:lightgrey;opacity:0.8;shape-rendering:crispEdges;}#mermaid-svg-3ieQYFHNAR8EzhN6 .grid .tick text{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;fill:#fff;}#mermaid-svg-3ieQYFHNAR8EzhN6 .grid path{stroke-width:0;}#mermaid-svg-3ieQYFHNAR8EzhN6 .today{fill:none;stroke:red;stroke-width:2px;}#mermaid-svg-3ieQYFHNAR8EzhN6 .task{stroke-width:2;}#mermaid-svg-3ieQYFHNAR8EzhN6 .taskText{text-anchor:middle;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-3ieQYFHNAR8EzhN6 .taskTextOutsideRight{fill:#fff;text-anchor:start;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-3ieQYFHNAR8EzhN6 .taskTextOutsideLeft{fill:#fff;text-anchor:end;}#mermaid-svg-3ieQYFHNAR8EzhN6 .task.clickable{cursor:pointer;}#mermaid-svg-3ieQYFHNAR8EzhN6 .taskText.clickable{cursor:pointer;fill:#003163!important;font-weight:bold;}#mermaid-svg-3ieQYFHNAR8EzhN6 .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163!important;font-weight:bold;}#mermaid-svg-3ieQYFHNAR8EzhN6 .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163!important;font-weight:bold;}#mermaid-svg-3ieQYFHNAR8EzhN6 .taskText0,#mermaid-svg-3ieQYFHNAR8EzhN6 .taskText1,#mermaid-svg-3ieQYFHNAR8EzhN6 .taskText2,#mermaid-svg-3ieQYFHNAR8EzhN6 .taskText3{fill:#fff;}#mermaid-svg-3ieQYFHNAR8EzhN6 .task0,#mermaid-svg-3ieQYFHNAR8EzhN6 .task1,#mermaid-svg-3ieQYFHNAR8EzhN6 .task2,#mermaid-svg-3ieQYFHNAR8EzhN6 .task3{fill:#10b981;stroke:hsl(160.1183431953, 44.07960199%, 29.4117647059%);}#mermaid-svg-3ieQYFHNAR8EzhN6 .taskTextOutside0,#mermaid-svg-3ieQYFHNAR8EzhN6 .taskTextOutside2{fill:#fff;}#mermaid-svg-3ieQYFHNAR8EzhN6 .taskTextOutside1,#mermaid-svg-3ieQYFHNAR8EzhN6 .taskTextOutside3{fill:#fff;}#mermaid-svg-3ieQYFHNAR8EzhN6 .active0,#mermaid-svg-3ieQYFHNAR8EzhN6 .active1,#mermaid-svg-3ieQYFHNAR8EzhN6 .active2,#mermaid-svg-3ieQYFHNAR8EzhN6 .active3{fill:hsl(160.1183431953, 84.07960199%, 62.4117647059%);stroke:#10b981;}#mermaid-svg-3ieQYFHNAR8EzhN6 .activeText0,#mermaid-svg-3ieQYFHNAR8EzhN6 .activeText1,#mermaid-svg-3ieQYFHNAR8EzhN6 .activeText2,#mermaid-svg-3ieQYFHNAR8EzhN6 .activeText3{fill:#fff!important;}#mermaid-svg-3ieQYFHNAR8EzhN6 .done0,#mermaid-svg-3ieQYFHNAR8EzhN6 .done1,#mermaid-svg-3ieQYFHNAR8EzhN6 .done2,#mermaid-svg-3ieQYFHNAR8EzhN6 .done3{stroke:grey;fill:lightgrey;stroke-width:2;}#mermaid-svg-3ieQYFHNAR8EzhN6 .doneText0,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneText1,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneText2,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneText3{fill:#fff!important;}#mermaid-svg-3ieQYFHNAR8EzhN6 .doneText0.taskTextOutsideLeft,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneText0.taskTextOutsideRight,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneText1.taskTextOutsideLeft,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneText1.taskTextOutsideRight,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneText2.taskTextOutsideLeft,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneText2.taskTextOutsideRight,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneText3.taskTextOutsideLeft,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneText3.taskTextOutsideRight{fill:#fff!important;}#mermaid-svg-3ieQYFHNAR8EzhN6 .crit0,#mermaid-svg-3ieQYFHNAR8EzhN6 .crit1,#mermaid-svg-3ieQYFHNAR8EzhN6 .crit2,#mermaid-svg-3ieQYFHNAR8EzhN6 .crit3{stroke:#ff8888;fill:red;stroke-width:2;}#mermaid-svg-3ieQYFHNAR8EzhN6 .activeCrit0,#mermaid-svg-3ieQYFHNAR8EzhN6 .activeCrit1,#mermaid-svg-3ieQYFHNAR8EzhN6 .activeCrit2,#mermaid-svg-3ieQYFHNAR8EzhN6 .activeCrit3{stroke:#ff8888;fill:hsl(160.1183431953, 84.07960199%, 62.4117647059%);stroke-width:2;}#mermaid-svg-3ieQYFHNAR8EzhN6 .doneCrit0,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneCrit1,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneCrit2,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneCrit3{stroke:#ff8888;fill:lightgrey;stroke-width:2;cursor:pointer;shape-rendering:crispEdges;}#mermaid-svg-3ieQYFHNAR8EzhN6 .milestone{transform:rotate(45deg) scale(0.8,0.8);}#mermaid-svg-3ieQYFHNAR8EzhN6 .milestoneText{font-style:italic;}#mermaid-svg-3ieQYFHNAR8EzhN6 .doneCritText0,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneCritText1,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneCritText2,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneCritText3{fill:#fff!important;}#mermaid-svg-3ieQYFHNAR8EzhN6 .doneCritText0.taskTextOutsideLeft,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneCritText0.taskTextOutsideRight,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneCritText1.taskTextOutsideLeft,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneCritText1.taskTextOutsideRight,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneCritText2.taskTextOutsideLeft,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneCritText2.taskTextOutsideRight,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneCritText3.taskTextOutsideLeft,#mermaid-svg-3ieQYFHNAR8EzhN6 .doneCritText3.taskTextOutsideRight{fill:#fff!important;}#mermaid-svg-3ieQYFHNAR8EzhN6 .vert{stroke:navy;}#mermaid-svg-3ieQYFHNAR8EzhN6 .vertText{font-size:15px;text-anchor:middle;fill:navy!important;}#mermaid-svg-3ieQYFHNAR8EzhN6 .activeCritText0,#mermaid-svg-3ieQYFHNAR8EzhN6 .activeCritText1,#mermaid-svg-3ieQYFHNAR8EzhN6 .activeCritText2,#mermaid-svg-3ieQYFHNAR8EzhN6 .activeCritText3{fill:#fff!important;}#mermaid-svg-3ieQYFHNAR8EzhN6 .titleText{text-anchor:middle;font-size:18px;fill:rgb(46.5298507462, 236.9701492537, 173.8656716418);font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-3ieQYFHNAR8EzhN6 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}09-1309-2009-2710-0410-1110-18拆 hermes_cli/gateway.py 进程后端 断 cli.py↔mixin 循环回引 回迁 COMPAT 垫片 (revert #102117 compat) 拆 agent 压缩三件套 拆 cli.py 模块级 helper 模块边界 CI (禁 agent→hermes_cli) 拆 gateway/run_turn.py hermes_state_* 包化 AIAgent.__init__ 参数分组 配置加载器 key 一致性 CI 平台 god-adapter 拆分 check_fn 缓存 scope 化 BasePlatformAdapter ABC 瘦身 cron/scheduler.py 拆分 P0 立即P1 短期P2 中期Hermes-Agent 重构路线图


    关键结论与下一步

  • 架构成熟且纪律严格:窄腰(AIAgent + ToolRegistry 单例)+ 厚边缘(34 平台 / 39 模型 provider / 记忆/看板/图像/上下文引擎插件 + 13 技能包)的分层清晰,受两条强不变量(prompt 缓存神圣、内核窄腰)约束(AGENTS.md:18-29)。turn 状态机已成功拆为 29 个 turn_*.py 兄弟文件(agent/conversation_loop.py:1423),是 god-file 治理的成功范本。

  • 调度设计优秀:CLI 子命令经 argparse func= + _forward_command 惰性转发(main.py:3351/1789);slash 经 COMMAND_REGISTRY + _SLASH_DISPATCH + 命名约定双路,无 elif 阶梯(AGENTS.md:14);插件三来源发现 + last-writer-wins 覆盖(providers/__init__.py:1-20)。

  • 最大债务集中:(a) 4 个界面层 god 文件——hermes_cli/gateway.py(6390 行)、gateway/run.py(285KB)、cli.py(4635 行)、gateway/run_turn.py(221KB);(b) 3 个 agent 压缩/辅助 god 文件——auxiliary_client.py(379KB)、context_compressor.py(277KB)、conversation_compression.py(216KB)未跟进 turn_*.py 的拆分;© cli.py↔mixin 循环回引 + agent/→hermes_cli/ 反向 18 文件使模块边界事实上被穿透;(d) 平台 god-adapter(telegram 382KB 等)。

  • 下一步:按 P0→P1→P2 路线图执行——P0 拆 hermes_cli/gateway.py + 断 cli↔mixin 循环 + 回迁 COMPAT 垫片;P1 拆 agent 压缩三件套 + 拆 cli.py + 加模块边界 CI(禁 agent→hermes_cli)+ 拆 run_turn.py;P2 包化 hermes_state + AIAgent 参数分组 + 配置加载器一致性 CI + 平台适配器拆分 + check_fn scope 化。所有拆分沿用已验证的「门面 + 兄弟阶段文件」模式,大型机械式抽取 PR 是项目明确鼓励的「wanted work」(AGENTS.md:53-55)。


  • 报告生成方式:只读分析(git/源码只读),所有结论附「文件:行号」证据;模块细节经 4 个并行只读子代理深挖 + 主代理亲自核验。Mermaid 图表使用彩色主题。

    赞(0)
    未经允许不得转载:171主机测评 » 【hermes-agent】Hermes-Agent v0.21.2 系统级架构分析
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址