fix: address Hermes review findings (5 medium issues)

- Add missing Hermes MCP import on first launch (lib.rs)
- Add Hermes branch in ProviderForm defaultValues fallback
- Include Hermes in session manager subtitle (zh/en/ja)
- Rename check_openclaw_stream to check_additive_app_stream
- Cache parsed HERMES_DEFAULT_CONFIG to avoid repeated JSON.parse
This commit is contained in:
Jason
2026-04-16 08:58:44 +08:00
Unverified
parent e8953c286f
commit 0ca36b9d51
7 changed files with 34 additions and 23 deletions
+8
View File
@@ -635,6 +635,14 @@ pub fn run() {
Ok(_) => log::debug!("○ No OpenCode MCP servers found to import"),
Err(e) => log::warn!("✗ Failed to import OpenCode MCP: {e}"),
}
match crate::services::mcp::McpService::import_from_hermes(&app_state) {
Ok(count) if count > 0 => {
log::info!("✓ Imported {count} MCP server(s) from Hermes");
}
Ok(_) => log::debug!("○ No Hermes MCP servers found to import"),
Err(e) => log::warn!("✗ Failed to import Hermes MCP: {e}"),
}
}
// 4. 导入提示词文件(表空时触发)
+11 -12
View File
@@ -684,7 +684,7 @@ impl StreamCheckService {
let result = match app_type {
AppType::OpenClaw => {
Self::check_openclaw_stream(
Self::check_additive_app_stream(
&client,
provider,
&model_to_test,
@@ -704,8 +704,7 @@ impl StreamCheckService {
.await
}
AppType::Hermes => {
// Hermes uses the same check path as OpenClaw for now
Self::check_openclaw_stream(
Self::check_additive_app_stream(
&client,
provider,
&model_to_test,
@@ -819,7 +818,7 @@ impl StreamCheckService {
/// - `anthropic-messages` → check_claude_stream + api_format="anthropic" (ClaudeAuth 策略)
/// - `google-generative-ai` → check_gemini_stream (Google API Key 策略)
/// - `bedrock-converse-stream` → 不支持(需要 AWS SigV4 签名)
async fn check_openclaw_stream(
async fn check_additive_app_stream(
client: &Client,
provider: &Provider,
model: &str,
@@ -829,7 +828,7 @@ impl StreamCheckService {
// 自定义认证头(如 Longcat 的 `apikey` 头)不走标准 Bearer
// 具体头名由 OpenClaw 网关内部决定,cc-switch 无法准确构造,
// 因此直接返回友好错误而不是让用户看到一个误导性的 401。
if Self::openclaw_uses_auth_header(provider) {
if Self::additive_app_uses_auth_header(provider) {
return Err(AppError::localized(
"openclaw_auth_header_not_supported",
"该供应商使用自定义认证头,暂不支持流式健康检查。建议直接通过 OpenClaw 测试。",
@@ -922,8 +921,8 @@ impl StreamCheckService {
}
}
/// 判断 OpenClaw 供应商是否使用自定义认证头(`authHeader: true`
fn openclaw_uses_auth_header(provider: &Provider) -> bool {
/// 判断 additive-mode 供应商是否使用自定义认证头(`authHeader: true`
fn additive_app_uses_auth_header(provider: &Provider) -> bool {
provider
.settings_config
.get("authHeader")
@@ -1040,7 +1039,7 @@ impl StreamCheckService {
.await
}
Some("@ai-sdk/anthropic") => {
// 见 check_openclaw_stream 对 anthropic-messages 的注释
// 见 check_additive_app_stream 对 anthropic-messages 的处理
// 用 ClaudeAuthBearer-only)兼容中转服务。
let auth = AuthInfo::new(api_key, AuthStrategy::ClaudeAuth);
Self::check_claude_stream(
@@ -1420,24 +1419,24 @@ mod tests {
}
#[test]
fn test_openclaw_uses_auth_header_true() {
fn test_additive_app_uses_auth_header_true() {
let p = make_provider(serde_json::json!({
"baseUrl": "https://api.longcat.chat/v1",
"apiKey": "k",
"api": "openai-completions",
"authHeader": true,
}));
assert!(StreamCheckService::openclaw_uses_auth_header(&p));
assert!(StreamCheckService::additive_app_uses_auth_header(&p));
}
#[test]
fn test_openclaw_uses_auth_header_default_false() {
fn test_additive_app_uses_auth_header_default_false() {
let p = make_provider(serde_json::json!({
"baseUrl": "https://api.deepseek.com/v1",
"apiKey": "k",
"api": "openai-completions",
}));
assert!(!StreamCheckService::openclaw_uses_auth_header(&p));
assert!(!StreamCheckService::additive_app_uses_auth_header(&p));
}
#[test]
@@ -99,6 +99,7 @@ import {
OPENCLAW_DEFAULT_CONFIG,
normalizePricingSource,
} from "./helpers/opencodeFormUtils";
import { HERMES_DEFAULT_CONFIG } from "./hooks/useHermesFormState";
import { resolveManagedAccountId } from "@/lib/authBinding";
import { useOpenClawLiveProviderIds } from "@/hooks/useOpenClaw";
import { useHermesLiveProviderIds } from "@/hooks/useHermes";
@@ -261,7 +262,9 @@ export function ProviderForm({
? OPENCODE_DEFAULT_CONFIG
: appId === "openclaw"
? OPENCLAW_DEFAULT_CONFIG
: CLAUDE_DEFAULT_CONFIG,
: appId === "hermes"
? HERMES_DEFAULT_CONFIG
: CLAUDE_DEFAULT_CONFIG,
icon: initialData?.icon ?? "",
iconColor: initialData?.iconColor ?? "",
}),
@@ -12,12 +12,14 @@ interface UseHermesFormStateParams {
getSettingsConfig: () => string;
}
const HERMES_DEFAULT_CONFIG_OBJ = {
name: "",
base_url: "",
api_key: "",
} as const;
export const HERMES_DEFAULT_CONFIG = JSON.stringify(
{
name: "",
base_url: "",
api_key: "",
},
HERMES_DEFAULT_CONFIG_OBJ,
null,
2,
);
@@ -46,8 +48,7 @@ function parseHermesField<T>(
if (initialData?.settingsConfig) {
return (initialData.settingsConfig[field] as T) || fallback;
}
const config = JSON.parse(HERMES_DEFAULT_CONFIG);
return (config[field] as T) || fallback;
return ((HERMES_DEFAULT_CONFIG_OBJ as Record<string, unknown>)[field] as T) || fallback;
} catch {
return fallback;
}
+1 -1
View File
@@ -663,7 +663,7 @@
},
"sessionManager": {
"title": "Session Manager",
"subtitle": "Manage Claude Code, Codex, OpenCode, OpenClaw and Gemini CLI sessions",
"subtitle": "Manage Claude Code, Codex, OpenCode, OpenClaw, Hermes and Gemini CLI sessions",
"searchPlaceholder": "Search by content, directory, or ID",
"searchSessions": "Search sessions",
"providerFilterAll": "All",
+1 -1
View File
@@ -663,7 +663,7 @@
},
"sessionManager": {
"title": "セッション管理",
"subtitle": "Claude Code / Codex / OpenCode / OpenClaw / Gemini CLI のセッションを管理",
"subtitle": "Claude Code / Codex / OpenCode / OpenClaw / Hermes / Gemini CLI のセッションを管理",
"searchPlaceholder": "内容・ディレクトリ・ID で検索",
"searchSessions": "セッションを検索",
"providerFilterAll": "すべて",
+1 -1
View File
@@ -663,7 +663,7 @@
},
"sessionManager": {
"title": "会话管理",
"subtitle": "管理 Claude Code、Codex、OpenCode、OpenClaw 与 Gemini CLI 会话记录",
"subtitle": "管理 Claude Code、Codex、OpenCode、OpenClaw、Hermes 与 Gemini CLI 会话记录",
"searchPlaceholder": "搜索会话内容、目录或 ID",
"searchSessions": "搜索会话",
"providerFilterAll": "全部",