ouroboros/tests/test_zai_provider.py
Ouroboros d3d7592849 Close the round-2 review findings on the Z.ai provider
Four independent reviewers (Fable 5.1, Opus 5.5, Codex gpt-6-sol, Grok 4.7)
ran the Ouroboros scope-review brief on the reworked candidate; all four
returned "merge after small fixes" and no round-1 blocker survived. The
accepted findings, each mirroring the MiniMax region pattern:

- The one-click Colab collector never asked for ZAI_API_KEY, so a Z.ai-only
  notebook was prompted for OpenRouter (colab_bootstrap.provider_keys).
- ZAI_PLAN is a transport choice, not a credential: it no longer satisfies the
  onboarding "has a provider" checks (settings_setup_contract, the wizard's
  two lists), and an unknown plan value is refused at settings save and by the
  provider Test instead of silently selecting pay-as-you-go.
- The Capability Evidence route readers (gateway/settings._active_main_route,
  reviewer_window.reviewer_route) resolve the plan's endpoint, so the two
  Z.ai plans no longer share one route fingerprint.
- The task loop classifies Z.ai's HTTP 429 code 1113 as quota_exhausted
  (typed code, exact match) instead of retrying it as a transient rate limit.
- OpenRouter's GLM namespace is z-ai/, so the catalog label key follows it.
- Docs: Z.ai joins the exclusive-direct-provider list in 02-startup-onboarding
  and the forbidden skill settings list in CREATING_SKILLS; the 02-naming
  sentence names the two provider-specific projections instead of implying
  direct OpenAI carries no effort; glm ids join the onboarding suggestions.

Declined as disproportionate or out of scope, with the reason recorded in
the review ledger: the CHECKLISTS.md prose parenthetical (protected file;
the runtime deny list is authoritative), the GAIA/Terminal-Bench launcher
key lists (benchmark-only), a recorded live wire fixture (no key), and
GLM-5.2's skip-thinking on none/minimal (owner-accepted, disclosed in the
external-fact inventory).
2026-09-25 18:19:15 +03:00

321 lines
13 KiB
Python

