Skip to content

Fix opencode-go custom provider overlap routing - #2204

Merged
1 commit merged into
nesquena:masterfrom
Michaelyklam:fix/issue-1894-opencode-go-provider-overlap
May 13, 2026
Merged

1 commit merged into
nesquena:masterfrom
Michaelyklam:fix/issue-1894-opencode-go-provider-overlap

Conversation

@Michaelyklam

Copy link
Copy Markdown
Contributor

Summary

  • Prefer the configured non-custom provider when it owns a requested bare model id, even if a named custom provider advertises the same model.
  • Preserve custom-provider routing for custom-only models.
  • Add focused regression coverage for the opencode-go/deepseek-v4-pro overlap and existing explicit provider/suffix parsing.

Verification

  • git diff --check
  • python -m py_compile api/*.py server.py
  • pytest -q tests/test_resolve_model_provider_free_suffix.py
  • pytest -q tests/test_issue1894_provider_overlap.py
  • pytest -q tests -k "resolve_model_provider or model_with_provider_context or issue1894"

Closes #1894

@nesquena-hermes

Copy link
Copy Markdown
Collaborator

Reading the diff at api/config.py:1576-1600 and the new tests/test_issue1894_provider_overlap.py, then comparing against the surrounding resolver context at api/config.py:1517-1610 and the static catalogs at _PROVIDER_MODELS["opencode-go"] (lines 1037-1052) and _PROVIDER_MODELS["opencode-zen"] (lines 998-1035). The fix is the right shape for #1894 and the tests target the exact overlap. A few notes worth a maintainer pass.

The fix correctly widens the existing #1922 guard

Old guard at master api/config.py:1579-1583:

_skip_custom_providers = (
    _is_explicit_non_custom_provider
    and _default_model is not None
    and model_id == _default_model
)

That guard only fired when the requested model was the configured default. For #1894 the user's configured opencode-go default could be any model in the catalog (e.g. glm-5.1), but the requested model was deepseek-v4-pro — same catalog, different model — so the guard didn't fire and routing fell into a name-overlapping custom_providers[] entry. The new disjunction:

or model_id in _provider_models_set

closes that hole by saying "if the configured non-custom provider's static catalog owns the model id, skip custom_providers". For opencode-go that's {glm-5.1, glm-5, kimi-k2.5, kimi-k2.6, deepseek-v4-pro, deepseek-v4-flash, mimo-v2-pro, ...}, which exactly matches the symptom.

Behavior change is broader than #1894 — worth flagging in the description

This same guard now fires for every (configured non-custom provider, model id in that provider's static catalog) pair. Concrete consequence: if a user has model.provider: anthropic (default = claude-opus-4.7) and adds a custom_providers[] entry named "bedrock-claude" that also serves claude-sonnet-4.6, and then picks claude-sonnet-4.6 from the dropdown:

  • Old behavior: routed through custom:bedrock-claude (because claude-sonnet-4.6 != default)
  • New behavior: routed through anthropic (because claude-sonnet-4.6 in _PROVIDER_MODELS["anthropic"])

This is probably correct — the configured provider is the user's explicit choice — and the escape hatch is @custom:bedrock-claude:claude-sonnet-4.6 (test case 3 covers that path). But it's a noticeable shift from #1922's narrower guard and the PR description / CHANGELOG should call it out so users with Bedrock/Vertex-mirror custom_providers aren't surprised by a silent re-route after upgrade.

A small efficiency nit

_provider_models_set is rebuilt from _PROVIDER_MODELS[config_provider] on every call. For hot paths (chat-start, model resolution per request) this is a tight loop, but _PROVIDER_MODELS is module-level static data — a @functools.lru_cache(maxsize=None) helper or a once-built _PROVIDER_MODEL_ID_SETS: dict[str, frozenset[str]] next to _PROVIDER_MODELS itself would avoid rebuilding the set on every resolve. Not a correctness concern, just a touch of stale-yak cleanup.

Test coverage is good but missing one case

tests/test_issue1894_provider_overlap.py covers the four scenarios cleanly:

  1. opencode-go overlap (with prefix-stripping via model_with_provider_context)
  2. direct resolve overlap
  3. custom-only model still routes to custom
  4. explicit @custom: prefix still works
  5. OpenRouter suffix still works

What I'd add: a regression test for the case where config_provider not in _PROVIDER_MODELS (e.g. a provider that's purely declared via custom_providers without a static catalog). The new code handles it (_provider_models_set stays empty, guard 2 stays False), but a test pin would catch a future refactor that accidentally dropped the membership check.

Net

I'd merge this once the PR description (and ideally CHANGELOG) reflects the broader behavior shift. The fix itself is the right resolver change for #1894.

@nesquena-hermes nesquena-hermes closed this pull request by merging all changes into nesquena:master in 6aedb7e May 13, 2026
pull Bot pushed a commit to TKaxv-7S/hermes-webui that referenced this pull request May 13, 2026
Fix opencode-go custom provider overlap routing (Michaelyklam, closes nesquena#1894)
SysAdminDoc pushed a commit to SysAdminDoc/hermes-webui that referenced this pull request Jun 26, 2026
Fix opencode-go custom provider overlap routing (Michaelyklam, closes nesquena#1894)
SysAdminDoc pushed a commit to SysAdminDoc/hermes-webui that referenced this pull request Jun 26, 2026
stage-350: medium-risk batch — auth trilogy (nesquena#2191/2/3) + cancel-status nesquena#2151 with conflict resolution + nesquena#2178 ollama guard + nesquena#2204 provider precedence + nesquena#2203 activity animation
bernyforce pushed a commit to bernyforce/hermes-webui that referenced this pull request Jul 29, 2026
Fix opencode-go custom provider overlap routing (Michaelyklam, closes nesquena#1894)
bernyforce pushed a commit to bernyforce/hermes-webui that referenced this pull request Jul 29, 2026
stage-350: medium-risk batch — auth trilogy (nesquena#2191/2/3) + cancel-status nesquena#2151 with conflict resolution + nesquena#2178 ollama guard + nesquena#2204 provider precedence + nesquena#2203 activity animation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

401 error via opencode go deepseek model

2 participants