Skip to content

Bug: /model provider picker shows duplicate entries when provider exists in both built-in catalog and config.yaml #7524

@ShuaiHui

Description

@ShuaiHui

Bug Description

The /model command's provider picker displays duplicate entries when a provider exists in both the built-in catalog (PROVIDER_TO_MODELS_DEV / HERMES_OVERLAYS) and the user's config.yaml providers: section.

For example, with nous configured in providers::

  • "Nous Portal (27)" — added by Section 2 (HERMES_OVERLAYS), shows curated model count
  • "nous (0)" — added by Section 3 (user_providers), shows 0 models

This affects all providers that appear in both locations: nous, copilot, deepseek, minimax, minimax-cn, etc.

Steps to Reproduce

  1. Have a provider configured in config.yaml under providers: that also exists as a built-in provider:
    providers:
      nous:
        allowed_models:
          - xiaomi/mimo-v2-pro
  2. Set the corresponding credentials (e.g., Nous Portal OAuth token)
  3. Run /model in Telegram or CLI
  4. Observe duplicate provider entries in the picker

Expected Behavior

Each provider appears exactly once in the picker, with the correct model count from the curated list.

Actual Behavior

Each provider appears twice:

  • Once from Section 2 (HERMES_OVERLAYS) with correct model count (e.g., "Nous Portal (27)")
  • Once from Section 3 (user_providers) with 0 models (e.g., "nous (0)")

Root Cause

In hermes_cli/model_switch.py, the list_authenticated_providers() function builds the provider list in 4 sections:

  • Section 1 (line ~771): Built-in providers from PROVIDER_TO_MODELS_DEV — uses seen_slugs for dedup ✅
  • Section 2 (line ~812): Hermes overlays from HERMES_OVERLAYS — uses seen_slugs for dedup ✅
  • Section 3 (line ~877): User-defined providers from config.yaml providers:does NOT check seen_slugs
  • Section 4 (line ~903): Custom providers from config.yaml custom_providers: — uses seen_slugs for dedup ✅

Section 3 is the only section that doesn't check seen_slugs before adding entries, and doesn't add its entries to seen_slugs after. This causes duplicates when the same provider key exists in both the built-in catalog and the user config.

Fix

Add seen_slugs deduplication to Section 3, consistent with the other sections:

# --- 3. User-defined endpoints from config ---
if user_providers and isinstance(user_providers, dict):
    for ep_name, ep_cfg in user_providers.items():
        if not isinstance(ep_cfg, dict):
            continue
        # Skip if this provider was already added by Sections 1/2
        if ep_name in seen_slugs:
            continue
        # ... existing logic ...
        seen_slugs.add(ep_name)  # Track after adding

Related Issues / PRs

Verification

from hermes_cli.model_switch import list_authenticated_providers

providers = list_authenticated_providers(
    current_provider="nous",
    user_providers={"nous": {}, "minimax-cn": {}, "copilot": {}, "deepseek": {}, "minimax": {}},
    max_models=50,
)

slugs = [p["slug"] for p in providers]
assert len(slugs) == len(set(slugs)), f"Duplicate slugs found: {[s for s in slugs if slugs.count(s) > 1]}"

Labels

bug good first issue area: /model command area: provider resolution

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/cliCLI entry point, hermes_cli/, setup wizardtype/bugSomething isn't working

    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