feat(hermes): P1-3 lazy_deps 预处理 - 加 IM 渠道不再「首启 Gateway 卡 30 秒后崩」

Hermes 内核 tools/lazy_deps.py 维护了一个 allowlist:每个 feature(如 platform.telegram /
tts.elevenlabs / search.exa)对应一组 PyPI 包。原本只有 Gateway 启动 platform 模块时
才会调 ensure() 装包,导致首次启动卡 30 秒甚至超时崩溃。

本 PR 把 lazy_deps 暴露给 ClawPanel UI,让用户能主动预装。

## 后端三个新 Tauri 命令
- hermes_lazy_deps_features() — 列所有 LAZY_DEPS allowlist feature(17 个)
- hermes_lazy_deps_status(features) — 批量查每个 feature 是否已装好
- hermes_lazy_deps_ensure(feature) — 主动调内核 tools.lazy_deps.ensure 装

实现方式:
- 找到 ~/.hermes-venv 的 python 路径(unix: bin/python,windows: Scripts/python.exe)
- 用 tokio::process::Command spawn `python -c "<embedded script>"` 跑临时 Python 脚本
- 脚本走 from tools.lazy_deps import ensure / feature_missing / LAZY_DEPS
- 把结果以 JSON dump 给 stdout,Rust 端解析最后一行
- enhanced_path() 注入 PATH 兼容 macOS Tauri 启动后 PATH 不全
- serde_json::to_string 把字符串和列表序列化为 Python 合法字面量(防注入)

已注册到 lib.rs,前端 wrapper 在 tauri-api.js(features 走 10min 缓存)。

## 前端
- 新页面 src/engines/hermes/pages/lazy-deps.js
- 分类 grid(消息渠道 / TTS / STT / 搜索 / 模型商 / 记忆 / 图像 / 其他),每类有 emoji
- 卡片式:feature 名(友好显示)+ specs 元信息 + 状态徽章(已装✓ / 未装warn / 未知)+ 装/重装按钮
- 装/重装按钮 await ensure,期间「安装中…」disabled,完成后刷新整张表
- 失败走 humanizeError 统一提示
- 17 个 feature 都有友好显示名 i18n(platform.telegram → Telegram,platform.dingtalk → 钉钉 等)
- 完整 11 语言 i18n(hermesLazyDeps 模块),其它语言 fallback 到 en

## sidebar
- Hermes 引擎「管理」section 新增「可选依赖管理」入口
- 路由 /h/lazy-deps

## CSS
- 加 .lazy-deps-grid / .lazy-deps-card / .lazy-deps-badge.{ok,warn,unknown}
- 复用现有 .empty-state / .empty-compact 风格

## Web 模式
- dev-api.js 加三个同名 handler:
  - features 返回内置常见 platform 列表
  - status 全标 unknown(无法 spawn python)
  - ensure 直接 reject,提示走桌面端

## 累计变动
- 2 新文件(lazy-deps.js page + hermesLazyDeps.js i18n)
- 7 修改(dev-api / hermes.rs / lib.rs / hermes/index.js / tauri-api.js / locales/index.js / components.css)
- 11 语言 × ~17 个新 i18n 键
- cargo check ✓ + npm build ✓
This commit is contained in:
晴天
2026-05-14 04:18:33 +08:00
parent c4bf769eab
commit b852ebb6ee
9 changed files with 564 additions and 1 deletions

View File

@@ -7159,6 +7159,41 @@ const handlers = {
return { model: displayModel, model_raw: modelName, base_url: baseUrl, provider, api_key: apiKey, config_exists: fs.existsSync(configPath) }
},
// P1-3 lazy_deps: Web 模式下不能调 venv python但仍提供 feature 列表 + 提示用户走桌面端装
hermes_lazy_deps_features() {
const features = [
{ feature: 'platform.telegram', specs: ['python-telegram-bot[webhooks]==22.6'] },
{ feature: 'platform.discord', specs: ['discord.py[voice]==2.7.1'] },
{ feature: 'platform.slack', specs: ['slack-bolt==1.27.0', 'slack-sdk==3.40.1', 'aiohttp==3.13.3'] },
{ feature: 'platform.matrix', specs: ['matrix-nio[e2e]'] },
{ feature: 'platform.dingtalk', specs: ['dingtalk-stream'] },
{ feature: 'platform.feishu', specs: ['lark-oapi'] },
{ feature: 'tts.edge', specs: ['edge-tts==7.2.7'] },
{ feature: 'tts.elevenlabs', specs: ['elevenlabs==1.59.0'] },
{ feature: 'stt.faster_whisper', specs: ['faster-whisper==1.2.1', 'sounddevice==0.5.5', 'numpy==2.4.3'] },
{ feature: 'search.exa', specs: ['exa-py==2.10.2'] },
{ feature: 'search.firecrawl', specs: ['firecrawl-py==4.17.0'] },
{ feature: 'search.parallel', specs: ['parallel-web==0.4.2'] },
{ feature: 'provider.anthropic', specs: ['anthropic==0.86.0'] },
{ feature: 'provider.bedrock', specs: ['boto3==1.42.89'] },
{ feature: 'memory.honcho', specs: ['honcho-ai==2.0.1'] },
{ feature: 'memory.hindsight', specs: ['hindsight-client==0.6.1'] },
{ feature: 'image.fal', specs: ['fal-client==0.13.1'] },
]
return { ok: true, features }
},
hermes_lazy_deps_status({ features }) {
// Web 模式无法实际查询 venv全部标 unknown
const status = {}
for (const f of features || []) status[f] = { known: true, satisfied: false, missing: [] }
return { ok: true, status }
},
hermes_lazy_deps_ensure({ feature }) {
return { ok: false, error: `Web 模式下无法预装依赖。请在桌面端 ClawPanel 完成 ${feature} 安装。` }
},
// P1-4完整解析 config.yaml让前端能读 14+ 高价值字段
// Web 模式不引入 yaml 依赖,简单返回 raw + null highlights前端按需渲染
hermes_read_config_full() {