From b388a48a2ea053c5beb88bdc5b5777acefbd401e Mon Sep 17 00:00:00 2001 From: kshitijk4poor <82637225+kshitijk4poor@users.noreply.github.com> Date: Fri, 18 Sep 2026 14:25:38 +0530 Subject: [PATCH] refactor(providers): drop the now-dead keyless provider plumbing The keyless OpenCode free tier was the only provider that ever set `HermesOverlay.keyless`, so the flag and everything keyed off it is now unreachable: the `keyless=` field on `HermesOverlay` and `ProviderDescriptor`, the `_overlay_has_creds` early return, both `_provider_is_keyless` copies (auth.py and inventory.py), the `get_api_key_provider_status` keyless short-circuit and its `key_source: "keyless"` placeholder, and the empty `_KEYLESS_STABLE_CACHE_PROVIDERS` set whose `_credential_fingerprint` branch could never match. Dropping the two catalog-derived test exemptions follows: they computed the empty set. --- hermes_cli/auth.py | 15 +-------------- hermes_cli/inventory.py | 13 +------------ hermes_cli/model_switch_providers.py | 2 -- hermes_cli/models.py | 6 ------ hermes_cli/models_catalog_static.py | 6 ------ hermes_cli/provider_catalog.py | 4 ---- hermes_cli/providers.py | 1 - tests/hermes_cli/test_provider_catalog.py | 7 +++---- tests/hermes_cli/test_provider_parity.py | 6 +----- 9 files changed, 6 insertions(+), 54 deletions(-) diff --git a/hermes_cli/auth.py b/hermes_cli/auth.py index 2afdf803c3..0205bfd5d3 100644 --- a/hermes_cli/auth.py +++ b/hermes_cli/auth.py @@ -1741,27 +1741,14 @@ def _provider_env_base_url(pconfig: ProviderConfig) -> str: return os.getenv(pconfig.base_url_env_var, "").strip() if pconfig.base_url_env_var else "" -def _provider_is_keyless(provider_id: str) -> bool: - """HermesOverlay keyless flag — the same source the provider catalog and GUI contract tests use.""" - try: - from hermes_cli.providers import HERMES_OVERLAYS - return bool(getattr(HERMES_OVERLAYS.get(provider_id), "keyless", False)) - except Exception: - return False - - def get_api_key_provider_status(provider_id: str) -> Dict[str, Any]: """Status snapshot for API-key providers (z.ai, Kimi, MiniMax).""" pconfig = PROVIDER_REGISTRY.get(provider_id) if not pconfig or pconfig.auth_type != "api_key": return {"configured": False} status = { - "configured": True, "provider": provider_id, "name": pconfig.name, "key_source": "keyless", + "configured": True, "provider": provider_id, "name": pconfig.name, "key_source": "", "base_url": pconfig.inference_base_url, "logged_in": True} - if _provider_is_keyless(provider_id): - # Keyless providers are served anonymously: every install counts as - # configured. - return status api_key, key_source = _resolve_api_key_provider_secret(provider_id, pconfig) env_url = _provider_env_base_url(pconfig) diff --git a/hermes_cli/inventory.py b/hermes_cli/inventory.py index d3778cd4a5..ae71396919 100644 --- a/hermes_cli/inventory.py +++ b/hermes_cli/inventory.py @@ -486,10 +486,9 @@ def _filter_explicit_provider_rows(rows: list[dict], ctx: ConfigContext) -> list # wrote an enabled preset into RAW config (the DEFAULT_CONFIG preset must not show MoA). return _raw_config_has_enabled_moa_preset() return ( - _provider_is_keyless(slug) # zero-setup providers need no configuration at all # Anthropic OAuth (device flow / Claude Code) and external-process CLIs (copilot-acp) are # deliberate sign-ins that leave no trace in config/env; keep the rows discovery accepted. - or (slug == "anthropic" and _anthropic_oauth_credentials_present()) + (slug == "anthropic" and _anthropic_oauth_credentials_present()) or _external_process_signed_in(slug) or is_provider_explicitly_configured(slug) ) @@ -509,16 +508,6 @@ def _external_process_signed_in(slug: str) -> bool: return False -def _provider_is_keyless(slug: str) -> bool: - """True when the provider's Hermes overlay declares it keyless.""" - try: - from hermes_cli.providers import HERMES_OVERLAYS - overlay = HERMES_OVERLAYS.get(slug) - return bool(overlay is not None and getattr(overlay, "keyless", False)) - except Exception: - return False - - def _raw_config_has_enabled_moa_preset() -> bool: """True when the user's RAW config enables MoA: ``load_config()`` merges the DEFAULT_CONFIG preset for everyone, which is not a user choice; visible once one enabled preset (or legacy flat config) is saved.""" diff --git a/hermes_cli/model_switch_providers.py b/hermes_cli/model_switch_providers.py index 4ce12a3f2c..4178f08b60 100644 --- a/hermes_cli/model_switch_providers.py +++ b/hermes_cli/model_switch_providers.py @@ -803,8 +803,6 @@ def _lap_builtin_rows(b: _PickerBuild, data: dict, user_providers: dict) -> None def _overlay_has_creds(b: _PickerBuild, pid: str, hermes_slug: str, overlay) -> bool: """Section-2 credential ladder: env/SDK, external-process executable, auth store, pool, anthropic's external credential files.""" - if overlay.keyless: - return True # served anonymously — no credential exists to configure if overlay.auth_type == "aws_sdk": has_creds = _has_aws_sdk_creds_for_listing(hermes_slug, b.current_provider) else: diff --git a/hermes_cli/models.py b/hermes_cli/models.py index 4207ed7d8f..598b34850c 100644 --- a/hermes_cli/models.py +++ b/hermes_cli/models.py @@ -37,7 +37,6 @@ from hermes_cli.models_catalog_static import ( _AZURE_FOUNDRY_RESPONSES_PREFIXES, _BORROWED_MODEL_PROVIDERS, _COPILOT_MODEL_ALIASES, - _KEYLESS_STABLE_CACHE_PROVIDERS, _LIVE_FIRST_PICKER_PROVIDERS, _MODELS_DEV_PREFERRED, _OPENAI_FAST_MODE_PREFIXES, @@ -1586,11 +1585,6 @@ def _credential_fingerprint(provider: str) -> str: credential files (OAuth re-auth busts the cache without parsing every file shape).""" import hashlib - # Keyless providers serve the catalog anonymously: nothing the user rotates should invalidate - # the entry, so a stable fingerprint keeps the SWR cache alive and busts only on TTL expiry. - if (provider or "").strip().lower() in _KEYLESS_STABLE_CACHE_PROVIDERS: - return "keyless:" + (provider or "").strip().lower() - parts: list[str] = [] try: from hermes_cli.auth import PROVIDER_REGISTRY diff --git a/hermes_cli/models_catalog_static.py b/hermes_cli/models_catalog_static.py index 80082227a8..3565e55b9a 100644 --- a/hermes_cli/models_catalog_static.py +++ b/hermes_cli/models_catalog_static.py @@ -532,12 +532,6 @@ _MODELS_DEV_PREFERRED: frozenset[str] = frozenset({ }) -# Providers whose catalog is served with NO credential get a constant credential fingerprint in -# the disk cache, so folding in unrelated auth.json mtimes would only bust the SWR cache needlessly. -# (Empty since the keyless OpenCode free tier was removed; kept as the extension point.) -_KEYLESS_STABLE_CACHE_PROVIDERS = frozenset() - - # OpenRouter-style ids -> Copilot ids. Dash-notation Claude ids are accepted too: Hermes' default # Claude IDs use hyphens (Anthropic native) but Copilot's API only accepts dot-notation, so a # copilot + hyphenated default would otherwise hit HTTP 400 "model_not_supported". diff --git a/hermes_cli/provider_catalog.py b/hermes_cli/provider_catalog.py index 25c31ab092..07b29bd931 100644 --- a/hermes_cli/provider_catalog.py +++ b/hermes_cli/provider_catalog.py @@ -37,7 +37,6 @@ class ProviderDescriptor: base_url_env_var: str # base-URL override env var (may be "") signup_url: str # signup / console URL (may be "") order: int # CANONICAL_PROVIDERS index — mirrors `hermes model` - keyless: bool = False # served anonymously — no credential exists to configure def tab_for_auth_type(auth_type: str) -> str: @@ -104,9 +103,6 @@ def provider_catalog() -> list[ProviderDescriptor]: slug=slug, label=label, description=(prof.description if prof else "") or entry.tui_desc or label, auth_type=auth_type, tab=tab_for_auth_type(auth_type), api_key_env_vars=api_key_vars, base_url_env_var=base_url_var, signup_url=signup_url, order=order, - # Keyless providers are served anonymously: no key card in the GUI, - # and contract tests exempt them. - keyless=bool(overlay.keyless) if overlay else False, ) ) return out diff --git a/hermes_cli/providers.py b/hermes_cli/providers.py index 55b1eef0f8..a27fe47df1 100644 --- a/hermes_cli/providers.py +++ b/hermes_cli/providers.py @@ -23,7 +23,6 @@ class HermesOverlay: extra_env_vars: Tuple[str, ...] = () # env vars models.dev doesn't list base_url_override: str = "" # override if models.dev URL is wrong/missing base_url_env_var: str = "" # env var for user-custom base URL - keyless: bool = False # served anonymously — no credential exists to configure HERMES_OVERLAYS: Dict[str, HermesOverlay] = { diff --git a/tests/hermes_cli/test_provider_catalog.py b/tests/hermes_cli/test_provider_catalog.py index 1ecff0947c..e666e00158 100644 --- a/tests/hermes_cli/test_provider_catalog.py +++ b/tests/hermes_cli/test_provider_catalog.py @@ -57,14 +57,13 @@ def test_api_key_providers_expose_a_credential_env_var(): surface at least one env var to write the key into (otherwise the GUI can't configure it). - Exemptions: ``aws_sdk`` (bedrock — uses AWS_REGION/AWS_PROFILE), the + Exemptions: ``aws_sdk`` (bedrock — uses AWS_REGION/AWS_PROFILE) and the ``custom`` bring-your-own-endpoint pseudo-provider (configured inline via - the ``local-endpoint`` flow), and keyless providers (``d.keyless`` — - served anonymously: there is no credential to write). + the ``local-endpoint`` flow). """ exempt = {"custom"} for d in provider_catalog(): - if d.auth_type == "api_key" and d.slug not in exempt and not d.keyless: + if d.auth_type == "api_key" and d.slug not in exempt: assert d.api_key_env_vars, f"{d.slug} is api_key but exposes no env var" diff --git a/tests/hermes_cli/test_provider_parity.py b/tests/hermes_cli/test_provider_parity.py index 1fb6a56c29..017c46b88b 100644 --- a/tests/hermes_cli/test_provider_parity.py +++ b/tests/hermes_cli/test_provider_parity.py @@ -31,11 +31,7 @@ HEADERS = {"X-Hermes-Session-Token": _SESSION_TOKEN} # derived from the catalog so any future virtual provider is covered without a # hardcoded slug. _VIRTUAL = {d.slug for d in provider_catalog() if d.auth_type == "virtual"} -# Keyless providers are served anonymously: no credential -# exists, so there is nothing to configure on either Providers tab. Derived -# from the catalog flag so any future keyless provider is covered. -_KEYLESS = {d.slug for d in provider_catalog() if d.keyless} -_EXEMPT = {"custom"} | _VIRTUAL | _KEYLESS +_EXEMPT = {"custom"} | _VIRTUAL # Providers that legitimately offer BOTH auth methods and so intentionally # appear on both desktop tabs (an API-key card AND an account sign-in card).