feat(hermes): expose '/v1/capabilities' as the 'hermes_capabilities' Tauri command

Hermes 已在 v2026.5.x 暴露 GET /v1/capabilities 给外部 UI 用作机器可读的能力描述,让前端能动态适配可用 endpoint / feature 而无需用版本号硬匹配。ClawPanel 之前完全没利用这层抽象,本 commit 加一条 Tauri 命令 + Web handler + 前端 wrapper,为后续 chat/runs/approval 等动态降级(老版 Gateway 没有的能力优雅隐藏 UI)打底。
This commit is contained in:
晴天
2026-05-14 02:31:35 +08:00
parent 69cce64985
commit 1d6843c4fb
4 changed files with 37 additions and 0 deletions

View File

@@ -7063,6 +7063,13 @@ const handlers = {
return await resp.json()
},
async hermes_capabilities() {
const url = `${hermesGatewayUrl()}/v1/capabilities`
const resp = await globalThis.fetch(url, { signal: AbortSignal.timeout(5000), headers: { 'User-Agent': 'ClawPanel-Web' } })
if (!resp.ok) throw new Error(`Gateway 返回 HTTP ${resp.status}`)
return await resp.json()
},
async hermes_api_proxy({ method, path: reqPath, body, headers: customHeaders } = {}) {
const url = `${hermesGatewayUrl()}${reqPath}`
const opts = { method: method || 'GET', headers: { 'User-Agent': 'ClawPanel-Web' } }

View File

@@ -2648,6 +2648,34 @@ pub async fn hermes_health_check() -> Result<Value, String> {
}
}
// ---------------------------------------------------------------------------
// hermes_capabilities — 探测 Gateway 暴露的 API 能力描述GET /v1/capabilities
//
// Hermes 内核 v2026.5.x 起暴露的「机器可读 capability 描述」,给外部 UI 用来
// 动态适配可用功能,避免在前端写死哪些 endpoint/feature 存在。例:
// 老版本的 Gateway 没有 `/v1/runs/{id}/approval`,新版有 → 用 capabilities 判
// 断而不是用版本号匹配。
//
// 不可达 / 老版 Gateway 没有该 endpoint → 返回 Err调用方应优雅降级。
// ---------------------------------------------------------------------------
#[tauri::command]
pub async fn hermes_capabilities() -> Result<Value, String> {
let url = format!("{}/v1/capabilities", hermes_gateway_url());
let client = hermes_gateway_http_client(std::time::Duration::from_secs(5))
.map_err(|e| format!("HTTP 客户端创建失败: {e}"))?;
match client.get(&url).send().await {
Ok(resp) if resp.status().is_success() => {
let body: Value = resp.json().await.unwrap_or(Value::Null);
Ok(body)
}
Ok(resp) => Err(format!("Gateway 返回 HTTP {}", resp.status())),
Err(e) => Err(format!("Gateway 不可达: {e}")),
}
}
// ---------------------------------------------------------------------------
// hermes_detect_environments — 检测 WSL2 / Docker 中的 Hermes Agent
// ---------------------------------------------------------------------------

View File

@@ -236,6 +236,7 @@ pub fn run() {
hermes::configure_hermes,
hermes::hermes_gateway_action,
hermes::hermes_health_check,
hermes::hermes_capabilities,
hermes::hermes_api_proxy,
hermes::hermes_agent_run,
hermes::hermes_read_config,

View File

@@ -471,6 +471,7 @@ export const api = {
configureHermes: (provider, apiKey, model, baseUrl) => invoke('configure_hermes', { provider, apiKey, model: model || null, baseUrl: baseUrl || null }),
hermesGatewayAction: (action) => invoke('hermes_gateway_action', { action }),
hermesHealthCheck: () => invoke('hermes_health_check'),
hermesCapabilities: () => invoke('hermes_capabilities'),
hermesApiProxy: (method, path, body, headers) => invoke('hermes_api_proxy', { method, path, body: body || null, headers: headers || null }),
hermesAgentRun: (input, sessionId, conversationHistory, instructions) => invoke('hermes_agent_run', { input, sessionId: sessionId || null, conversationHistory: conversationHistory || null, instructions: instructions || null }),
hermesAgentRunStream: (input, sessionId, conversationHistory, instructions, onEvent, options) => webStreamInvoke('hermes_agent_run_stream', { input, sessionId: sessionId || null, conversationHistory: conversationHistory || null, instructions: instructions || null }, onEvent, options),