NousResearch/hermes-agent

Z.ai GLM coding-plan vision endpoint and GLM-5V-Turbo support

Cluster 9888 · agent. Data as of

3 open items. Fix merged in #9907 on 14 Apr 2026. Check it covers your case.

The short answer

1open issue
2open PRs
5items grouped
Known?
Yes. 5 related items grouped here, 1 issue already closed.
Fix event
A fix was merged to main in PR #9907. Check it covers your case. No release data is tracked.
Tracker
The maintainers' tracker marks this partially resolved, deciding PR #9907. That is separate from the fix event.
Still open
1 issue and 2 PRs.

Members center on Z.ai's coding plan: adding GLM-5V-Turbo support, and a reported issue where hardcoded vision base URLs (paas/v4) may bypass the coding-plan endpoint and lead to metered billing. Two pull requests propose trying the coding-plan vision endpoint before metered fallbacks.

Open issues1

  • Issue#55112[Bug]: hardcoded zai vision base_urls (paas/v4) bypass the coding-plan endpoint → silent metered billing

Open PRs2

  • PR#55116fix(auxiliary): prepend zai coding-plan vision endpoint before metered paas/v4 (fixes #55112)
  • PR#55156fix(auxiliary): try zai coding-plan vision endpoint before metered fallbacks (#55112)

