diff --git a/src-tauri/src/commands/config.rs b/src-tauri/src/commands/config.rs index e5e0c13..adb6a41 100644 --- a/src-tauri/src/commands/config.rs +++ b/src-tauri/src/commands/config.rs @@ -5400,6 +5400,9 @@ fn find_json_string(value: &Value, keys: &[&str], depth: usize) -> Option, id: &str, @@ -5433,6 +5436,7 @@ fn push_client_candidate( })); } +#[allow(clippy::too_many_arguments)] fn scan_json_client_file( out: &mut Vec, id: &str, diff --git a/src/engines/hermes/pages/lazy-deps.js b/src/engines/hermes/pages/lazy-deps.js index 91d90b1..f6cf6e5 100644 --- a/src/engines/hermes/pages/lazy-deps.js +++ b/src/engines/hermes/pages/lazy-deps.js @@ -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 = `
${escapeHtml(humanizeErrorText(e, t('hermesLazyDeps.loadFailed')))}
` + // 这里 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 = ` +
+
${escapeHtml(h.message)}
+ ${detail ? `
${escapeHtml(detail)}
` : ''} +
+ ` return } diff --git a/src/pages/assistant.js b/src/pages/assistant.js index 772c008..3dc9a93 100644 --- a/src/pages/assistant.js +++ b/src/pages/assistant.js @@ -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 使用'