v3 M3: finalize z.ai against the real usage endpoint (monitor/quota/limit)

Probing a live GLM Coding Plan key showed the Anthropic-compat /v1/messages
response carries NO rate-limit headers. z.ai instead exposes a dedicated status
endpoint (found via github.com/rygel/AIUsageTracker):

    GET https://api.z.ai/api/monitor/usage/quota/limit
    Authorization: <raw key>   (no "Bearer")   Accept-Language: en-US,en
    -> data.limits[] of TOKENS_LIMIT windows {percentage 0-100, nextResetTime ms, unit,number}
       + data.level (plan tier)

ZaiProvider now GETs that: the shortest TOKENS_LIMIT window -> the 5h bar (s/sr),
the longest -> the weekly bar (w/wr); the monthly TIME_LIMIT (web-tool quota) is
ignored; level -> status ("Lite"/"Pro"/…), any window at 100% -> "limited". It's
a status GET, so it does NOT spend the prompt-metered plan — no self-throttle
needed, polls on the normal cadence. Monitor URL derives from the configured
base host.

Verified live: s=1% (5h, resets ~4.9h), w=2% (weekly, resets ~6.5d), st="Lite".
test_zai rewritten for the JSON envelope (9 tests). probe_zai.py repointed to the
monitor endpoint. 122 passed, 2 Linux-only failures (baseline).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wenil
2026-07-10 08:53:32 +03:00
co-authored by Claude Opus 4.8
parent ac0742d92c
commit 4eeb6e242b
3 changed files with 192 additions and 183 deletions
+12 -31
View File
@@ -1,17 +1,13 @@
#!/usr/bin/env python3
"""One-off diagnostic: see exactly what z.ai's Anthropic-compatible endpoint
returns, so the ZaiProvider's rate-limit header mapping can be finalized against
a real response (the header names aren't documented).
"""One-off diagnostic for the z.ai GLM Coding Plan usage endpoint (the source
ZaiProvider reads). Dumps the raw quota JSON so the window mapping can be
checked against a live plan.
Usage (key via env so it never lands in shell history):
ZAI_API_KEY=... python tools/probe_zai.py [base_url] [model]
ZAI_API_KEY=... python tools/probe_zai.py [host]
Defaults: base = https://api.z.ai/api/anthropic , model = glm-4.6
Prints the HTTP status and the FULL response header set (highlighting any header
mentioning limit/rate/quota/usage/reset), plus a short body preview. Sends a
1-token "hi" — on a prompt-metered plan that is one prompt, so run it sparingly.
The API key is read from the environment and never printed.
Default host = https://api.z.ai . It's a status GET — it does NOT spend the
prompt-metered plan. The API key is read from the environment and never printed.
"""
import json
import os
@@ -19,36 +15,21 @@ import sys
import httpx
BASE = (sys.argv[1] if len(sys.argv) > 1 else "https://api.z.ai/api/anthropic").rstrip("/")
MODEL = sys.argv[2] if len(sys.argv) > 2 else "glm-4.6"
HOST = (sys.argv[1] if len(sys.argv) > 1 else "https://api.z.ai").rstrip("/")
KEY = os.environ.get("ZAI_API_KEY") or os.environ.get("ANTHROPIC_AUTH_TOKEN")
if not KEY:
sys.exit("Set ZAI_API_KEY in the environment first (it is not printed).")
url = f"{BASE}/v1/messages"
headers = {
"Authorization": f"Bearer {KEY}",
"anthropic-version": "2023-06-01",
"Content-Type": "application/json",
}
body = {"model": MODEL, "max_tokens": 1, "messages": [{"role": "user", "content": "hi"}]}
print(f"POST {url} (model={MODEL})")
url = f"{HOST}/api/monitor/usage/quota/limit"
print(f"GET {url}")
try:
resp = httpx.post(url, headers=headers, json=body, timeout=30.0)
resp = httpx.get(url, headers={"Authorization": KEY, "Accept-Language": "en-US,en"}, timeout=30.0)
except httpx.HTTPError as e:
sys.exit(f"request failed: {e}")
print(f"HTTP {resp.status_code}\n")
INTEREST = ("limit", "rate", "quota", "usage", "reset", "remaining")
print("--- response headers ---")
for k in sorted(resp.headers.keys()):
mark = " <<<" if any(w in k.lower() for w in INTEREST) else ""
print(f" {k}: {resp.headers[k]}{mark}")
print("\n--- body preview ---")
try:
print(json.dumps(resp.json(), ensure_ascii=False)[:600])
print(json.dumps(resp.json(), indent=2, ensure_ascii=False))
except ValueError:
print(resp.text[:600])
print(resp.text[:1000])