← Open Source
cclank

Hermes-Wiki

Hermes agent + LLM Wiki + 源代码 完成 Hermes agent wiki

TutorialsTool-specific tutorials
Open on GitHub
Momentum
+0stars in 24 hours0.0%
654
Stars
72
Forks
—
This week
3
Contributors
Created 2026-04-08 · Updated 2026-10-02 · #13395 today
Top developers
README

Hermes Agent Architecture Wiki

Wiki Source Knowledge Base Changelogs Version Verified License

基于 Nous Research Hermes Agent 源码的深度架构文档。 所有页面均经过逐行源码验证,确保准确性与时效性。


目录结构

核心架构

记忆与会话

工具与能力

  • browser-tool-architecture: 多后端浏览器自动化,accessibility tree+三层安全防护
  • web-tools-architecture: 八大后端插件化搜索/提取(WebSearchProvider ABC + 注册表),LLM 智能内容压缩(web_crawl 工具于 2026-05-29 移除 #33824)
  • code-execution-sandbox: execute_code 沙箱,7 工具限制+UDS/File RPC 两种通信模式
  • voice-mode-architecture: Push-to-talk 语音交互,STT(5 Provider)+ TTS(10 内置 Provider,含 Piper 本地神经 TTS)
  • context-references: @file/@folder/@diff/@url/@git 引用系统,安全沙箱+注入量限制
  • fuzzy-matching-engine: 8 策略链模糊匹配,从精确到相似度匹配
  • large-tool-result-handling: 三层溢出防护(工具内截断/单结果持久化/轮次聚合预算)
  • lsp-integration: NEW v0.14 LSP 语义诊断集成,agent/lsp/ 11 modules + file-mutation footer 三层后写校验
  • i18n-and-locales: NEW v0.13 i18n 薄切片本地化(仅 hermes 自身静态消息,不动 agent 输出)

性能与优化

安全与可靠性

多 Agent

平台与扩展

更新日志(50 个,最新优先 — 完整列表见 index.md)

  • 2026-06-21-update: 179 commits 单日同步(hermes-agent 5a53e0f0 → 87ab373,v0.17.0 维护未发新版;约 70 fix / 16 feat / 13 test / 6 chore / 16 docs + 23 merge;~26h 单日窗口;266 文件 +17145/−1079)— ⭐ Compression cluster 9 commit(14ef631 agent/context_compressor.py:1935-1950 _effective_protect_first_n() 衰减 + 7ace96b rotation 三状态修复(goal 经 hermes_cli/goals.py:282 migrate_goal_to_session move-not-copy + 子 create_session 失败回滚 agent.session_id = old_session_id + :694-701 on_session_start(platform=) 转发)+ 2f3177a agent/auxiliary_client.py:121 _aux_interrupt_protection = threading.local() + aux_interrupt_protection() ctx mgr 让 Codex aux 流尊重压缩摘要保护(#23975)+ 1f874df fallback 摘要 active_task 单点(#49307)+ b6a4638 空 content raise 不再静默替换为空摘要(#11978/#11914)+ 3509be7 _MIN_CTX_TRIGGER_RATIO = 0.85 + _compute_threshold_tokens() 让 64K-ctx 模型在 ~54.4K 触发(#14690)+ d0de460 TUI /compress 显示前后摘要(#46686)+ 04730f3 新 hermes_cli/context_switch_guard.py preflight-compress 预警 + 41e0c10 重复压缩告警走 _emit_status(#36908))— ⭐ Kanban cluster 8 commit + lifecycle hooks(d164ed0 4 reclaim RESET SQL 加 AND claim_lock IS ?(#50366)+ 1f4c5ae _resolve_auto_decompose_settings 每 tick 重读(#50358)+ 84ba83b bounded init lock 10s(#50353)+ 9630ec6 _default_spawn env["TERMINAL_CWD"]=workspace(#50348)+ e217fd4 三新 plugin hook kanban_task_claimed/completed/blocked 注册 hermes_cli/plugins.py:192-194 VALID_HOOKS + _fire_kanban_lifecycle_hook write commit 后 best-effort(#50349)+ e581740 _dispatch_tick_lock board-scoped 非阻塞 flock(#50331)+ 15cfc28 无路径 worktree 锚 board.default_workdir + d79f67f _ensure_git_worktree 实物化 + _git_common_dir 短路复用(worktree 现真有 linked worktree 在 /.worktrees/ 上分支 wt/))— ⭐ Security cluster 9 commit(ed96669 tools/url_safety.py:285-287 + :359-365 ip_str.split('%')[0] 剥 IPv6 scope-ID + fail-closed + ed3d12a WebSocket 空 peer fail-closed 4 endpoint + 5b45fb2 kanban markdown HTML 白名单消毒 plugins/kanban/dashboard/dist/index.js:337/:354/:368/:387 + ae46699/87615f4 restore_quick_snapshot 路径穿越(snapshot_id + snap_dir + manifest src/dst 全 .relative_to() 校验)+ 3b56d3a kanban tool payload secret redact 经 redact_sensitive_text(force=True) + a18bae6 _SECRET_CONFIG_KEYS frozenset + redact_config_value() 递归 masker(#50245/#50313 config show/set api_key 屏蔽)+ 9078b4b tools/file_tools.py:286 _is_blocked_device_path normpath + 20 symlink 跳 walk + def3f63 _is_blocked_device(filepath, base_dir=) 锚 task cwd + 71274f2/16899ae _looks_like_read_file_line_numbered_content 拒 read_file 行号显示文本经 write_file 回写)— ⭐ Gateway/API server cluster 13 commit(b5b8a4c fresh-final 尊重 prefers_fresh_final_streaming 适配器 decline + __dict__ 双查防 MagicMock(#47048)+ 4c206b9/79f2978 5 plugin adapter sys.path.insert(parents[3]) 修 cron 命名空间冲突(#49410)+ 03563da hygiene 硬上限 400→5000 默(#50194)+ 4c349e8 hygiene 无法 rotate 时保留 transcript(#21301 P1)+ 8ac5e90 _JSON_MEDIA_TOOL_PATH_FIELDS + _collect_history_media_paths() 让 image_generate JSON-payload 路径入历史去重集(#46627)+ c11c510 busy 模式文本 follow-up 经 _queue_or_replace_pending_event FIFO 不再 newline-merge(#43066 sub-bug 2)+ d19aabb _finalize_shutdown_agents flush _session_messages 经 idempotent identity-tracked(#13121)+ 93ea9b0 入站媒体下载 128MiB cap(防 Discord Nitro 500MB OOM)+ bb77a8b 未映射 Windows gateway 经 detached watcher 重生(#50090/#50373)+ 7a131f7 stateless HTTP path supports_async_delivery=False 经 contextvar + notify_unsupported/sync fallback(#50319)+ e499d69 gateway.api_server.max_concurrent_runs 统一并发 cap 跨 3 endpoint + OpenAI 风格 429 + Retry-After(#50007)+ 51a338a + 0ee7546 + b577f25 + 4d7bb38 active_agents 轮边界 publish + /api/status 加 gateway_busy/drainable + parse_active_agents 三处统一)— ⭐ Telegram cluster 9 commit(6183e8c Bot API 10.1 rich messages 默改 off hermes_cli/config.py:2161 "rich_messages": False + adapter _coerce_bool_extra 经 platforms.telegram.extra.rich_messages: true opt-in;CJK 不走 rich + 表格不强换行 + slash 富文本保留换行 + chunk 标记移出代码栅栏 + native rich echo reply 文本恢复 + 流式 final 经 editMessageText 重索引 + finalize 前暂停 typing + 最终回复后 typing indicator 不残留)— ⭐ Cron cluster 6 commit(07424da ticker BaseException 不死 + heartbeat-aware status + f1f36b3 迁移期时区偏移修复防双触发 + 65d7c7f action='run' 立即执行 + 4cc28aa Telegram DM-topic 经 DeliveryRouter(#22773)+ d548908 直播适配器显式 confirmation 步骤(#38922/#47056/#43014)+ 73b9226 model.default 解析 fail-fast)— Plugins/Session lifecycle 7 commit(9d883ac ctx.profile_name wrap get_active_profile_name() 经 HERMES_HOME(#50346)+ 9f67ba1 finalize_turn 三段 cleanup 各自 try/except + result["cleanup_errors"](#50009)+ b17180d AIAgent.close() step 7 session_db.end_session() + 9e4fe32 background review fork opt out + 56255f8 _collect_delegate_child_ids() 用父 id seed found 集合 + 99233fa/c7e8854 CLI/TUI force-quit/signal 持久化)— Misc(c0409a8 SendResult.error_kind 7 类 typed(too_long/bad_format/forbidden/not_found/rate_limited/transient/unknown)+ 2609bcc i18n Spanish 完整(README.es.md 220 / CONTRIBUTING.es.md 602 / SECURITY.es.md 322)+ 65a477f Desktop About 加 Update now(#50186)+ 8666fd7 模型可见性跨 provider 保留 hide-all + 5e3e89c Hindsight 健康 grace 可配(#50341)+ 7bc6f18 Hindsight root 跳 + 472c068 MCP "unknown method" ping keepalive(#50028)+ Photon 三修 + 2f4f23f Codex app-server item/started → Telegram tool-progress 桥接(#38835)+ e0498bd Bedrock prompt-cache 计价 + 跨区域前缀剥除(#50307)+ a4b1554/491579f WhatsApp JID 规范 + bridge dir HERMES_HOME mirror + 4467c22 chat-completions timestamp 剥 + ac83365 Windows install 8.3 短 %TEMP% 展长 + 6f5f58e/41ba90f poll() 只读 + CLI drain dedup(#10156)+ 3e354b6 Copilot headers 保留 + 6984026 browser SSRF 容器化 + 8a506ed credential_pool env-seeded 非破坏 + 587b5b9 memory provider 外部 backup paths(#50325)+ 模型切换 3 修(#50375/#23767)+ 824c9d3 model.api_base→model.base_url 别名(#50385)+ a9c8025 approval honor 中断(#8697)+ Email 配置硬化(#40715)+ 16+ docs commit + AUTHOR_MAP 10+ salvage)— 验证基线 /tmp/hermes-agent clone @ 87ab373 + 4 个并行 research agent 实证(A: Security 9 commit / B: Kanban 8 + lifecycle hooks / C: Compression 9 + Gateway/API 13 / D: Telegram 9 + Cron 6 + Misc 30+)

  • 2026-06-20-update: 69 commits 单日同步(hermes-agent 01f581d8d → 5a53e0f0,v0.17.0 维护未发新版;约 34 fix / 8 feat / 6 chore / 5 test / 3 refactor / 3 docs / 1 style + 8 merge;~22h 单日窗口;250 文件 +12225/−3725)— ⭐ Compression in-place compaction 6 commit(compression.in_place:bool=False opt-in 保留单 session_id;新 archive_and_compact 软归档非破坏性(hermes_state.py:2700+ + :2734-2737 UPDATE messages SET active=0, compacted=1)+ 新 compacted 列 3 态语义(:570 + :3489-3494 文档 active=1/compacted=0=live, active=0/compacted=1=archive in search, active=0/compacted=0=rewind out search)+ search_messages WHERE 放宽 (m.active=1 OR m.compacted=1)(:3528-3532 主 FTS5 + :3611-3614 trigram)+ 边界 hook 双模触发(agent/conversation_compression.py:625 _is_boundary = bool(_old_sid) or in_place)+ gateway auto-compress 强 history_offset=0(gateway/run.py:15872-15874)+ /compress slash gate 扩 if rotated or _in_place:(gateway/slash_commands.py:2636-2659)+ agent._last_compaction_in_place 信号 + 解 PR body 列 14 个 rotation 引发 issue 集群 #33618/#14238/#33907/#36777/#45117/#42228/#48989)— ⭐ Background delegation fan-out PR #49734(单 commit 5 文件 +721/-333;dispatch_async_delegation_batch(tools/async_delegation.py:337)批量当单异步槽位;runner _execute_and_aggregate(tools/delegate_tool.py:2247)join 所有子;完成事件 is_batch=True(:389)+ 单 consolidated 渲染 _format_async_delegation(tools/process_registry.py:1549-1628 header :1586 TASK i/N :1614);模型级 background 入参作废由 _dispatch_delegate_task(run_agent.py:5210-5222)顶层强制 background = (not _is_subagent);3 并发限 delegation.max_concurrent_children + max_async_children=3 默 + max_spawn_depth;满槽拒绝退化 inline sync 非排队;a6f08ff0 单行 docs 澄清 subagent 模型 config 级非 per-call)— ⭐ Blank Slate setup mode PR #36733(第三 setup 模式 hermes_cli/setup.py:2853-2861(不新 subcommand)+ 235 行 wizard :3056-3134 + agent.disabled_toolsets 全减集到 {file, terminal}(:3026)+ platform_toolsets.cli=["file","terminal"](:3006)+ 全 opt-out web/browser/code/vision/memory/delegation/cronjob/skills/imagegen/kanban/plugins/mcp/gateway/compression/checkpoints/smart_model_routing/session_reset(_blank_slate_minimize_config :3031)+ set_bundled_skills_opt_out(True)(:3117-3118)+ _blank_slate_walkthrough :3137-3214 逐节 opt-in + gating invariant tools_config.py:1528-1536 _get_platform_tools 末尾减 agent.disabled_toolsets)— ⭐ Gateway adapters → bundled plugins 9 个迁移(单 commit 56001054(salvage PR #41284)124 文件 +3647/-2583;slack/dingtalk/whatsapp/matrix/feishu/telegram/wecom/email/sms 全从 gateway/platforms/.py 迁到 plugins/platforms//{adapter,plugin.yaml,__init__}.py + 旧路径全删无 stub;signal 不迁仍在 gateway/platforms/signal.py 1701 行;注册 register(ctx) PluginContext → ctx.register_platform() → PlatformEntry → platform_registry.register();发现 _scan_directory walk 一级 + plugin.yaml manifest;Matrix YAML 补 4 键 allowed_users/ignore_user_patterns/process_notices/session_scope(plugins/platforms/matrix/adapter.py:4288 _apply_yaml_config :4297/:4312/:4317/:4319);~60 test 原地 retarget;单一新 test_slack_plugin_setup.py;c3292794 跟进补 2 漏字符串字面量)— Desktop 浮动 composer popout PR #49488(renderer-only 不开新 BrowserWindow 无 IPC channel;apps/desktop/src/store/composer-popout.ts nanostore + localStorage hermes.desktop.composerPopout.{enabled,position} + POPOUT_WIDTH_REM=19.5 + apps/desktop/src/app/chat/composer/index.tsx:196 popoutAllowed=!isSecondaryWindow() 二级窗强制 docked + apps/desktop/src/app/chat/composer/hooks/use-popout-drag.ts:93 useComposerPopoutGestures + dock zone 4 常量 DOCK_ZONE_BOTTOM_PX=72/CENTER_TOLERANCE_PX=150/VERTICAL_FALLOFF_PX=260/HORIZONTAL_FALLOFF_PX=220;无键盘快捷 —— 纯手势双击+拖拽切换)— Provider 失效转移 5 commit(5a53e0f0 aux 摘要 401/403 abort(agent/context_compressor.py:771 _last_summary_auth_failure + :1593-1602 _is_auth_error + :2335 不管 config flag abort)+ f22dd8a7 agent loop is_auth 真失败转 fallback(agent/conversation_loop.py:2842-2858 + 新 retry flag turn_retry_state.py:65 auth_failover_attempted: bool = False)+ c884ff64 rewrite_prompt_model_identity(agent/chat_completion_helpers.py:1045-1071)只改最后一次出现 + _sync_failover_system_message(agent/conversation_loop.py:469-492)8 站点接 + c253b073 clear_model_endpoint_credentials 中央 helper(hermes_cli/config.py:3934)+ 12 picker flow 接入 + 95a3affc Nous picker 重 load_config() + 37a4dd49 heal poisoned inference_base_url 经 DEFAULT_NOUS_INFERENCE_URL(hermes_cli/auth.py:71)双站点)— Signal 加固 14 commit(_validate_send_result(gateway/platforms/signal.py:1020)解 results[] + SignalRateLimitError 抛 + 新 gateway/platforms/signal_format.py 140 行共享 markdown→Signal UTF-16 偏移 textStyles + ADTS AAC 识别(:83 _guess_extension lines 105-109 if (data[1] & 0xF6) == 0xF0: return ".aac")+ ffmpeg remux to MP4(:141 _remux_aac_to_m4a)+ OrderedDict echo ring 50→512 + 5min TTL(:315-316)+ _consume_sent_timestamp(:1110)替 set.discard + quote-cache _sent_message_timestamps OrderedDict[str, None] FIFO(:324 + :809-820)+ reply-to-own 追踪 _extract_quote_author/_quote_references_own_message(:773/:790)+ MessageEvent 加 reply_to_author_id/name/is_own_message 3 字段 + 群组自身 mention 全剥(:640-641)+ stop-typing RPC(:1517-1538)+ 新 env_float(utils.py:326)+ 11 文件 22 处 env cast 替为 env_int/env_float;PR #49260/#49530/#49558/#49563/#49583/#49678/#49680)— Teams 原生附件 PR #49308(_send_media_attachment shared helper(plugins/platforms/teams/adapter.py:1192-1240)+ send_video/send_voice/send_document + microsoft_teams.api.Attachment SDK + URL ref / data URI 双路径,无显式 size cap)— Language-aware title generation PR #45296(auxiliary.title_generation.language config + _TITLE_PROMPT/_TITLE_PROMPT_PINNED_LANGUAGE 双模板(agent/title_generator.py:22-34)+ detection-by-instruction 无 code-level locale 检测)— Creative-ideation skill v2.1.0 PR #42402(22 新方法 + method-catalog/heuristics/anti-slop/exercises;28 文件 +2269/-190)— Dashboard 隐藏 sidecar 会话 PR #49269(HERMES_SESSION_SOURCE ContextVar 多站点 + _session_source + source="tool" 标记)— 内联键盘 model picker 默 persist PR #49176 salvage(gateway/slash_commands.py:1155 is_global=persist_global + :1219-1247 config.yaml 写 + 扁平字符串 coerce 嵌套)— 终止 busy session internal-event 中断 PR #49738(gateway/run.py:4172-4184 if getattr(event, "internal", False): return False —— delegate_task background + notify_on_complete 不再中止活跃轮)— gateway resume restart loop 修(_strip_dangling_tool_call_tail gateway/run.py:940-980)— 工具 model whitelist 不剥 prompt/image_urls + slash exec dispatch payload TUI/Desktop 双修 + Raft check_fn 静默 + Desktop GPU 加速被禁横幅(IPC hermes:get-remote-display-reason + `` 5 语 i18n)+ 隐藏 link-title 窗口静音(setAudioMuted(true) 防 YouTube watch 自播)+ 右侧栏 tooltip + memory shutdown hook warning + CLI agent ref publish 让 on_session_end 生效 + 5 条 AUTHOR_MAP salvage(IamSanchoPanza/hakanpak/lkz-de/rratmansky/w31rdm4ch1nZ)+ 3 stale comment 清(tools/memory_tool.py:20,141-144,197-200 + tools/fuzzy_match.py:9 + run_agent.py:1531) — 验证基线 /tmp/hermes-agent clone @ 5a53e0f0 + 4 个并行 research agent 实证(A: Compression in-place + auth failover 11 commit / B: Blank Slate + delegation + composer popout + Teams + lang titles + Creative-ideation 8 commit / C: gateway adapter migration + Signal 16 commit / D: 23 个 misc commit + AUTHOR_MAP + 7 merges)

  • 2026-06-19-update: 181 commits 跨日同步 + ⭐ v0.16.0 → v0.17.0 release(hermes-agent 03d9a95 → 01f581d8d,v0.17.0 已发经 2bd1977d8 chore: release v0.17.0 (2026.6.19) + 866f1d65c (#49236) Desktop fallback;约 76 fix / 39 feat / 14 test / 14 chore / 10 refactor / 4 docs / 24 merge;~24h 主活跃窗口;282 文件 +20287/−1661)— ⭐ Gateway Multiplex Phase 0-4 主轴 9 commit(单 gateway 进程内多 profile 并发;gateway/config.py:553 multiplex_profiles:bool=False opt-in + gateway/session.py:616-651 _session_key_namespace(profile)/build_session_key(profile=) 默 profile→"agent:main" 命名→"agent:" + :97-104 SessionSource.profile:Optional[str]=None wire 字段 + :813-831 SessionStore._resolve_profile_for_key(source) + gateway/platforms/webhook.py:199-202 注册 /p/{profile}/webhooks/{route_name} 与默 /webhooks/{route_name} 双路由 + :60-65 _PROFILE_REJECTED 哨兵 + :413-441 _resolve_request_profile() 验证 → 404 + :693-696 Source.profile stamping + 新 agent/secret_scope.py 205 行 Phase 2 fail-closed credential 隔离::35 _MULTIPLEX_ACTIVE:bool=False + :39-50 set_multiplex_active/is_multiplex_active + :55-56 _SECRET_SCOPE:ContextVar[Optional[Mapping]] + :60-66 class UnscopedSecretError(RuntimeError) + :69-80 set_secret_scope/reset_secret_scope/current_secret_scope + :97-113 _GLOBAL_ENV_EXACT=frozenset({PATH, HOME, ...}) allowlist + :114-116 _GLOBAL_ENV_PREFIXES + :122-163 get_secret(name) -> Optional[str] multiplex active + 无 scope + 不 allowlist → raise;否则 os.environ.get + :166-209 load_env_file/build_profile_secret_scope + gateway/run.py:46-52 @contextmanager _profile_runtime_scope(profile_home) + :1269 class MultiplexConfigError(RuntimeError) + :1275-1283 _PORT_BINDING_PLATFORM_VALUES=frozenset({webhook, api_server, msgraph_webhook, feishu, wecom_callback, bluebubbles, sms}) 不可多路 + :2401 _profile_adapters:Dict[str, Dict[Platform, BasePlatformAdapter]] + :5367-5370 set_multiplex_active() + :6726-6794 _start_secondary_profile_adapters()->int orchestrator + 凭据指纹 + :6796-6854 _start_one_profile_adapters()->int 端口/凭据冲突检测 raise MultiplexConfigError + :6857-6864 _make_profile_message_handler() stamp source.profile + :6866-6879 _adapter_credential_fingerprint() salted hash + hermes_cli/runtime_provider.py 所有 os.getenv 走 _getenv→get_secret + agent/credential_pool.py env fallback 经 get_secret + tools/mcp_tool.py MCP config interpolation 用 get_secret + hermes_cli/gateway.py:3854-3933 _guard_named_profile_under_multiplexer(force=False) lifecycle guard 防 named profile 在 multiplex 已运行时单独启动 + gateway/status.py:578-603 write_runtime_status(served_profiles=) 写 runtime_status.json + 新文档 website/docs/user-guide/multi-profile-gateways.md 133 行 opt-in/路由/凭据隔离/端口绑定限制/--force + 4 套测试 phase0_165行/phase1_73行/credential_isolation_88行/adapter_registry_136行/lifecycle_55行/secret_scope_130行)— ⭐ Cron Chronos NAS-mediated scale-to-zero provider 11 commit(新 cron/scheduler_provider.py:27-178 class CronScheduler(ABC) 实验性 + name 抽象 + is_available() invariant:不得网络 IO + start(stop_event, *, adapters, loop, interval) 阻塞调度循环 + stop/on_jobs_changed/fire_due/reconcile 五 hook + class InProcessCronScheduler name="builtin" 60s 阻塞 ticker + :114-151 resolve_cron_scheduler() -> CronScheduler 读 cron.provider 失败 degrade builtin + 新 plugins/cron/__init__.py 344 行 discovery machinery + @register_cron_scheduler 装饰器 + load_cron_scheduler(name) + gateway/run.py _start_cron_ticker() deprecated shim + _start_gateway_housekeeping() 拆出 channel-dir/cache cleanup/paste sweep/curator + start_gateway() resolve_cron_scheduler().start() + hermes_cli/web_server.py _start_desktop_cron_ticker() 同走 resolver + cron/scheduler.py 抽 run_one_job shared helper + cron/jobs.py:1076-1090 _machine_id() HERMES_MACHINE_ID env 或 hostname:pid + :1093-1127 claim_job_for_fire(job_id, *, claim_ttl_seconds=300) -> bool 多机 at-most-once CAS:missing/disabled/paused→False / fresh claim→False / stale claim→overwrite + True;赢时 stamp fire_claim={at, by} 推进 next_run_at + :979-981 mark_job_run() 完成清 fire_claim + 新插件 plugins/cron/chronos/__init__.py 241 行 class ChronosCronScheduler(CronScheduler) + _armed:dict cache + name="chronos" + is_available() config check only 无网络 + _have_nous_token()/_get_client()/_callback_url() lazy + start() reconcile + RETURN(非阻塞,由 NAS webhook 推触发)+ on_jobs_changed()→reconcile + fire_due()→ABC default (claim + run_one_job) + re-arm 下一次 + reconcile()→arm 缺失/改变 cancel orphan + 新 _nas_client.py 123 行 class NasCronClient HTTP wrapper (provision/cancel/list) + 新 verify.py 103 行 _FIRE_PURPOSE="cron_fire" + verify_nas_fire_token(*, token, expected_audience, jwks_or_key, issuer, leeway_seconds) -> Optional[Dict] 仅 RS/ES family(symmetric 拒)+ 校验 aud/exp/nbf/iss/purpose + 失败 None 不抛 + get_fire_verifier() -> Callable pluggable indirection + gateway/platforms/api_server.py:3345-3402 _handle_cron_fire(request) -> web.Response POST /api/cron/fire Bearer + get_fire_verifier(cron.chronos) 401 on bad token / 400 on 缺 job_id / 202 + background provider.fire_due() + dashboard 同 surface + cron/scheduler.py:961-1041 _run_job_script() :1034 env=_sanitize_subprocess_env(os.environ) 防 provider 凭据泄漏给用户脚本 + tools/environments/local.py:206 _sanitize_subprocess_env(base_env, extra_env) -> dict blocklists 复用 + 测试 scheduler_provider/claim_job_for_fire 84行/chronos_cron 203行/chronos_verify 182行(真 RS256 sign-verify)/cron_fire_webhook 152行 + 新 docs docs/chronos-managed-cron-contract.md + bfb6e0bb3 docs(cron): CronScheduler provider + cron.provider key)— ⭐ MCP late-connecting tools snapshot 8 commit(修:MCP HTTP/SSE 异步 connect 期间 agent build snapshot 时它们尚未 list_tools → 工具不入 system prompt;本 series:tools/mcp_tool.py:4361-4480 refresh_agent_mcp_tools(agent, *, quiet_mode=False) 每轮调用:snapshot registry._generation (line 4424) 在 rebuild 前 → rebuild → atomic publish:published_gen_raw = getattr(agent, "_tool_snapshot_generation", -1) (4458) → if snapshot_generation < published_gen: return 拒 stale (4460) → agent._tool_snapshot_generation = max(published_gen, snapshot_generation) (4479) + agent/turn_context.py:126-129 build_turn_context() 廉价预检 has_registered_mcp_tools() 然后 refresh_agent_mcp_tools(quiet_mode=True) + 3 轮 adversarial review:round 1 cache parity/gates/races / round 2 stale-publish race/parity holes / round 3 generation capture adjacency(捕获从"rebuild 开始"挪到"rebuild 前最后一刻"缩 race 窗)+ revert ACP rebuild 改回原始路径 + harden generation guard + tools/mcp_tool.py:22 服务端 config 文档 keepalive_interval:10 + :291 _DEFAULT_KEEPALIVE_INTERVAL=180 + :292 _MIN_KEEPALIVE_INTERVAL=5 + :1694-1696 keepalive_interval = max(_MIN_KEEPALIVE_INTERVAL, float(config.get("keepalive_interval", _DEFAULT_KEEPALIVE_INTERVAL))) 让短 TTL HTTP/SSE MCP 不每 idle 周期 reconnect + 新 :1235-1389 class ElicitationHandler MCP 1.1+ 服务端主动 elicitation 协议::1258 _OUTER_TIMEOUT_GRACE_SECONDS=5 + :1260 __init__(server_name, config, owner) + :1281 async __call__(context, params) + :1320 import request_elicitation_consent from tools.approval + :1342 captured = getattr(self.owner, "_pending_call_context", None) 抓 contextvars + :1354 captured.copy().run(request_elicitation_consent, ...) gateway-aware approval routing 让 Telegram/Discord/Slack 等平台正确弹审批 UI)— ⭐ Managed scope 系统级 /etc/hermes 配置层 10 commit(新 hermes_cli/managed_scope.py 215 行::33 _DEFAULT_MANAGED_DIR=Path("/etc/hermes") POSIX 默 + :56 $HERMES_MANAGED_DIR env override 优先(IT/bootstrap)+ :52-71 get_managed_dir() -> Optional[Path] 三级回退(env override → /etc/hermes 非 pytest → None)+ :74 _invalidate_managed_cache() 测试 hook + :115-125 load_managed_config() -> dict LRU cached + fail-open(读不到/格式错→{})+ :128-134 load_managed_env() -> Dict[str, str] 同 fail-open + :137-177 apply_managed_overlay(config) -> dict 深合并 + env expansion + :202-204 managed_config_keys() -> set 扁平 dotted key 集 + :207-209 is_key_managed(dotted_key) -> bool + :212-214 is_env_managed(name) -> bool + hermes_cli/config.py:5673-5726 user config 加载后调 apply_managed_overlay + :6119-6211 写 hermes config set/env set 经 is_key_managed/is_env_managed 拒 managed 键 + :5840-5842 managed_keys = managed_scope.managed_config_keys() doctor 输出 + managed .env 后置覆盖(管理员强制 override user)+ cli.py 内 fast-path 也接 overlay + standalone loaders 都补 + config→env 桥经 overlay + 新文档 website/docs/admin/managed-scope.md 含部署模式 + 路径权限 + 重启行为 + IT 工作流 + bf9a0481f 测试 pin config/env load 行为 before managed scope 防 regression)— ⭐ Unified provider catalog 8 commit(新 hermes_cli/provider_catalog.py:45-52 _ACCOUNTS_AUTH_TYPES=frozenset({...}) + :56-68 @dataclass(frozen=True) class ProviderDescriptor 字段 slug/label/description/auth_type/tab("keys"|"accounts")/api_key_env_vars/base_url_env_var/signup_url/order + :71-73 tab_for_auth_type(auth_type) -> str + :83-165 provider_catalog() -> list[ProviderDescriptor] 单源含 OpenAI/Anthropic/Bedrock/OpenRouter/xAI/Codex/Custom + :168-170 provider_catalog_by_slug() -> dict + hermes_cli/web_server.py:3971-4056 _catalog_provider_env_metadata() 经 catalog 派生 Keys tab metadata + :4059-4100 get_env_vars(profile) /api/env 挂 provider/provider_label hints → Desktop Keys tab 按 backend grouping + :5836-5881 _build_oauth_catalog() Accounts tab 经 catalog flow="external" 含 catalog-only 未连 provider + :5884-5924 list_oauth_providers(profile) + Desktop apps/desktop/src/app/settings/providers-settings.tsx:121 OAuthPicker() + apps/desktop/src/app/settings/keys-settings.tsx 按 provider 分组 + API-keys 搜索框 + priority-sorted by ProviderDescriptor.order + apps/desktop/src/hermes.ts:361 getEnvVars()/.:408 listOAuthProviders() + parity test 锁 GUI ⊇ hermes model provider 集含 Bedrock + catalog-only OAuth status fallthrough)— Raft 新平台插件 3 commit(新 plugins/platforms/raft/plugin.yaml name:raft-platform / label:Raft / kind:platform / version:1.0.0 / author:botiverse / kind:platform;requires_env:RAFT_PROFILE 设置即 enable;adapter "external agent via wake-channel bridge",loopback HTTP 接 wake hints,不碰消息正文 / 投递游标 + plugins/platforms/raft/adapter.py 774 行::174 _make_activity_event schema raft-activity.v1 + :260 class ActivityQueue bounded telemetry 队列 + :438 class RaftAdapter HTTP 服务器 + :768-774 注册 7 activity hooks + bridge subprocess stdin=DEVNULL + AUTHOR_MAP [email protected]→xxchan)— simplify-code skill db744e7d1(skills/software-development/simplify-code/SKILL.md 212 行 灵感来自 Claude Code /simplify;3 risk tier SAFE(auto-apply 无 semantics 改变)/CAREFUL(verify 后)/RISKY(flag only) + Chesterton's Fence lines 90-91 删前 git blame 查 fence 缘由 + AI slop 检测 (redundant comments / as any cast / 过度 null-check / unused param) + silent failure 检测 (空 catch / 错误抑制无日志 / Optional 默静默) + 3 并行 subagent reviewer reuse/quality/efficiency + 触发关键词 simplify / review my code / clean up;不 auto-run)— html-artifact skill 9362ce257 (#48899) 加后立即 revert 92451151c HEAD 上 ABSENT 三个 sub-skill sketch/architecture-diagram/concept-diagrams 仍独立 — Relay WS-only Phase 3 (#48294) + hosted gateway 实际 connect 修 (#48828) + self-provision 触发改 relay-config+NAS-token 非 is_managed() (#48724) + terminal 块禁内部 gateway lifecycle (#245b95b09)(d2c53ff55 gateway/relay/adapter.py:85,89 set_inbound_handler/set_interrupt_inbound_handler 全绑 WebSocketRelayTransport 删 signed-HTTP fallback;a64fc490f hosted gateway 真 connect inbound/outbound round-trip;2c6e266e8 gateway/relay/__init__.py:207 self_provision_relay() :219 触发改 "relay_url 配 + NAS token + 无 secret 钉";245b95b09 tools/terminal_tool.py:2068-2082 gateway 进程内拒 hermes gateway start/stop/restart 防 agent 自杀)— image_generate 加 image-to-image / editing c02192ff6 (#48705)(agent/image_gen_provider.py +79 ImageGenProvider ABC generate() 加 keyword-only image_url + reference_image_urls + 新方法 capabilities() 声明 modalities + max_reference_images(默 0 text-only 向后兼容)+ success_response.modality + normalize_reference_images() + tools/image_generation_tool.py +426 顶层 schema 暴露 + 动态 schema 反映当前模型 actual edit capability + 6 plugin 更新:openai +146 行 DALL-E edit endpoint / xai +104 行 grok image edit / krea +69 行 保 dict-shaped image_style_references verbatim 防 KeyError / fal +41 行 text-to-image delegation 时不传 None kwargs(保字节相同)/ openai-codex +28 行 text-only 友好错误消息 / 测试 image_to_image 349 行 + 文档 image-gen-provider-plugin/image-generation/tools-reference)— Desktop UX 18 commit(Cmd+K Restart gateway apps/desktop/src/app/command-palette/index.tsx:368 + apps/desktop/src/store/system-actions.ts:15 $gatewayRestarting jotai atom 状态栏 spinner + 重命名 Restart messaging→Restart gateway + 选 logs 可复制 + Restart action 在 messaging save/toggle toasts + Refresh Models cache bust apps/desktop/src/app/shell/model-menu-panel.tsx:119 refresh:true + 通知 click apps/desktop/src/lib/session-ids.ts:15 resume stored session id + selectable slash/shell logs preview-console.tsx:88 selectedLogIds + reasoning-effort picker web/src/components/ReasoningPicker.tsx 在 chat sidebar + session switcher panel apps/desktop/src/app/session-switcher.tsx:16 Chat tab + sessions 实时刷新 dc5cb0a44 + sessions sort by 最近活动 0d7abd555 + prefill 指令通知 b936f92b2 (/goal /undo) + vitest 入 dashboard npm test)— Gateway 鲁棒性 12 commit(cached agent max_iterations/max_turns 每轮 refresh from config gateway/run.py:1206-1214 _current_max_iterations() + :14802-14804 + 测 + Windows restart silent outage 修 gateway/status.py:166-203 looks_like_gateway_command_line() 严格 matcher + hermes_cli/gateway.py:321-490 _scan_gateway_pids() + hermes_cli/gateway_windows.py:1304-1325 _wait_for_gateway_absent() + :1327-1353 restart() hardened + Discord 非对话 metadata 跟踪 gateway/run.py:429-439 _non_conversational_metadata() + plugins/platforms/discord/adapter.py:622-625 _DISCORD_NONCONVERSATIONAL_METADATA_KEYS=frozenset + :668-720 class _DiscordNonConversationalMessageTracker 防 startup status message 切割 history backfill + Telegram /title 命名 topic gateway/slash_commands.py:2805-2821 propagate _schedule_telegram_topic_title_rename() 非仅 auto-titles + Telegram opt-in 在线/离线指示 gateway/platforms/telegram.py:477-494 _status_indicator_enabled/_status_online_text/_status_offline_text + :2245-2298 _set_status_indicator() async + Discord reply 上下文 hydrate plugins/platforms/discord/adapter.py:28-40 class _Snowflake + :4255-4257 _fetch_channel_context(reply_target=) + :4315-4382 reply-anchored window scan + clarify dict-choice unwrap tools/clarify_tool.py:23-53 _flatten_choice() + :88-90 调 + :137-142 CLARIFY_SCHEMA docstring 明确 options 仅在 choices[] 不在 question text + Discord 同 _flatten_choice + soft-boundary truncate buttons)— Kanban 5 commit(机器全局 singleton 锁 gateway/kanban_watchers.py:26-59 _acquire_singleton_lock(lock_path) + :62-74 _release_singleton_lock + :660-680 init + :1129-1143 双退出释放 防 embedded dispatcher 多副本 + hermes_cli/kanban_db.py:128-132 RECLAIM_DEFER_GRACE_SECONDS=120 + :3296-3305 release_stale_claims() defer 守 + :5154-5169 _worker_survived_termination() + :5172-5210 _defer_reclaim_for_live_worker() 延 claim_expires by GRACE_SECONDS + :5449-5458 detect_stale_running() 同守 + :5131-5145 _terminate_reclaimed_worker() ProcessLookupError → terminated=True + cross-platform fcntl/msvcrt + UTF-8 encoding)— OpenViking + Hindsight 6 commit(OpenViking structured sync attribution + tool parts;plugins/memory/openviking/__init__.py:124-125 _SYNC_TRACE_ENV + _OPENVIKING_RECALL_TOOL_NAMES + :163-164 _sync_trace_enabled() + :2461-2464 空 tool_id batch skip guard + _TOOL_STATUS_* 常量 + alias sets + 复用 env_var_enabled + agent/message_content.py _message_text/_message_matches_text static + Hindsight plugins/memory/hindsight/__init__.py:53 _MIN_CLIENT_VERSION="0.6.1" + :101-111 _ensure_cloud_client_dependency() lazy install + :1004 在 import 前调 + plugin.yaml:5 hindsight-client>=0.6.1)— Agent 8 commit(Anthropic aux 经 stream agent/anthropic_adapter.py:2538-2589 _is_stream_unavailable_error/create_anthropic_message + run_agent.py:4079-4085 _anthropic_messages_create + FTS5 trigram fallback 不禁 FTS5 hermes_state.py:775-792 _is_fts5_unavailable_error/_is_tokenizer_unavailable_error + :858-862 _warn_fts5_unavailable() 条件触发 + 非可重试 API 错误摘要 _summarize_api_error() 防 HTML 漏入对话 + hermes_cli/debug_bundle.py 含 gui.log + 1d2e35967 session store 不可用 visible warning + e48554a3e worktree 互斥锁防多进程 clobber)— CLI/TUI 10 commit(/model 切换默认跨会话持久 hermes_cli/model_switch.py:362-391 resolve_persist_behavior() + :304-365 parse_model_flags() is_session flag + cli.py:6974 + hermes_cli/config.py:1590 cli_refresh_interval=1.0 状态栏 keep alive + viewport 宽度变化清屏 c06898098 (#49120) + 状态栏 idle 不隐 1b04e4ede (#49105) + tmux 内 fast-echo 关 ab8f06381/e52fffb60 防游标漂移含 SSH-from-tmux + TUI 托管 dashboard chat 不死 15e3b64b7 + idle exit 重启 12dfcfdf7 + /update 守 hosted a7b4fbcbc + DASHBOARD_TUI_MODE 重用 + pending-input 经 command.dispatch() 169952563 (#48848))— Dashboard 8 commit(chat TUI argv 出 event loop d06104a9e (#48561) + /api/cron/fire c34840e22 + DS Button prefix/size API d573e7c9e + upload temp file disconnect 清理 + python-multipart 锁 6752da9a7 (NS-501) + Slack allowed users wildcard 83c034bd5 + Slack setup hints + 验证 + sessions sort by 最近活动)— Sessions/Backup/Misc 10 commit(hermes_state.py 递归 CTE 让 child session 继承祖先 title 跨 compression lineage 6ad0bc20f/65d050cf0/8c70346e3 + hermes_cli/backup.py EXCLUDED_BACKUP_DIRS 排 .venv/node_modules/pycache e738c0833 (#48887) + Stripe Projects skill docs cfb55de5e (#48673) + undici audit bump b266ad748 (#49113) + hashless npm via importNpmLock 3ca0ef7e3 (#48883) + Docker WebUI 只读源 36851fa57 (#48541) + Windows managed-node 路径解析 7a7b56d49/fcc169057/d4e7dd609 (#49254) + 多条 AUTHOR_MAP salvage:lgalabru→PR#43112 / salesondemandio→PR#42664 / OpenViking / carlos.dddo / Cdddo / JoaoMarcos44 / channkim→PR#47049 / Sahil-SS9→PR#48466/44919/44909/42209 / tt-a1i / xxchan)— 验证基线 /tmp/hermes-agent clone @ 01f581d8d + 4 个并行 research agent 实证(A: Gateway Multiplex + Chronos cron 11 commit / B: MCP late-connect + managed_scope + provider catalog 17 commit / C: Raft + simplify-code + Relay + Desktop UX 14 commit / D: Gateway 鲁棒性 + Kanban + Agent/CLI/TUI + Dashboard 40+ commit)

  • 2026-06-18-update: 164 commits 跨日同步(hermes-agent d1ecebc → 03d9a95,仍 v0.16.0 未发新版;约 70 fix / 25 feat / 16 test / 12 chore / 10 refactor / 7 docs / 3 perf / 21 merge;~48h 双日窗口;285 文件 +25193/−1708)— ⭐ Relay/A2 Trust-Boundary 传输 Phase 0-3 主轴 23 commit(新文件 gateway/relay/descriptor.py:77 CapabilityDescriptor frozen dataclass JSON-serializable handshake payload + contract_version, platform, label, max_message_length, supports_draft_streaming/edit/threads, markdown_dialect, len_unit, emoji, platform_hint, pii_safe + to_json()/from_json() forward-compat + :76-120 from_platform_entry() + CONTRACT_VERSION=1 additive-only;新 gateway/relay/adapter.py:44-130 RelayAdapter(BasePlatformAdapter) 从 descriptor 读 MAX_MESSAGE_LENGTH/message_len_fn(chars/utf16)/supports_draft_streaming/supports_code_blocks + :32-41 _utf16_len/_LEN_FNS + :79-110 connect() 注 _on_inbound handler + :139-149 on_interrupt(session_key, chat_id) → interrupt_session_activity + :190-221 send_follow_up(session_key, kind, content, metadata) → SendResult token-less A2 op + gateway/config.py:167 Platform.RELAY + :7-9 _PLATFORM_CONNECTED_CHECKERS RELAY checker;新 gateway/relay/transport.py:1-75 RelayTransport(Protocol) lifecycle(connect/disconnect/handshake)+ inbound(set_inbound_handler)+ outbound(send_outbound/send_follow_up/get_chat_info/send_interrupt);新 gateway/relay/ws_transport.py:102-299 WebSocketRelayTransport newline-delimited JSON 帧协议 + 7 帧类型 hello/descriptor/inbound/outbound/interrupt/outbound_result/interrupt_inbound + uuid requestId 相关 per-request future + 30s handshake/outbound timeout + send_interrupt fire-and-forget + :57-100 _event_from_wire SessionSource snake_case wire→dataclass + :158-174 _upgrade_headers Authorization Bearer 在 /relay WS upgrade;新 gateway/relay/auth.py:50-135 make_token/make_upgrade_token(gateway_id, secret, ttl_seconds)/verify_token(token, secrets) base64url(payload:exp:sig) HMAC_SHA256 多 secret 轮换窗 + Python port of connector's relayAuthToken.ts/deliverySigning.ts 字节级互证;新 gateway/relay/inbound_receiver.py:204 InboundDeliveryReceiver aiohttp 双 POST routes /message 和 /interrupt 验 x-relay-signature/x-relay-timestamp over 原始 raw request 字节(re-serialize 破 HMAC)+ 300s replay 窗 + per-tenant delivery key verify list;新 hermes_cli/gateway_enroll.py:250 hermes gateway enroll 子命令 (subcommands/gateway.py:50 cmd_gateway_enroll) 解 Nous Portal access token + POST {enrollmentToken, gatewayId} 到 connector /relay/enroll + 持久化 GATEWAY_RELAY_ID/SECRET/DELIVERY_KEY 到 ~/.hermes/.env + is_managed() 拒;Phase 3 gateway/relay/__init__.py:116-340 self_provision_if_managed() MANAGED + relay 已配 + secret 未钉时 in-process 自供给:resolve_nous_access_token() → POST connector /relay/provision 断言 endpoint+route keys → 设 env 让 register_relay_adapter() 读到 + 凭据仅驻内存(永不写 ~/.hermes/.env)+ 显式钉的 secret 尊重跳 self-provision + relay_endpoint()/relay_route_keys()/_provision_url()/_post_provision() + 12 单测覆盖;237fa7d29 删 HERMES_GATEWAY_RELAY dark-launch flag 改配置驱动 relay_url() 读 GATEWAY_RELAY_URL 或 gateway.relay_url + register_relay_adapter() URL 已配时注册无配时 no-op + gateway/run.py GatewayRunner.start() 在插件发现后调 + 失败 log 不阻启;6 套测试:test_descriptor.py:66(6 测 roundtrip/frozen/unknown-key/optional defaults)+ test_descriptor_from_entry.py:64 + test_relay_adapter.py:77 + test_relay_roundtrip.py:122(Discord+Telegram round-trip 泛化证明,utf16+markdown_v2 dialect)+ test_relay_registration.py:55(配置驱动 gate)+ test_relay_interrupt.py:69 + test_ws_transport.py:179(live in-process websockets server real handshake/inbound/outbound/follow_up/disconnect pending waiter fail)+ test_auth.py:167(upgrade token/deliver signature/rotation 窗)+ test_inbound_receiver.py:150 + test_no_stub_leak.py:44 CI guard:production 路径不 import StubConnector + test_relay_sheds_crypto.py A2 不变式:relay 路径不 import 平台 crypto(ed25519/HMAC/webhook sig)+ test_relay_contract_conformance.py 钉 contract docs ↔ Python 字段(SessionSource.to_dict() 7 wire 键也加入文档)+ 整套 57 passed;测试用 tests/gateway/relay/stub_connector.py:66 StubConnector(in-memory 测试专用 + canned send_result + push_inbound test driver);新 docs/relay-connector-contract.md:143 v1 契约 + §6 重写 A2 trust-boundary 模型:connector 是唯一 crypto/identity 边界 + §6.1 channel-auth schemes + SessionSource 判别器表(Discord guild_id REQUIRED)+ signed-body verify-at-edge + additive-only contract_version 政策) — ⭐ /billing 终端账单 #45449(新 agent/billing_view.py 295 行 surface-agnostic BillingState/parse_money/format_money/CardInfo/MonthlyCap/AutoReload dataclass + fail-open builder + 新 hermes_cli/nous_billing.py 406 行 类型化 HTTP client 接 4 个 /api/billing/* endpoint + BillingScopeRequired/BillingRateLimited/BillingAuthError 异常 + Idempotency-Key 强制 + cli.py +657 行 5 个 screen overview/buy→confirm→poll/auto-reload/monthly-limit(read-only)+ _show_billing handler + 2s 节流/5min 可取消 poll + tui_gateway/server.py +216 行 billing.state/charge/charge_status/auto_reload/step_up JSON-RPC + 结构化 success envelope result.ok + result.error= + 新 ui-tui/src/app/slash/commands/billing.ts 332 行 全 TUI overlay 状态机 + ConfirmReq overlay 复用 + insufficient_scope→lazy step-up/no_payment_method→portal 错分支 + 新 ui-tui/src/components/billingOverlay.tsx 684 行 + hermes_cli/auth.py +97 行 NOUS_BILLING_MANAGE_SCOPE/nous_token_has_billing_scope()/step_up_nous_billing_scope() lazy 重 auth 持久化按 _login_nous 方式但不弹模型 picker;6 套测试共 1266 行 51+6+7+16+12+53 行(billing_view 决策+预算+fail-open / CLI / scope-stepup / portal URL / RPC / vitest);端到端 Decimal money(server 发 decimal 串 → 保 Decimal → 仅显示格式化)+ poll loop token 缓存避锁争用 + 401 时重 resolve fresh + CLI 非交互(_app is None)渲文本+portal deep-link 永不 prompt + CommandDef 入 _SLACK_VIA_HERMES_ONLY 经 Slack /hermes 保 50-cap 对齐 + 截图 .github/pr-screenshots/45449/) — ⭐ OpenViking session-boundary race 12 commit 收口(4 并发原语:(1) state lock Lock 保护 session 旋转 sync_turn 不跨边界 (2) per-session writer registry plugins/memory/openviking/__init__.py:1664 _inflight_writers: Dict[str, Set[Thread]] + :2080-2102 _spawn_writer 自注+自反注 + :2129-2156 _drain_writers(sid, timeout) loop+re-join + 全部 drain 才允许 commit (3) prefetch_generation 单调 int worker capture 长操作完成时 if 已升 → 拒写 (4) async finalize :2232-2260 _finalize_session_async daemon offload drain+pending GET+commit POST 让命令线程立返 /new//branch//resume//undo 不卡;12 commit:813a4e383 (#28296) :2373-2439 on_session_switch hook bounded join 10s + commit if turn_count>0 + drain stale prefetch / a30b40c73 sync_turn :2309-2320 capture sid before worker + on_session_end :2360-2370 reset turn_count for 幂等 + 测 test_end_then_switch_does_not_double_commit / eddbf291a re-check is_alive after join 未 drain 跳 commit + on_memory_write 同 sid 快照 + prefetch_generation 拒 stale write / 91e9459e1 per-session writer dict 替单槽 _sync_thread 防 bounded join drop live worker / 00c045b43 综合硬化 / f3b813c02 测试 preserve content/write writes / 3ac6551ba :2399 rewound=bool(kwargs.get("rewound")) :2411-2430 rewound 时跳旋转只 invalidate prefetch / c83544890 命令线程不卡 drain+commit / 2a5d51c16 (#48206) adapt current api / 4de4a4e2d (#47973) type-correct skill-scaffolding sentinels / 5494c1e9b (#48262) :858-863 _write_ovcli_config 改用 atomic_json_write(mode=0o600) 共享 helper 关 chmod-after-write TOCTOU / 99a20f8d9 plugin 期望更新) — ⭐ Memory 单轮 batch ops #48507(tools/memory_tool.py:450-563 MemoryStore.apply_batch(target, operations) 全 op 按最终预算校验 + 原子写 + 任一失败回滚整批 + :792-826 _apply_batch_write_gate 跨 op auth + :839-922 memory_tool(operations=[{action,content?,old_text?}]) dispatcher + 桥接外部 provider agent/agent_runtime_helpers.py:1842-1875 + agent/tool_executor.py:1012-1050 遍历 batch op 对 add/replace 调 on_memory_write + agent/background_review.py:300-408 batch op 显示;live 验证:consolidate-and-add 7→1 调用) — ⭐ Skills 用户修改 bundled-skill 发现+diff CLI(tools/skills_sync.py:825 list_user_modified_bundled_skills() 用 manifest origin-hash 基线 + :813 _is_tracked_user_modification(origin_hash, user_hash) 共用谓词防 sync loop/discovery 漂移 + :881 diff_bundled_skill(name) 文件级 difflib.unified_diff() 检 modified/added/removed/binary + :836 _read_for_diff 单读返 (bytes,text);CLI hermes_cli/skills_hub.py:1152 hermes skills list-modified [--json] + :1185 hermes skills diff + :1870+ /skills list-modified /skills diff slash 镜像 + subcommands/skills.py:164/194 argparse + hermes update 提示在 main.py:9063 + 6073 两路径都点向新命令 + 不变式测 test_update_modified_notice.py:50 5 行窗内必现 hint 不固定路径数;f6fac60e6 refactor _skill_file_list() helper 去重 + diff 契约删 user_present;25c590ccd rmtree guard 拒 SKILLS_DIR root(不只外部)+ f1254c8ea (#48200) :695 _rmtree_writable() 必须严格 SKILLS_DIR 的 child 防坏路径拼接/恶意 manifest/折叠路径静默 wipe ~/.hermes/ + hermes_cli/config.py:2502-2510 pre_update_backup 默 True + 5 case scope guard tests/tools/test_skills_sync.py:237;功能测 test_skills_list_modified_diff.py 132 行 6 测 pristine 不假阳/edited listed/diff pristine clean/diff modified+added/未知 ok=False/reset 一致) — ⭐ Langfuse trace state 按 turn/request id 隔离(plugins/observability/langfuse/__init__.py:247 _trace_key(task_id, session_id, turn_id="", api_request_id="") 三 tier:Tier 1 turn-scoped task:T:turn:U/session:S:turn:U/thread:PID:turn:U;Tier 2 request-scoped task:T:api:R/...;Tier 3 legacy 裸 task_id/session:S;turn_id 优先(turn-scoped post_llm_call 无 api_request_id 必须 resolve 到 request hook 同 key)+ :231 _scope_prefix 抽取共用 task/session/thread fallback ladder 防漂移;:65 _MAX_TRACE_STATE=256 + :713 _evict_stale_locked() 在 _STATE_LOCK 下 insert 前调 LRU 驱逐非-finalizing turn(被打断/tool-only final/空 final content)防 _TRACE_STATE 无界增长 + 驱逐前结 root span;hook 签名升级 :785 on_pre_llm_call/:843 on_pre_llm_request/:883 on_post_llm_call/:1050 on_pre_tool_call/:1056 on_post_tool_call 全传 turn_id+api_request_id;端到端隔离 tests/plugins/test_langfuse_plugin.py:254 TestTurnTraceIsolation 2 turn(1 非-finalizing+2 normal)2 separate root trace 开(pre-fix 只 1,turn 2 merge into turn 1)+ :381 test_non_finalizing_turns_do_not_grow_state_unboundedly 50 turn vs cap=8 surviving keys turn 42-49 LRU 驱 0-41 + :402 test_trace_key_strings_unchanged_by_refactor 钉所有 task/session/turn/api 组合精确输出防漂移) — ⭐ Anthropic OAuth wire mcp__ 双下划线前缀 #47723(关键 wire-format 变更:单下划线 mcp_ 被 Anthropic 工具分类器算第三方 → HTTP 400 + 路由 extra-usage 计费 lane;agent/anthropic_adapter.py:375 _MCP_TOOL_PREFIX="mcp__"(之前 "mcp_")+ :2349+ tool prefix 跳已 mcp_/mcp__防双前缀 +agent/transports/anthropic.py:91 MCP_PREFIX="mcp_"+:2370-2391 to_oauth_wire_name()归一化所有mcp到mcp__(裸 native + MCP server 工具如 mcp_linear_get_issue):startswith("mcp__")不变 /startswith("mcp_")→"mcp__" + name[len("mcp_"):]/ else →MCP_TOOL_PREFIX + name;应用于 tool 定义和**消息历史** tool_use 块 + agent/transports/anthropic.py:132-151 normalize_response反向解经 registry 查找:registered name → single-underscore + bare(MCP server 工具)→ bare name(native)→ 兜底保留mcp_ wire;测试重写:零单下划线到达 OAuth wire;mcp__圆 trip 解为 registered name 两类工具;实证:单mcp_工具翻整请求到 extra-usage /mcp__ 在 plan) — **⭐ Curator skill consolidation 改 opt-in #47840**(agent/curator.py:64 DEFAULT_CONSOLIDATE=False+:190-203 get_consolidate()读curator.consolidate默 False +:1428 run_curator_review(consolidate=None)None 读 config / True/False 覆盖 +:1546-1570 not consolidate 跳 fork aux-model review 整段直接写 prune-only;fc1119ca6rollback safety snapshot 自保护:可选 protect set 经snapshot_skills()穿到_prune_old() 防 evict 正被恢复 snapshot;992b92238restore 收紧到 archive_skill() 的精确 14 位时间戳后缀防同前缀无关 archived skill) — **Dashboard 流式 multipart 上传 #47663**(之前 file 上传走 base64 data URL in JSON body 膨 33% + 内存缓冲 + 撞 proxy 502;新hermes_cli/web_server.py:1486-1560 upload_managed_file_stream UploadFile+Form按 1 MiB 块直读到 temp + 100 MB cap streaming 中 enforce 413(不 full buffer 后)+ 原子os.replace(partial/abort 不覆盖现有)+ 加 python-multipart依赖;前端api.uploadFile改multipart/form-data raw 字节)— **Docker supervised gateway --replace #47555 + 安装树自我修改硬化 #47490 + macOS launchd in-tree 推迟 #47842** + **runtime-pid 本机 only liveness + await-safe config-only scope /api/status + Chat tab session-end 恢复 #47674 + 完整 MCP catalog 明细 #48520** + **OpenViking 设置 UX 10 commit**(手动 setup path/密钥类型前置选/预创建 0600 关 TOCTOU/chmod 失败日志/15s health wait/_classify_runtime_openviking_health区分 responded vs unreachable/不健康端点跳 autostart)+ **Hindsight memory provider 入 Desktop 配置面板 #37546**(新apps/desktop/src/app/settings/provider-config-panel.tsx 1-182声明式 + schema-drivenhermes_cli/memory_providers.py 1-149 ProviderField/ProviderFieldOption+ GET/PUT/api/memory/providers/{name}/config+constants.ts:242 ENUM_OPTIONS 'hindsight' 进 memory.provider)+ **xAI grok-composer-2.5-fast 入 OAuth picker + 200k ctx 修 + native web_search swap-only + incomplete-call 守 + Codex 设备码 429 重试 #47860 + session_id/x-client-request-id headers 复原 #47335**(agent/model_metadata.pygrok-composer 200000 /grok-composer-2.5-fast 262144+agent/transports/codex.py:60+/43+swap-only web_search 不额外授 +agent/codex_responses_adapter.py:69+不算 in_progress 为 incomplete +hermes_cli/auth.py:78+设备码 capped 指数退避 4 次 + raiseAuthError(code=CODEX_RATE_LIMITED_CODE)含 wait hint)+ **Model pickermax_models=0 ≠ unlimited 语义锁 + 移除 50 cap #48279**(hermes_cli/model_switch.py:10+切片改is not Nonecheck /build_models_payload/list_authenticated_providers/list_picker_providers 默改 None unlimited)+ **Prompt 跨平台 platform_hints override + context-file cap 按模型 ctx 自适配 #47846 + parallel-tool-call steer 去重**(agent/agent_init.py:1242读agent._platform_hint_overrides+agent/system_prompt.py:61-113 _resolve_platform_hint()append/replace/shorthand +hermes_cli/config.py:2173-2189 DEFAULT_CONFIG.platform_hints 文档;agent/prompt_builder.py:961-984 _dynamic_context_file_max_chars() ctx_tokens40.06floor 20K ceiling 500K +:1540-1549 _truncate_content(context_length, read_path)标记点 truncated 文件路径引导 read_file;删GOOGLE_MODEL_OPERATIONAL_GUIDANCE 重复 Parallel tool calls 段 + 注释修正)+ **Resume 跟随 compression-tip #48633 + /compress 跳旋转保护 + 旋转前 flush 待持久化消息 #47202**(hermes_state.py:2820-2841 resolve_resume_session_id()经get_compression_tip()forward 跟随 + 只跟end_reason='compression' parent,不混 delegation/branch;gateway/slash_commands.py:2588-2613仅当_compress_context产新 sid 才调rewrite_transcript;agent/conversation_compression.py:512-523 compress_context+cli.py:5975-5989 new_session旋前 flush + catch)+ **Kanban auto-subscribe calling session on create**(gateway sessions 用HERMES_SESSION_PLATFORM+HERMES_SESSION_CHAT_IDContextVars / TUI/desktop 用HERMES_SESSION_KEY子进程 env / 门kanban.auto_subscribe_on_create 默 True)+ **Backup hermes import 跳易失 gateway 状态 #48243 + Update install-method stamp scope 改 code-tree #48188**(_IMPORT_SKIP_NAMES={gateway_state.json, gateway.pid, cron.pid, gateway.lock, processes.json} basename 跳防 hosted 实例 reconciler 读陈旧外来 state;detect_install_method()stamp 改驻 code tree(macOS~/Library/Application Support/Hermes// Linux~/.local/share/hermes/ Windows%APPDATA%\Hermes)防 Docker bind-mount $HERMES_HOME 单 stamp 描述两安装)+ **Photon iMessage mixed attachment text 保留 #46818**(plugins/platforms/photon/adapter.py:119+处理 'group' content type 扁平化 text+attachment +_normalize_binary_payloadhelper + sidecarindex.mjs/patch-spectrum-mixed-attachments.mjs 155 行 在 npm postinstall+sidecar 启动应用 + Windows pathToFileURL+CRLF↔LF)+ **cua-driver MCP 操作员环境 scrub #37878**(tools/computer_use/cua_backend.py:3+ _sanitize_subprocess_env() 防 credential exfil 到第三方 cua-driver binary 含 ANTHROPIC_API_KEY 测试)+ **MCP catalog Unreal Engine 5.8**(optional-mcps/unreal-engine/manifest.yaml 54 行HTTP127.0.0.1:8000/mcp 无 auth;Epic experimental Unreal MCP plugin 嵌在 Editor)+ **Agent empty-name 工具调用循环抑制 #47967/#48109 + 多模态用户内容持久化保留 + send_message tool 撤回 #47856**(agent/conversation_loop.py:26+ empty-name → 短 anti-priming error 无 catalog dump / 非空 unknown 仍 catalog;run_agent.py:10+ 避免 text-only persist_user_message override 覆盖 ACP image block;toolsets.py:14+ drop model-tool 注册 + 空 'messaging' toolset,send engine 保留给 cron/gateway notifier/hermes send CLI)+ **search_files headroom densification #47866**(tools/file_operations.py:250-278 _densify_matches() path-grouped lossless 57.8% token 降;≥5 matches 触发;不变式:ripgrep matches path-ordered)+ **Approval glob allowlist #43051**(tools/approval.py glob 命令 allowlist 守 + shell chaining 防)+ **Container 检测 cgroup-v2/containerd/CRI/K8s #47131**(hermes_constants.py:486+ KUBERNETES_SERVICE_HOSTenv +kubepods/containerd/criomarker +/proc/self/mountinfo fallback)+ **Windows 跨进程日志轮替**(hermes_logging.py:36+ ConcurrentRotatingFileHandler as RotatingFileHandler仅sys.platform=='win32' + portalocker pywin32 锁 + concurrent-log-handler==0.9.29)+ **install.ps1 PowerShell host 解析 + EAP 松绑后 uv venv fail-fast + native stderr 松绑 #48352/#48341**(scripts/install.ps1:320 Get-PowerShellHostExe用Get-Process -Id $PIDPATH-independent +:186 Invoke-NativeWithRelaxedErrorActionEAP=Continue 包 git/uv 防 PowerShell 5.1 NativeCommandError +:1460-1471relax 后立刻捕$LASTEXITCODE 非 0 throw 防伪成功)+ **Desktop 23 commit**(stranded session 窗恢复 #47655 :43/:307 $resumeExhaustedSessionId + ErrorState 含 Retry 按钮;session 删幂等 #48641 hermes_cli/web_server.py:7046-7067+ absent → 200already_absent:True;secondary 窗 streaming #47919 electron/session-windows.cjs:24-34 chatWindowWebPreferences backgroundThrottling:false 主+secondary 共用 factory;PTY before-quit dispose #92e6d8c85 electron/main.cjs:6554-6558;Electron 40.10.2 钉 #47792 package.json:137 electronVersion: "40.10.2" + 删 @electron-internal/extract-zip + nix npmDepsHash 刷新 + react-simple-icons @=13.11.1;electronDist 动态解析+self-heal #48091 apps/desktop/scripts/run-electron-builder.cjs 57 行 require.resolve("electron/package.json")动态 +_try_redownload_electron_dist() 镜像 retry;self-update 重 build retry once #48122 apps/bootstrap-installer/src-tauri/src/update.rs:296-328 rebuild_needs_retry()+electron/update-rebuild.cjs:21-29 runRebuildWithRetry();oversized 消息不冻结 markdown-text.tsx:461 MAX_MARKDOWN_CHARS=200_000+:463-500 HugeTextFallback content-visibility:auto + ExpandableBlock;huge fenced block stack overflow 防 markdown-preprocess.ts:154-160 extend() 替 spread 防 V8 argument-count overflow;message-render 隔离 markdown-text.tsx:60-66 preprocessWithTailRepair try/catch+directive-text.tsx:325-339 safeEmbeddedImages/safeDirectiveSegments;failed turn 跨 thread 隔离 use-message-stream.ts:1102-1109 errorMessage toast 稳 id;long user message 滚 #48619 thread.tsx:830 USER_BUBBLE_BASE_CLASS overflow-hidden→overflow-y-auto;error banner dismiss #47985 desktop-controller.tsx:753-785 dismissError 双清;/title 前置创行 #47987 tui_gateway/server.py:5004 _ensure_session_db_row;RTL list marker + quote border markdown-text.tsx:541/546/549 dir="auto"+:525 code dir="ltr";named custom provider 不退 bare custom #48547 agent/agent_init.py:1227-1233 4 站守;backend skew toast 24h snooze #47913 store/updates.ts:99-145 SKEW_TOAST_COOLDOWN_MS;pre-session 模型选黏 + reasoning/fast 设置 #47447 lib/model-status-label.ts:25-34 currentPickerSelection();self-improvement review summary use-message-stream.ts:1084-1109 review.summary持久 system 消息 +tui_gateway/server.py:1911-1926 _load_memory_notifications)+ **TUI Enter slash 完成 + MCP late refresh + MCP 计数 connected only #48425/#48403/#48402**(ui-tui/src/domain/slash.ts applyCompletiontrailing-space-only 算 noop fall-through 提交 +tui_gateway/server.py:3413 _schedule_mcp_late_refresh30s 等 discovery 后 rebuild snapshot 仅 pre-first-turn 安全 + 重 emit session.info +ui-tui/src/components/branding.tsx:223+ mcpConnected=filter(s.connected) 替全部配置计数;mcpConnected==0 时段整 drop)+ **CLI keystroke 延迟 + URL 不当 path 补全 + 弃用 login 优雅降级 #47701/#47706**(cli.py:12714 ThreadedCompleter(_completer)把补全移出 event loop /hermes_cli/commands.py:1291+ if "://" in word: return None拒 URL token /subcommands/login.py:10删choices=+description=让任何 provider 都到 handler 打 redirect 到hermes auth/hermes model)+ **hermes debug 显 commit 日期 #48104**(hermes_cli/dump.py:59 _get_git_commit_date()跑git log -1 --format=%cd --date=short返 YYYY-MM-DD;Docker/wheel 无.git 时返空 baked SHA 仍识别)+ **6 条 AUTHOR_MAP salvage**(iamlukethedev / srojk34 / infinitycrew39 / Adolanium / #47904 / Rivuza全进scripts/release.py Python dict)+ **PR infographic 资源删除 #48261**(docs/assets/ns504-chat-session-reconnect.png 1024 字节+infographic/kanban-db-corruption-defense/infographic.png 1200 KB都无引用) — 验证基线/tmp/hermes-agentclone @03d9a95` + 5 个并行 research agent 实证(A: Desktop UI 23 commit / B: Gateway+Relay+A2+Compression+Docker+Update 32 commit / C: OpenViking+Memory+Curator+Dashboard 35 commit / D: Skills+Langfuse+CLI+TUI+Install 33 commit / E: Prompt+Billing+xAI+Codex+Anthropic+Picker+Photon+MCP-catalog+cua-driver+AUTHOR_MAP+Merges 41 commit)

  • 2026-06-16-update: 65 commits 单日同步(hermes-agent cffd6e3c8 → d1ecebc,仍 v0.16.0 未发新版;约 25 fix / 18 feat / 6 chore / 5 test / 4 docs / 1 refactor / 6 merge;~28h 单日窗口;本期 65 commit 全部 committer date ∈ (2026-06-15 20:35 UTC, 2026-06-16 20:40 UTC] 的真正新增;cffd6e3c8..HEAD 总 141 commit 中其余 76 个为前期 sync 已覆盖的旧 PR salvage(photon spectrum-ts/iMessage gRPC、yuanbao media pipeline middleware、agent char-based output-cap overflow、honcho identity-tree 各 sub-PR、apps/desktop sleep/wake recovery 等),本期不重复记录)— ⭐ Desktop composer model picker 全面替代 statusbar(PR #46959 4 commit):新文件 apps/desktop/src/app/chat/composer/model-pill.tsx 72 行 订阅 $currentModel/$currentProvider/$currentFastMode/$currentReasoningEffort + formatModelStatusLabel + apps/desktop/src/store/model-presets.ts 86 行 per-model effort/fast preset 本地化 STORAGE_KEY="hermes.desktop.model-presets" + modelPresetKey(provider,model)="${provider}::${model}" + applyModelPreset({effort,fast}, ctx) 在无 ctx.sessionId 时 no-op 避免写穿网关 agent.reasoning_effort + apps/desktop/src/store/session.ts:18-23 4 个 composer localStorage key hermes.desktop.composer.{model,provider,reasoning-effort,fast} + apps/desktop/src/app/shell/model-menu-panel.tsx:45 ModelMenuCloseContext React Context 关闭 + 989d5d0 apps/desktop/src/lib/model-status-label.ts:71 /-\d{8}$/ 折叠日期 pinned snapshot + apps/desktop/src/store/model-visibility.ts:54-57 collapseModelFamilies 同折叠(claude-opus-4-5-20251101 → claude-opus-4-5)+ 7d938cc agent/conversation_loop.py:303 _stored_prompt_matches_runtime(agent, prompt) 比对 Model:/Provider: 行 vs runtime + tui_gateway/server.py:1684 _persist_live_session_system_prompt(session) 经 db.update_system_prompt 重建 + :1705 _append_model_switch_marker(session, model, provider) 追加 [System: The active model for this chat has changed to {model} via provider {provider}…] 进史历 + :2166-2168 _apply_model_switch 接 — ⭐ Compact session window 家族 PR #46951 3 commit:apps/desktop/electron/main.cjs:5087 spawnSecondaryWindow({sessionId, watch, newSession}) + :5148 createSessionWindow + :5155 createNewSessionWindow + apps/desktop/electron/preload.cjs:9 openNewSessionWindow:() => ipcRenderer.invoke('hermes:window:openNewSession') + apps/desktop/src/store/windows.ts:9 NEW_SESSION_WINDOW_FLAG="1" + :33 isNewSessionWindow() + :110-114 openNewSessionInNewWindow() + apps/desktop/src/lib/keybinds/actions.ts:69 {id:'session.newWindow', defaults:['mod+shift+n']} + apps/desktop/src/app/hooks/use-keybinds.ts:136 调度 + i18n en.ts:192+zh.ts:188 + 0f75e99 apps/desktop/src/app/shell/app-shell.tsx:86 hideTitlebarControls=isSecondaryWindow()(从 isNewSessionWindow 扩到所有 secondary)+ statusbar :194 !isSecondaryWindow() 门 + apps/desktop/src/app/chat/index.tsx:127 ChatHeader 早返 + :311 secondary 跳 showIntro + 67233d1 新文件 apps/desktop/src/store/session-sync.ts 25 行 CHANNEL='hermes:sessions' BroadcastChannel + broadcastSessionsChanged() + onSessionsChanged(handler) + apps/desktop/src/app/desktop-controller.tsx:468-475 订阅(跳 secondary 窗口)+ apps/desktop/src/app/session/hooks/use-message-stream.ts:644 title commit 后广播 + apps/desktop/src/app/session/hooks/use-session-actions.ts:476 乐观创建后广播 + dd0e3e0 apps/desktop/src/components/assistant-ui/thread-list.tsx:140 主窗 pad pt-[calc(var(--titlebar-height)+1.5rem)]→pt-[calc(var(--titlebar-height)-0.5rem)] — ⭐ Watch window subagent 流 PR #47060 44e5848:tools/delegate_tool.py:870-876 进度中继转发 subagent.text(预览)+ :1638-1647 _relay_child_text(delta) 经 child.run_conversation(..., stream_callback=_relay_child_text) + tui_gateway/server.py:907-913 _start_agent_build lazy watch 跳过 + :2878-2884 _on_tool_progress 对 subagent.text 跳父 emit + :2945-2951 _mirror_subagent_to_child 把 subagent.text 映 child sid message.delta(subagent.start 退化单次 header)+ :4248-4258 lazy session.resume 在 _child_run_active 时早返空 history(WSL race 修)+ 窗口 chrome apps/desktop/src/app/chat/index.tsx:124-127 ChatHeader 在 isSecondaryWindow() 早返(从 isNewSessionWindow 扩)+ app-shell.tsx:83-86 hideTitlebarControls=isSecondaryWindow() + thread-list.tsx:147 secondaryTitlebarGap='calc(var(--titlebar-height) + 0.75rem)'(空格 load-bearing)+ :265-270 不透明拖条 — 远端 gateway artifact 鉴权下载 PR #46895 c6b0eb4:apps/desktop/src/lib/media.ts:62 mediaExternalUrl(path) 远端感知 + :67 isRemoteGateway() 分支构 ${conn.baseUrl}/api/files/download?path=…&token=… + apps/desktop/src/app/artifacts/index.tsx:128-133 artifactHref 把 file:// 与 / 路径都过 mediaExternalUrl + hermes_cli/web_server.py:253 _QUERY_TOKEN_API_PATHS=frozenset({"/api/files/download"}) + :1425 @app.get("/api/files/download") Content-Disposition: attachment、auth-gated、不在 PUBLIC_API_PATHS 中 + 测试 apps/desktop/src/lib/media.remote.test.ts + tests/hermes_cli/test_web_server_files.py 60 行 — 全局 remote profile REST 路由 PR #47011 0441b7f:apps/desktop/electron/connection-config.cjs:175 pathWithGlobalRemoteProfile(path, profile, opts) global-remote 模式 + 无每-profile override 时追加 ?profile= + :283 导出 + apps/desktop/electron/main.cjs:66 导入 + :5619 hermes:api handler 调;后端 hermes_cli/web_server.py OAuth provider 路由按 profile scope + 新测 tests/hermes_cli/test_web_oauth_dispatch.py 133 行 — Electron pack 失败镜像 redownload PR #47266 d1ecebc:hermes_cli/main.py:5113 _electron_dist_binary(project_root)(mac Electron.app/.../Electron/win electron.exe/linux electron)+ :5130 _electron_dist_ok + :5144-5194 _redownload_electron_dist(project_root, env, *, mirror=None) 清残 dist+path.txt+注 ELECTRON_MIRROR 跑 node install.js + :5459-5463 首次重试 + :5489-5493 镜像重试用 https://npmmirror.com/mirrors/electron/;redownload 仍失败时跳 npm run pack + scripts/install.ps1/scripts/install.sh 加 Restore-ElectronDist/Test-ElectronDist helper + 测 tests/hermes_cli/test_gui_command.py +155 行 — /browser 限本地 gateway PR #47245 a68ac0c:apps/desktop/src/lib/desktop-slash-commands.ts:33 加 'browser' 进 DesktopActionId + :107-112 /browser spec surface:action('browser') + :152 从 terminal-only blocklist 移除 + apps/desktop/src/app/types.ts:49-53 新 BrowserManageResponse {connected?, url?, messages?[]} + apps/desktop/src/app/session/hooks/use-prompt-actions.ts:1148-1219 browser handler $connection.get()?.mode==='remote' → "local gateway only",否则 connect|disconnect|status 调 requestGateway('browser.manage', {action, session_id, url?});同 PR tools/skill_manager_tool.py 加 _validate_delete_target 守 tree-escape — 外部 provider 终端断开 a0ec4f5:apps/desktop/src/app/right-sidebar/store.ts:16 $terminalInjection=atom(null) + :21-30 runInTerminal(command) 置 takeover+injection + apps/desktop/src/app/right-sidebar/terminal/use-terminal-session.ts:680-700 useEffect 在 status==='open' 时订阅 + 写 ${command}\r 至 hermesDesktop.terminal.write + 写完清 atom + apps/desktop/src/app/settings/providers-settings.tsx:34 GroupLabel helper + :174 第二个 "Other providers" header + :218 terminalDisconnect=!canDisconnect && Boolean(provider.disconnect_command) && canRunInTerminal() + :325-339 handleTerminalDisconnect 调 runInTerminal(command) + apps/desktop/src/types/hermes.ts 加 disconnect_command;后端 hermes_cli/web_server.py 返 per-OS disconnect_command — Right-sidebar explorer refresh 始终可点 PR #46244 9d2ec8d:apps/desktop/src/app/right-sidebar/index.tsx:134 HEADER_ACTION_LABEL_REVEAL 从 peer-hover/project-label 改 group-hover/project-header+group-focus-within/project-header + :219 RightSidebarSectionHeader div 挂 group/project-header class + 测试 +75 行 index.test.tsx — ⭐ display.memory_notifications 三态 off/on/verbose(3 feat + 2 fix):hermes_cli/config.py:1441 DEFAULT_CONFIG["display"] 加 "memory_notifications":"on" + agent/agent_init.py:303 agent.memory_notifications 属性 + agent/background_review.py:626 summarize_background_review_actions(notification_mode=...) 解析 mode + 构 Memory ➕/✏️/➖ 预览(add/replace 120 char、remove 60 char)+ gateway/run.py:14805-14812 网关解析 display.memory_notifications 赋 agent + 文档 website/docs/user-guide/features/memory.md:248-267 新 ## Background review notifications 段 + 测 tests/run_agent/test_background_review.py:390/397/404/414/425 test_memory_notifications_{off_returns_nothing,on,verbose,default_is_on,skill_patch_off_silent_verbose_shows_diff};4cf9d80 verbose skill change 预览 tools/skill_manager_tool.py:616 _create_skill 加 _change:{description} + :667 _edit_skill 同(message 改 "updated (full rewrite)")+ :764 _patch_skill 加 _change:{old,new} 截 200 + agent/background_review.py 渲 📝 Skill '{name}' patched: "old" → "new" / created: / rewritten: + 转发 _summarize_background_review_actions 进 run_agent.py:1411;c2c55c4 全 provider 共用 strip:新规范解析器 agent/skill_commands.py:58 extract_user_instruction_from_skill_message() + 标记常量 _SKILL_INVOCATION_PREFIX/_SINGLE_SKILL_MARKER/_BUNDLE_MARKER/_BUNDLE_USER_INSTRUCTION/_BUNDLE_FIRST_SKILL_BLOCK/_RUNTIME_NOTE(~:44-53)+ agent/memory_manager.py:435 MemoryManager._strip_skill_scaffolding 静态方法 + prefetch_all(:458)/queue_prefetch_all(:485)/sync_all(:544)三调 + 新测 tests/agent/test_memory_skill_scaffolding.py;e3adbb5 前置 plugins/memory/openviking/__init__.py:71 _derive_openviking_user_text() 在 queue_prefetch(:548)+ sync(:588)调(c2c55c4 后改 :42 from agent.skill_commands import extract_user_instruction_from_skill_message + :81 调用) — ⭐ Hooks session:compress 事件 e76e7b5:init_agent 接 event_callback: Optional[Callable[[str, dict], None]] 进 agent/agent_init.py:198 + :430 赋值 + agent/conversation_compression.py:611-618 触发 payload {platform, session_id, old_session_id, compression_count} + gateway/run.py:14374 _event_callback_sync 桥 _hooks_ref.emit(event_type, context) 经 asyncio.run_coroutine_threadsafe + :14747 agent.event_callback=_event_callback_sync + AIAgent.__init__ 在 run_agent.py:388 透传 kwarg;28f9247 删 from urllib.parse import urlparse, parse_qs, urlunparse 死引 + 测 tests/run_agent/test_compression_boundary_hook.py:165 TestSessionCompressEvent + :213 test_event_emitted_on_compression 断 compress_events + ctx["old_session_id"]/compression_count + test_no_callback_is_safe + test_callback_exception_does_not_break_compression — prompt.context_file_max_chars 可配 f6a42b1:hermes_cli/config.py:1110 "context_file_max_chars":20_000 默认 + agent/prompt_builder.py:962 _get_context_file_max_chars() 读 + :1516 _truncate_content(max_chars=None) + :1522 警告 "increase context_file_max_chars or trim the file!" + build_system_prompt 在 agent/system_prompt.py 经 drain_truncation_warnings() 推 agent._emit_status() + 文档 configuration.md:614/620 / context-files.md:112/174/188 / prompt-assembly.md:198;6ebc449 截断警告 contextvar 隔离 agent/prompt_builder.py:11 import contextvars + :984 _truncation_warnings = contextvars.ContextVar("context_file_truncation_warnings", default=None) + _record_truncation_warning(~:991)+ drain_truncation_warnings()(:998)+ 测 test_warnings_isolated_across_contexts — tool_progress_style → tool_progress_grouping 改名(同日 fc956b9 引入→6373aba 改名):gateway/display_config.py:35 _GLOBAL_DEFAULTS["tool_progress_grouping"] + :242 _normalise 保 accumulate|separate + gateway/run.py:13688 解析 + :14027 can_edit = progress_grouping != "separate" + hermes_cli/config.py:1498 "tool_progress_grouping":"accumulate" + 测 tests/gateway/test_display_config.py:454-510 TestToolProgressGrouping + 文档 website/docs/user-guide/messaging/index.md:323-327 — Codex pool-only rate-limit 不弹 relogin 9a59ad7:新分类器 hermes_cli/auth.py:3875 _codex_pool_rate_limit_status() 扫 auth_store["credential_pool"]["openai-codex"] 找 last_status="exhausted" + code 429/quota/rate_limit + resolve_codex_runtime_credentials 在 :3809-3826 raise AuthError(code=CODEX_RATE_LIMITED_CODE, relogin_required=False)(不再 "missing credentials")+ get_codex_auth_status() 在 :6003-6014 返 {logged_in:True, rate_limited:True, error_code:CODEX_RATE_LIMITED_CODE, reset_at} + 常量 :723 CODEX_RATE_LIMITED_CODE="codex_rate_limited" — xAI 默认 grok-build-0.1 bbc842d+f4ef70f:hermes_cli/models.py:113 _XAI_STATIC_FALLBACK[0]="grok-build-0.1" + :121 _XAI_TOP_MODEL="grok-build-0.1" + plugins/web/xai/provider.py:49 DEFAULT_MODEL="grok-build-0.1" + hermes_cli/model_setup_flows.py:520 _prompt_model_selection fallback;docs plugins/web/xai/provider.py:22 例 + website/docs/user-guide/features/web-search.md+zh-Hans+website/docs/guides/xai-grok-oauth.md;grok-4.3 仍在 :114;聚合目录(Nous/OpenRouter)不动 — Models live+curated 合并 + curated-first + validate 兜底 PR #46857 3 commit:630b438 hermes_cli/models.py:2263-2280 Anthropic 分支 curated = list(_PROVIDER_MODELS.get("anthropic", [])) → merged = list(curated) → 大小写 insensitive merged_lower set 追 live-only ID + 同 pattern 在 fetch_models 调用点 ~models.py:2376 泛化 + 测 tests/hermes_cli/test_provider_live_curated_merge.py 113 行;ee7b8a4 :3585 validate_requested_model + :3947-3962 "Model not in live /v1/models — check the curated catalog before rejecting" 分支返 {accepted:True, recognized:True, message:"Note: ... exists in the curated catalog — accepted."};658ac1d :1762 _model_in_provider_catalog(name_lower, providers) + :3952 验证用纯目录 helper(无网)+ :1861, 1896 其他 catalog 成员检查走该 helper + 合并代码在 :2263-2280 保 curated 在前再追 live-only — model.base_url 透传 fetch_models 1b962f0:providers/base.py:162-217 fetch_models(*, api_key, base_url, timeout) 解析顺序 models_url → base_url → self.base_url + "/models" + hermes_cli/models.py:2374 live = _p.fetch_models(api_key=api_key, base_url=base_url or None) + 子类 override plugins/model-providers/custom/__init__.py:42-52/openrouter/__init__.py:50-73 + 新测 tests/providers/test_fetch_models_base_url.py 140 行;db44af0 两 overlap user-defined provider 跨过滤测 22 行进 tests/hermes_cli/test_inventory.py — 无 api_key 仍探针 /v1/models 1039e90:hermes_cli/model_switch.py:1741-1758 注释 "With an api_key: always probe… Without an api_key AND no explicit models: probe anyway" + should_probe = bool(api_url) and discover and (bool(api_key) or not has_explicit_models) + fetch_api_models(api_key, api_url);7493de7 78 行新测 tests/hermes_cli/test_user_providers_model_switch.py + scripts/release.py:420 "[email protected]":"chimpera" — 自定义 provider dedup 保留 b7fa62c:hermes_cli/inventory.py:175-195 先扫 is_user_defined 行收 user_models 然后主循环 if row.get("is_user_defined"): continue 才调 _is_aggregator(slug) + 回归测 tests/hermes_cli/test_inventory.py — GLM-5.2 入 OpenRouter+Nous b2da39a PR #47391:hermes_cli/models.py:64 ("z-ai/glm-5.2","") 进 OPENROUTER_MODELS + :187 "z-ai/glm-5.2" 进 _PROVIDER_MODELS["nous"](在 glm-5.1 之前)+ :263 "glm-5.2" 进 zai picker + 重生成 website/static/api/model-catalog.json — auxiliary auto 任务沿主 fallback chain PR #47235 4858942:agent/auxiliary_client.py:3106 _fallback_entry_api_key + :3117 _resolve_fallback_entry(... ←resolve_provider_client) + :3135 _try_main_fallback_chain 读 get_fallback_chain(load_config()) 迭代跳 failed/main/unhealthy + _resolve_auto 接 task 参 + :3320-3333 在 Step 2 插用户 fallback + resolve_provider_client(... task=None) :3459 — Telegram 富文本默认开 + 流式 final 仍 rich PR #46890 a6364bf:gateway/platforms/telegram.py:428 _rich_messages_enabled 默认翻 True + :984 _needs_rich_rendering():富专用于 table/task-list/ /block-math + :1006 _rich_eligible() 共享核心去 expect_edits 门 + :1257 async def _try_edit_rich(...) editMessageText+rich_message 路 + :2680-2681 if finalize and self._rich_eligible(content): rich_result = await self._try_edit_rich(...) — Rich-reply 跨重启 send-time 索引恢复 01ae9b8+8ed16a7:新文件 gateway/rich_sent_store.py :23 _MAX_ENTRIES=1000 + :36 def record(...) + :68 def lookup(...) + JSON store ~/.hermes/state/rich_sent_index.json + gateway/platforms/telegram.py:1248-1249 发送后 record (chat_id, message_id)→content + :6718-6720 reply 时 text+caption 都空 → reply_to_text=rich_sent_store.lookup(str(chat.id), reply_to_id) + 107 行新测 4 个(test_rich_reply_records_and_recovers_text/_lookup_miss_leaves_text_none/_native_quote_wins_over_lookup/_caption_wins_over_lookup)+ 3f80bca scripts/release.py:94 "[email protected]":"x1erra" — Slack /debug via /hermes PR #47248 4d470b3:hermes_cli/commands.py:1057 _SLACK_VIA_HERMES_ONLY=frozenset({"credits","debug"}) 加 debug(与 Telegram 对齐)+ check 点 :1107 — Mattermost notify-only flat-fallback 16fc717+5a0e0d3:gateway/platforms/base.py:80 _mark_notify_metadata(metadata) 浅克隆置 notify=True 应用 :3899/:4005/:4055/:4282 _final_thread_metadata + plugins/platforms/mattermost/adapter.py:155 async def _thread_root_for_send 从 reply_to/metadata 解析 root + :170 def _last_post_failure_is_broken_thread_root 400/404+body 标识 + :181 async def _post_preserving_thread 仅 metadata.get("notify") 且 broken-root 时 flat-fallback + 接 :352/:534/:575/:663 text/image/file/document 发送 — WhatsApp/email send_image(metadata=) e65d74b:gateway/platforms/whatsapp.py:843-862 async def send_image(... metadata: Optional[Dict[str, Any]] = None) + :862 super().send_image(..., metadata) fallback + gateway/platforms/email.py:675-683 同 + 新契约测 tests/gateway/test_media_metadata_contract.py 80 行 + _accepts_metadata() helper 扫所有 adapter — Photon spectrumProjectId 收敛 5b3fa26:plugins/platforms/photon/auth.py:15-17 文档:post-unify project.id==spectrumProjectId + :168 def load_dashboard_project_id() 优先 spectrum_project_id 而非 legacy dashboard_project_id + :185 entry-key fallback 链 + get_project() 删 + create_project 不再发 spectrum: true 切换始终 provisioned — ⭐ Honcho 网关身份树 gateway-gated 替换部署形状 PR #44431 merge d2b34e8:bb5cb32 _migrate_pin_peer_name() 在 plugins/memory/honcho/cli.py:380-391 pop pinPeerName 写 pinUserPeer + 克隆路径 cli.py:51/56 包 pinUserPeer + legacy 迁移;d7dfeed _gateway_platforms() 在 cli.py:394-408 懒导 gateway.config.load_gateway_config 返已连平台或 None + cli.py:681-707 无网关时 auto-skip 否则菜单 [1] just me / [2] me + others / [3] only others / [s] skip / [e] edit raw keys + cli.py:724-735 orphan-guard:un-pin 会孤悬 peerName 历史时重提 + 各分支 cli.py:741/:754-758/:766-769 scrub 后写 pinUserPeer/userPeerAliases/runtimePeerPrefix;99feb03 docs plugins/memory/honcho/README.md:140-144 pinUserPeer/userPeerAliases/runtimePeerPrefix 表行 + pinPeerName 降 deprecated;23a7458 website/docs/user-guide/features/honcho.md:160 "Gateway Identity Mapping" 节 + :174 解析器顺序 + :177 orphan 警告 + :181 deprecated 别名;2708c33+1544813 隐私 alice + Telegram UID 7654321 跨 README/cli.py/测试/docs;后续 6dde7d4 docs website/docs/user-guide/features/memory-providers.md:98 pinUserPeer 行 + :211 "every non-agent gateway user collapses to peerName" 进 Gateway Identity Mapping 子段;c7513df plugins/memory/honcho/README.md:140 "every gateway runtime user collapses…" reframe 为 non-agent + pin-overrides-aliases + cli.py:458 菜单提示词改 + honcho.md:168 "every non-agent gateway user collapses to your peer. Pin overrides all aliases" 交叉引用 session.py:335 解析器优先级 — Skills 跳支持目录 9137b86:agent/skill_utils.py:50 SKILL_SUPPORT_DIRS=frozenset(("references","templates","assets","scripts")) + :73 def is_skill_support_path(path) + :68 should_exclude_skill_path OR is_skill_support_path 与既有 EXCLUDED_SKILL_DIRS + tools/skills_tool.py:84/1027/1032/1043/1050/1077 接 _is_skill_support_path 守 skill_view/发现遍历 — shop-app → CLI 化 shop skill v1.0.1:5094325 optional-skills/productivity/shop/SKILL.md:2-7 name:shop, version:1.0.1, prerequisites.commands:[curl,node] 引 catalog-mcp.md 236 行/direct-api.md 278 行/safety.md 36 行/legal.md,旧 productivity/shop-app/SKILL.md 删;d7668aa description ≤60 char + :5 author: Joe Rinaldi Johnson (joerj123), Hermes Agent;e236bb8 docs regen 删 website/docs/optional/productivity/productivity-shop-app.md 354 行 + 新 productivity-shop.md 238 行 + 更 website/docs/reference/optional-skills-catalog.md + website/sidebars.ts;cf52370 scripts/release.py:59 "[email protected]":"joerj123" — TUI session-create no-race 测试隔离 PR #47230 2483200:tests/test_tui_gateway_server.py:4901-4942 test_session_create_no_race_keeps_worker_alive 快照 server._sessions → _saved_sessions + server._sessions.clear() + finally 还原 + agent_ready.wait(timeout=2.0→10.0) 并断言 built 返回值(之前默吞 timeout)+ 服务端引用点 server.py:1011 'replaced' check — 5 条 AUTHOR_MAP salvage(全进 scripts/release.py Python dict 而非 tools/release/AUTHOR_MAP.json):3f80bca :94 x1erra / 7493de7 :420 chimpera / 1ac76a9 :52 MrDiamondBallz / db01910 :419 cyb0rgk1tty / cf52370 :59 joerj123 / 925b0d1 :95 zimigit2020 — 验证基线 /tmp/hermes-agent clone @ d1ecebc + 4 个并行 research agent 实证(A: Desktop UI 17 commit / B: Memory/Display/Gateway/Hooks/Prompt/Auth 15 commit / C: Models/xAI/Skills/Honcho 18 commit / D: Messaging Telegram/Slack/Mattermost/Photon/WhatsApp/AUTHOR_MAP 13 commit)

  • 2026-06-15-update: 77 commits 单日同步(hermes-agent 2a14e8957 → cffd6e3c8,仍 v0.16.0 未发新版;约 44 fix / 7 test / 4 feat / 4 chore / 3 docs / 2 🐛 fix / 2 refactor / 1 revert / 1 redact / 1 nix / 1 ci / 1 change / 1 unscoped / 5 merge;~31.5h 跨夜单日窗口;164 文件 +18569/−17867)— ⭐ feat — 异步后台子代理 delegate_task(background=true) c66ecf0bc (#40946)(新文件 tools/async_delegation.py 386 行 — :96-97 _records 注册表 + :124 active_count() + :152 dispatch_async_delegation() + :215-226 lock 内原子容量检查 + :266 _finalize 完成回调推 type="async_delegation" event 进 process_registry.completion_queue + :337 list_async_delegations() + :362 interrupt_all();tools/delegate_tool.py:2053 background:bool 参 + :2090-2095 batch+background 互斥拒 + :2243-2317 父线程取 get_current_session_key() + :2261-2270 从 parent_agent._active_children 解绑让父中断/缓存 evict//new 不杀后台 + :3037-3054 schema + :3099 注册;tools/process_registry.py:1549-1616 _format_async_delegation() 渲 [ASYNC DELEGATION COMPLETE — ] 自包含块 + :1619 format_process_notification 加 evt_type=="async_delegation" 路由;gateway/run.py:5393 启动 schedule _async_delegation_watcher + :12337-12382 2s 轮询 + 非 async event 立即 requeue + _enrich_async_delegation_routing 解析 session_key + _inject_watch_notification;cli.py:981-982 shutdown interrupt_all + cli_commands_mixin.py:227-258 /stop + :260-295 /agents + tui_gateway/server.py:5598-5600 TUI 按 delegation_id dedup + hermes_cli/config.py:1778 delegation.max_async_children=3 + 测 tests/tools/test_async_delegation.py 473 行 15 测试)— feat — Hindsight observation_scopes 可配置 a376ca008(plugins/memory/hindsight/__init__.py:21 文档 HINDSIGHT_RETAIN_OBSERVATION_SCOPES env + :330 _load_config 读 + :381 _OBSERVATION_SCOPE_KEYWORDS={"per_tag","combined","all_combinations"} + :384 _normalize_observation_scopes() 接受 keyword/JSON list-of-lists/扁平 tag list + :1240-1243/:1498-1499 retain kwargs 注入 + :1614-1620 tool retain 路径切 client.aretain → client.aretain_batch 因前者不接此参)— feat — /status 显 model+context ead38107a(gateway/slash_commands.py:395-509 _handle_status_command() 优先 status_agent.model/provider/context_compressor.last_prompt_tokens/.context_length → SessionDB row → user config + 新 locale 键 gateway.status.model/model_provider/context/context_used + 17 locale 同步 + 73 行测试)— feat — Display 显 delegate_task goals 5035fa902(agent/display.py:180 _delegate_task_goal_parts + :212-222 build_tool_preview 渲 "{count} tasks: Goal A | Goal B | Goal C" + :1057-1060 _get_cute_tool_message_impl 渲 "3x: Goal A | Goal B")— Auth — xAI OAuth 跨 profile 解析 + write-through global root + access skew 120→3600s(5 commit PR #43589 salvage):f1d6f0436 hermes_cli/auth.py:3899 _xai_oauth_state_from_store() 扫 credential_pool["xai-oauth"] 找含 access_token+refresh_token 条目 + :3937 _xai_oauth_state_has_usable_tokens() 守 + :3946-3956 _read_xai_oauth_tokens() profile 缺 → 回退 global root;497352bc4 :1087 _save_auth_store 加 target_path 参 + :3996 _profile_has_own_xai_oauth_state() + :4007 _write_through_xai_oauth_to_global_root() 守 _global_auth_file_path() is None 与 pytest 安全带 :4030 + :4061-4079 _save_xai_oauth_tokens 在 _auth_store_lock() 内 write-through;febdddb41 :111 XAI_ACCESS_TOKEN_REFRESH_SKEW_SECONDS=3600(原 120)适配 6h xAI access token;1227007ae scripts/release.py:1557 AUTHOR_MAP [email protected]=capt-marbles;8844e091c merge — MCP — fail-fast noninteractive OAuth dcc321695(tools/mcp_oauth.py:756-763 build_oauth_auth() 现 raise OAuthNonInteractiveError(...) 在 not _is_interactive() and not storage.has_cached_tokens() 时,消息含 hermes mcp login {server_name} hint + tools/mcp_oauth_manager.py:411/427-434 MCPOAuthManager 镜像)— Security — Disk-cleanup protected walks 显式 frozenset + 后序 DFS(3 commit):c1a70a543/40699c329/a688d2a1b plugins/disk-cleanup/disk_cleanup.py:147 _EMPTY_DIR_PROTECTED_TOP_LEVEL=frozenset({"logs","memories","sessions","cron","cronjobs","cache","skills","plugins","disk-cleanup","optional-skills","hermes-agent","backups","profiles",".worktrees"}) + :153 _EMPTY_DIR_SWEEP_PRUNE_DIRS=frozenset({".git","node_modules","venv",".venv","site-packages","__pycache__"}) + :364-402 quick() 空目录 sweep 重写 sweep_stack: List[Tuple[Path, bool]] 显式后序 DFS(替 rglob("*") 全遍历)防 gateway event loop 卡分钟级 — Privacy — API debug dump 全字段 redact ad58dd51a + aab2e99ba(agent/agent_runtime_helpers.py:1228-1231 dump_api_request_debug() 经 redact_sensitive_text(force=True) + atomic_json_write + :1236 HERMES_DUMP_REQUEST_STDOUT 也走 redacted + agent/redact.py:107 _PREFIX_PATTERNS 新 r"ntn_[A-Za-z0-9]{10,}"(Notion internal integration token)+ dump 现在无条件触发 API 错误)— Gateway scoped lock 第三 stale 分支 ec05d2bc3(gateway/status.py:646-660 acquire_scoped_lock() 新分支:PID + start_time 都非 None 且相等但 not _looks_like_gateway_process(existing_pid) 时调 _read_process_cmdline 检 cmdline 可读 → stale=True,防 Linux/systemd 启动期 PID+jiffy start_time 重用让 cron/nginx/sshd 冒名 gateway) — Bedrock boto3>=1.34.59 软守 2cddc9c89(agent/bedrock_adapter.py:61 _MIN_BOTO3_VERSION=(1,34,59) + :64-88 _require_boto3() 解析 boto3.__version__ 三 int tuple,低版 RuntimeError 含升级 hint,parse 失败不阻塞 — 修 Ubuntu 24.04 系统 boto3==1.34.46 shadow venv pin 致 converse_stream 裸 AttributeError) — s6 / Supervisor 5 修硬化:40d7c264f #46266 hermes_cli/profiles.py:1271 _maybe_register_gateway_service() 调 register_profile_gateway(start_now=False) + service_manager.py:964-965 写 (tmp_dir / "down").touch() marker;61ee2dbfd #46291 service_manager.py:756 _render_log_run 加 chown hermes:hermes "$HERMES_HOME/logs/gateways" 非递归 + docker/stage2-hook.sh:319 cont-init 预创父;b77096726 #46292 :359 _write_gateway_desired_state(name, desired_state) + 三 mutator (:821/:873/:883) 写 + container_boot.py:258 _read_desired_state 优先 desired_state 字段防 transient 抹运维意图;c2b7669ad #46289 :758 加 rm -f "$log_dir/lock" 在 chown 后 s6-log exec 前清陈旧 lockfile;95715dcb0 #46483 hermes_cli/main.py:467 _apply_profile_override 守 if profile_name is None and not os.environ.get("HERMES_S6_SUPERVISED_CHILD") 让 supervised gateway-default 跳过 sticky active_profile 回退 — Container / Dashboard 4 修:4eb0ff639 #46290 service_manager.py:118 gate 从 is_container() and _s6_running() 改为裸 _s6_running() 修 Fly Firecracker microVM 上 s6 dispatch 路径全 inert;aca11c227 #46293 container_boot.py:210 _strip_container_argv_prefix() + :237 _is_dashboard_container() + :439 main() 在 reconcile 前跳过;80f8ffc74 #46487 hermes_cli/main.py:10785-10790 cmd_dashboard() reroute env["HERMES_HOME"]=str(get_default_hermes_root()) 钉机器根防 $HOME/.hermes fallback;f79551378 #45120 scripts/install.ps1:1431-1442 重建 venv 前 taskkill /F /T /IM hermes.exe /FI "PID ne $myPid" + 800ms sleep 释 _bcrypt.pyd 锁 — Tools — 文件工具尊重 session cwd(PR #46552 salvage 5 commit):d6a8d9dca _authoritative_workspace_root 加新 "registered task/session cwd override" 步 + ddf7c7af8 terminal_tool.py:1037-1052 resolve_task_overrides(task_id) 单 helper 路由 file_tools._registered_task_cwd_override 与 _get_file_ops + b0c99c12d docstring 列四步顺序 + 8fce54499 file_tools.py:99-113 _sentinel_free_abs_cwd(raw) 抽 sentinel + expanduser + isabs validation 尾段(用 _TERMINAL_CWD_SENTINELS frozenset :96)+ 6cb88a087 merge — Cron — jobs.json 跨进程 fcntl/msvcrt 锁 e5b4cf7be + 733472952(cron/jobs.py:58-59 _jobs_file_lock=threading.RLock() + _jobs_lock_state=threading.local() 重入追踪 + :70 _jobs_lock() contextmanager Unix fcntl.flock(LOCK_EX) / Windows msvcrt.locking(LK_LOCK,1) 跨进程 + :89-129 depth-count 重入 + :554 _save_jobs_unlocked() private + 全 mutator 包 with _jobs_lock():(create/update/remove/mark_job_run/advance_next_run/get_due_jobs/rewrite_skill_refs)+ agent/curator_backup.py:459/466 _restore_cron_skill_links 走 _jobs_lock)— Process — completion 五态 + termination_source be7c919bf #46659(tools/process_registry.py:103-104 ProcessSession.completion_reason: str = "exited" 枚举 exited|killed|lost|failed_start|already_exited + termination_source: str = "" 枚举 process.kill|kill_all|backend_lost|failed_start + kill_process(*, source="process.kill") + 全 payload 含两字段 + :1619 format_process_notification 按 completion_reason 选 _status 文本 + exit code -15/143 append ", SIGTERM" + gateway/run.py:12337 agent-notify 合成走 format_process_notification({...}))— Messaging — WhatsApp group JID 路由 target ea49a7963 + 0d82060c7(tools/send_message_tool.py:47-49 _WHATSAPP_JID_RE 匹配 @g.us|s.whatsapp.net|lid|broadcast|newsletter + :520-525 _parse_target_ref whatsapp 分支返 (target_ref, None, True) + gateway/channel_directory.py:26 CHANNEL_ALIASES_PATH=get_hermes_home()/"channel_aliases.json" + :29 _load_channel_aliases + :40 _apply_channel_aliases(platforms) 在 rebuild 与 load 时都应用 + 0d82060c7 加入备份) — Desktop cluster:eae3836eb + f02484feb + 30377e108 + 45e2f4fdc @assistant-ui/store 0.2.13 pin(package.json:38-41 overrides + .github/workflows/typecheck.yml:33-42 新 desktop-build job 跑 npm run --prefix apps/desktop build 让 vite break 在 CI 暴露 + nix/lib.nix:24 npmDepsHash="sha256-m9cjbjzi4SaFCjODfdrawS5e+1ag+MpRn528/upSNqo=");f3b32e9f5 + c23a2eec1 + c33e0457d #46836 macOS Electron pack 重命名前补缺(apps/desktop/package.json:23 "prebuilder": ".../patch-electron-builder-mac-binary.cjs" + :138 "electronDist": "../../node_modules/electron/dist" + 新脚本 60 行 darwin-only patch app-builder-lib/out/electron/electronMac.js doRename() 在 rename → Hermes 前从 runtime dist 复缺失的 Contents/MacOS/Electron 修 ENOENT);fbabf438a + bee13817f apps/desktop/src/store/profile.ts:213 ensureGatewayProfile() 在 gateway swap 后 resync $connection,让 remote pool profile 激活为后台后 image 附件走 image.attach_bytes 而非路径 image.attach;0bbf325a8 #46665 dashboard 聊天侧栏 model card 经 session.create 传 management profile;ed20f5ed0 #42241/#46796 tui_gateway/server.py:1957 _apply_model_switch(parsed_flags=...) + :7013-7030 config.set 预解析显式 --provider 时绕开 broken-default agent build + Renderer use-model-controls.ts 发 config.set 替 slash.exec;368fcf1ff #46772 新 apps/desktop/electron/windows-user-env.cjs parse reg query + main.cjs:243-265 resolveHermesHome() Windows 上先读 HKCU\Environment 注册表;8fe334b05 #44159 apps/desktop/src/components/pane-shell/pane-shell.tsx:88 HOVER_REVEAL_EDGE_GUTTER='calc(0.5rem + 2px)';ae433634d apps/bootstrap-installer/tsconfig.json + shared/tsconfig.json ES2023 — Install / Deps:a4ee1f223 + 98205da00 + 1db8f7ea8 + 39f479cba #46085 scripts/install.sh:427-433 configure_managed_node_npm_prefix() + scripts/lib/node-bootstrap.sh:65-71 _nb_configure_npm_prefix() 写 prefix=$(dirname link_dir) 进 $HERMES_HOME/node/etc/npmrc 让 npm install -g 落 on-PATH 命令链接目录;0bbff1fc7 #46744 pyproject.toml:104 "websockets==15.0.1" 入核 + :138 dev=[..., "setuptools==81.0.0"] 从 82.0.1 降配 torch>=2.11 caps setuptools<82;5f6be7f31 #46764 :182 teams=["microsoft-teams-apps==2.0.13.4","aiohttp==3.13.4"] optional extra + tools/lazy_deps.py:159 "platform.teams" lazy-install + plugins/platforms/teams/adapter.py check_teams_requirements() 调 ensure_and_bind('platform.teams',...) — CI:9eb0bcd60 删 .github/workflows/nix-lockfile-fix.yml + nix.yml;29c698559 nix/lib.nix:24 npmDepsHash 刷新;92a456f71 esbuild/vite 锁回升(vite ^8.0.16 / esbuild ^0.28.1)+ hermes_cli/main.py autostash 防 update 时丢本地编辑;30377e108 Desktop renderer build on PRs(见上 @assistant-ui/store 集群)— Discord — slash 100 cap PR #46078:5e851bc6b + 8f4a718f9 + cffd6e3c8(merge) plugins/platforms/discord/adapter.py:39 _DISCORD_MAX_APP_COMMANDS=100 + :3530 slot_cap=_DISCORD_MAX_APP_COMMANDS-1 保 /skill group + skip 逻辑两循环 + :3613-3620 一条警告 + 200 commands 回归测 — Web — revert(web) Parallel keyless search 撤回 f3fe99863 #46350(plugins/web/parallel/provider.py 净 -345 + 删两测试文件 + tools/web_tools.py -234 + pyproject.toml SDK pin 撤)— Misc:a829e04d6 #46345 hermes_cli/profiles.py:458-486 _migrate_profile_config_if_outdated(profile_dir) 用 set_hermes_home_override scope check_config_version() / migrate_config(interactive=False, quiet=True) 到新 profile + 清 override 防伪 v0→latest 警告 + b2a476646/2a08b8c86 hermes_cli/dump.py:255-272 env override ≠ config 时输出 "{env_backend} (TERMINAL_ENV overrides ...)"+ 2f2e3616b tools/browser_tool.py:1180-1201 _get_session_inactivity_timeout() 读 browser.inactivity_timeout + 5b2604df9 hermes_state.py:1133-1135 v10 trigram 回填在 v11 FTS rebuild 前跳 + 9df1a1a8d hermes_cli/doctor.py:791-802 providers_accepting_vendor_slugs 加 "nvidia" + 60cc42e38 hermes_cli/inventory.py:160-188 user-defined ↔ aggregator 模型去重 + ba3883cd1 + 49e743985 MiniMax M3 reasoning extra_body 入 plugins/model-providers/minimax/__init__.py MiniMaxProfile.extra_body_for() 只在 api.minimax.io AND {"minimax-m3","minimax/minimax-m3"} 两 predicate 都真时发 {"reasoning_split":True} + 975b9f0a5 #46646 CONTRIBUTING.md 加 standard installer 节 + f7c1cbe66 #46795 桌面下载链接到站点根 + 4 条 AUTHOR_MAP(f79b109f4 0xneobyte / c17469cb1 Veritas-7 / 1227007ae capt-marbles / c23a2eec1 #38673 salvaged)— 验证基线 /tmp/hermes-agent clone @ cffd6e3c8 + 4 个并行 research agent 实证

  • 2026-06-14-update: 83 commits 单日同步(hermes-agent 0a865e5 → 2a14e8957,仍 v0.16.0 未发新版;约 54 fix / 6 perf / 6 feat / 5 test / 3 chore / 1 refactor / 1 docs / 1 style / 1 unscoped / 5 merge;~23.5h 单日窗口;166 文件 +8907/−692)— SSL CA bundle fail-fast guard a218a0f15 主轴 + 5 修 新建 agent/ssl_guard.py 94 行 + agent/errors.py SSLConfigurationError + escape hatch HERMES_SKIP_SSL_GUARD + hermes_cli/doctor.py:316-318 "SSL / CA Certificates" 节 + 调用点上移到 agent/agent_init.py:903-905 _create_openai_client setup 内 — MCP stdio config exfil-shape 拦截:972a9885e (#46083) + a27d7e68c (#46112) 新 hermes_cli/mcp_security.py 96 行 双门匹配 _SHELL_INTERPRETERS frozenset + _EGRESS_PATTERN curl|wget|nc|ncat|socat|/dev/tcp/|Invoke-WebRequest + _EXFIL_HINT_PATTERN .env|--data-binary|-X POST| + 89bdb1e54 hermes_cli/web_server.py:10659/10709 read_text(encoding="utf-8") — Agent — 模型 refusal 不重试改直透 content_filter c8ad2ca99 PR#46013 4 连:bb46bf8ce Anthropic + Chat Completions transport 把 refusal 映射 finish_reason="content_filter" + 12c84d6c7 只在 refusal 是唯一 payload 时算终止 + 10bd01972 共享 _content_policy_blocked_result() builder agent/conversation_loop.py:411-433 + _CONTENT_POLICY_RECOVERY_HINT 常量 :405-408 提 hermes fallback add — Codex reasoning thinking-only 069bfd654 + 1d584a301 run_agent.py:905-936 _disable_codex_reasoning_replay() 弹 codex_reasoning_items + :3278-3343 _is_thinking_only_assistant() 把 item.type=="reasoning" 列表项当 thinking-only — Gateway 中断 replay 清理 5191c1c2c + 2c174bce2 gateway/run.py:767-776 _is_interrupted_tool_result() 识 exit_code 130/-1 + :779-822 _strip_interrupted_tool_tails() 删被中断 assistant→tool 段 + :825-837 _AUTO_CONTINUE_NOTE_PREFIX="[System note: Your previous turn" + 保新输入 — Gateway 启动 auto-resume 串行 10bad2faf #46074 gateway/run.py:4642-4699 新 _queue_startup_restore_event() / _drain_startup_restore_queue() / _finish_startup_restore() — Gateway repaired-turn 持久 2b4873f7f #46071 run_agent.py:1548-1641 改 _flushed_db_message_ids 身份追踪取代位置切片防 repair_message_sequence 缩短历史时丢新尾 — Gateway intentional silence tokens 293c04fef + 0e22bf643 #46105 gateway/response_filters.py:13 SILENT_REPLY_TOKEN="NO_REPLY" + :18-23 LIVE_GATEWAY_SILENT_MARKERS=frozenset({"[SILENT]","SILENT","NO_REPLY","NO REPLY"}) + :30-44 is_intentional_silence_response() 精确匹配 ≤64 字符 + 全响应等于 token 才静默 — Gateway shell-supervisor guard 7433d5f0e + 143679305 hermes_cli/gateway.py:3798-3818 _running_under_gateway_supervisor() 检 INVOCATION_ID/HERMES_S6_SUPERVISED_CHILD/XPC_SERVICE_NAME!="0" + :3821-3858 _guard_supervised_gateway_conflict() + :3861-3880 PID 文件 scoping — Gateway 回复消息媒体附件 efbe1635d #46107 gateway/platforms/telegram.py:5563-5606 _cache_replied_media() 从 msg.reply_to_message 下载 + cache + 文本附 [Replied-to '' saved at: ] — Profile / HOME 隔离 b00060ce5 + 723c2331b + d842155da + 9f33d673e hermes_constants.py:362-395 get_subprocess_home() 看 TERMINAL_HOME_MODE=auto|real|profile + :398-405 apply_subprocess_home_env() 设 HERMES_REAL_HOME 与 HOME + TUI tui_gateway/server.py:1222-1236 _set_session_cwd() 走 profile-scoped _session_db(session) helper — Skills cluster 6c34088a1 PR#46237 + fc2b8b3d3 PR#46236 5 commit:7f245b003 #45966 gateway/run.py:14376-14414 跨进程缓存失效经 message_count 对比 + 3bc4a2ff7 :12801-12850 _refresh_agent_cache_message_count() 每轮 rebase + 7bbe7024c #46201 全局/平台 disabled 并集 + ce19fdb7c 解析点全跟进 + 4e6d05c6a #46149 agent/skill_utils.py:275 _RAW_CONFIG_CACHE mtime+size keyed — Skills bundled-update 备份崩溃安全 3581131e7 + 9a2b97632 tools/skills_sync.py:509-525/590-595/608-625 三段孤儿 .bak 复原 / 清陈旧 .bak 防 move 失败 / restore 前清部分 dest — Telegram rich messages 24h 内两次翻转:57c2a55be 端点 404 退路 → 12682d96b feat 配置 opt-out 还原 → 9459057d7 #46102 math crash 守 → a1f51feb7 #46206(HEAD)默 False + prefers_fresh_final_streaming() 无条件返 False(gateway/platforms/telegram.py:426 _coerce_bool_extra("rich_messages", False)) — Email SMTP_SSL port 465 + IPv4 兜底 04d4471d7 + cf7d5932f gateway/platforms/email.py:354-394 _connect_smtp() 合并 4 call site;port 465 走 smtp_ssl_cls(...),否则 SMTP+starttls;超时/连接错 retry _connect(ipv4_only=True);:110 _IPv4SMTP_SSL 用 AF_INET/SOCK_STREAM — Models — ZAI GLM-5.2 1M 上下文 bff78a34d + Kimi K2.7 Code 原生 picker 2a14e8957 #46309 agent/model_metadata.py:270 "glm-5.2": 1_048_576(needle-in-haystack 789K 实证)+ hermes_cli/models.py:60/181/260/285 全链路 + provider_model_ids() 对 {"kimi-coding","kimi-coding-cn"} 合并 curated 与 live 保留 K2.7-code — OpenRouter 元数据磁盘缓存 13a1bd0f8 #46114 agent/model_metadata.py:116-119 cache/openrouter_model_metadata.json + 紧凑 JSON atomic_json_write(indent=0) + :110 _MODEL_CACHE_TTL=3600 1 小时 + 内存→磁盘→live /api/v1/models 三级回退 — Perf wave:afc861550 #46065 Webhook 增量 prune(Deque 懒 O(stale) + _RATE_WINDOW_SECONDS=60.0)+ 110687914 #45831 tools/process_registry.py:132 _completion_event: threading.Event + :1098-1127 wait() 替 sleep(1) + 8f278403d #45948 _rpc_server_loop(stop_event) settimeout 5→0.05 + 5105c3651 #46079 api-server _normalize_chat_content O(n²)→O(n) + 4b5ba112a #45979 agent/conversation_loop.py:74-100 _image_error_max_dimension() 解析 provider 错文本 clamp [512, 8000] — Misc:bf8effad0 #43852 utils.py:63 atomic_replace() 跨设备 EXDEV/EBUSY → copyfile+copystat+fsync+unlink 兜底 + 85e6232a0 Anthropic proxy /v1 支持(build_anthropic_client() 剥尾 + _endpoint_speaks_anthropic_messages() 识 /anthropic/v1)+ 8d5d36d79 #28479 model_tools.py:1115-1125 透 session_id 到 registry.dispatch + e986e3fc6 + 1b16c4817 Provider OAuth 账号移除 DELETE /api/providers/oauth/{provider_id} 守 _require_token + _oauth_provider_disconnect_hint + 1fa761f8d #36142 Search 超时保部分结果 limit_reason="search_timeout" + 288f7026e Weixin "Personal" 重标 + d76a58bd1 sudo profile system install + 3 条 AUTHOR_MAP — 验证基线 /tmp/hermes-agent clone @ 2a14e8957 + 4 个并行 research agent 实证

  • 2026-06-13-update: 391 commits 跨日同步(hermes-agent 6c752ca3a → 0a865e5,仍 v0.16.0 未发新版;约 211 fix / 39 chore / 35 feat / 21 test / 18 refactor / 10 docs / 9 perf / 30 merge;~48h 双日窗口;含两批 historic salvage 2026-05-19~05-23 ≈167 commit 在本期并入;446 文件 +31366/−4724)— Desktop UX 大改 d62979a (#44630)(composer status stack apps/desktop/src/store/composer-status.ts 257 行 合并 $subagentsBySession/$backgroundStatusBySession/$todosBySession + 实时 subagent 窗口 openSessionInNewWindow + 用户气泡 `` 流式中可编辑 thread.tsx:976 + BrailleSpinner → GlyphSpinner 改名)+ Stick-to-bottom bbf020e (#45263)(use-stick-to-bottom: ^1.1.6 + 76b9386 删 thread-virtualizer.tsx 481 行 改 thread-list.tsx 307 行 useStickToBottom + scroll-to-bottom-button.tsx 59 行 + withSessionBusyRetry 包所有 prompt.submit)+ Perf 三连 492c402 (#45343)(7c226cc ChatRuntimeBoundary 隔 $messages 订阅 + edc36f3 remend-tail.ts 108 行 LRU BLOCK_CACHE_MAX + REVEAL_MIN_COMMIT_MS = 33 + 3cf7d43 warm AudioContext 省 850ms)+ Worktree-aware 侧栏 e906726(git-worktrees.cjs 174 行 + use-worktree-info.ts 68 行 + workspace-groups.ts 326 行 + WorkspaceHeader/ReorderableList 抽取) — WhatsApp Business Cloud API 新平台 984e6cb(gateway/platforms/whatsapp_cloud.py 1956 行 + whatsapp_common.py 367 行 + setup_whatsapp_cloud.py 530 行;HMAC webhook + wamid dedup + 原生按钮 + opus 语音;Platform.WHATSAPP_CLOUD 在 gateway/run.py:6229-6239)— Photon iMessage spectrum-ts 3.0→3.1 573c4e6/9bfff6e(pkg :15 "spectrum-ts": "3.1.0" + markdown() builder 经 PHOTON_MARKDOWN + /react//unreact sidecar 端点)+ 156f4fb add_reaction/remove_reaction API + 05470aa action='unreact' send_message + tools/send_message_tool.py:173-177 + 0a963d8 hermes photon telemetry CLI 切换 — Telegram 富文本永远 on a59d5e3 (#45584) + 7c0605b 流式 final 仍富文本(prefers_fresh_final_streaming + RICH_MESSAGE_MAX_CHARS=32768) — 安全 fail-closed wave:fc46354 fix(security) own-policy adapter 无 allowlist 时 fail-closed(WhatsApp/WeCom/Weixin/QQBot/Yuanbao)gateway/authz_mixin.py:90-150,271-301 + 3380563 /api/status 受门时删 hermes_home/config_path/env_path/gateway_pid/gateway_health_url web_server.py:1679-1681 + c6a992e _host_derived_api_key() 注册标签链尾兜底 runtime_provider.py:103 + 5908822/9514ddb API key 不漏到非权威端点 + 4ead464 secure_parent_dir 拒 chmod / 和 len(parts) < 3 + 5edb346 profile 下 write-deny /.env agent/file_safety.py — Gateway auto-resume 重复 agent 防御 6e2fd95 + 63097ee(_schedule_resume_pending_sessions 在 asyncio.create_task 前占 _AGENT_PENDING_SENTINEL 槽 gateway/run.py:4498-4602 + 全路径回归 test_restart_resume_pending.py)+ JSONL 抄写降级 4 commit(b4b118c/351fdcc/024a8e3/1d27be0 state.db 唯一存储;磁盘既有 .jsonl 不动) + Kanban 6 修(34120a0 sticky block + 7bcdced respawn defer blocker_auth + 88ee58f stale 不计 failure + 7552e0f/7c622b6 idx 后置 migration + cb125c2 (#45590) worker toolsets 钉 profile) — Billing /credits 7ba5df0 (#44776)(agent/account_usage.py:342 CreditsView + cli.py:8399 _show_credits + gateway slash_commands.py:2945 + TUI server.py:4773 + c196269 充值时不提示) — Dashboard profile-scope 全量(62b4618 (#45598) 会话+分析 + 88dbf95 (#44792) Channels + _profile_scope(profile) 包所有端点)+ 28bf8fb feat clone profiles from any source + d206e1f 本地文件浏览 home + 9102d4a Win11 host 显示 + a118b94 (#45150) skill install 加 --yes — CLI 持久 approval scrollback 4474873 (#44702) + aa07983/bd66e7e/311ff96 Codex token 自愈(hermes_cli/auth.py:3527 _recover_codex_tokens_from_cli 从 ~/.codex 重导) + xAI 退役迁移 cluster(新 hermes_cli/xai_retirement.py:16 RETIREMENT_DATE="May 15, 2026" + hermes_cli/migrate.py cmd_migrate_xai ruamel 圆滑改写 + b4ba425 doctor 表面 + a8a05c8 启动告警 + b4afc65 encrypted reasoning replay + 64a9a19 (#28952) 钉 x.ai 源 + a0c0312 xAI Web Search plugin 560 行 + ca192cf opt-in TTS 停顿) — Bitwarden Secrets Manager 552e9c7 (#30035)(agent/secret_sources/bitwarden.py 515 行 + _BWS_VERSION="2.0.0" + install_bws() 懒载到 ~/.hermes/bin/bws SHA-256 校验 + secrets_cli.py setup/status/sync/disable/install) — Context Compression 重构波 11 commit(aec3885 保近期轮 + 434c684/c7bee8f 自动聚焦近期用户轮 + 8905ee6/5d0408d flush 游标 clamp/snapshot + 691ff7c (#29824) 末助手 reply 留 tail + 2fef3e2 (#29824) 合并 tail 拆分 + 0db5cb8 _SUMMARY_END_MARKER 提至 :92 + 749b721 两 role 都附 marker + 956af7f (#38389) COMPRESSED_SUMMARY_METADATA_KEY = "_compressed_summary" 下划线前缀 wire 自剥 + 286ecd2/8e5b759 _MEDIA_DIRECTIVE_RE 剥摘要器输入) — Perf wave:544c31b (#28866) agent-loop 47% per-conv 函数调用削减(load_config_readonly 快路径 + agent/redact.py 重写 + _resolved_api_call_timeout 缓存)+ 6bd4311 (#29006) adaptive subprocess poll 省 ~195ms/工具调用 + 6cb9917 (#28957) 压缩可行性检查延后 — Models / Providers:957a8ff Bedrock 受限 Claude 省采样参数 + eed61a1 Gemini systemInstruction 加 role + c8e5f34 (#36141) 剥 google//gemini/ 自前缀 + 5acd185 Moonshot union 数组 + 4fd9397 Codex chatgpt.com 移 extra_headers + 7d11fa4 Codex final_answer 完成顶层 incomplete 响应 + bc060c7 (#45492) 移 unavailable claude-fable-5 + 643dc82 自定义 provider 会话身份保真 + e256f4a 不恢复 bare billing provider {"auto","openrouter","custom"} + 4b646bc (#45587) 辅助保主 base_url + 6a159be (#27132) ollama/vllm/llamacpp 别名信任 — Delegation 默认子代理时钟移除 bba9b51 (#45149)(DEFAULT_CHILD_TIMEOUT: Optional[float] = None) — MCP 5affecb (#44550) capability-gate tools/list 让 prompt-only MCP server 也连 — Skills hub:2ee69d0 (#44500) ClawHub 浏览预算允许 unlimited + fc7e04e/8f92327/c6a380e identifier 级去重 + 1899c8f youtube 经 uv + 3fde8c1 (#30042) 排除依赖/venv + 4373e80 (#45616) Pages 部署回退健康索引 — Computer-use:e02a7e5/531efe7 SOM/vision 路由 auxiliary.vision + 5aa4727 app= 过滤无匹配明示 + 4cc1887 保 capture_after 的 app context + 18cd1e5 type_text MCP 名修正 + drag 动作 — Approval allow_permanent 81436e1/55a18e6 端到端透传到 TUI + Desktop 提示 — Update / Installer:aedb8ac (#28669) post-pull 语法校验 + 自动回滚 + 573b964/c814d3d 安装前清 unmerged-index + 9b01c4d (#45145) 不弹 polkit + 2a7308b (#26670) Windows hermes.exe 与并发实例隔离 + 78c11d9 更新前停 Windows gateway — Platform:f82cb48 + 1185dfd .xls/.doc/.ppt 加 SUPPORTED_DOCUMENT_TYPES + gateway/platforms/{signal.py,email.py} + plugins/platforms/simplex/adapter.py DOCUMENT 兜底 + 0fd34e8 (#44778) Teams 文档/视频/音频缓存 — TUI:2667601 reasoning-only 助手轮在恢复时仍可见 + b6c7ebf (#44953) provider_routing 透传 + b3f5e17/81cdbbd/d6df38b 长 approval 命令换行 — Misc:05b9c84/652dd9c Telegram Bot API 10.1 富文本 + 6724daa (#45592) CLI idle timer + 0333a99 (#45582) session-only analytics 合并 + dba6380ca/d1f23bb2d salvage Yuanbao wechat forward e20e0bd (#43508)

  • 2026-06-11-update: 212 commits 跨日同步(hermes-agent a5d05cf30 → 6c752ca3a,仍 v0.16.0 未发新版;约 131 fix / 25 feat / 9 chore / 6 test / 6 refactor / 3 style / 3 docs / 3 change / 1 revert / 1 perf / 15 merge / 5 misc;~48h 双日窗口)— Cron Recipes → Automation Blueprints 改名 + 14 蓝图 catalog(1593ca540 上线 → e8b757845/e976faac7 硬化 → cb29e8a82 rebrand:cron/recipe_catalog.py → cron/blueprint_catalog.py 713 行,tools/recipes → tools/blueprints,/cron-recipe → /blueprint(alias /bp),hermes://cron-recipe/ → hermes://blueprint/,dashboard /api/cron/recipes → /api/cron/blueprints;BlueprintSlot/AutomationBlueprint/fill_blueprint/blueprint_form_schema/blueprint_slash_command/blueprint_deeplink/blueprint_catalog_entry;slot 4 type time/enum/text/weekdays + WEEKDAY_PRESETS;14 个 blueprint;终结于同一 cron.jobs.create_job,无第二套 job 引擎;Electron hermes:// URL scheme + single-instance lock)+ Suggested Cron Jobs 9a09ea69f(cron/suggestions.py 257 行 + cron/suggestion_catalog.py 154 行 4 个 catalog entry;4 来源 catalog/recipe/usage/integration;dedup+latch 按 key、pending cap、accept 走同一 create_job;tools/blueprints.py:217 register_blueprint_suggestion)+ memory/skills write_approval 布尔门(96af61b6e (#38199) 上线三态 on|off|approve → 095f526b1 (#43354) 重构为 boolean write_approval 默 false + _config_version 28→29 migration → 70d5d7e39 (#43452) 修 inline prompt callback + gateway staging + /skills gateway review;tools/write_approval.py 493 行 write_approval_enabled/evaluate_gate;gateway /memory pending|approve|reject|mode + /skills pending|approve|reject|diff|mode;acd7932c0 文档 cross-link)+ Dashboard 统一多 profile 管理 875aa8f16 (#44007) 1419+/310− 跨 21 文件(web_server.py +566 行 profile 参数 query/body 加到 /api/config|env|mcp/servers|mcp/catalog|model/info|model/set 全走 _profile_scope();chat PTY ?profile= 让 child HERMES_HOME 指向 profile dir;CLI dashboard 走机器 dashboard --isolated 保旧;前端 ProfileProvider/ProfileSwitcher 全局 selector URL-persisted;body.profile > ?profile=;amber ProfileScopeBanner)+ 73dd58499 (#44220) MCP loop HERMES_HOME 上下文 propagate(OAuth token-store 跨 profile 修) + d986bb0c6 (#39084) Profile Builder + a09343cc9 (#44231) SKILL.md editor + cron modal attach-skill + fa7f24e89 Webhook enable from dashboard + 9c051f57c (#44286) Anthropic API Key 检 + 9c16ca879 (#44237) model 标准化 + backup confirm + c7bfc938d (#44374) Config 页 profile 路径 + 63a421d4c (#42578) _require_token 全部走 OAuth gate + 7df3aa34b (#43214) public_url 静默拒绝 warn — Coding-Context Posture 3e74f75e4 (#43316)(agent/coding_context.py 731 行 ContextProfile/RuntimeMode;4 域:System prompt operating brief + per-model edit-format tuning + skill index demote + Toolset collapse;activation agent.coding_context: auto|focus|on|off;subagent 自动继承;不 memoize)+ Skill index demote 而非 hide(ee1a744ac (#44342) API 改名 compact_skill_categories,每 skill 名字仍在 prompt 一行 names-only;4d6a133a9 (#44387) 一天后反转:demotion 只在 focus 模式下) + a4f179c50 (#44411) GPT/Codex steer V4A 单文件编辑(OpenAI codex-rs apply_patch 唯一 file editor) — Parallel Web Search & Extract e0e257171 1206+/98− 跨 15 文件(keyless 免费 Search MCP search.parallel.ai/mcp Streamable-HTTP JSON-RPC;keyed v1 REST client.search/extract;parallel-web 0.4.2→0.6.0)+ 0a5762c78 mcp-web-client 中性 identity + 93764b930/32a73010b keyless web default 永远兜底 — Bedrock e24c935cf (#44293) IAM 拒绝 InvokeModelWithResponseStream 时自动 fallback converse()(agent/bedrock_adapter.py:211 is_streaming_access_denied_error) — Anthropic 交错 thinking 5 连:aaccaada2 顺序保真 anthropic_content_blocks 端到端 verbatim + 529bb1c3d strip output-only SDK 字段 + 7a1eed826 redact replayed tool input + 加宽 400 classifier + 86e10dd87 thinking-modified 400 路由 recovery + 9f95f72b9 strip api_messages + efcbbde48 in-memory only — SUMMARY_PREFIX 4 连:8f8cad7ec (#41607) 抗陈旧任务 + d5e2fbf24 historical context framing + acb2954d8 历史 prefix 冻 + 6c752ca3a HEAD 收紧 wording(topic-overlap 三句塌缩成 WINS+discard 两句) — OpenRouter 183d86b3e (#43436) reasoning_effort 改 verbosity for adaptive Anthropic — Streaming 615ad9792 (#43570) socket read timeout floor 到 stale-stream 180/240/300s — Params 19c07c403 newer OpenAI 系列 max_completion_tokens 名匹配 + 2ce3ae3d1 错分类不误判 unsupported-param — Model 选择:af978ecb1/243cada15 昂贵模型确认 + 57c671499 (#43103) Anthropic aliases 保留 + 5a4297a11 MiniMax M3 hardcode 1M — Desktop registry-driven slash + /resume/handoff 3ffbdfbcc (#42351) 1914+/478− 跨 31 文件 — Desktop composer 解耦 + 草稿 localStorage 6 连(c710868fb/292192f7d/d7d281fa3/18d61bd06/3d14f01fd/fdc0d1956/65ddc7c4a per-session 附件) — Desktop VS Code Marketplace 主题 + 可调终端 pane + Floating HUD(27a321157 .vsix zlib 手写 zip reader + WCAG AA + 8f73d0d94 (#42521) resizable terminal pane + Ctrl+\`` toggle + 833410e02ANSI palette + Cmd-K HUD +ab5f1a1f1 (#43111)Mac 风^Tab/^⇧Tab/^1-9switcher +b96bd4808 (#43219)per-window chat +d33965396 (#43188)TUI titlebar session name) — **Desktop 远端 FS/api/fs/* 5 连**(51f47f9a9 web_server.py:1439-1514+db79e9013facade +8878484f8remote-picker.tsx 177 行 +56a0f48ba/9121834b3 tighten/scope) + **Desktop 远端 attach 5 连**(4906dcfc2stage OS dropsfile.attach/image.attach_bytes 覆盖每 drop surface + 缩略图/spinner/race/16MB toast 4 连) — **Desktop misc 18 修**(1770263cc (#43234)default project dir +0d3e2cc53 (#43487) lineage dedup + 9 个 #4xxxx 修 + Nous overlay HUD/filled icons) — **Sessions 3 连**:e96ca1a0d empty 退出/轮转清理(hermes_state.py:3697 delete_session_if_empty+cli.py:5863 _discard_session_if_empty)+ 04b3f1953归档压缩 lineage +218452b05 (#43149) sqlite_master 自愈(PRAGMA writable_schema=ONsurgery) — **Agent binary @file 引用 actionable**7ffc216bc + **PDF/DOCX/音频附件 note 改写**(e7ae145acPDF/DOCX +13650ab7f音频 +4e9be3ee3 test) — **Telegram 5 连**(3b4c715e1stripped-text fallback + tail-only delete guard + re-finalize skip +590b3c0d7partial overflow recover +da818510estream consumer cancelled finalize +d0e017bac (#44245)voice/audio >20MB pre-download gate +9ca969734 (#42090) transcribe tuple) — **Gateway 9 连**(13f1efdd1 (#43968)终端 header 折叠 +a8f404b29 (#40831)launchd domain probe +fa32af886/984e69ff6restart 去重 + post-Telegram QR auto-restart +5cf6e28a2 (#42675/#43236)容器重启 auto-start +f456f302d (#44267)临时 HERMES_HOME 拒写 service definition +264ac72b6/cb2c13055restart watcher env scrub +6a30cfca8 (#37556)post-delivery 前停 typing) — **Matrix4717989c1 (#18505)** room context 隔离 + handle_sync + allowed_users authz + i18n key + slash_commands mixin port — **Discord 7 连**:c3464ecf4 (#44383)runtime gateway task exit 恢复 +020ef76cf/08b1c44a5connect timeout cancel +311900842/aea0b7397voice-off 不断开 +e5580f43c/4eadef18a DISCORD_ALLOWED_ROLES 端到端 — **Skills hub 7 连**:298bb93d3 (#43398)live per-source 进度 +105625d65overall_timeout 真 honor + ClawHubCATALOG_WALK_BUDGET_SECONDS+eee1da45f (#43395)cold start bound +9caa12f4efrontmatter name 解析 +0a593f132/d1383a6b1 .envHERMES_HOME-aware +fdc90346e (#43221) red-team skills 移 optional(95%→25% block rate) — **Plugins/Web 3 连**:114e26573失败 sweep 不缓存 +93764b930/32a73010b keyless 兜底 — **Cron 5 连**:7d8d000b1 (#43956)per-job profile revert +acd4f34e6/f7a6d6a6aprovider "custom" resolve +702f4df19 (#41976)容器重启 ownership +b4170f3ac (#43223) no-skills 不严检 — **CLI/TUI**:8972a151a (#44265)状态栏 idle clock +2f1951234 (#43439)全平台 UTF-8 stdout/stderrTextIOWrapper.reconfigure()+b2043cf15/5508f4bc5TUI/whatsapp-bridge UTF-8 +f8fd30942 (#43320)/d03cdd63e (#43036)one-shot cleanup +0b5b7ddfd/help quick commands +3c489fda8 Slack 50-cap aliases — **Install/Update/Backup 7 连**:899acfe42winget 0x8A15002B 陈旧注册修 +9662b76d5PATH merge +a5c32cdf3 (#42172)中断 venv 自愈 +cedd9b6d4SSH 跳 passive +dd40600e0/ed2b9e43c backup SQLite 同位 + 嵌套 skill 纳入 — **Tooling 20 连**:a72bb0375 (#38749)Docker 缩减 +5d8c44a39 (#30399)matrix 预装 +464276228Langfuse data URI redact +47e77ae16Curator atomic +dca11b665/e71d74682MCP stdio +3edd09a46 (#44205)WhatsApp stale bridge restart +4cecb1a13/90f4b3040/3bfbb3f2anpm audit / TS 6 / CI typecheck +72154ad87CI uv cache +f082b4ec5/07ac18590exit-4 runner +af3c8b80bpid-file race +6110aed9b (#43669)free model 抑 +15813336c/e4a1b35a3.env mode +1c055a4c5Grok Build code +6b330522e (#42641) AGENTS.md 设计哲学 — **TTS Gemini**:5718811depersona +2c1920822 audio tag rewrite(tools/tts_tool.py +143 行`)

  • 2026-06-09-update: 105 commits 跨日同步(hermes-agent 754154a9c → a5d05cf30,仍 v0.16.0 未发新版;约 56 fix / 17 feat / 11 test / 5 chore / 3 refactor / 2 docs / 1 ci / 1 style / 8 merge)— Photon iMessage 4e4d27875 feat: gRPC-native iMessage channel (no webhook) 主轴收官(删 aiohttp webhook receiver + HMAC-SHA256 验签 + PHOTON_WEBHOOK_* 5 个 env + CLI webhook register/list/delete 3 子命令;改 GET /inbound NDJSON 长连接 + 25s heartbeat + consumer-state-machine;adapter docstring 重写 "Bidirectional bridge via spectrum-ts SDK gRPC stream";plugin.yaml:4 0.1.0 → 0.2.0;project_id 语义改写为 spectrumProjectId)+ 20 commit 跟进硬化(92dfd70d6 (#42732) 生产硬化六件套:5 条 npm overrides 钉补丁版钳 protobufjs GHSA-66ff-xgx4-vchm + 4 个 @opentelemetry OTLP exporter CVE / crypto.timingSafeEqual 替 !== token compare / 2 MiB body size cap / re-subscribe capped exponential backoff + jitter / unhandledRejection 处理 / dedup 按 insertion order 严格淘汰 4000 entries;b3aef57f2 TYPE_CHECKING 包 httpx 修类型 + connect 局部 client ref 防 race;9fb83eaa2 spectrum-ts ^1.18.0 + npm install spectrum-ts@latest;314af28e8 + dbf2470d4 入站附件/语音 base64 inline cap 20MiB → cache image/audio/document + voice MessageType + force_audio kwarg;4615e08d3 (#42397) 出站 6 方法 override (send_image/_file/_voice/_video/_document/_animation) 经 spectrum-ts attachment()/voice() builder + /send-attachment 端点 + cron multimedia + validate_media_delivery_path 二次校验;fdf48c63c/e79e44af7/0d25cae04 API 收敛走 spectrumText/spectrumReply/spectrumTyping 后又删 replyTo(实测 iMessage 不可靠)+ typing 统一 space.send(spectrumTyping(state));2130ef68b flattenGroups: true;064665688/92179352f/3b983e779 Home channel 支持裸 E.164 + DM GUID + _PHONE_PLATFORMS 加 photon + setup 自动 allowlist + _env_enablement home_channel seed;e9b26c7c8/84e4b4b9a/b58ff9345 彩色 banner + assignedPhoneNumber 取号 + auth.json 持久化 phone numbers;033765890 user API 全迁 Spectrum backend Basic auth + DEFAULT_SPECTRUM_HOST="https://spectrum.photon.codes";37561c214 device client_id hermes-agent → photon-cli 修 400 invalid_client + token 双重 validate(PhotonDashboardAuthError + validate_photon_token 先 /api/auth/get-session 再 /api/projects/);637cf94be strip_markdown + _send_with_retry(max_retries=2, base_delay=2.0) 指数退避)— SimpleX 1.1.0 大演进 0c2e81df0(PR #27978 salvage:群组 SIMPLEX_GROUP_ALLOWED 逗号分隔或 * 默认 disabled + chat_id=group:;入站文件 rcvFileDescrReady→rcvFileComplete 延迟流程 + _pending_file_transfers;原生出站媒体 send_image/video/document/voice 全按