调试与排错
看日志
插件在 Hermes 自身日志管线之外,额外用了一套 OpenClaw 风格的文件日志,按天写在:
~/.yoooclaw/plugins/yoooclaw-hermes/logs/YYYY-MM-DD.logYOOOCLAW_HERMES_LOG_DIR 可以覆盖日志目录。稳定版会在写文件、以及把记录交给 Hermes 上游日志 handler 之前,脱敏常见的密钥、用户文本、用户 URL、邮箱、手机号、bearer token、JWT 和长十六进制 token;版本号里带 beta 的构建会保留原始日志,方便调试(和 OpenClaw 插件的行为一致)。排错时要留意:脱敏可能把真正出问题的那个值(比如 api-key 的某个片段)也一起遮住了,需要看原始值时确认插件版本号是否带 beta。超过 30 天的日志会自动清理,用 YOOOCLAW_HERMES_LOG_RETENTION_DAYS 调整保留天数。
通过 Hermes 插件 CLI 检索日志:
hermes yoooclaw logs --keyword relay --from 2026-06-01 --to 2026-06-04 --limit 50自更新安装日志单独存放:<state_root>/hermes-plugin/update/update.log,退出码在同目录的 exit_code 文件里。
Lifecycle 诊断
升级或连接异常时,先看 lifecycle 状态:
hermes yoooclaw lifecycle status重点看三处:components.mode 是不是 daemonless、daemon.storage.claimed 是不是 true(写者锁已被本进程持有)、generation 是否匹配当前插件版本 / profile / Relay environment / api-key。对不上时插件本该自动重建服务组;如果没有,手动触发一次:
hermes yoooclaw lifecycle restartgeneration 是插件版本、当前 profile、Relay environment、PHONE_NOTIFICATIONS_ENV、openclaw-service URL 和 api-key 指纹一起算出的 SHA-256(取前 24 位)。任何一项变化都会让 generation 对不上,触发整组重建。
lifecycle status 的 status 字段:
| 状态 | 含义 | watchdog 行为 |
|---|---|---|
running | 隧道已连接且 generation 与当前配置一致 | 无动作 |
stopped | 没有已登记的 transport(插件未连接 / 已断开) | 无动作 |
mismatch | generation 与当前配置对不上,或收到过 lifecycle restart 请求 | 下一轮轮询(默认 ≤5 秒)disconnect + connect 重建隧道;需连续达到 YOOOCLAW_HERMES_LIFECYCLE_MISMATCH_STREAK(默认 2 次)门槛,避免探测抖动误杀 |
daemon 字段名保留是为了兼容 lifecycle.json 的历史消费方,内容已经是存储接管状态(mode: daemonless + storage.{claimed,profileDir,writerLock}),不再有 daemon 进程信息。
环境与 Relay 排查
hermes yoooclaw env # 当前 profile + Relay 状态
yoooclaw auth status # api-key 是否就位(与插件共享 credentials.json)插件模式下不要看 yoooclaw tunnel status
隧道在插件进程里,CLI 侧没有 daemon 也没有隧道。实际的 openclaw-service 连接由插件的 OpenClawRelayTransport 维护,状态只以 lifecycle status 和插件日志为准。同理,yoooclaw daemon start 在插件持锁期间会返回 YOOOCLAW_DAEMON_DISABLED_BY_PLUGIN —— 这是预期行为,不是故障。
云端主机(隧道 / 灯效 / 灯效规则 / ASR 共用)的解析优先级是 PHONE_NOTIFICATIONS_ENV 等环境变量 > cloud.host > relay.url 的域名 > 内置默认 production。环境变量传了未知值不会报错,会静默回落到 production —— 如果发现环境切换「看起来没生效」,先确认变量拼写,再看 yoooclaw config show 里的 cloud.host。完整规则见独立 CLI:环境 / 主机对不上。
常见错误信息对照
以下是插件代码里会抛出的原始错误信息(含 code),可以直接拿关键字去日志或对话里搜:
| 错误信息 | code | 触发场景 | 处理 |
|---|---|---|---|
Embedded YoooClaw CLI is not available for <os>/<arch>. | YOOOCLAW_CLI_UNSUPPORTED_PLATFORM | 当前平台没有内置的 CLI 二进制(仅支持 darwin-arm64/x64、linux-arm64/x64、win32-x64) | 确认运行平台是否受支持 |
Embedded CLI binary is missing: <path>. | YOOOCLAW_CLI_BINARY_MISSING | 内置二进制文件丢失 | 重新安装插件 |
Embedded CLI checksum mismatch: <path>. | YOOOCLAW_CLI_CHECKSUM_MISMATCH | 内置二进制被篡改或安装损坏 | 见下文「CLI 校验和不匹配」 |
YoooClaw CLI timed out after <n>s. | YOOOCLAW_CLI_TIMEOUT | 调用内置 CLI 子进程超时 | 看插件日志确认是哪条命令,必要时加大超时 |
Could not find \yc`, `yoooclaw` in PATH.` | YOOOCLAW_CLI_NOT_FOUND | PATH 里既没有内置 shim 也没有本地开发环境的 yc/yoooclaw | 检查 YOOOCLAW_HERMES_INSTALL_CLI 是否被设为 0,或 YOOOCLAW_CLI_PATH 指向了不存在的路径 |
profile writer lock is held by another process: <path> | — | 存储写者锁被别的进程占着(多半是还在跑的 yoooclaw daemon,或另一个 Hermes 实例) | 停掉那个进程后 hermes yoooclaw lifecycle restart;接管失败不阻塞聊天,只是 ingest 走回退路径 |
YOOOCLAW_NOT_IMPLEMENTED on recordings.retranscribe / asr.init | YOOOCLAW_NOT_IMPLEMENTED | 插件模式下本机不跑 ASR | 预期行为:Hermes 场景的转写由 App 侧完成并经 recordings.result.write 下发 |
YoooClaw openclaw-service Relay api-key is missing | — | 没有配置 api-key 就尝试连接 Relay | yoooclaw auth set-default-api-key |
YoooClaw openclaw-service Relay authentication failed label=... : ... Update ~/.yoooclaw/credentials.json and reconnect. | — | api-key 被拒绝(401/403/4401/invalid apikey),不会无限静默重试 | 更新 credentials.json 里对应的 key,仅靠自动重连解决不了 |
Timed out connecting to YoooClaw openclaw-service Relay | — | 握手阶段超时 | 检查网络连通性 |
YoooClaw Relay is disconnected / openclaw-service Relay is disconnected | — | 尝试在没有已连接隧道时发送帧 | 等待重连,或手动 lifecycle restart |
No active YoooClaw APP route for chat <id> | — | 目标 APP 会话没有对应的活跃连接 | 确认 APP 端是否在线 |
YoooClaw daemon is not running / YoooClaw daemon status did not include a port | — | 少数仍会回退 daemon HTTP 的路径找不到 daemon(daemonless 模式下正常没有) | 确认 lifecycle status 里 storage.claimed 为 true;接管成功后这些路径不会被走到 |
更新未执行:需要用户在对话中明确同意后,以 confirm=true 调用。 | YOOOCLAW_UPDATE_NOT_CONFIRMED | 模型调用更新工具时没有传 confirm=true | 需要在对话里明确同意后再次调用 |
当前插件是开发(editable/源码树)安装,拒绝自动更新;请在插件仓库里手动升级。 | YOOOCLAW_UPDATE_EDITABLE_INSTALL | 插件是 pip install -e 的可编辑安装 | 手动在源码树里升级,不要走自更新 |
已有更新正在进行(目标版本 ...),请等待其完成。 | YOOOCLAW_UPDATE_IN_PROGRESS | 已有一次更新在跑 | 等待完成;如果 pending.json 已经超过超时时间(默认 1800s)仍未清除,会被视为「陈旧」并自动放行新的更新 |
目标版本号不合法:<v> | YOOOCLAW_UPDATE_BAD_VERSION | 传入的版本号格式不对 | 检查版本号格式 |
当前版本 ... 已不低于目标版本 ...,无需更新。 | YOOOCLAW_UPDATE_NOT_NEWER | 目标版本不比当前版本新 | 无需操作 |
下载安装器失败:<error> | YOOOCLAW_UPDATE_INSTALLER_FETCH_FAILED | 从 OSS 拉取安装脚本失败 | 检查网络,或稍后重试 |
启动更新进程失败:<error> | YOOOCLAW_UPDATE_SPAWN_FAILED | 启动更新子进程失败 | 检查权限与磁盘空间 |
常见症状 → 处理
hermes plugins enable yoooclaw 报错找不到插件
Hermes 0.15.1 及更早版本的 plugins enable/disable/list 只认目录形式插件,不扫描 Python entry points。直接编辑 ~/.hermes/config.yaml:
plugins:
enabled: [yoooclaw, yoooclaw_app]再 hermes gateway restart。一键安装器已经自动写好这一步,只有手动 pip install 时才需要自己处理。
安装器报「Hermes 版本过低」直接中止
需要 Hermes Agent >= 0.14.0,因为 APP 适配器依赖的 PluginContext.register_platform 平台 API 更早版本没有。先升级 Hermes(hermes update),再重新跑安装器 —— 这是设计如此的硬性检查,不是安装器 bug。
安装器报「无法确定 Hermes 的 Python 环境」
安装器会尝试若干标准路径寻找 Hermes 使用的 venv Python,找不到就直接拒绝安装(不会装进一个通用 Python 环境,避免 gateway 之后 import 不到插件)。报错会列出它尝试过的路径。解决办法三选一:设置 HERMES_HOME;把 Hermes 自带的 hermes 命令加进 PATH;或者直接用 --python /path/to/hermes-agent/venv/bin/python 显式指定。
安装器报「Python 版本过低」
yoooclaw-hermes-plugin 要求 Python ≥ 3.11。检查 Hermes 使用的 venv 是用什么 Python 版本创建的,必要时重建 venv。
CLI 校验和不匹配(YOOOCLAW_CLI_CHECKSUM_MISMATCH)
内置 CLI 二进制文件的哈希和插件包内 manifest.json 记录的不一致,通常是安装包损坏或文件被意外改动。插件会先尝试回退到之前缓存过的安装(按 mtime 取最新一份),如果没有可用的缓存就保持 PATH 不变(此时命令会报 YOOOCLAW_CLI_NOT_FOUND)。彻底解决需要重新安装插件。
APP 连不上 / 会话没反应
按顺序确认:
yoooclaw auth status—— account 级 api-key 已配置,且和插件共享同一份~/.yoooclaw/credentials.json;- 环境变量里没有残留的
YOOOCLAW_APP_API_KEY/YOOOCLAW_API_KEY/YOOOCLAW_APP_ALLOWED_USERS/YOOOCLAW_APP_ALLOW_ALL_USERS/ 已废弃的YOOOCLAW_APP_RELAY_URL(安装器每次安装都会从~/.hermes/.env里清掉这几个,但手动改过环境变量的话要自己查); hermes yoooclaw lifecycle status——status=running、storage.claimed=true、generation 对得上;- 插件日志里
--keyword relay看有没有连接错误; - 如果报的是
chat.send is only allowed for yoooclaw_app sessions,说明目标 session 不属于yoooclaw_app—— 插件对跨渠道的chat.send会直接拒绝,不是 bug; - 多设备场景下,同一个 api-key 的所有连接会收到同一条广播,每个 Hermes 实例各自处理一次,可能导致重复的响应帧——如果看到「同一条消息回复了两次」,先确认是不是跑了多个 Hermes 实例共用同一把 key。
Relay websocket 反复断开
适配器自带 watchdog:断连超过 YOOOCLAW_HERMES_WS_RESTART_AFTER(默认 30s)会自动重建服务组(短暂网络抖动不会触发整组重建),失败按指数退避重试(上限 YOOOCLAW_HERMES_LIFECYCLE_MAX_BACKOFF,默认 60s)。断连期间产生的事件(如 recording.status)会先缓冲(上限 100 条,TTL 60s,过期丢弃),重连后按顺序补发,不会丢最近的事件。如果一直卡在重连,通常是网络问题或 api-key 失效(401/403/4401/invalid apikey 都会快速失败而不是无限静默重试),而不是 watchdog 本身的问题;先用 yoooclaw auth status 确认 key 没过期。
隧道断开不影响本地存储:写者锁仍由插件持有,yoooclaw notification search 之类的只读命令照常可用。
升级后插件行为没变 / skills 没更新
~/.hermes/skills/yoooclaw/ 是插件安装时复制进去的(不是软链接,因为 Hermes 不信任 site-packages 路径),带一个 .yoooclaw-managed 标记。如果这个目录已经存在但不是插件创建的(没有该标记),插件会打一条警告日志然后跳过覆盖,不会强制替换用户自己放的内容。升级后发现 skills 没更新,先检查这个目录是不是被手动改动过。
更新卡住 / 更新完没收到通知
自更新是异步的:旧进程里的 watcher 线程会持续把 update.log 流式推送到最后一次交互的 APP 会话,直到 exit_code 文件出现或超过超时时间(默认 1800s,超时按退出码 124 处理)。hermes gateway restart 由安装脚本自己触发,重载后的新插件进程会调用 resume_after_reload(),通过原子改名 pending.json → pending.claimed.json 保证新旧进程不会同时各发一次通知。如果长时间没反应,看 <state_root>/hermes-plugin/update/update.log 和同目录下的 exit_code 文件确认实际状态。
卸载插件
仓库里没有专门的卸载脚本。需要卸载时执行 pip uninstall yoooclaw-hermes-plugin,再手动从 ~/.hermes/config.yaml 的 plugins.enabled 里移除 yoooclaw 和 yoooclaw_app,然后重启 gateway。