mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-05-29 20:30:00 +08:00
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:
@@ -5400,6 +5400,9 @@ fn find_json_string(value: &Value, keys: &[&str], depth: usize) -> Option<String
|
||||
None
|
||||
}
|
||||
|
||||
// 客户端配置导入需要把所有渲染必需的字段一次性塞进 Value,分组成 struct 反而会
|
||||
// 让调用站全部要先建一个临时结构体,可读性更差。这里显式 allow,仅作用于这个函数。
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn push_client_candidate(
|
||||
out: &mut Vec<Value>,
|
||||
id: &str,
|
||||
@@ -5433,6 +5436,7 @@ fn push_client_candidate(
|
||||
}));
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn scan_json_client_file(
|
||||
out: &mut Vec<Value>,
|
||||
id: &str,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 使用'
|
||||
|
||||
Reference in New Issue
Block a user