{"repo":"NousResearch/hermes-agent","public_id":"9888","display_label":"Z.ai GLM coding-plan vision endpoint and GLM-5V-Turbo support","summary":"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.","subsystem":"agent","counts":{"members":5,"open_issues":1,"open_issues_distinct":1,"open_prs":2,"closed_issues":1,"merged_prs":1,"attempt_prs":2},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":9907,"merged_at":"2026-04-14T23:26:01+00:00"},"resolution":{"state":"partially_resolved","by":"pr-9907"},"freshness":{"state":"stale","last_verified_at":"2026-04-14T23:26:01+00:00","is_stale":true},"grouping":{"backbone":"STRUCTURAL_PARTIAL","link_density":0.33599999999999997},"fix_edges":[{"issue_number":8461,"pr_number":9907,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false,"pr_merged_at":"2026-04-14T23:26:01+00:00"},{"issue_number":9888,"pr_number":9907,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true,"pr_merged_at":"2026-04-14T23:26:01+00:00"}],"members":[{"kind":"issue","number":9888,"title":"[Feature]: Glm-5v-turbo for GLM Coding Plan","url":null,"state":"closed"},{"kind":"issue","number":55112,"title":"[Bug]: hardcoded zai vision base_urls (paas/v4) bypass the coding-plan endpoint → silent metered billing","url":null,"state":"open"},{"kind":"pr","number":9907,"title":"feat(zai): add GLM-5V-Turbo support for coding plan","url":null,"state":"merged","close_reason":{"category":"merged"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["agent/auxiliary_client.py","hermes_cli/auth.py","hermes_cli/models.py"],"fix_hunks":[{"file":"agent/auxiliary_client.py","hunks":["@@ -112,6 +112,7 @@ def _normalize_aux_provider(provider: Optional[str]) -> str:\n # \"exotic provider\" branch checks this before falling back to the main model.\n _PROVIDER_VISION_MODELS: Dict[str, str] = {\n     \"xiaomi\": \"mimo-v2-omni\",\n+    \"zai\": \"glm-5v-turbo\",\n }\n \n # OpenRouter app attribution headers"]},{"file":"hermes_cli/auth.py","hunks":["@@ -383,13 +383,16 @@ def _resolve_api_key_provider_secret(\n # Z.AI has separate billing for general vs coding plans, and global vs China\n # endpoints.  A key that works on one may return \"Insufficient balance\" on\n # another.  We probe at setup time and store the working endpoint.\n+# Each entry lists candidate models to try in order — newer coding plan accounts\n+# may only have access to recent models (glm-5.1, glm-5v-turbo) while older\n+# ones still use glm-4.7.\n \n ZAI_ENDPOINTS = [\n-    # (id, base_url, default_model, label)\n-    (\"global\",        \"https://api.z.ai/api/paas/v4\",        \"glm-5\",   \"Global\"),\n-    (\"cn\",            \"https://open.bigmodel.cn/api/paas/v4\", \"glm-5\",   \"China\"),\n-    (\"coding-global\", \"https://api.z.ai/api/coding/paas/v4\",  \"glm-4.7\", \"Global (Coding Plan)\"),\n-    (\"coding-cn\",     \"https://open.bigmodel.cn/api/coding/paas/v4\", \"glm-4.7\", \"China (Coding Plan)\"),\n+    # (id, base_url, probe_models, label)\n+    (\"global\",        \"https://api.z.ai/api/paas/v4\",        [\"glm-5\"],   \"Global\"),\n+    (\"cn\",            \"https://open.bigmodel.cn/api/paas/v4\", [\"glm-5\"],   \"China\"),\n+    (\"coding-global\", \"https://api.z.ai/api/coding/paas/v4\",  [\"glm-5.1\", \"glm-5v-turbo\", \"glm-4.7\"], \"Global (Coding Plan)\"),\n+    (\"coding-cn\",     \"https://open.bigmodel.cn/api/coding/paas/v4\", [\"glm-5.1\", \"glm-5v-turbo\", \"glm-4.7\"], \"China (Coding Plan)\"),\n ]\n \n ","@@ -397,35 +400,37 @@ def detect_zai_endpoint(api_key: str, timeout: float = 8.0) -> Optional[Dict[str\n     \"\"\"Probe z.ai endpoints to find one that accepts this API key.\n \n     Returns {\"id\": ..., \"base_url\": ..., \"model\": ..., \"label\": ...} for the\n-    first working endpoint, or None if all fail.\n+    first working endpoint, or None if all fail.  For endpoints with multiple\n+    candidate models, tries each in order and returns the first that succeeds.\n     \"\"\"\n-    for ep_id, base_url, model, label in ZAI_ENDPOINTS:\n-        try:\n-            resp = httpx.post(\n-                f\"{base_url}/chat/completions\",\n-                headers={\n-                    \"Authorization\": f\"Bearer {api_key}\",\n-                    \"Content-Type\": \"application/json\",\n-                },\n-                json={\n-                    \"model\": model,\n-                    \"stream\": False,\n-                    \"max_tokens\": 1,\n-                    \"messages\": [{\"role\": \"user\", \"content\": \"ping\"}],\n-                },\n-                timeout=timeout,\n-            )\n-            if resp.status_code == 200:\n-                logger.debug(\"Z.AI endpoint probe: %s (%s) OK\", ep_id, base_url)\n-                return {\n-                    \"id\": ep_id,\n-                    \"base_url\": base_url,\n-                    \"model\": model,\n-                    \"label\": label,\n-                }\n-            logger.debug(\"Z.AI endpoint probe: %s returned %s\", ep_id, resp.status_code)\n-        except Exception as exc:\n-            logger.debug(\"Z.AI endpoint probe: %s failed: %s\", ep_id, exc)\n+    for ep_id, base_url, probe_models, label in ZAI_ENDPOINTS:\n+        for model in probe_models:\n+            try:\n+                resp = httpx.post(\n+                    f\"{base_url}/chat/completions\",\n+                    headers={\n+                        \"Authorization\": f\"Bearer {api_key}\",\n+                        \"Content-Type\": \"application/json\",\n+                    },\n+                    json={\n+                        \"model\": model,\n+                        \"stream\": False,\n+                        \"max_tokens\": 1,\n+                        \"messages\": [{\"role\": \"user\", \"content\": \"ping\"}],\n+                    },\n+                    timeout=timeout,\n+                )\n+                if resp.status_code == 200:\n+                    logger.debug(\"Z.AI endpoint probe: %s (%s) model=%s OK\", ep_id, base_url, model)\n+                    return {\n+                        \"id\": ep_id,\n+                        \"base_url\": base_url,\n+                        \"model\": model,\n+                        \"label\": label,\n+                    }\n+                logger.debug(\"Z.AI endpoint probe: %s model=%s returned %s\", ep_id, model, resp.status_code)\n+            except Exception as exc:\n+                logger.debug(\"Z.AI endpoint probe: %s model=%s failed: %s\", ep_id, model, exc)\n     return None\n \n "]},{"file":"hermes_cli/models.py","hunks":["@@ -44,6 +44,7 @@\n     (\"minimax/minimax-m2.7\",            \"\"),\n     (\"minimax/minimax-m2.5\",            \"\"),\n     (\"z-ai/glm-5.1\",                    \"\"),\n+    (\"z-ai/glm-5v-turbo\",               \"\"),\n     (\"z-ai/glm-5-turbo\",                \"\"),\n     (\"moonshotai/kimi-k2.5\",            \"\"),\n     (\"x-ai/grok-4.20\",                  \"\"),","@@ -89,6 +90,7 @@ def _codex_curated_models() -> list[str]:\n         \"minimax/minimax-m2.7\",\n         \"minimax/minimax-m2.5\",\n         \"z-ai/glm-5.1\",\n+        \"z-ai/glm-5v-turbo\",\n         \"z-ai/glm-5-turbo\",\n         \"moonshotai/kimi-k2.5\",\n         \"x-ai/grok-4.20-beta\",","@@ -134,6 +136,7 @@ def _codex_curated_models() -> list[str]:\n     \"zai\": [\n         \"glm-5.1\",\n         \"glm-5\",\n+        \"glm-5v-turbo\",\n         \"glm-5-turbo\",\n         \"glm-4.7\",\n         \"glm-4.5\",\n"]}]},{"kind":"pr","number":55116,"title":"fix(auxiliary): prepend zai coding-plan vision endpoint before metered paas/v4 (fixes #55112)","url":null,"state":"open","close_reason":{"refs":[{"kind":"pr","value":"#62467","number":62467}],"category":"superseded_by_pr","implication":"superseded"},"merged":false},{"kind":"pr","number":55156,"title":"fix(auxiliary): try zai coding-plan vision endpoint before metered fallbacks (#55112)","url":null,"state":"open","close_reason":{"refs":[{"kind":"pr","value":"#55116","number":55116},{"kind":"pr","value":"#55112","number":55112}],"category":"duplicate_of","implication":"duplicate"},"merged":false}],"trust":{"default_tier":"verified","includes_suggested":false}}