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

0open issues
0open PRs
5items grouped
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

No open issues.

Open PRs0

No open pull requests.

Fixes on record

Merged to main. A stamp counts the issues a fix is linked to.

  • #8794 fix: preserve dots in model names for OpenCode Zen and ZAI providers

    merged to main

    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.py

    Show 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

  • #7719 fix(zai): preserve dots in GLM model names on Anthropic-compatible endpoints · merged via another change → #8794
  • #60967 fix(auxiliary): respect explicit auxiliary.vision.model over _PROVIDER_VISION_MODELS mapping · done elsewhere → #60381
Closed issues · 2
  • Closed#7475[Bug]: Select Model GLM-4.7 get "提示模型不存在,请检查模型代码"
  • Closed#60381bug: zai provider vision — glm-4v-flash returns 1211 '模型不存在' despite model working via direct API
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.00 means 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 Lab

At 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.

For your agent

The same facts, typed.