fix(zai): ignore chat-completions api base on responses route

This commit is contained in:
togear 2026-09-07 18:52:05 +08:00
parent c96fe090fd
commit 92c1eebe56
2 changed files with 53 additions and 1 deletions

View file

@ -20,6 +20,8 @@ class ZAIResponsesAPIConfig(OpenAIResponsesAPIConfig):
``Authorization: Bearer`` header.
"""
_ZAI_CHAT_API_BASE_SUFFIXES: Final = ("/api/paas/v4", "/api/coding/paas/v4")
@property
def custom_llm_provider(self) -> LlmProviders:
return LlmProviders.ZAI
@ -44,7 +46,17 @@ class ZAIResponsesAPIConfig(OpenAIResponsesAPIConfig):
api_base: str | None,
litellm_params: dict,
) -> str:
base_url = api_base or get_secret_str("ZAI_RESPONSES_API_BASE") or "https://api.z.ai/api/v1"
# ``litellm_params.api_base`` can carry the Z.AI chat-completions base
# (``/api/paas/v4``) when the generic provider resolver pre-fills it from
# the chat config. Z.AI serves Responses on a different base, so ignore
# the chat-only bases and use the Responses base instead.
normalized_api_base = (api_base or "").rstrip("/")
chat_base_passed_in: Final = normalized_api_base.endswith(self._ZAI_CHAT_API_BASE_SUFFIXES)
base_url = (
api_base
if api_base and not chat_base_passed_in
else get_secret_str("ZAI_RESPONSES_API_BASE") or "https://api.z.ai/api/v1"
)
base_url = base_url.rstrip("/")
if base_url.endswith("/responses"):

View file

@ -30,6 +30,46 @@ def test_zai_responses_url_defaults_to_responses_endpoint(monkeypatch):
assert config.get_complete_url(api_base=api_base, litellm_params={}) == expected_url
def test_zai_responses_url_ignores_chat_completions_api_base(monkeypatch):
monkeypatch.delenv("ZAI_RESPONSES_API_BASE", raising=False)
config = ZAIResponsesAPIConfig()
chat_bases = (
"https://api.z.ai/api/paas/v4",
"https://api.z.ai/api/paas/v4/",
"https://api.z.ai/api/coding/paas/v4",
)
for chat_base in chat_bases:
assert config.get_complete_url(api_base=chat_base, litellm_params={}) == "https://api.z.ai/api/v1/responses"
def test_zai_responses_url_keeps_custom_api_base(monkeypatch):
monkeypatch.delenv("ZAI_RESPONSES_API_BASE", raising=False)
config = ZAIResponsesAPIConfig()
assert (
config.get_complete_url(
api_base="https://gateway.example.com/openai/v1",
litellm_params={},
)
== "https://gateway.example.com/openai/v1/responses"
)
def test_zai_responses_url_env_overrides_chat_completions_api_base(monkeypatch):
monkeypatch.setenv("ZAI_RESPONSES_API_BASE", "https://gateway.example.com/responses-root")
config = ZAIResponsesAPIConfig()
assert (
config.get_complete_url(
api_base="https://api.z.ai/api/paas/v4",
litellm_params={},
)
== "https://gateway.example.com/responses-root/responses"
)
def test_zai_responses_headers_use_bearer_token():
config = ZAIResponsesAPIConfig()
litellm_params = GenericLiteLLMParams(api_key="sk-zai")