refactor: tie api_mode to provider config instead of env var (#1656)

Remove HERMES_API_MODE env var. api_mode is now configured where the
endpoint is defined:

- model.api_mode in config.yaml (for the active model config)
- custom_providers[].api_mode (for named custom providers)

Replace _get_configured_api_mode() with _parse_api_mode() which just
validates a value against the whitelist without reading env vars.

Both paths (model config and named custom providers) now read api_mode
from their respective config entries rather than a global override.
This commit is contained in:
Teknium 2026-03-17 02:13:26 -07:00 committed by GitHub
parent 4e66d22151
commit 766f4aae2b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 42 additions and 41 deletions

View file

@ -33,21 +33,15 @@ def _get_model_config() -> Dict[str, Any]:
return {}
def _get_configured_api_mode(model_cfg: Optional[Dict[str, Any]] = None) -> Optional[str]:
"""Return an optional API mode override from env or config.
_VALID_API_MODES = {"chat_completions", "codex_responses"}
Allows custom OpenAI-compatible endpoints to opt into codex_responses
mode via HERMES_API_MODE env var or model.api_mode in config.yaml,
without requiring the OpenAI Codex OAuth provider path.
"""
candidate = os.getenv("HERMES_API_MODE", "").strip().lower()
if not candidate:
cfg = model_cfg if isinstance(model_cfg, dict) else _get_model_config()
raw = cfg.get("api_mode")
if isinstance(raw, str):
candidate = raw.strip().lower()
if candidate in {"chat_completions", "codex_responses"}:
return candidate
def _parse_api_mode(raw: Any) -> Optional[str]:
"""Validate an api_mode value from config. Returns None if invalid."""
if isinstance(raw, str):
normalized = raw.strip().lower()
if normalized in _VALID_API_MODES:
return normalized
return None
@ -104,11 +98,15 @@ def _get_named_custom_provider(requested_provider: str) -> Optional[Dict[str, An
menu_key = f"custom:{name_norm}"
if requested_norm not in {name_norm, menu_key}:
continue
return {
result = {
"name": name.strip(),
"base_url": base_url.strip(),
"api_key": str(entry.get("api_key", "") or "").strip(),
}
api_mode = _parse_api_mode(entry.get("api_mode"))
if api_mode:
result["api_mode"] = api_mode
return result
return None
@ -139,7 +137,7 @@ def _resolve_named_custom_runtime(
return {
"provider": "openrouter",
"api_mode": _get_configured_api_mode() or "chat_completions",
"api_mode": custom_provider.get("api_mode", "chat_completions"),
"base_url": base_url,
"api_key": api_key,
"source": f"custom_provider:{custom_provider.get('name', requested_provider)}",
@ -208,11 +206,10 @@ def _resolve_openrouter_runtime(
)
source = "explicit" if (explicit_api_key or explicit_base_url) else "env/config"
api_mode = _get_configured_api_mode(model_cfg) or "chat_completions"
return {
"provider": "openrouter",
"api_mode": api_mode,
"api_mode": _parse_api_mode(model_cfg.get("api_mode")) or "chat_completions",
"base_url": base_url,
"api_key": api_key,
"source": source,