Skip to content

CLI doesn't honor user-defined providers via chat --provider or -m <alias> #16767

@westers

Description

@westers

Summary

User-defined providers configured under the providers: dict in ~/.hermes/config.yaml are reachable through some CLI paths (top-level oneshot, TUI /model, delegation:) but blocked or ignored by two heavily-used paths:

  1. hermes chat --provider <user-name> is rejected by argparse choices=.
  2. -m <alias> from the CLI doesn't propagate the alias's base_url (only the model name).

Both result in requests silently routing to whatever model.base_url is in config, instead of the user-intended endpoint — verified via log inspection on the targeted endpoint.

Reproducible setup (~/.hermes/config.yaml)

model:
  default: "gemma-4-26b"
  provider: "custom"
  base_url: "http://localhost:8080/v1"

providers:
  host-a:
    api: "http://localhost:8080/v1"
    default_model: "gemma-4-26b"
    transport: "openai"
  host-b:
    api: "http://localhost:11435/v1"
    default_model: "gemma-4-31b"
    transport: "openai"

model_aliases:
  my-31b:
    model: "gemma-4-31b"
    provider: "custom"
    base_url: "http://localhost:11435/v1"

(Two local llama.cpp instances on different ports — common multi-model pattern.)

Bug 1 — hermes chat --provider <user-name> rejected by argparse

$ hermes chat --provider host-b -m gemma-4-31b -q "Hello"
hermes chat: error: argument --provider: invalid choice: 'host-b'
  (choose from 'auto', 'openrouter', 'nous', 'openai-codex', ...)

Expected: routes through _resolve_named_custom_runtime (which already handles user providers:) when --provider matches a key in user config.

Root cause: hermes_cli/main.py ~L7765 — chat subcommand argparse hardcodes choices= to built-in providers only. The top-level hermes --provider … flag does NOT have this restriction and routes correctly.

Suggested fix: drop choices= on the chat subparser's --provider, or build the list at runtime as BUILTIN_PROVIDERS | set(config.get("providers", {}).keys()).

Bug 2 — -m <alias> doesn't propagate base_url

$ hermes -m my-31b -z "Hello"

Request silently goes to model.base_url (port 8080) with the literal string my-31b as the model name. Verified by tailing the llama.cpp log on each port — port 11435 records no activity, port 8080 receives the request.

Expected: alias resolves to (model=gemma-4-31b, provider=custom, base_url=http://localhost:11435/v1) and the request hits port 11435.

Root cause (two layers):

  1. hermes_cli/models.py:1537detect_provider_for_model() only searches built-in static catalogs and the OpenRouter catalog. It does not consult user providers: or DIRECT_ALIASES.

  2. hermes_cli/model_switch.py:434–436resolve_alias() returns a 3-tuple that drops base_url:

    direct = DIRECT_ALIASES.get(key)
    if direct is not None:
        return (direct.provider, direct.model, key)   # drops direct.base_url

    Callers in hermes_cli/oneshot.py therefore can't thread base_url through to resolve_runtime_provider(explicit_base_url=...).

Suggested fix: extend detect_provider_for_model() to consult DIRECT_ALIASES (matched by alias name or default_model), and have resolve_alias() return a 4-tuple (or DirectAlias) including base_url; update CLI callers to pass it through.

Workarounds verified to work today

  • hermes --provider host-b -m gemma-4-31b -z "…" (top-level oneshot, no chat subcommand) ✓
  • TUI /model my-31b (uses a separate path that handles base_url correctly) ✓
  • For multi-model parallel use, delegation.base_url works as designed (tools/delegate_tool.py:2178) ✓

Environment

  • Hermes Agent v0.11.0 (2026.4.23)
  • Python 3.11.14, uv-managed venv
  • Linux / Ubuntu
  • Two local llama.cpp servers (Gemma 4 26B and Gemma 4 31B) on different ports

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existsarea/configConfig system, migrations, profilescomp/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