"""Z.ai (GLM) direct provider: registry, plan-selected endpoint, the effort
projection at the send boundary, and the 429/1113 billing classification.
Facts pinned here come from the contributor's live probe (PR #1207, 2026-09-21,
Coding Plan key, glm-5.3) and docs.z.ai: the provider accepts exactly
``low``/``high``/``max``, an ABSENT ``reasoning_effort`` is served at max,
thinking cannot be disabled (HTTP 400 code 1210), forced tool_choice works with
thinking on, and plan exhaustion arrives as HTTP 429 code 1113.
"""
import os
import pytest
from ouroboros import provider_models
from ouroboros.llm import LLMClient
from ouroboros.provider_models import (
DIRECT_PROVIDER_DEFAULTS,
DIRECT_PROVIDER_REVIEW_ROLES,
DIRECT_PROVIDER_SCOPE_DEFAULTS,
ZAI_DIRECT_DEFAULTS,
ZAI_PLAN_ENDPOINTS,
ZAI_REASONING_EFFORT_ALIASES,
migrate_model_value,
normalize_model_identity,
normalize_zai_reasoning_effort,
provider_for_model,
provider_has_credentials,
resolve_zai_base_url,
)
_PROVIDER_ENV_KEYS = (
"OPENROUTER_API_KEY", "OPENAI_API_KEY", "OPENAI_BASE_URL",
"OPENAI_COMPATIBLE_API_KEY", "OPENAI_COMPATIBLE_BASE_URL",
"ANTHROPIC_API_KEY", "MINIMAX_API_KEY", "DEEPSEEK_API_KEY",
"ZAI_API_KEY", "ZAI_PLAN",
"CLOUDRU_FOUNDATION_MODELS_API_KEY", "GIGACHAT_CREDENTIALS",
"GIGACHAT_USER", "GIGACHAT_PASSWORD", "USE_LOCAL_MAIN",
)
def _clear_provider_env(monkeypatch):
for key in _PROVIDER_ENV_KEYS:
monkeypatch.delenv(key, raising=False)
def _zai_target(model="glm-5.3"):
return {
"provider": "zai",
"resolved_model": model,
"usage_model": f"zai/{model}",
"api_key": "sk-x",
"base_url": ZAI_PLAN_ENDPOINTS["payg"],
"supports_openrouter_extensions": False,
}
def _build(target, effort, tool_choice="auto", tools=None):
client = LLMClient()
kwargs = client._build_remote_kwargs(
target, [{"role": "user", "content": "hi"}], effort, 256, tool_choice, None, tools,
)
return kwargs, client._pop_effort_clamp_disclosure()
class TestRegistry:
def test_prefix_routes_direct(self):
assert provider_for_model("zai::glm-5.3") == "zai"
def test_slash_form_stays_openrouter(self):
from ouroboros.pricing import infer_api_key_type
assert provider_for_model("zai/glm-5.3") == "openrouter"
assert infer_api_key_type("zai/glm-5.3") == "openrouter"
assert infer_api_key_type("zai::glm-5.3") == "zai"
def test_credentials_mapping(self, monkeypatch):
_clear_provider_env(monkeypatch)
assert provider_has_credentials("zai") is False
monkeypatch.setenv("ZAI_API_KEY", "sk-x")
assert provider_has_credentials("zai") is True
def test_direct_defaults_registered(self):
assert DIRECT_PROVIDER_DEFAULTS["zai"] is ZAI_DIRECT_DEFAULTS
assert ZAI_DIRECT_DEFAULTS["main"] == "zai::glm-5.3"
assert ZAI_DIRECT_DEFAULTS["light"] == "zai::glm-5.3-flash"
assert DIRECT_PROVIDER_REVIEW_ROLES["zai"] == ("main", "main", "main")
assert DIRECT_PROVIDER_SCOPE_DEFAULTS["zai"] == "zai::glm-5.3"
def test_migrate_and_normalize_round_trip(self):
assert migrate_model_value("zai", "zai/glm-5.3") == "zai::glm-5.3"
assert migrate_model_value("zai", "zai::glm-5.3") == "zai::glm-5.3"
assert normalize_model_identity("zai::glm-5.3") == "zai/glm-5.3"
class TestPlanSwitch:
@pytest.mark.parametrize("plan", [None, "", "payg", " PAYG ", "unknown-plan"])
def test_payg_is_the_default_and_the_fallback(self, plan):
assert resolve_zai_base_url(plan) == ZAI_PLAN_ENDPOINTS["payg"]
def test_coding_plan_endpoint(self):
assert resolve_zai_base_url("coding") == ZAI_PLAN_ENDPOINTS["coding"]
assert ZAI_PLAN_ENDPOINTS["payg"].startswith("https://api.z.ai/")
assert ZAI_PLAN_ENDPOINTS["coding"].startswith("https://api.z.ai/")
def test_resolve_target_uses_plan(self, monkeypatch):
_clear_provider_env(monkeypatch)
monkeypatch.setenv("ZAI_API_KEY", "sk-x")
monkeypatch.setenv("ZAI_PLAN", "coding")
monkeypatch.setattr(
"ouroboros.llm_routing.runtime_setting",
lambda key, default="": os.environ.get(key, default),
)
target = LLMClient()._resolve_remote_target("zai::glm-5.3")
assert target["provider"] == "zai"
assert target["base_url"] == ZAI_PLAN_ENDPOINTS["coding"]
assert target["api_key"] == "sk-x"
assert target["usage_model"] == "zai/glm-5.3"
def test_route_readers_follow_the_plan(self, monkeypatch):
# The Capability Evidence route identity (main route + reviewer route)
# must name the plan's endpoint, exactly as MiniMax's follows its region.
from ouroboros.gateway.settings import _active_main_route
from ouroboros.reviewer_window import reviewer_route
monkeypatch.setattr("ouroboros.config.runtime_settings", lambda: {"ZAI_PLAN": "coding"})
assert reviewer_route("zai::glm-5.3") == ("zai", ZAI_PLAN_ENDPOINTS["coding"])
route = _active_main_route({"OUROBOROS_MODEL": "zai::glm-5.3", "ZAI_PLAN": "coding"})
assert (route["provider"], route["base_url"]) == ("zai", ZAI_PLAN_ENDPOINTS["coding"])
assert _active_main_route({"OUROBOROS_MODEL": "zai::glm-5.3"})["base_url"] == ZAI_PLAN_ENDPOINTS["payg"]
def test_provider_test_rejects_an_unknown_plan(self, monkeypatch):
from ouroboros.gateway import models as provider_api
monkeypatch.setattr(provider_api, "load_settings", lambda: {})
monkeypatch.setattr(
provider_api, "_run_provider_test_with_settings",
lambda *_args: (_ for _ in ()).throw(AssertionError("must not probe")),
)
body = provider_api._run_provider_test("zai", {"ZAI_API_KEY": "x", "ZAI_PLAN": "codign"})
assert body == {"error": "unknown Z.ai plan", "_http_status": 400}
def test_plan_alone_is_not_a_provider(self):
# A plan is a transport choice, not a credential: a draft carrying only
# ZAI_PLAN must be refused exactly like a MiniMax region without a key,
# while the same draft with the key is accepted.
from ouroboros.settings_setup_contract import validate_setup_payload
plan_only = {"ZAI_PLAN": "coding", "OUROBOROS_MODEL": "zai::glm-5.3",
"OUROBOROS_MODEL_LIGHT": "zai::glm-5.3-flash", "OUROBOROS_MODEL_FALLBACKS": "zai::glm-5.3-flash"}
_prepared, error = validate_setup_payload(plan_only, {})
assert error
_prepared, error = validate_setup_payload({**plan_only, "ZAI_API_KEY": "sk-zai-key-1234567890"}, {})
assert not error
class TestEffortCarriage:
"""The canonical scale is always projected onto Z.ai's low/high/max enum:
an absent tier would be served (and billed) at max."""
@pytest.mark.parametrize(
("requested", "wire"),
[
("none", "low"),
("minimal", "low"),
("low", "low"),
("medium", "high"),
("high", "high"),
("xhigh", "max"),
("max", "max"),
("ultra", "max"),
],
)
def test_projection_reaches_the_wire(self, requested, wire):
kwargs, note = _build(_zai_target(), requested)
assert kwargs["reasoning_effort"] == wire
assert "thinking" not in (kwargs.get("extra_body") or {})
if requested == wire:
assert note is None
else:
assert note == {
"requested": requested, "applied": wire,
"reason": "provider_wire_mapping", "model": "glm-5.3",
}
def test_table_stays_inside_the_provider_enum(self):
assert set(ZAI_REASONING_EFFORT_ALIASES.values()) == {"low", "high", "max"}
assert normalize_zai_reasoning_effort("not-a-tier") == "low"
def test_forced_tool_choice_keeps_thinking_on(self):
tools = [{"type": "function", "function": {"name": "f", "parameters": {"type": "object"}}}]
kwargs, _ = _build(_zai_target(), "high", tool_choice="required", tools=tools)
assert kwargs["reasoning_effort"] == "high"
assert "thinking" not in (kwargs.get("extra_body") or {})
def test_generic_compatible_lane_is_untouched(self):
# The same GLM model id on an owner's OpenAI-compatible endpoint keeps
# today's behavior: the projection is keyed on the zai provider id,
# never on the model name.
target = {
"provider": "openai-compatible", "resolved_model": "glm-5.3",
"usage_model": "openai-compatible::glm-5.3", "api_key": "",
"base_url": "http://127.0.0.1:11434/v1", "supports_openrouter_extensions": False,
}
kwargs, note = _build(target, "medium")
assert "reasoning_effort" not in kwargs
assert note is None
class TestSingleProviderIndependence:
def test_exclusive_direct_env_detection(self, monkeypatch):
_clear_provider_env(monkeypatch)
monkeypatch.setenv("ZAI_API_KEY", "sk-x")
from ouroboros.config import _exclusive_direct_remote_provider_env
assert _exclusive_direct_remote_provider_env() == "zai"
def test_startup_gate_accepts_zai_only(self):
from ouroboros.server_runtime import (
_exclusive_direct_remote_provider,
has_remote_provider,
has_startup_ready_provider,
)
settings = {"ZAI_API_KEY": "sk-x"}
assert has_remote_provider(settings) is True
assert has_startup_ready_provider(settings) is True
assert _exclusive_direct_remote_provider(settings) == "zai"
def test_review_fallback_compiles_for_zai(self, monkeypatch):
_clear_provider_env(monkeypatch)
monkeypatch.setenv("ZAI_API_KEY", "sk-x")
monkeypatch.setenv("OUROBOROS_MODEL", "zai::glm-5.3")
monkeypatch.setenv("OUROBOROS_MODEL_LIGHT", "zai::glm-5.3-flash")
monkeypatch.setattr(
"ouroboros.review_model_routes.runtime_setting",
lambda key, default="": os.environ.get(key, default),
)
from ouroboros.config import get_review_models
assert get_review_models() == ["zai::glm-5.3"] * 3
def test_local_only_review_route_sees_zai(self, monkeypatch):
_clear_provider_env(monkeypatch)
monkeypatch.setenv("USE_LOCAL_MAIN", "1")
monkeypatch.setenv("ZAI_API_KEY", "sk-x")
assert provider_models.local_only_review_route_env() is False
class TestSecretSurfaces:
def test_forbidden_for_skills_and_masked(self):
from ouroboros.contracts.plugin_api import FORBIDDEN_SKILL_SETTINGS
from ouroboros.secret_masking import MASKED_SECRET_SETTING_KEYS
assert "ZAI_API_KEY" in FORBIDDEN_SKILL_SETTINGS
assert "ZAI_API_KEY" in MASKED_SECRET_SETTING_KEYS
def test_settings_defaults(self):
from ouroboros.config import SETTINGS_DEFAULTS
assert SETTINGS_DEFAULTS["ZAI_API_KEY"] == ""
assert SETTINGS_DEFAULTS["ZAI_PLAN"] == ""
class TestSafetyRouting:
def test_zai_only_install_reaches_the_real_safety_check(self, monkeypatch):
"""A zai-only install must reach the remote safety check, not fail open."""
from ouroboros import safety
_clear_provider_env(monkeypatch)
assert safety._any_remote_provider_configured() is False
monkeypatch.setenv("ZAI_API_KEY", "sk-x")
assert safety._any_remote_provider_configured() is True
assert safety._PROVIDER_KEY_ENV["zai"] == "ZAI_API_KEY"
def test_light_model_reaches_its_provider_key(self, monkeypatch):
from ouroboros import safety
from ouroboros.pricing import infer_api_key_type
_clear_provider_env(monkeypatch)
monkeypatch.setenv("ZAI_API_KEY", "sk-x")
assert safety._PROVIDER_KEY_ENV.get(infer_api_key_type("zai::glm-5.3-flash")) == "ZAI_API_KEY"
class TestProbeBilling:
"""HTTP 429 code 1113 "Insufficient balance" is billing, not rate limiting."""
def test_1113_maps_to_no_credits(self):
from ouroboros.llm_probe import controlled_probe_error
class Exhausted(Exception):
status_code = 429
code = "1113"
type = ""
result = controlled_probe_error(Exhausted("Insufficient balance"))
assert result["error"] == "No credits"
assert result["status_code"] == 429
def test_task_loop_does_not_retry_an_exhausted_plan(self):
from ouroboros.loop_llm_call import classify_llm_exception
class Exhausted(Exception):
status_code = 429
code = "1113"
body = {"error": {"code": "1113", "message": "Insufficient balance"}}
exhausted = classify_llm_exception(Exhausted("Insufficient balance"))
assert exhausted.kind == "quota_exhausted"
assert exhausted.retry_same_request is False
# An ordinary 429 keeps its transient, retryable classification.
assert classify_llm_exception(RuntimeError("Error code: 429 - too many requests")).retry_same_request is True
def test_plain_429_stays_rate_limited(self):
from ouroboros.llm_probe import controlled_probe_error
class Plain(Exception):
status_code = 429
code = ""
type = ""
assert controlled_probe_error(Plain("too many requests"))["error"] == "Rate limited"