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.
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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."""
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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".
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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] = {
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
Reference in New Issue
Block a user