Skip to content

Make providers the single source of truth for model registry #16622

@joejiao

Description

@joejiao

Problem

hermes model and /model tab completion use completely different data sources, creating a fragmented UX:

Step Current behavior Expected behavior
hermes model Writes model.default (single value, overwrites) Should append to providers.<slug>.models (list, cumulative)
/model tab Reads hardcoded MODEL_ALIASES + external models.dev catalog Should read from providers in config.yaml
Model switching Overwrites model.default, previously selected models "disappear" model.default points into providers, nothing is lost

Details

  1. _save_model_choice() (hermes_cli/auth.py:3815) only writes config["model"]["default"] = model_id. It never touches the providers section.

  2. _model_flow_api_key_provider() (hermes_cli/main.py:4489-4501) only writes model["provider"] and model["base_url"]. Again, providers is never updated.

  3. Tab completion reads from MODEL_ALIASES (hardcoded dict in hermes_cli/model_switch.py:105-154) and falls back to models.dev catalog. It does not read the user's providers config at all.

  4. The providers section in config.yaml (which supports api_key_env, base_url, models) is effectively a second-class citizen — only useful if manually edited.

Proposed Solution

Make providers the single source of truth for model registry:

1. hermes model should write to providers

When a user selects a model through hermes model:

  • API key → .env (already works ✅)
  • Base URL → .env (already works ✅)
  • Model entry → providers.<slug>.models (new — currently only writes model.default)

Example result after running hermes model twice for the same provider:

providers:
  deepseek:
    api_key_env: DEEPSEEK_API_KEY
    base_url: DEEPSEEK_BASE_URL
    models:
      deepseek-v4-pro:
        name: deepseek-v4-pro
        provider: deepseek
      deepseek-v4-flash:
        name: deepseek-v4-flash
        provider: deepseek

2. /model tab completion should read from providers

Tab completion should list all models from providers in config.yaml first, then fall back to catalog/aliases for models not yet configured.

3. Keep MODEL_ALIASES as fallback only

The hardcoded aliases are still useful for first-time setup or providers not yet in config.yaml. They should serve as suggestions, not the primary data source.

Benefits

  • Unified mental model: "models in providers are what I can use"
  • No lost models: previously selected models accumulate in providers, not overwritten
  • Config portability: providers + .env fully describes all available models
  • Minimal code change: mainly _save_model_choice() and tab completion data source

Affected Files

  • hermes_cli/auth.py_save_model_choice() should also update providers
  • hermes_cli/main.py_model_flow_api_key_provider() post-save logic
  • hermes_cli/model_switch.py — tab completion should read providers first
  • hermes_cli/model_switch.pyMODEL_ALIASES becomes fallback, not primary

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low — cosmetic, nice to havearea/configConfig system, migrations, profilescomp/cliCLI entry point, hermes_cli/, setup wizardtype/featureNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions