feat(hermes): P1-4 hermes_read_config_full 全字段解析 - 解锁 14+ Gateway 高价值配置

之前 hermes_read_config 只读 5 字段(model/base_url/provider/api_key/config_exists),
为「快速面板」服务。Hermes Gateway 实际有 14+ 个顶层配置项,ClawPanel 完全没读到。

本次新增 hermes_read_config_full 命令,作为高级配置编辑器的数据源。

## 后端实现
- 加 serde_yaml 0.9 依赖
- 新命令 hermes_read_config_full:
  · 用 serde_yaml 完整解析 config.yaml
  · 转 JSON 返回 { exists, raw, config, highlights }
  · highlights 字段单独抽出 14 个高价值顶层字段:
    streaming / stt_enabled / quick_commands / reset_triggers /
    default_reset_policy / unauthorized_dm_behavior /
    session_store_max_age_days / always_log_local /
    group_sessions_per_user / thread_sessions_per_user /
    platforms / dashboard / memory / skills
  · 已注册到 lib.rs

## 前端
- tauri-api.js 加 hermesReadConfigFull wrapper

## Web 模式
- dev-api.js 加 hermes_read_config_full handler(Web 模式不强制 yaml 解析,
  返回 raw + null highlights,前端按需 fallback)

## 后续
- 实际「高级配置编辑器」UI 后续单独开 — 本次仅打通数据通道
- 与轻量版 hermes_read_config 互补共存,model 配置页继续用轻量版
This commit is contained in:
晴天
2026-05-14 03:56:17 +08:00
parent 7eababad4a
commit c4bf769eab
6 changed files with 127 additions and 0 deletions

View File

@@ -2068,6 +2068,88 @@ pub async fn hermes_read_config() -> Result<Value, String> {
}))
}
// ---------------------------------------------------------------------------
// hermes_read_config_full — 解析整个 config.yaml 为 JSON 返回给前端
//
// 与轻量版 hermes_read_config仅返回 5 个 model 相关字段)互补:
// 前者用于 model 配置页快速展示,本命令用于「高级配置编辑器」让用户能看到/改
// Gateway 端 14+ 个顶层配置项,比如 quick_commands / streaming / reset_triggers /
// stt_enabled / unauthorized_dm_behavior 等。
//
// 返回值结构:
// {
// "exists": true, // config.yaml 是否存在
// "raw": "...yaml string...", // 原文(给 yaml editor
// "config": { ...full json... }, // 整份 yaml 转成 JSON
// "highlights": { // 14 个高价值字段单独抽出,前端直接 .x 访问
// "streaming": {...}, "stt_enabled": true, "quick_commands": {...},
// "reset_triggers": [...], "default_reset_policy": {...},
// "unauthorized_dm_behavior": "pair", "session_store_max_age_days": 90,
// "always_log_local": true,
// "group_sessions_per_user": false, "thread_sessions_per_user": false,
// ... 等
// }
// }
// ---------------------------------------------------------------------------
#[tauri::command]
pub async fn hermes_read_config_full() -> Result<Value, String> {
let config_path = hermes_home().join("config.yaml");
if !config_path.exists() {
return Ok(serde_json::json!({
"exists": false,
"raw": "",
"config": {},
"highlights": {},
}));
}
let raw = std::fs::read_to_string(&config_path)
.map_err(|e| format!("Failed to read config.yaml: {e}"))?;
// 解析 YAML → JSON
let yaml_value: serde_yaml::Value = serde_yaml::from_str(&raw)
.map_err(|e| format!("Invalid YAML in config.yaml: {e}"))?;
let config_json: Value = serde_json::to_value(&yaml_value)
.map_err(|e| format!("YAML→JSON conversion failed: {e}"))?;
// 抽取 14 个高价值顶层字段(如不存在保持 null前端按需渲染
let highlight_keys = [
"streaming",
"stt_enabled",
"quick_commands",
"reset_triggers",
"default_reset_policy",
"unauthorized_dm_behavior",
"session_store_max_age_days",
"always_log_local",
"group_sessions_per_user",
"thread_sessions_per_user",
"platforms",
"dashboard",
"memory",
"skills",
];
let highlights: serde_json::Map<String, Value> = highlight_keys
.iter()
.map(|k| {
let v = config_json
.get(*k)
.cloned()
.unwrap_or(Value::Null);
((*k).to_string(), v)
})
.collect();
Ok(serde_json::json!({
"exists": true,
"raw": raw,
"config": config_json,
"highlights": Value::Object(highlights),
}))
}
// ---------------------------------------------------------------------------
// hermes_fetch_models — 从 API 获取模型列表(后端代理,避免 CORS
// ---------------------------------------------------------------------------

View File

@@ -240,6 +240,7 @@ pub fn run() {
hermes::hermes_api_proxy,
hermes::hermes_agent_run,
hermes::hermes_read_config,
hermes::hermes_read_config_full,
hermes::hermes_fetch_models,
hermes::hermes_update_model,
hermes::hermes_detect_environments,