fix: model dropdown shows only hermes-configured providers (#155)

Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
This commit is contained in:
nesquena-hermes
2026-04-06 14:29:06 -07:00
committed by GitHub
parent 01896d67f3
commit 107c446187

View File

@@ -363,6 +363,20 @@ _PROVIDER_MODELS = {
{'id': 'MiniMax-M2.5-highspeed', 'label': 'MiniMax M2.5 Highspeed'}, {'id': 'MiniMax-M2.5-highspeed', 'label': 'MiniMax M2.5 Highspeed'},
{'id': 'MiniMax-M2.1', 'label': 'MiniMax M2.1'}, {'id': 'MiniMax-M2.1', 'label': 'MiniMax M2.1'},
], ],
# GitHub Copilot — model IDs served via the Copilot API
'copilot': [
{'id': 'gpt-5.4', 'label': 'GPT-5.4'},
{'id': 'gpt-5.4-mini', 'label': 'GPT-5.4 Mini'},
{'id': 'gpt-4o', 'label': 'GPT-4o'},
{'id': 'claude-opus-4.6', 'label': 'Claude Opus 4.6'},
{'id': 'claude-sonnet-4.6', 'label': 'Claude Sonnet 4.6'},
{'id': 'gemini-2.5-pro', 'label': 'Gemini 2.5 Pro'},
],
# 'gemini' is the hermes_cli provider ID for Google AI Studio
'gemini': [
{'id': 'gemini-2.5-pro', 'label': 'Gemini 2.5 Pro'},
{'id': 'gemini-2.0-flash', 'label': 'Gemini 2.0 Flash'},
],
} }
@@ -470,7 +484,27 @@ def get_available_models() -> dict:
except Exception: except Exception:
pass pass
# 4. Check for API keys that imply available providers # 4. Detect available providers.
# Primary: ask hermes-agent's auth layer — the authoritative source. It checks
# auth.json, credential pools, and env vars the same way the agent does at runtime,
# so the dropdown reflects exactly what the user has configured.
# Fallback: scan raw API key env vars (matches old behaviour if hermes not available).
detected_providers = set()
if active_provider:
detected_providers.add(active_provider)
_hermes_auth_used = False
try:
from hermes_cli.models import list_available_providers as _lap
for _p in _lap():
if _p.get('authenticated'):
detected_providers.add(_p['id'])
_hermes_auth_used = True
except Exception:
pass
if not _hermes_auth_used:
# Fallback: scan .env and os.environ for known API key variables
try: try:
from api.profiles import get_active_hermes_home as _gah2 from api.profiles import get_active_hermes_home as _gah2
hermes_env_path = _gah2() / '.env' hermes_env_path = _gah2() / '.env'
@@ -486,18 +520,12 @@ def get_available_models() -> dict:
env_keys[k.strip()] = v.strip().strip('"').strip("'") env_keys[k.strip()] = v.strip().strip('"').strip("'")
except Exception: except Exception:
pass pass
# Merge with actual env
all_env = {**env_keys} all_env = {**env_keys}
for k in ('ANTHROPIC_API_KEY', 'OPENAI_API_KEY', 'OPENROUTER_API_KEY', for k in ('ANTHROPIC_API_KEY', 'OPENAI_API_KEY', 'OPENROUTER_API_KEY',
'GOOGLE_API_KEY', 'GLM_API_KEY', 'KIMI_API_KEY', 'DEEPSEEK_API_KEY'): 'GOOGLE_API_KEY', 'GLM_API_KEY', 'KIMI_API_KEY', 'DEEPSEEK_API_KEY'):
val = os.getenv(k) val = os.getenv(k)
if val: if val:
all_env[k] = val all_env[k] = val
detected_providers = set()
if active_provider:
detected_providers.add(active_provider)
if all_env.get('ANTHROPIC_API_KEY'): if all_env.get('ANTHROPIC_API_KEY'):
detected_providers.add('anthropic') detected_providers.add('anthropic')
if all_env.get('OPENAI_API_KEY'): if all_env.get('OPENAI_API_KEY'):
@@ -628,14 +656,11 @@ def get_available_models() -> dict:
'models': [{'id': default_model, 'label': default_model.split('/')[-1]}], 'models': [{'id': default_model, 'label': default_model.split('/')[-1]}],
}) })
else: else:
# No providers detected -- use fallback grouped list # No providers detected. Show only the configured default model so the user
by_provider = {} # can at least send messages with their current setting. Avoid showing a
for m in _FALLBACK_MODELS: # generic multi-provider list — those models wouldn't be routable anyway.
by_provider.setdefault(m['provider'], []).append( label = default_model.split('/')[-1] if '/' in default_model else default_model
{'id': m['id'], 'label': m['label']} groups.append({'provider': 'Default', 'models': [{'id': default_model, 'label': label}]})
)
for provider_name, models in by_provider.items():
groups.append({'provider': provider_name, 'models': models})
# Ensure the user's configured default_model always appears in the dropdown. # Ensure the user's configured default_model always appears in the dropdown.
# It may be missing if the model isn't in any hardcoded list (e.g. openrouter/free, # It may be missing if the model isn't in any hardcoded list (e.g. openrouter/free,