ZAI/GLM model name and auxiliary provider corrections
NousResearch/hermes-agent · cluster 7475 · agent
Data as of
Nothing open on GitHub. Fix merged in #8794. Check it covers your case.
The short answer
- Known?
- Yes. 5 related items grouped here, 2 issues already closed.
- Fix event
- A fix was merged to main in PR #8794. Check it covers your case. No release data is tracked.
- Tracker
- The maintainers' tracker marks this
unresolved. That is separate from the fix event. - Still open
- Nothing open on GitHub.
Several issues with GLM model names having dots stripped (causing 'model not found' errors) on ZAI and OpenCode Zen providers were addressed, along with corrections to how auxiliary vision models and provider overrides are handled.
Open issues0
Open PRs0
Fixes on record
-
#8794 fix: preserve dots in model names for OpenCode Zen and ZAI providers
files:
hermes_cli/model_normalize.py,hermes_cli/models.py,hermes_cli/setup.py,run_agent.py,tests/agent/test_minimax_provider.py,tests/hermes_cli/test_model_normalize.pyShow the diff
-
hermes_cli/model_normalize.py@@ -8,8 +8,9 @@ hyphens: ``claude-sonnet-4-6``. - **Copilot** expects bare names *with* dots preserved: ``claude-sonnet-4.6``. -- **OpenCode Zen** follows the same dot-to-hyphen convention as - Anthropic: ``claude-sonnet-4-6``. +- **OpenCode Zen** preserves dots for GPT/GLM/Gemini/Kimi/MiniMax-style + model IDs, but Claude still uses hyphenated native names like + ``claude-sonnet-4-6``. - **OpenCode Go** preserves dots in model names: ``minimax-m2.7``. - **DeepSeek** only accepts two model identifiers: ``deepseek-chat`` and ``deepseek-reasoner``. @@ -67,7 +68,6 @@ # Providers that want bare names with dots replaced by hyphens. _DOT_TO_HYPHEN_PROVIDERS: frozenset[str] = frozenset({ "anthropic", - "opencode-zen", }) # Providers that want bare names with dots preserved. @@ -329,6 +329,9 @@ def normalize_model_for_provider(model_input: str, target_provider: str) -> str: >>> normalize_model_for_provider("claude-sonnet-4.6", "opencode-zen") 'claude-sonnet-4-6' + >>> normalize_model_for_provider("minimax-m2.5-free", "opencode-zen") + 'minimax-m2.5-free' + >>> normalize_model_for_provider("deepseek-v3", "deepseek") 'deepseek-chat' @@ -351,7 +354,16 @@ def normalize_model_for_provider(model_input: str, target_provider: str) -> str: if provider in _AGGREGATOR_PROVIDERS: return _prepend_vendor(name) - # --- Anthropic / OpenCode: strip matching provider prefix, dots -> hyphens --- + # --- OpenCode Zen: Claude stays hyphenated; other models keep dots --- + if provider == "opencode-zen": + bare = _strip_matching_provider_prefix(name, provider) + if "/" in bare: + return bare + if bare.lower().startswith("claude-"): + return _dots_to_hyphens(bare) + return bare + + # --- Anthropic: strip matching provider prefix, dots -> hyphens --- if provider in _DOT_TO_HYPHEN_PROVIDERS: bare = _strip_matching_provider_prefix(name, provider) if "/" in bare: -
hermes_cli/models.py@@ -130,6 +130,7 @@ def _codex_curated_models() -> list[str]: "gemma-4-26b-it", ], "zai": [ + "glm-5.1", "glm-5", "glm-5-turbo", "glm-4.7", -
hermes_cli/setup.py@@ -104,7 +104,7 @@ def _supports_same_provider_pool_setup(provider: str) -> bool: "gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.5-flash-lite", "gemma-4-31b-it", "gemma-4-26b-it", ], - "zai": ["glm-5", "glm-4.7", "glm-4.5", "glm-4.5-flash"], + "zai": ["glm-5.1", "glm-5", "glm-4.7", "glm-4.5", "glm-4.5-flash"], "kimi-coding": ["kimi-k2.5", "kimi-k2-thinking", "kimi-k2-turbo-preview"], "minimax": ["MiniMax-M2.7", "MiniMax-M2.5", "MiniMax-M2.1", "MiniMax-M2"], "minimax-cn": ["MiniMax-M2.7", "MiniMax-M2.5", "MiniMax-M2.1", "MiniMax-M2"], -
run_agent.py@@ -5856,11 +5856,12 @@ def _anthropic_preserve_dots(self) -> bool: """True when using an anthropic-compatible endpoint that preserves dots in model names. Alibaba/DashScope keeps dots (e.g. qwen3.5-plus). MiniMax keeps dots (e.g. MiniMax-M2.7). - OpenCode Go keeps dots (e.g. minimax-m2.7).""" - if (getattr(self, "provider", "") or "").lower() in {"alibaba", "minimax", "minimax-cn", "opencode-go"}: + OpenCode Go/Zen keeps dots for non-Claude models (e.g. minimax-m2.5-free). + ZAI/Zhipu keeps dots (e.g. glm-4.7, glm-5.1).""" + if (getattr(self, "provider", "") or "").lower() in {"alibaba", "minimax", "minimax-cn", "opencode-go", "opencode-zen", "zai"}: return True base = (getattr(self, "base_url", "") or "").lower() - return "dashscope" in base or "aliyuncs" in base or "minimax" in base or "opencode.ai/zen/go" in base + return "dashscope" in base or "aliyuncs" in base or "minimax" in base or "opencode.ai/zen/" in base or "bigmodel.cn" in base def _is_qwen_portal(self) -> bool: """Return True when the base URL targets Qwen Portal.""" -
tests/agent/test_minimax_provider.py@@ -308,6 +308,34 @@ def test_anthropic_does_not_preserve_dots(self): from run_agent import AIAgent assert AIAgent._anthropic_preserve_dots(agent) is False + def test_opencode_zen_provider_preserves_dots(self): + from types import SimpleNamespace + agent = SimpleNamespace(provider="opencode-zen", base_url="") + from run_agent import AIAgent + assert AIAgent._anthropic_preserve_dots(agent) is True + + def test_opencode_zen_url_preserves_dots(self): + from types import SimpleNamespace + agent = SimpleNamespace(provider="custom", base_url="https://opencode.ai/zen/v1") + from run_agent import AIAgent + assert AIAgent._anthropic_preserve_dots(agent) is True + + def test_zai_provider_preserves_dots(self): + from types import SimpleNamespace + agent = SimpleNamespace(provider="zai", base_url="") + from run_agent import AIAgent + assert AIAgent._anthropic_preserve_dots(agent) is True + + def test_bigmodel_cn_url_preserves_dots(self): + from types import SimpleNamespace + agent = SimpleNamespace(provider="custom", base_url="https://open.bigmodel.cn/api/paas/v4") + from run_agent import AIAgent + assert AIAgent._anthropic_preserve_dots(agent) is True + + def test_normalize_preserves_m25_free_dot(self): + from agent.anthropic_adapter import normalize_model_name + assert normalize_model_name("minimax-m2.5-free", preserve_dots=True) == "minimax-m2.5-free" + def test_normalize_preserves_m27_dot(self): from agent.anthropic_adapter import normalize_model_name assert normalize_model_name("MiniMax-M2.7", preserve_dots=True) == "MiniMax-M2.7" -
tests/hermes_cli/test_model_normalize.py@@ -54,14 +54,19 @@ def test_anthropic_strips_vendor_prefix(self): # ── OpenCode Zen regression ──────────────────────────────────────────── -class TestOpenCodeZenDotToHyphen: - """OpenCode Zen follows Anthropic convention (dots→hyphens).""" +class TestOpenCodeZenModelNormalization: + """OpenCode Zen preserves dots for most models, but Claude stays hyphenated.""" @pytest.mark.parametrize("model,expected", [ ("claude-sonnet-4.6", "claude-sonnet-4-6"), - ("glm-4.5", "glm-4-5"), + ("opencode-zen/claude-opus-4.5", "claude-opus-4-5"), + ("glm-4.5", "glm-4.5"), + ("glm-5.1", "glm-5.1"), + ("gpt-5.4", "gpt-5.4"), + ("minimax-m2.5-free", "minimax-m2.5-free"), + ("kimi-k2.5", "kimi-k2.5"), ]) - def test_zen_converts_dots(self, model, expected): + def test_zen_normalizes_models(self, model, expected): result = normalize_model_for_provider(model, "opencode-zen") assert result == expected @@ -69,6 +74,10 @@ def test_zen_strips_vendor_prefix(self): result = normalize_model_for_provider("opencode-zen/claude-sonnet-4.6", "opencode-zen") assert result == "claude-sonnet-4-6" + def test_zen_strips_vendor_prefix_for_non_claude(self): + result = normalize_model_for_provider("opencode-zen/glm-5.1", "opencode-zen") + assert result == "glm-5.1" + # ── Copilot dot preservation (regression) ──────────────────────────────
-
2 PRs closed without merging
From the close comments: done elsewhere 1 · merged via another change 1
Closed issues · 2
How this cluster was grouped
-
Link evidence (
partly structural links): some members are connected by structural evidence (shared changed files, or a closing/superseded reference); the rest are joined by an automated relevance judgement over their text. - Members outside that structural core may belong to a different underlying problem.
-
Pairwise link density
0.34: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36.1.00means every pair is linked.
Pick up a Lab task
Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.
Open the LabAt a glance
- Subsystem
- agent
- Merged PRs
- #8794
- Closed issues
- 2
- Attempts
- 2 PRs closed without merging
- Fix link checked
- 13 Apr 2026. This confirmation is old and may be out of date (a revert or reopen would not have invalidated it here); re-verify.