mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-06-16 13:34:04 +08:00
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:
@@ -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. 导入提示词文件(表空时触发)
|
||||
|
||||
@@ -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 的处理:
|
||||
// 用 ClaudeAuth(Bearer-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;
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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": "すべて",
|
||||
|
||||
@@ -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": "全部",
|
||||
|
||||
Reference in New Issue
Block a user