Skip to content

bug(models): providers not in hardcoded _PROVIDER_MODELS dict are invisible in WebUI model picker despite being authenticated #1236

@SadBoen

Description

@SadBoen

Summary

Providers that are successfully authenticated and fully functional in the CLI (hermes auth list, hermes model switch) do not appear in the WebUI model picker when they are absent from the hardcoded _PROVIDER_MODELS dictionary in api/config.py.

In my case, the minimax-cn provider — configured via MINIMAX_CN_API_KEY and working perfectly in CLI — is completely invisible in the WebUI model dropdown. This is a general problem: any provider not listed in _PROVIDER_MODELS and not properly mapped in config.yaml will silently disappear from the picker.

Steps to reproduce

  1. Configure a provider via environment variable that has an API key supported by hermes_cli but is not listed in _PROVIDER_MODELS (e.g. minimax-cn via MINIMAX_CN_API_KEY)
  2. Verify the provider works in CLI: hermes auth list shows it as authenticated, hermes model switch can select its models
  3. Open the WebUI and click the model picker dropdown
  4. The provider group is absent — only providers with entries in _PROVIDER_MODELS appear

Root cause

The detection logic in _build_available_models_uncached() (api/config.py) has a gap between provider detection and model group generation:

1. Env-var detection maps MINIMAX_CN_API_KEY to wrong provider ID

# Line ~1441
if all_env.get("MINIMAX_API_KEY") or all_env.get("MINIMAX_CN_API_KEY"):
    detected_providers.add("minimax")   # ← always "minimax", never "minimax-cn"

hermes_cli registers MINIMAX_CN_API_KEY as provider minimax-cn (separate from minimax). The env-var detection maps it to minimax — a different provider ID. So minimax-cn never enters detected_providers via the env-var path.

2. The config.yaml providers: path can add minimax-cn to detected_providers, but model group generation still fails

# Line ~1685
elif pid in _PROVIDER_MODELS or pid in cfg.get("providers", {}):

"minimax-cn" not in _PROVIDER_MODELS → False. minimax-cn in cfg.get("providers", {}) → True. So the elif branch is entered. However:

provider_cfg = cfg.get("providers", {}).get(pid, {})
if isinstance(provider_cfg, dict) and "models" in provider_cfg:
    # only this path generates model lists for unlisted providers

If providers.minimax-cn is an empty dict {} (as auto-configured by hermes_cli), it has no "models" key. raw_models falls back to _PROVIDER_MODELS.get("minimax-cn", []) which returns []. An empty model list means no group is appended.

3. CLI detection is different — it uses hermes_cli directly

The CLI calls hermes_cli.model_switch.list_authenticated_providers() which scans API keys independently of _PROVIDER_MODELS. This is why the CLI correctly shows minimax-cn with its models.

The mismatch chain

MINIMAX_CN_API_KEY set in .env
  ↓
hermes_cli registers provider "minimax-cn" → CLI works ✓
WebUI env-var detection → detected_providers.add("minimax") ← wrong provider ID
WebUI config.yaml path → providers.minimax-cn:{} → no "models" key → empty model list
WebUI _PROVIDER_MODELS → "minimax-cn" not found
  ↓
minimax-cn invisible in WebUI ✗

Expected behavior

A provider that the CLI authenticates and lists as available should also appear in the WebUI model picker without requiring the user to manually add model definitions to config.yaml.

Workaround (currently applied)

Add providers.minimax-cn.models to config.yaml with explicit model mappings:

providers:
  minimax-cn:
    api_key: ''
    models:
      MiniMax-M2.7: MiniMax M2.7
      MiniMax-M2.7-highspeed: MiniMax M2.7 Highspeed
      MiniMax-M2.5: MiniMax M2.5
      MiniMax-M2.1: MiniMax M2.1
      MiniMax-M2: MiniMax M2

Then delete ~/.hermes/webui/models_cache.json and restart the WebUI service.

Downsides:

  • Model list is static — must be manually updated when the provider adds new models
  • No fallback to hermes_cli's dynamic model discovery
  • Requires users to know model IDs that the CLI already has access to

Suggested fix directions

Option A: Auto-discover models from hermes_cli for unlisted providers

When pid is in detected_providers but not in _PROVIDER_MODELS, and providers.<pid>.models is absent, try to discover models dynamically from hermes_cli.model_switch.list_authenticated_providers():

elif pid in cfg.get("providers", {}):
    provider_cfg = cfg.get("providers", {}).get(pid, {})
    if isinstance(provider_cfg, dict) and "models" in provider_cfg:
        # existing: use config.yaml models
    else:
        # try hermes_cli discovery for unlisted providers
        cli_models = _discover_models_from_cli(pid)
        if cli_models:
            raw_models = cli_models
        # else: still skip (no models available)

Option B: Map MINIMAX_CN_API_KEY to the correct provider ID

if all_env.get("MINIMAX_CN_API_KEY"):
    detected_providers.add("minimax-cn")  # separate from minimax
if all_env.get("MINIMAX_API_KEY"):
    detected_providers.add("minimax")

And add a "minimax-cn" entry to _PROVIDER_MODELS and _PROVIDER_DISPLAY.

Option C: Both A and B

A provides a general fallback for any future provider that hermes_cli supports but _PROVIDER_MODELS hasn't been updated for. B provides the specific fix for the known minimax-cn case with proper display name and static model catalog.

Impact

This affects any user of providers that hermes_cli supports but _PROVIDER_MODELS does not include. minimax-cn is the current known case, but the same pattern applies to any provider ID that differs from what the env-var detection block maps to.

The issue is particularly confusing because:

  • The CLI shows the provider and its models correctly
  • The WebUI silently hides it with no error or warning
  • There is no UI indication that a provider is "configured but invisible"

Files

  • api/config.py_PROVIDER_MODELS dict (line ~612), env-var detection block (line ~1415–1448), model group generation logic (line ~1685–1700), _PROVIDER_DISPLAY dict (line ~519)
  • api/config.py_PROVIDER_ALIASES dict (line ~540) — no alias for minimax-cn

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingprioritysprint-candidateStrong candidate for next sprint

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions