hermes - ✅(Solved) Fix resolve_alias() reverse lookup returns wrong provider when multiple providers share the same model [1 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#14614Fetched 2026-04-24 06:16:01
View on GitHub
Comments
0
Participants
1
Timeline
5
Reactions
0
Participants
Timeline (top)
labeled ×4cross-referenced ×1

When model_aliases contains multiple entries pointing to the same model ID but different providers (e.g. two providers both offering claude-opus-4-6), resolve_alias() in model_switch.py returns the first matching alias by dict iteration order, regardless of which provider was actually requested. This causes /model <name> --provider <slug> to silently use the wrong provider's base_url and api_key.

Root Cause

In hermes_cli/model_switch.py, resolve_alias() (around line 331) does a reverse lookup by iterating all DIRECT_ALIASES and returning the first entry where da.model == key:

for alias_name, da in DIRECT_ALIASES.items():
    if da.model.lower() == key:
        return (da.provider, da.model, alias_name)

This doesn't consider the current_provider / target provider parameter. In PATH A of switch_model() (line 535), when explicit_provider is given:

alias_result = resolve_alias(new_model, target_provider)
if alias_result is not None:
    _, new_model, resolved_alias = alias_result

The returned resolved_alias may belong to a different provider. Later, DIRECT_ALIASES.get(resolved_alias) retrieves the wrong base_url, overwriting the correct one from resolve_runtime_provider().

Fix Action

Fixed

PR fix notes

PR #14851: fix(model-switch): prefer matching provider in reverse alias lookup

Description (problem / solution / changelog)

Summary

  • make direct-alias reverse lookup prefer the alias whose provider matches the requested provider
  • keep the previous fallback behavior when only one matching alias exists
  • add regressions for shared-model aliases and explicit provider switches so the correct base_url wins

Testing

  • python3 -m pytest -o addopts= -q tests/hermes_cli/test_ollama_cloud_auth.py

Closes #14614

Changed files

  • hermes_cli/model_switch.py (modified, +13/-4)
  • tests/hermes_cli/test_ollama_cloud_auth.py (modified, +67/-0)

Code Example

custom_providers:
     - name: provider-a
       base_url: https://api-a.example.com
       api_key: sk-aaa
       model: claude-opus-4-6
     - name: provider-b
       base_url: https://api-b.example.com
       api_key: sk-bbb
       model: claude-opus-4-6

---

model_aliases:
     my-a:
       model: claude-opus-4-6
       provider: custom:provider-a
     my-b:
       model: claude-opus-4-6
       provider: custom:provider-b

---

for alias_name, da in DIRECT_ALIASES.items():
    if da.model.lower() == key:
        return (da.provider, da.model, alias_name)

---

alias_result = resolve_alias(new_model, target_provider)
if alias_result is not None:
    _, new_model, resolved_alias = alias_result

---

alias_result = resolve_alias(new_model, target_provider)
if alias_result is not None:
    _alias_prov, new_model, resolved_alias = alias_result
    if _alias_prov and target_provider and _alias_prov != target_provider:
        resolved_alias = ""
        logger.debug(
            'Alias resolve mismatch: wanted %s, got %s — discarding alias override',
            target_provider, _alias_prov,
        )
RAW_BUFFERClick to expand / collapse

Summary

When model_aliases contains multiple entries pointing to the same model ID but different providers (e.g. two providers both offering claude-opus-4-6), resolve_alias() in model_switch.py returns the first matching alias by dict iteration order, regardless of which provider was actually requested. This causes /model <name> --provider <slug> to silently use the wrong provider's base_url and api_key.

Reproduction

  1. Configure two custom_providers with the same model name:
    custom_providers:
      - name: provider-a
        base_url: https://api-a.example.com
        api_key: sk-aaa
        model: claude-opus-4-6
      - name: provider-b
        base_url: https://api-b.example.com
        api_key: sk-bbb
        model: claude-opus-4-6
  2. Add aliases for both:
    model_aliases:
      my-a:
        model: claude-opus-4-6
        provider: custom:provider-a
      my-b:
        model: claude-opus-4-6
        provider: custom:provider-b
  3. Run /model claude-opus-4-6 --provider custom:provider-b
  4. Observe that the request is sent to https://api-a.example.com (provider-a) instead of https://api-b.example.com (provider-b)

Root Cause

In hermes_cli/model_switch.py, resolve_alias() (around line 331) does a reverse lookup by iterating all DIRECT_ALIASES and returning the first entry where da.model == key:

for alias_name, da in DIRECT_ALIASES.items():
    if da.model.lower() == key:
        return (da.provider, da.model, alias_name)

This doesn't consider the current_provider / target provider parameter. In PATH A of switch_model() (line 535), when explicit_provider is given:

alias_result = resolve_alias(new_model, target_provider)
if alias_result is not None:
    _, new_model, resolved_alias = alias_result

The returned resolved_alias may belong to a different provider. Later, DIRECT_ALIASES.get(resolved_alias) retrieves the wrong base_url, overwriting the correct one from resolve_runtime_provider().

Suggested Fix

In switch_model() PATH A, validate that the resolved alias's provider matches the target:

alias_result = resolve_alias(new_model, target_provider)
if alias_result is not None:
    _alias_prov, new_model, resolved_alias = alias_result
    if _alias_prov and target_provider and _alias_prov != target_provider:
        resolved_alias = ""
        logger.debug(
            'Alias resolve mismatch: wanted %s, got %s — discarding alias override',
            target_provider, _alias_prov,
        )

Alternatively, resolve_alias() itself could filter by provider during the reverse lookup.

Impact

High — causes 401 errors when the wrong provider's API key is used, and the user has no indication that the wrong provider was selected. The model picker card shows the correct provider but the actual API call goes to a different one.

Environment

  • Hermes agent version: 1acf81fd (Apr 13, 2026)
  • Platform: Feishu channel, also affects CLI

extent analysis

TL;DR

Modify the resolve_alias() function to filter by provider during the reverse lookup or validate the resolved alias's provider in switch_model() to ensure the correct provider is used.

Guidance

  • In switch_model(), validate that the resolved alias's provider matches the target provider to prevent using the wrong provider's base_url and api_key.
  • Consider modifying resolve_alias() to filter by provider during the reverse lookup to directly return the correct alias.
  • Review the DIRECT_ALIASES data structure to ensure it can efficiently handle multiple providers with the same model name.
  • Test the fix with different provider configurations to ensure the correct provider is selected.

Example

alias_result = resolve_alias(new_model, target_provider)
if alias_result is not None:
    _alias_prov, new_model, resolved_alias = alias_result
    if _alias_prov and target_provider and _alias_prov != target_provider:
        resolved_alias = ""
        logger.debug(
            'Alias resolve mismatch: wanted %s, got %s — discarding alias override',
            target_provider, _alias_prov,
        )

Notes

The suggested fix assumes that the resolve_alias() function is the primary cause of the issue. However, the root cause may be more complex, and additional modifications may be necessary to fully resolve the problem.

Recommendation

Apply the workaround by validating the resolved alias's provider in switch_model() to ensure the correct provider is used, as this is a more straightforward and less invasive change.

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