mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-08-04 19:45:34 +08:00
feat(hermes): add API mode dropdown and per-provider model editor in form
The Hermes provider form previously only exposed Base URL and API Key, forcing users to drop into the Model panel to hand-edit model IDs after adding a provider. Following OpenClaw's shape, the form now carries: - An API Mode selector (auto-detect / chat_completions / anthropic_messages). "auto" is a UI-only sentinel — selecting it deletes api_mode from the config so the YAML doesn't leak a redundant field. - A model list editor where the first row is badged as the default and each row has a collapsible Advanced panel for context_length and max_tokens. Adding/removing rows uses a UUID-keyed ref so typing in one input doesn't drop focus when another row is added. - A Fetch Models button that pulls /v1/models from the configured endpoint and exposes the catalog in a per-row dropdown, identical to OpenClaw's flow. The vendor grouping is memoized so keystrokes don't trigger a reduce+sort per model row — Radix DropdownMenuContent does not lazy-mount, so the inner JSX evaluates on every render regardless of whether the menu is open. Three-locale i18n keys are added together (zh/en/ja).
This commit is contained in:
@@ -1,6 +1,11 @@
|
||||
import { useState, useCallback, useMemo } from "react";
|
||||
import type { AppId } from "@/lib/api";
|
||||
import { useProvidersQuery } from "@/lib/query/queries";
|
||||
import type {
|
||||
HermesApiModeChoice,
|
||||
HermesModel,
|
||||
HermesProviderSettingsConfig,
|
||||
} from "@/config/hermesProviderPresets";
|
||||
|
||||
interface UseHermesFormStateParams {
|
||||
initialData?: {
|
||||
@@ -29,14 +34,14 @@ export interface HermesFormState {
|
||||
setHermesProviderKey: (key: string) => void;
|
||||
hermesBaseUrl: string;
|
||||
hermesApiKey: string;
|
||||
hermesApiMode: HermesApiModeChoice;
|
||||
hermesModels: HermesModel[];
|
||||
existingHermesKeys: string[];
|
||||
handleHermesBaseUrlChange: (baseUrl: string) => void;
|
||||
handleHermesApiKeyChange: (apiKey: string) => void;
|
||||
resetHermesState: (config?: {
|
||||
name?: string;
|
||||
base_url?: string;
|
||||
api_key?: string;
|
||||
}) => void;
|
||||
handleHermesApiModeChange: (mode: HermesApiModeChoice) => void;
|
||||
handleHermesModelsChange: (models: HermesModel[]) => void;
|
||||
resetHermesState: (config?: Partial<HermesProviderSettingsConfig>) => void;
|
||||
}
|
||||
|
||||
function parseHermesField<T>(
|
||||
@@ -48,7 +53,10 @@ function parseHermesField<T>(
|
||||
if (initialData?.settingsConfig) {
|
||||
return (initialData.settingsConfig[field] as T) || fallback;
|
||||
}
|
||||
return ((HERMES_DEFAULT_CONFIG_OBJ as Record<string, unknown>)[field] as T) || fallback;
|
||||
return (
|
||||
((HERMES_DEFAULT_CONFIG_OBJ as Record<string, unknown>)[field] as T) ||
|
||||
fallback
|
||||
);
|
||||
} catch {
|
||||
return fallback;
|
||||
}
|
||||
@@ -84,6 +92,23 @@ export function useHermesFormState({
|
||||
return parseHermesField(initialData, "api_key", "");
|
||||
});
|
||||
|
||||
const [hermesApiMode, setHermesApiMode] = useState<HermesApiModeChoice>(
|
||||
() => {
|
||||
if (appId !== "hermes") return "auto";
|
||||
const stored = parseHermesField<HermesApiModeChoice | "">(
|
||||
initialData,
|
||||
"api_mode",
|
||||
"",
|
||||
);
|
||||
return stored || "auto";
|
||||
},
|
||||
);
|
||||
|
||||
const [hermesModels, setHermesModels] = useState<HermesModel[]>(() => {
|
||||
if (appId !== "hermes") return [];
|
||||
return parseHermesField<HermesModel[]>(initialData, "models", []);
|
||||
});
|
||||
|
||||
const updateHermesConfig = useCallback(
|
||||
(updater: (config: Record<string, unknown>) => void) => {
|
||||
try {
|
||||
@@ -117,11 +142,41 @@ export function useHermesFormState({
|
||||
[updateHermesConfig],
|
||||
);
|
||||
|
||||
const handleHermesApiModeChange = useCallback(
|
||||
(mode: HermesApiModeChoice) => {
|
||||
setHermesApiMode(mode);
|
||||
updateHermesConfig((config) => {
|
||||
if (mode === "auto") {
|
||||
delete config.api_mode;
|
||||
} else {
|
||||
config.api_mode = mode;
|
||||
}
|
||||
});
|
||||
},
|
||||
[updateHermesConfig],
|
||||
);
|
||||
|
||||
const handleHermesModelsChange = useCallback(
|
||||
(models: HermesModel[]) => {
|
||||
setHermesModels(models);
|
||||
updateHermesConfig((config) => {
|
||||
if (models.length === 0) {
|
||||
delete config.models;
|
||||
} else {
|
||||
config.models = models;
|
||||
}
|
||||
});
|
||||
},
|
||||
[updateHermesConfig],
|
||||
);
|
||||
|
||||
const resetHermesState = useCallback(
|
||||
(config?: { name?: string; base_url?: string; api_key?: string }) => {
|
||||
(config?: Partial<HermesProviderSettingsConfig>) => {
|
||||
setHermesProviderKey("");
|
||||
setHermesBaseUrl(config?.base_url || "");
|
||||
setHermesApiKey(config?.api_key || "");
|
||||
setHermesApiMode(config?.api_mode ?? "auto");
|
||||
setHermesModels(config?.models ?? []);
|
||||
},
|
||||
[],
|
||||
);
|
||||
@@ -131,9 +186,13 @@ export function useHermesFormState({
|
||||
setHermesProviderKey,
|
||||
hermesBaseUrl,
|
||||
hermesApiKey,
|
||||
hermesApiMode,
|
||||
hermesModels,
|
||||
existingHermesKeys,
|
||||
handleHermesBaseUrlChange,
|
||||
handleHermesApiKeyChange,
|
||||
handleHermesApiModeChange,
|
||||
handleHermesModelsChange,
|
||||
resetHermesState,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user