feat(hermes): align provider schema with Hermes Agent 0.10.0

Hermes 0.10.0 tightened custom_providers validation (commit 2cdae233):
invalid base_urls are rejected, unknown fields produce warnings, and
new fields (rate_limit_delay, bedrock_converse, key_env) landed.

- Add bedrock_converse to the api_mode selector (and i18n labels)
- Expose rate_limit_delay in a provider-level advanced panel
- Validate base_url client-side (URL shape, template-token friendly)
- Drop per-model max_tokens — not in _VALID_CUSTOM_PROVIDER_FIELDS
- Round-trip test asserts set_provider preserves rate_limit_delay /
  key_env / any unknown forward-compat field
This commit is contained in:
Jason
2026-04-20 22:13:54 +08:00
parent 111ddf8d73
commit 0be75668cc
9 changed files with 375 additions and 89 deletions
@@ -37,11 +37,13 @@ export interface HermesFormState {
hermesApiKey: string;
hermesApiMode: HermesApiMode;
hermesModels: HermesModel[];
hermesRateLimitDelay: number | undefined;
existingHermesKeys: string[];
handleHermesBaseUrlChange: (baseUrl: string) => void;
handleHermesApiKeyChange: (apiKey: string) => void;
handleHermesApiModeChange: (mode: HermesApiMode) => void;
handleHermesModelsChange: (models: HermesModel[]) => void;
handleHermesRateLimitDelayChange: (delay: number | undefined) => void;
resetHermesState: (config?: Partial<HermesProviderSettingsConfig>) => void;
}
@@ -63,6 +65,12 @@ function parseHermesField<T>(
}
}
function parseRateLimitDelay(raw: unknown): number | undefined {
return typeof raw === "number" && Number.isFinite(raw) && raw >= 0
? raw
: undefined;
}
export function useHermesFormState({
initialData,
appId,
@@ -108,6 +116,13 @@ export function useHermesFormState({
return parseHermesField<HermesModel[]>(initialData, "models", []);
});
const [hermesRateLimitDelay, setHermesRateLimitDelay] = useState<
number | undefined
>(() => {
if (appId !== "hermes") return undefined;
return parseRateLimitDelay(initialData?.settingsConfig?.rate_limit_delay);
});
const updateHermesConfig = useCallback(
(updater: (config: Record<string, unknown>) => void) => {
try {
@@ -165,6 +180,20 @@ export function useHermesFormState({
[updateHermesConfig],
);
const handleHermesRateLimitDelayChange = useCallback(
(delay: number | undefined) => {
setHermesRateLimitDelay(delay);
updateHermesConfig((config) => {
if (delay === undefined) {
delete config.rate_limit_delay;
} else {
config.rate_limit_delay = delay;
}
});
},
[updateHermesConfig],
);
const resetHermesState = useCallback(
(config?: Partial<HermesProviderSettingsConfig>) => {
setHermesProviderKey("");
@@ -172,6 +201,7 @@ export function useHermesFormState({
setHermesApiKey(config?.api_key || "");
setHermesApiMode(config?.api_mode ?? HERMES_DEFAULT_API_MODE);
setHermesModels(config?.models ?? []);
setHermesRateLimitDelay(parseRateLimitDelay(config?.rate_limit_delay));
},
[],
);
@@ -183,11 +213,13 @@ export function useHermesFormState({
hermesApiKey,
hermesApiMode,
hermesModels,
hermesRateLimitDelay,
existingHermesKeys,
handleHermesBaseUrlChange,
handleHermesApiKeyChange,
handleHermesApiModeChange,
handleHermesModelsChange,
handleHermesRateLimitDelayChange,
resetHermesState,
};
}