Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 38 additions & 7 deletions hermes_cli/model_switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -784,40 +784,71 @@ def list_authenticated_providers(

# --- 2. Check Hermes-only providers (nous, openai-codex, copilot) ---
from hermes_cli.providers import HERMES_OVERLAYS

# Build reverse mapping: models.dev ID -> Hermes provider ID
# e.g. "github-copilot" -> "copilot", so overlay keys resolve correctly.
_mdev_to_hermes = {v: k for k, v in PROVIDER_TO_MODELS_DEV.items()}

for pid, overlay in HERMES_OVERLAYS.items():
if pid in seen_slugs:
continue

# Resolve the Hermes provider slug for this overlay.
# Overlay keys may be models.dev IDs (e.g. "github-copilot") while
# the config and curated lists use Hermes IDs (e.g. "copilot").
hermes_slug = _mdev_to_hermes.get(pid, pid)
if hermes_slug in seen_slugs:
continue

# Check if credentials exist
has_creds = False
if overlay.extra_env_vars:
has_creds = any(os.environ.get(ev) for ev in overlay.extra_env_vars)
if overlay.auth_type in ("oauth_device_code", "oauth_external", "external_process"):
if not has_creds and overlay.auth_type in ("oauth_device_code", "oauth_external", "external_process"):
# These use auth stores, not env vars — check for auth.json entries
try:
from hermes_cli.auth import _load_auth_store
store = _load_auth_store()
if store and (pid in store.get("providers", {}) or pid in store.get("credential_pool", {})):
providers_store = store.get("providers", {})
pool_store = store.get("credential_pool", {})
# Check both the overlay key AND the Hermes slug
if store and (
pid in providers_store or pid in pool_store
or hermes_slug in providers_store or hermes_slug in pool_store
):
has_creds = True
except Exception as exc:
logger.debug("Auth store check failed for %s: %s", pid, exc)
if not has_creds:
# Last resort: check credential pool under Hermes slug too
if not has_creds:
try:
from hermes_cli.auth import _load_auth_store
store = _load_auth_store()
pool_store = store.get("credential_pool", {})
if hermes_slug in pool_store or pid in pool_store:
has_creds = True
except Exception:
pass
if not has_creds:
continue

# Use curated list
model_ids = curated.get(pid, [])
# Use curated list — look up by both Hermes slug and overlay key
model_ids = curated.get(hermes_slug, []) or curated.get(pid, [])
total = len(model_ids)
top = model_ids[:max_models]

results.append({
"slug": pid,
"name": get_label(pid),
"is_current": pid == current_provider,
"slug": hermes_slug,
"name": get_label(hermes_slug),
"is_current": hermes_slug == current_provider or pid == current_provider,
"is_user_defined": False,
"models": top,
"total_models": total,
"source": "hermes",
})
seen_slugs.add(pid)
seen_slugs.add(hermes_slug)

# --- 3. User-defined endpoints from config ---
if user_providers and isinstance(user_providers, dict):
Expand Down
22 changes: 21 additions & 1 deletion hermes_cli/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,19 +96,39 @@
"copilot-acp",
],
"copilot": [
# OpenAI — GPT-5 family
"gpt-5.4",
"gpt-5.4-mini",
"gpt-5-mini",
"gpt-5.3-codex",
"gpt-5.2-codex",
"gpt-5.2",
"gpt-5.1",
"gpt-5-mini",
# OpenAI — GPT-4 family
"gpt-4.1",
"gpt-4o",
"gpt-4o-mini",
"gpt-4.1-2025-04-14",
"gpt-4o-2024-11-20",
"gpt-4o-2024-08-06",
"gpt-4o-2024-05-13",
"gpt-4o-mini-2024-07-18",
"gpt-4-o-preview",
"gpt-4",
"gpt-4-0613",
# OpenAI — GPT-3.5
"gpt-3.5-turbo",
"gpt-3.5-turbo-0613",
# Anthropic — Claude 4.x
"claude-opus-4.6",
"claude-opus-4.5",
"claude-sonnet-4.6",
"claude-sonnet-4.5",
"claude-sonnet-4",
"claude-haiku-4.5",
# Google
"gemini-2.5-pro",
# xAI
"grok-code-fast-1",
],
"gemini": [
Expand Down