hermes - ✅(Solved) Fix [Bug]: Custom Model Provider is not Enumerating Models for Model Picker, only the Default Model [2 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#11677Fetched 2026-04-18 05:59:27
View on GitHub
Comments
0
Participants
1
Timeline
5
Reactions
0
Participants
Timeline (top)
cross-referenced ×3labeled ×1referenced ×1

Error Message

Additional Logs / Traceback (optional)

Root Cause

📎 Root cause in code In hermes_cli/model_switch.py:

Fix Action

Fixed

PR fix notes

PR #11681: fix(model-picker): expose full custom provider model maps (#11677)

Description (problem / solution / changelog)

What does this PR do?

Fixes #11677: named custom_providers: entries with a populated models: map only surfaced the single default model in the shared /model picker. After this change, the picker exposes the full configured model set for those saved custom providers in both the CLI and gateway fallback list.

The root cause was in hermes_cli/model_switch.py: the custom_providers grouping path only appended entry[\"model\"] (currently around lines 1103-1105) and never iterated entry[\"models\"], even though Hermes already persists that map for saved custom providers.

This is the smallest safe fix because it only changes the read-only picker aggregation path. It does not change provider resolution, runtime routing, persistence, slug generation, or auth.

Related Issue

Fixes #11677

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • Teach list_authenticated_providers() to append model names from custom_providers[].models when building grouped rows for named custom providers.
  • Preserve existing behavior for custom_providers[].model by keeping it first and deduping any overlap with the models map/list.
  • Add a CLI regression test that proves a single named custom provider exposes its full models map.
  • Add a gateway /model regression test that proves the fallback text list also includes the expanded model set.

Backward Compatibility / Precedence

This change only affects how the picker displays saved custom providers; it does not alter persisted config.

Config shapeBehavior beforeBehavior after
model only, no modelsShows the default modelUnchanged
model + models dict/listShows only modelShows model first, then the rest of models
models dict/list onlyOften showed nothing beyond grouping metadataShows all configured model names
model duplicated inside modelsSingle visible entryStill a single visible entry (deduped)

Narrow Scope — Why Only This Path

This PR only fixes the legacy/named custom_providers: aggregation branch in hermes_cli/model_switch.py, because that is the broken path reported in #11677.

I deliberately did not touch:

  • providers: dict handling — it already has dedicated coverage in tests/hermes_cli/test_user_providers_model_switch.py and already exposes full model lists.
  • runtime provider resolution — not part of the bug.
  • setup/persistence flows — they already save the models map; the bug was that the picker ignored it.

If maintainers want broader cleanup across other provider shapes, that should be a separate follow-up.

How to Test

  1. Configure a named custom_providers: entry with both model: and a populated models: map.
  2. Run /model in the CLI or a gateway platform.
  3. Confirm the provider row now lists the full configured model set instead of only the default model.

Validation

Targeted change validation:

  1. source venv/bin/activate && python -m pytest tests/hermes_cli/test_model_switch_custom_providers.py -q
    • 6 passed
  2. source venv/bin/activate && python -m pytest tests/gateway/test_model_command_custom_providers.py -q
    • 2 passed
  3. source venv/bin/activate && python -m pytest tests/hermes_cli/test_user_providers_model_switch.py -q
    • 9 passed
  4. git diff --check
    • passed
  5. source venv/bin/activate && python -m py_compile hermes_cli/model_switch.py tests/hermes_cli/test_model_switch_custom_providers.py tests/gateway/test_model_command_custom_providers.py
    • passed

CI-aligned broad suite:

  1. source venv/bin/activate && python -m pytest tests/ -q --ignore=tests/integration --ignore=tests/e2e --tb=short -n auto
    • local environment still has unrelated baseline failures outside this change.

Baseline-confirmed unrelated failures reproduced on clean origin/main:

  • tests/gateway/test_matrix.py::TestMatrixUploadAndSend::test_upload_encrypted_room_uses_file_payload
  • tests/hermes_cli/test_gateway_wsl.py::TestSupportsSystemdServicesWSL::test_wsl_with_systemd
  • tests/hermes_cli/test_gateway_wsl.py::TestSupportsSystemdServicesWSL::test_native_linux
  • tests/gateway/test_approve_deny_commands.py::TestBlockingApprovalE2E::test_blocking_approval_approve_once
  • tests/gateway/test_approve_deny_commands.py::TestBlockingApprovalE2E::test_blocking_approval_deny
  • tests/tools/test_file_staleness.py::TestStalenessCheck::test_warning_when_file_modified_externally
  • tests/tools/test_file_staleness.py::TestPatchStaleness::test_patch_warns_on_stale_file
  • tests/tools/test_approval_heartbeat.py::TestApprovalHeartbeat::test_heartbeat_fires_while_waiting_for_approval
  • tests/tools/test_approval_heartbeat.py::TestApprovalHeartbeat::test_wait_returns_immediately_on_user_response

One additional failure, tests/gateway/test_internal_event_bypass_pairing.py::test_non_internal_event_without_user_triggers_pairing, appeared during the full-suite run but passed in isolation on clean origin/main, so it looks like an order-dependent baseline flake rather than something introduced here.

Tested platform:

  • macOS (local darwin arm64 dev environment)

Adjacent surfaces checked:

  • providers:-dict picker coverage in tests/hermes_cli/test_user_providers_model_switch.py
  • gateway /model fallback rendering in gateway/run.py

No standalone lint command is defined; CI runs python -m pytest tests/ -q --ignore=tests/integration --ignore=tests/e2e --tb=short -n auto.

Because this touches hermes_cli/**, the Nix workflow should also run on the PR.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS (darwin arm64)

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Changed files

  • hermes_cli/model_switch.py (modified, +13/-0)
  • tests/gateway/test_model_command_custom_providers.py (modified, +45/-0)
  • tests/hermes_cli/test_model_switch_custom_providers.py (modified, +33/-0)

PR #11696: fix: resolve duplicate custom provider (e.g., ollama) in /model picker and add live model discovery

Description (problem / solution / changelog)

Summary

Right now, the custom provider gets duplicated and /model picker does not pick all the models in the custom provider:

Fixes: #11677, #10011

╭─ ⚙ Model Picker — Select Provider ────────────────────╮
│                                                       │
│ Current: gemini-3-flash-preview on GitHub Copilot     │
│                                                       │
│   GitHub Copilot (14 models)  ← current               │
│   OpenRouter (31 models)│   Anthropic (8 models)│   OpenAI Codex (7 models)│ ❯ Ollama Local (1 model)│   OpenAI (0 models)│   Ollama Local (0 models)│   Cancel                                              │
│                                                       │
╰───────────────────────────────────────────────────────╯
  • Fix duplicate entries in the /model TUI picker for named custom providers configured using base_url in the providers: dict — section 3 of list_authenticated_providers was creating a phantom zero-model entry because it only reads api/url keys, while section 4 correctly handles base_url
  • Add live /v1/models probing for named custom providers in the /model picker — selecting a custom provider now shows all models the server has loaded, not just the one configured in config.yaml
  • Document the providers: dict format alongside the legacy custom_providers: list, and clarify live model discovery behavior
<!-- Check the one that applies. -->
  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)

Changes Made

  • hermes_cli/model_switch.py: Guard in section 3 to skip entries with no resolvable URL; probe each custom provider group's endpoint via fetch_api_models in section 4
  • cli.py: Use fetch_api_models directly for user-defined providers in the model picker selection stage instead of provider_model_ids (which doesn't handle custom:* slugs)
  • tests/hermes_cli/test_model_switch_custom_providers.py: Mock fetch_api_models to prevent live network calls in tests
  • website/docs/integrations/providers.md: Document both config formats, add live discovery tip
  • website/docs/reference/slash-commands.md: Update /model description

Changed files

  • cli.py (modified, +4/-4)
  • hermes_cli/model_switch.py (modified, +22/-0)
  • tests/hermes_cli/test_model_switch_custom_providers.py (modified, +3/-0)
  • website/docs/integrations/providers.md (modified, +32/-8)
  • website/docs/reference/slash-commands.md (modified, +2/-2)

Code Example

My config has keys in it. here is the providers

custom_providers:
- name: Thor
  base_url: http://thor.lab:8337/v1
  api_key: demo
  model: gemma-4-26B-A4B-it-MXFP4_MOE
  models:
    Qwen3.5-122B-A10B-MXFP4_MOE:
      context_length: 131072
    Qwen3.5-35B-A3B-MXFP4_MOE:
      context_length: 262144
    Qwen3.5-35B-A3B-IQ4_XS-4.06bpw:
      context_length: 262144
    Qwen3.5-4B-Q4_K_M:
      context_length: 262144
    gemma-4-31B-it-Q4_K_M:
      context_length: 262144
    gemma-4-26B-A4B-it-MXFP4_MOE:
      context_length: 262144
    supergemma4-26b-uncensored-fast-v2-Q4_K_M:
      context_length: 262144
    Qwopus-MoE-35B-A3B-Q4_K_M:
      context_length: 262144
    Qwen3.6-35B-A3B-MXFP4_MOE:
      context_length: 262144

---

Hermes Agent v0.10.0 (2026.4.16)
Project: /Users/matt/.hermes/hermes-agent
Python: 3.11.14
OpenAI SDK: 2.30.0
Up to date
RAW_BUFFERClick to expand / collapse

Bug Description

It’s a code limitation / bug in the model picker, not your Thor config.

✅ Your config does contain multiple Thor models under custom_providers[].models
❌ But the picker code currently only reads the single top-level model field for named custom providers.

📍 What I verified

  • Your config has Thor models under:
    • ~/.hermes/config.yaml:289-312
  • The live Thor endpoint returns multiple models, including:
    • Qwen3.6-35B-A3B-MXFP4_MOE
    • Qwen3.5-35B-A3B-MXFP4_MOE
    • Qwen3.5-122B-A10B-MXFP4_MOE
    • gemma-4-31B-it-Q4_K_M
  • But Hermes’ picker currently shows Thor as:
    • slug: custom:thor
    • models: only ["gemma-4-26B-A4B-it-MXFP4_MOE"]

📎 Root cause in code In hermes_cli/model_switch.py:

  • around 1078-1120, the picker groups custom_providers
  • it does this:
    • reads entry.get("model")
    • appends only that one model
  • it does not iterate through entry.get("models")

So this block is effectively the problem:

  • default_model = (entry.get("model") or "").strip()
  • then only that one gets added to the picker row

🧠 Important nuance

  • Hermes does read custom_providers[].models[...] for some runtime behavior like context-length resolution
  • but the shared /model picker UI is not yet using that full model map

✅ Bottom line Your Thor provider is configured correctly.
The model selector is incomplete for named custom providers and is only surfacing the default model.

Steps to Reproduce

  1. type /model in hermes in TUI or Telegram Channel
  2. Click on Customer Provider (Thor)
  3. View models list (only default model displayed)

Expected Behavior

  1. type /model in hermes in TUI or Telegram Channel
  2. Click on customer Provider (Thor)
  3. View models list (all configured models should be displayed)

Actual Behavior

A single default model is shown, ignoring the rest.

Affected Component

Gateway (Telegram/Discord/Slack/WhatsApp), CLI (interactive chat)

Messaging Platform (if gateway-related)

Telegram

Debug Report

My config has keys in it. here is the providers

custom_providers:
- name: Thor
  base_url: http://thor.lab:8337/v1
  api_key: demo
  model: gemma-4-26B-A4B-it-MXFP4_MOE
  models:
    Qwen3.5-122B-A10B-MXFP4_MOE:
      context_length: 131072
    Qwen3.5-35B-A3B-MXFP4_MOE:
      context_length: 262144
    Qwen3.5-35B-A3B-IQ4_XS-4.06bpw:
      context_length: 262144
    Qwen3.5-4B-Q4_K_M:
      context_length: 262144
    gemma-4-31B-it-Q4_K_M:
      context_length: 262144
    gemma-4-26B-A4B-it-MXFP4_MOE:
      context_length: 262144
    supergemma4-26b-uncensored-fast-v2-Q4_K_M:
      context_length: 262144
    Qwopus-MoE-35B-A3B-Q4_K_M:
      context_length: 262144
    Qwen3.6-35B-A3B-MXFP4_MOE:
      context_length: 262144

Operating System

MacOS

Python Version

3.11.14

Hermes Version

v0.10.0 (2026.4.16)

Additional Logs / Traceback (optional)

Hermes Agent v0.10.0 (2026.4.16)
Project: /Users/matt/.hermes/hermes-agent
Python: 3.11.14
OpenAI SDK: 2.30.0
Up to date

Root Cause Analysis (optional)

No response

Proposed Fix (optional)

No response

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

extent analysis

TL;DR

The model picker in Hermes needs to be updated to read and display all models under custom_providers[].models for named custom providers, not just the single top-level model field.

Guidance

  • The issue lies in hermes_cli/model_switch.py, specifically around lines 1078-1120, where the code only reads the entry.get("model") and appends that one model to the picker row, instead of iterating through entry.get("models").
  • To fix this, the code should be modified to handle both the single model field and the models dictionary for custom providers.
  • The default_model variable should be updated to include all models from entry.get("models"), not just the single entry.get("model").
  • Verification can be done by checking the model picker UI after the code change to ensure all configured models for a custom provider are displayed.

Example

# Example of how the code might be updated to handle both model and models
if "models" in entry:
    models = list(entry["models"].keys())
else:
    models = [entry.get("model", "")]

# Then, append these models to the picker row
for model in models:
    # Append model to the picker row
    pass

Notes

  • This fix assumes that the models dictionary in the config contains all the models that should be displayed for a custom provider.
  • The exact implementation details may vary depending on the rest of the codebase and the desired behavior.

Recommendation

  • Apply workaround: Update the hermes_cli/model_switch.py file to handle both the single model field and the models dictionary for custom providers, as described in the guidance section. This will allow the model picker to display all configured models for a custom provider.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix [Bug]: Custom Model Provider is not Enumerating Models for Model Picker, only the Default Model [2 pull requests, 1 participants]