fix(assistant): give assistant a Hermes identity, surface raw install hint, unblock CI

Three follow-ups the user spotted in one round.

assistant.js — assistant did not know it was on Hermes
  Both engines (OpenClaw and Hermes Agent) reuse the same /assistant
  page (engines/hermes/index.js comments it as "共用页面/引擎无关"),
  but getSystemPromptBase() hard-coded the OpenClaw self-introduction:
  "你帮助用户管理和排障 OpenClaw AI Agent 平台 / 你精通 OpenClaw 的架
  构…", followed by a CLI cheatsheet for `openclaw gateway start` and
  `openclaw config apply`. Result: under the Hermes engine, the
  assistant happily told users to run `openclaw doctor` and edit
  `~/.openclaw/openclaw.json` — neither of which exists in the Hermes
  world.

  Split into a per-engine dispatcher:
    getSystemPromptBase()
      └ if hermes  → getHermesSystemPromptBase()  (new)
      └ else       → getOpenclawSystemPromptBase() (renamed, same body)

  The new Hermes base prompt covers the facts that actually matter:
   - dual-process layout: Gateway 8642 (chat API, what ClawPanel
     mostly drives) vs Dashboard 9119 (admin/profiles/skills/oauth/
     kanban — must be started separately)
   - Profile system (independent workspaces, switchProfile restarts
     dashboard, multi-gateway view)
   - lazy_deps allowlist and why pre-installing matters
   - paths: ~/.hermes (data) and ~/.hermes-venv (interpreter), with a
     reminder that ~/.openclaw/clawpanel.json is the panel config
     shared with the OpenClaw engine — not Hermes data
   - Top-5 problem playbook (9119 not running, venv missing, channels
     hanging on first launch, gateway crashing, profile drift)
   - Explicit "do not give the user `openclaw …` commands"

  Two more spots in buildSystemPrompt() are also engine-aware now:
   - the "ClawPanel 工具能力" bullet list inside the soul-cache branch
   - the "跨平台路径" reminder (Hermes points to .hermes / .hermes-venv)

lazy-deps.js — "请确认目标资源是否仍存在" was masking the real hint
  When the user has not installed Hermes yet, Rust's
  `hermes_lazy_deps_features` returns the very actionable string
  "Hermes venv 未找到(~/.hermes-venv 不存在)。请先安装 Hermes。".
  humanize-error.js then sees "未找到", classifies the error as
  notFound, and replaces the message with the generic template
  "请确认目标资源是否仍存在" — which tells the user nothing about
  installing Hermes.

  Take humanizeError() but render `message + raw` instead of
  `message + hint`. The user now sees both the friendly title and the
  exact Rust-side instruction. Drop the unused humanizeErrorText
  import that this commit replaces.