Fixes on record

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

  • #9907 feat(zai): add GLM-5V-Turbo support for coding plan

    merged to main

    files: agent/auxiliary_client.py, hermes_cli/auth.py, hermes_cli/models.py

    Show the diff
    • agent/auxiliary_client.py
      @@ -112,6 +112,7 @@ def _normalize_aux_provider(provider: Optional[str]) -> str:
       # "exotic provider" branch checks this before falling back to the main model.
       _PROVIDER_VISION_MODELS: Dict[str, str] = {
           "xiaomi": "mimo-v2-omni",
      +    "zai": "glm-5v-turbo",
       }
       
       # OpenRouter app attribution headers
    • hermes_cli/auth.py
      @@ -383,13 +383,16 @@ def _resolve_api_key_provider_secret(
       # Z.AI has separate billing for general vs coding plans, and global vs China
       # endpoints.  A key that works on one may return "Insufficient balance" on
       # another.  We probe at setup time and store the working endpoint.
      +# Each entry lists candidate models to try in order — newer coding plan accounts
      +# may only have access to recent models (glm-5.1, glm-5v-turbo) while older
      +# ones still use glm-4.7.
       
       ZAI_ENDPOINTS = [
      -    # (id, base_url, default_model, label)
      -    ("global",        "https://api.z.ai/api/paas/v4",        "glm-5",   "Global"),
      -    ("cn",            "https://open.bigmodel.cn/api/paas/v4", "glm-5",   "China"),
      -    ("coding-global", "https://api.z.ai/api/coding/paas/v4",  "glm-4.7", "Global (Coding Plan)"),
      -    ("coding-cn",     "https://open.bigmodel.cn/api/coding/paas/v4", "glm-4.7", "China (Coding Plan)"),
      +    # (id, base_url, probe_models, label)
      +    ("global",        "https://api.z.ai/api/paas/v4",        ["glm-5"],   "Global"),
      +    ("cn",            "https://open.bigmodel.cn/api/paas/v4", ["glm-5"],   "China"),
      +    ("coding-global", "https://api.z.ai/api/coding/paas/v4",  ["glm-5.1", "glm-5v-turbo", "glm-4.7"], "Global (Coding Plan)"),
      +    ("coding-cn",     "https://open.bigmodel.cn/api/coding/paas/v4", ["glm-5.1", "glm-5v-turbo", "glm-4.7"], "China (Coding Plan)"),
       ]
       
       
      @@ -397,35 +400,37 @@ def detect_zai_endpoint(api_key: str, timeout: float = 8.0) -> Optional[Dict[str
           """Probe z.ai endpoints to find one that accepts this API key.
       
           Returns {"id": ..., "base_url": ..., "model": ..., "label": ...} for the
      -    first working endpoint, or None if all fail.
      +    first working endpoint, or None if all fail.  For endpoints with multiple
      +    candidate models, tries each in order and returns the first that succeeds.
           """
      -    for ep_id, base_url, model, label in ZAI_ENDPOINTS:
      -        try:
      -            resp = httpx.post(
      -                f"{base_url}/chat/completions",
      -                headers={
      -                    "Authorization": f"Bearer {api_key}",
      -                    "Content-Type": "application/json",
      -                },
      -                json={
      -                    "model": model,
      -                    "stream": False,
      -                    "max_tokens": 1,
      -                    "messages": [{"role": "user", "content": "ping"}],
      -                },
      -                timeout=timeout,
      -            )
      -            if resp.status_code == 200:
      -                logger.debug("Z.AI endpoint probe: %s (%s) OK", ep_id, base_url)
      -                return {
      -                    "id": ep_id,
      -                    "base_url": base_url,
      -                    "model": model,
      -                    "label": label,
      -                }
      -            logger.debug("Z.AI endpoint probe: %s returned %s", ep_id, resp.status_code)
      -        except Exception as exc:
      -            logger.debug("Z.AI endpoint probe: %s failed: %s", ep_id, exc)
      +    for ep_id, base_url, probe_models, label in ZAI_ENDPOINTS:
      +        for model in probe_models:
      +            try:
      +                resp = httpx.post(
      +                    f"{base_url}/chat/completions",
      +                    headers={
      +                        "Authorization": f"Bearer {api_key}",
      +                        "Content-Type": "application/json",
      +                    },
      +                    json={
      +                        "model": model,
      +                        "stream": False,
      +                        "max_tokens": 1,
      +                        "messages": [{"role": "user", "content": "ping"}],
      +                    },
      +                    timeout=timeout,
      +                )
      +                if resp.status_code == 200:
      +                    logger.debug("Z.AI endpoint probe: %s (%s) model=%s OK", ep_id, base_url, model)
      +                    return {
      +                        "id": ep_id,
      +                        "base_url": base_url,
      +                        "model": model,
      +                        "label": label,
      +                    }
      +                logger.debug("Z.AI endpoint probe: %s model=%s returned %s", ep_id, model, resp.status_code)
      +            except Exception as exc:
      +                logger.debug("Z.AI endpoint probe: %s model=%s failed: %s", ep_id, model, exc)
           return None
       
       
    • hermes_cli/models.py
      @@ -44,6 +44,7 @@
           ("minimax/minimax-m2.7",            ""),
           ("minimax/minimax-m2.5",            ""),
           ("z-ai/glm-5.1",                    ""),
      +    ("z-ai/glm-5v-turbo",               ""),
           ("z-ai/glm-5-turbo",                ""),
           ("moonshotai/kimi-k2.5",            ""),
           ("x-ai/grok-4.20",                  ""),
      @@ -89,6 +90,7 @@ def _codex_curated_models() -> list[str]:
               "minimax/minimax-m2.7",
               "minimax/minimax-m2.5",
               "z-ai/glm-5.1",
      +        "z-ai/glm-5v-turbo",
               "z-ai/glm-5-turbo",
               "moonshotai/kimi-k2.5",
               "x-ai/grok-4.20-beta",
      @@ -134,6 +136,7 @@ def _codex_curated_models() -> list[str]:
           "zai": [
               "glm-5.1",
               "glm-5",
      +        "glm-5v-turbo",
               "glm-5-turbo",
               "glm-4.7",
               "glm-4.5",
Closed issues · 1
  • Closed#9888[Feature]: Glm-5v-turbo for GLM Coding Plan
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
#9907
Closed issues
1
Attempts
0 PRs closed without merging
Fix link checked
14 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.