mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-25 13:45:03 +08:00
feat: add Hermes frontend types, API layer, and hooks (Phase 7)
- Add "hermes" to AppId union type and all exhaustive Record<AppId> - Add HermesModelConfig, HermesAgentConfig, HermesEnvConfig types - Add hermes field to VisibleApps, McpApps, ProxyTakeoverStatus - Create src/lib/api/hermes.ts with Tauri invoke wrappers - Create src/hooks/useHermes.ts with 5 query + 3 mutation hooks - Register hermes in APP_IDS, APP_ICON_MAP (violet color scheme) - Split MCP_SKILLS_APP_IDS into MCP_APP_IDS (includes hermes) and SKILLS_APP_IDS (excludes hermes, since Hermes has no Skills support) - Wire hermes additive-mode into App.tsx (remove/duplicate handlers), ProviderList.tsx (live provider ID query + In Config badge), mutations.ts (cache invalidation on switch/add/delete) - Add Hermes checkbox to McpFormModal - Add basic hermes i18n keys (en/zh/ja)
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import type {
|
||||
HermesModelConfig,
|
||||
HermesAgentConfig,
|
||||
HermesEnvConfig,
|
||||
HermesHealthWarning,
|
||||
HermesWriteOutcome,
|
||||
} from "@/types";
|
||||
|
||||
/**
|
||||
* Hermes Agent configuration API
|
||||
*
|
||||
* Manages Hermes config sections:
|
||||
* - model (model selection and provider)
|
||||
* - agent (agent behavior)
|
||||
* - env (environment variables)
|
||||
*/
|
||||
export const hermesApi = {
|
||||
// ============================================================
|
||||
// Model Configuration
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Get model configuration
|
||||
*/
|
||||
async getModelConfig(): Promise<HermesModelConfig | null> {
|
||||
return await invoke("get_hermes_model_config");
|
||||
},
|
||||
|
||||
/**
|
||||
* Set model configuration
|
||||
*/
|
||||
async setModelConfig(config: HermesModelConfig): Promise<HermesWriteOutcome> {
|
||||
return await invoke("set_hermes_model_config", { config });
|
||||
},
|
||||
|
||||
// ============================================================
|
||||
// Agent Configuration
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Get agent configuration
|
||||
*/
|
||||
async getAgentConfig(): Promise<HermesAgentConfig | null> {
|
||||
return await invoke("get_hermes_agent_config");
|
||||
},
|
||||
|
||||
/**
|
||||
* Set agent configuration
|
||||
*/
|
||||
async setAgentConfig(config: HermesAgentConfig): Promise<HermesWriteOutcome> {
|
||||
return await invoke("set_hermes_agent_config", { config });
|
||||
},
|
||||
|
||||
// ============================================================
|
||||
// Env Configuration
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Get env configuration (.env file)
|
||||
*/
|
||||
async getEnv(): Promise<HermesEnvConfig> {
|
||||
return await invoke("get_hermes_env");
|
||||
},
|
||||
|
||||
/**
|
||||
* Set env configuration (.env file)
|
||||
*/
|
||||
async setEnv(env: HermesEnvConfig): Promise<HermesWriteOutcome> {
|
||||
return await invoke("set_hermes_env", { env });
|
||||
},
|
||||
|
||||
// ============================================================
|
||||
// Health
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Scan config health and return warnings
|
||||
*/
|
||||
async scanHealth(): Promise<HermesHealthWarning[]> {
|
||||
return await invoke("scan_hermes_config_health");
|
||||
},
|
||||
|
||||
/**
|
||||
* Get live provider config by ID
|
||||
*/
|
||||
async getLiveProvider(
|
||||
providerId: string,
|
||||
): Promise<Record<string, unknown> | null> {
|
||||
return await invoke("get_hermes_live_provider", { providerId });
|
||||
},
|
||||
};
|
||||
@@ -136,6 +136,14 @@ export const providersApi = {
|
||||
return await invoke("get_openclaw_live_provider_ids");
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取 Hermes live 配置中的供应商 ID 列表
|
||||
* 用于前端判断供应商是否已添加到 Hermes 配置
|
||||
*/
|
||||
async getHermesLiveProviderIds(): Promise<string[]> {
|
||||
return await invoke("get_hermes_live_provider_ids");
|
||||
},
|
||||
|
||||
/**
|
||||
* 从 OpenClaw live 配置导入供应商到数据库
|
||||
* OpenClaw 特有功能:由于累加模式,用户可能已在 openclaw.json 中配置供应商
|
||||
@@ -143,6 +151,14 @@ export const providersApi = {
|
||||
async importOpenClawFromLive(): Promise<number> {
|
||||
return await invoke("import_openclaw_providers_from_live");
|
||||
},
|
||||
|
||||
/**
|
||||
* 从 Hermes live 配置导入供应商到数据库
|
||||
* Hermes 特有功能:由于累加模式,用户可能已在 Hermes 配置中配置供应商
|
||||
*/
|
||||
async importHermesFromLive(): Promise<number> {
|
||||
return await invoke("import_hermes_providers_from_live");
|
||||
},
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
||||
@@ -2,7 +2,13 @@ import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
import type { AppId } from "@/lib/api/types";
|
||||
|
||||
export type AppType = "claude" | "codex" | "gemini" | "opencode" | "openclaw";
|
||||
export type AppType =
|
||||
| "claude"
|
||||
| "codex"
|
||||
| "gemini"
|
||||
| "opencode"
|
||||
| "openclaw"
|
||||
| "hermes";
|
||||
|
||||
/** Skill 应用启用状态 */
|
||||
export interface SkillApps {
|
||||
@@ -11,6 +17,7 @@ export interface SkillApps {
|
||||
gemini: boolean;
|
||||
opencode: boolean;
|
||||
openclaw: boolean;
|
||||
hermes: boolean;
|
||||
}
|
||||
|
||||
/** 已安装的 Skill(v3.10.0+ 统一结构) */
|
||||
|
||||
@@ -1,2 +1,8 @@
|
||||
// 前端统一使用 AppId 作为应用标识(与后端命令参数 `app` 一致)
|
||||
export type AppId = "claude" | "codex" | "gemini" | "opencode" | "openclaw";
|
||||
export type AppId =
|
||||
| "claude"
|
||||
| "codex"
|
||||
| "gemini"
|
||||
| "opencode"
|
||||
| "openclaw"
|
||||
| "hermes";
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { Provider, SessionMeta, Settings } from "@/types";
|
||||
import { extractErrorMessage } from "@/utils/errorUtils";
|
||||
import { generateUUID } from "@/utils/uuid";
|
||||
import { openclawKeys } from "@/hooks/useOpenClaw";
|
||||
import { hermesKeys } from "@/hooks/useHermes";
|
||||
|
||||
export const useAddProviderMutation = (appId: AppId) => {
|
||||
const queryClient = useQueryClient();
|
||||
@@ -22,7 +23,7 @@ export const useAddProviderMutation = (appId: AppId) => {
|
||||
) => {
|
||||
let id: string;
|
||||
|
||||
if (appId === "opencode" || appId === "openclaw") {
|
||||
if (appId === "opencode" || appId === "openclaw" || appId === "hermes") {
|
||||
if (
|
||||
providerInput.category === "omo" ||
|
||||
providerInput.category === "omo-slim"
|
||||
@@ -75,6 +76,12 @@ export const useAddProviderMutation = (appId: AppId) => {
|
||||
});
|
||||
}
|
||||
|
||||
if (appId === "hermes") {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: hermesKeys.health,
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await providersApi.updateTrayMenu();
|
||||
} catch (trayError) {
|
||||
@@ -127,6 +134,11 @@ export const useUpdateProviderMutation = (appId: AppId) => {
|
||||
queryKey: openclawKeys.health,
|
||||
});
|
||||
}
|
||||
if (appId === "hermes") {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: hermesKeys.health,
|
||||
});
|
||||
}
|
||||
toast.success(
|
||||
t("notifications.updateSuccess", {
|
||||
defaultValue: "供应商更新成功",
|
||||
@@ -180,6 +192,12 @@ export const useDeleteProviderMutation = (appId: AppId) => {
|
||||
});
|
||||
}
|
||||
|
||||
if (appId === "hermes") {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: hermesKeys.health,
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await providersApi.updateTrayMenu();
|
||||
} catch (trayError) {
|
||||
@@ -244,6 +262,14 @@ export const useSwitchProviderMutation = (appId: AppId) => {
|
||||
queryKey: openclawKeys.health,
|
||||
});
|
||||
}
|
||||
if (appId === "hermes") {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: hermesKeys.liveProviderIds,
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: hermesKeys.health,
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await providersApi.updateTrayMenu();
|
||||
|
||||
Reference in New Issue
Block a user