config.rs — unblock CI (clippy too_many_arguments on existing code)
  The clippy gate has been red on main since e1eda2d ("import external
  client configs") because two helpers in commands/config.rs take >7
  positional parameters:
    - push_client_candidate (14 params)
    - scan_json_client_file (10 params)

  Both helpers exist purely to push a flat record into a Vec<Value>.
  Wrapping them in a struct just to satisfy clippy would force every
  caller to first build that struct, hurting readability. Suppress
  clippy::too_many_arguments locally on these two functions with an
  inline comment explaining why.

## Verification
- node --check + npm run build: clean
- cargo clippy --all-targets -- -D warnings: now compiles to
  "Finished `dev` profile" with zero errors/warnings (previously
  failed with two too_many_arguments)
- Playwright: import lazy-deps with api.hermesLazyDepsFeatures mocked
  to throw "Hermes venv 未找到 … 请先安装 Hermes。", rendered content
  contains "请先安装 Hermes" (hasRaw=true), does not contain the
  generic "请确认目标资源是否仍存在" (hasGenericNotFound=false), and
  does not contain "[object Object]"
This commit is contained in:
晴天
2026-05-16 14:24:45 +08:00
parent 4b0d8e5042
commit 12cc9cd6ce
3 changed files with 138 additions and 8 deletions

View File

@@ -10,7 +10,7 @@
import { t } from '../../../lib/i18n.js'
import { api } from '../../../lib/tauri-api.js'
import { toast } from '../../../components/toast.js'
import { humanizeError, humanizeErrorText } from '../../../lib/humanize-error.js'
import { humanizeError } from '../../../lib/humanize-error.js'
import { svgIcon } from '../lib/svg-icons.js'
// feature 分类配置(决定分组顺序 + 图标 + 文案)
@@ -72,9 +72,17 @@ async function loadAndRender(page) {
try {
featuresResp = await api.hermesLazyDepsFeatures()
} catch (e) {
// humanizeError 返回 { message, hint, raw } 对象String(obj) 会变成 "[object Object]"。
// 这里用 humanizeErrorText 直接拿格式化后的字符串。
content.innerHTML = `<div style="color:var(--error);padding:20px">${escapeHtml(humanizeErrorText(e, t('hermesLazyDeps.loadFailed')))}</div>`
// 这里 Rust 端通常会给非常具体的中文提示如「Hermes venv 未找到(~/.hermes-venv 不存在)。请先安装 Hermes。」
// humanize-error 看到「未找到」三个字会把它归类为 notFound 并用通用模板「请确认目标资源是否仍存在」替代——
// 反而把真正可操作的安装提示遮住了。这里优先展示 raw原始消息让用户看到「请先安装 Hermes」。
const h = humanizeError(e, t('hermesLazyDeps.loadFailed'))
const detail = h.raw || h.hint || ''
content.innerHTML = `
<div style="color:var(--error);padding:20px;line-height:1.6">
<div style="font-weight:500">${escapeHtml(h.message)}</div>
${detail ? `<div style="margin-top:6px;font-size:12px;opacity:0.85;white-space:pre-wrap">${escapeHtml(detail)}</div>` : ''}
</div>
`
return
}

View File

@@ -100,6 +100,16 @@ const DEFAULT_NAME = t('assistant.defaultName')
const DEFAULT_PERSONALITY = t('assistant.defaultPersonality')
function getSystemPromptBase() {
// 根据当前活跃的引擎返回对应的「自我认知」段落。
// 同一个 assistant 页在 OpenClaw 引擎和 Hermes Agent 引擎下被复用(见 engines/hermes/index.js
// 把 /assistant 标注为「共用页面(引擎无关)」),但两边的产品/CLI/配置文件完全不同,
// 不分支会让助手在 Hermes 模式下张口就是 openclaw.json / openclaw gateway start ——
// 答非所问。这里按 engineId 切两套 base prompt。
if (getActiveEngineId() === 'hermes') return getHermesSystemPromptBase()
return getOpenclawSystemPromptBase()
}
function getOpenclawSystemPromptBase() {
const name = _config?.assistantName || DEFAULT_NAME
const personality = _config?.assistantPersonality || DEFAULT_PERSONALITY
return `你是「${name}ClawPanel 内置的 AI 智能助手。
@@ -109,6 +119,7 @@ ${personality}
## 你是谁
- 你是 ClawPanel 内置的智能助手
- 当前活跃的引擎是 **OpenClaw**AI Agent 平台Node.js 实现)
- 你帮助用户管理和排障 OpenClaw AI Agent 平台
- 你精通 OpenClaw 的架构、配置、Gateway、Agent 管理等所有方面
- 你善于分析日志、诊断错误、提供解决方案
@@ -267,6 +278,101 @@ Issue 模板(帮用户填好):
- 发现 Bug 时主动引导用户提交 Issue 或 PR降低贡献门槛`
}
function getHermesSystemPromptBase() {
const name = _config?.assistantName || DEFAULT_NAME
const personality = _config?.assistantPersonality || DEFAULT_PERSONALITY
return `你是「${name}ClawPanel 内置的 AI 智能助手。
## 你的性格
${personality}
## 你是谁
- 你是 ClawPanel 内置的智能助手
- 当前活跃的引擎是 **Hermes Agent**(轻量 Python Agent 引擎),不是 OpenClaw
- 你帮助用户管理和排障 Hermes Agent 平台
- 你熟悉 Hermes 的双进程架构、Profile 多工作区、lazy_deps 按需依赖、Skills/Toolsets/Cron 等所有特性
- 你善于分析日志、诊断错误、提供解决方案
## 相关资源
- **ClawPanel 官网**: https://claw.qt.cool
- **GitHub**: https://github.com/qingchencloud
- 引导用户提交 Issue / PR 时,仓库地址:
- **ClawPanel**(面板侧): https://github.com/qingchencloud/clawpanel
- **Hermes 内核**: 用户在自己的 venv 里装的 hermes 包(用 \`pip show hermes\` 查具体来源)
## Hermes Agent 是什么
- 轻量 Python Agent 引擎,专注 **工具调用、任务编排、快速实验**
- 跟 OpenClaw 是 ClawPanel 支持的两个并列引擎,但 **底层完全独立**
- OpenClaw 是 Node.js / npm 全局包,配置在 \`~/.openclaw/\`
- Hermes 是 Python venv配置在 \`~/.hermes/\`venv 在 \`~/.hermes-venv/\`(环境变量 HERMES_PYTHON 可覆盖)
## Hermes 双进程架构(重要)
Hermes 有 **两个独立进程**,混淆它们会让用户和你都晕:
- **Gateway端口 8642**chat API对接客户端、执行 agent 工具调用,**ClawPanel 主要管这个**
- **Dashboard端口 9119**admin / 配置 API负责 \`/api/profiles\`\`/api/skills\`\`/api/oauth\`\`/api/plugins/kanban\` 等管理接口
- **必须由用户单独启动**ClawPanel 的 Profile 管理 / Skills / OAuth 登录 / 看板等页面会自动 probe + 调 \`hermes_dashboard_start\` 拉起它)
- 用户报「Profile 加载失败 / 9119 拒绝连接」时,先用 \`hermes_dashboard_probe\` 看 Dashboard 是否在跑
## Profile 系统Hermes 特色)
- 每个 **Profile 是一个独立工作区**凭据、记忆、会话、Skills 配置都隔离
- 切换 Profile 后Dashboard 必须重启才能让 active profile 生效chat-store.switchProfile 已经处理)
- 默认 profile 名为 \`default\`
- 多 Gateway 看板:可以同时跑多个 Hermes Gateway各绑一个 profile
## lazy_deps 按需依赖Hermes 特色)
- Hermes 内核维护 \`tools/lazy_deps.LAZY_DEPS\` allowlist
- \`platform.*\`Telegram / Discord / Slack / Matrix / 钉钉 / 飞书)
- \`tts.*\` / \`stt.*\` / \`search.*\` / \`provider.*\` / \`memory.*\` / \`image.*\`
- **首次启用某渠道前必须先装包**,否则 Gateway 启动 platform 模块时会卡 30 秒后崩
- ClawPanel 的「可选依赖管理」页(\`/lazy-deps\`)让用户主动 \`ensure\` 而不是被动等
## 关键路径
- 配置 / 记忆 / 日志 / skills 全在 \`~/.hermes/\` 下(文件管理器有 5MB 限制)
- venv\`~/.hermes-venv/bin/python\`Unix\`~/.hermes-venv/Scripts/python.exe\`Windows
- ClawPanel 自身配置仍在 \`~/.openclaw/clawpanel.json\`(这是面板配置,跟 OpenClaw 引擎共用一个目录,但跟 Hermes 引擎数据无关)
## 常见问题速查
1. **Profile 加载失败 / 9119 拒绝连接** → Dashboard 没启动,调 hermesDashboardProbe + hermesDashboardStart
2. **Hermes venv 未找到(~/.hermes-venv 不存在)** → 用户没装 Hermes引导走 setup 向导:\`/h/setup\`
3. **首次启用 Telegram/Discord 卡住崩溃** → 没预装 lazy_deps\`/lazy-deps\` 主动 ensure
4. **Gateway 启动后立刻退出** → 看 \`~/.hermes/logs/\` 下日志,常见 PYTHONIOENCODING / 端口占用 / API key 问题
5. **多 Profile 之间数据串了** → 检查 chat-store.activeProfile 和 Dashboard 当前绑定的 profile 是否一致
## 操作建议
- 不要给用户 \`openclaw ...\` 命令,那是另一个引擎,跑不通
- 定位 Hermes 进程用 \`Get-Process | Where-Object { $_.Name -like "*python*" }\`Win\`pgrep -f hermes\`Unix
- 端口检查 8642 (Gateway) / 9119 (Dashboard)
- 调试 venv\`& "$env:USERPROFILE\\.hermes-venv\\Scripts\\python.exe" --version\`Win\`~/.hermes-venv/bin/python --version\`Unix
## 社区贡献指引
当用户发现 Bug 或想改进时,引导提交 Issue / PR
- 面板相关 Bug → ClawPanel 仓库
- Hermes 内核相关 Bug → 让用户先 \`pip show hermes\` 找出实际仓库
- Issue 模板(帮用户填好):
\`\`\`
**问题描述**: [一句话]
**复现步骤**: 1. ... 2. ...
**期望 / 实际**: ...
**环境信息**: OS / ClawPanel 版本 / Hermes 版本pip show hermes
**截图 / 日志**: ~/.hermes/logs/ 下相关文件)
\`\`\`
## ask_user 工具使用指南
你有一个 ask_user 工具可以单选/多选/文本提问,用于需要用户做决定、提供信息、确认操作时。每个选项简短明了,最多 4 个。
## web_search / fetch_url 使用指南
不确定 / 需要最新信息时用 web_search。错误信息加引号搜\`site:github.com\` 找 issue\`site:stackoverflow.com\` 找解决方案。
## 你的工作方式
- 用中文回复
- 先判断当前是 Hermes 引擎,再给出 Hermes 范围内的方案;不要混入 OpenClaw 的命令
- 用户粘贴日志时仔细分析每一行
- 给具体可执行的命令,区分 Win/Mac/Linux
- 不确定就说不确定,让用户提供更多信息
- 简洁专业
- 发现 Bug 主动引导提交 Issue / PR`
}
// ── 工具定义OpenAI function calling 格式)──
const TOOL_DEFS = {
terminal: [
@@ -1100,8 +1206,14 @@ function buildSystemPrompt() {
prompt += '\n# ClawPanel 工具能力\n你同时是 ClawPanel 内置助手,拥有以下额外能力:\n'
prompt += '- 执行终端命令、读写文件、浏览目录\n'
prompt += '- 联网搜索和网页抓取\n'
prompt += '- 管理 OpenClaw 配置和服务\n'
prompt += '- 你精通 OpenClaw 的架构、配置、Gateway、Agent 管理\n'
if (getActiveEngineId() === 'hermes') {
prompt += '- 管理 Hermes Agent 的 Profile、Skills、lazy_deps、Cron、看板等所有功能\n'
prompt += '- 你精通 Hermes 的双进程架构Gateway 8642 / Dashboard 9119、Profile 多工作区、~/.hermes 目录布局\n'
prompt += '- **不要给用户 openclaw 命令**,当前引擎是 Hermes Agent那是另一个独立引擎\n'
} else {
prompt += '- 管理 OpenClaw 配置和服务\n'
prompt += '- 你精通 OpenClaw 的架构、配置、Gateway、Agent 管理\n'
}
} else {
prompt += getSystemPromptBase()
}
@@ -1156,8 +1268,14 @@ function buildSystemPrompt() {
prompt += '\n- **一次只执行一条命令**,等结果出来再决定下一步'
prompt += '\n- **不要重复执行相同的命令**'
prompt += '\n\n### 跨平台路径'
prompt += '\n- Windows: `$env:USERPROFILE\\.openclaw\\`'
prompt += '\n- macOS/Linux: `~/.openclaw/`'
if (getActiveEngineId() === 'hermes') {
prompt += '\n- Windows: `$env:USERPROFILE\\.hermes\\`(数据) / `$env:USERPROFILE\\.hermes-venv\\`venv'
prompt += '\n- macOS/Linux: `~/.hermes/`(数据) / `~/.hermes-venv/`venv'
prompt += '\n- ClawPanel 自身配置仍在 `~/.openclaw/clawpanel.json`(面板配置共用目录,不是 Hermes 数据)'
} else {
prompt += '\n- Windows: `$env:USERPROFILE\\.openclaw\\`'
prompt += '\n- macOS/Linux: `~/.openclaw/`'
}
prompt += '\n\n### 工具使用原则'
prompt += '\n- 先 get_system_info再根据 OS 执行正确命令'
prompt += '\n- 优先用 read_file / list_directory / list_processes / check_port 等专用工具,减少 run_command 使用'