mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-10 22:41:41 +00:00
test_zai_provider.py set LITELLM_LOCAL_MODEL_COST_MAP and litellm.model_cost directly and never put them back, so every test that ran after it in the same process saw a local cost map instead of the real one. The two respx tests did the same to litellm.disable_aiohttp_transport with no restore at all. Both now go through monkeypatch, which restores on teardown including when the test fails. The cost-map setup moves into a fixture requested by exactly the five tests that read the cost map.
174 lines
5.1 KiB
Python
174 lines
5.1 KiB
Python
"""
|
|
Tests for Z.AI (Zhipu AI) provider - GLM models
|
|
"""
|
|
|
|
import json
|
|
import math
|
|
|
|
import pytest
|
|
import respx
|
|
|
|
import litellm
|
|
from litellm import completion
|
|
from litellm.cost_calculator import cost_per_token
|
|
|
|
|
|
@pytest.fixture
|
|
def local_model_cost_map(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
monkeypatch.setenv("LITELLM_LOCAL_MODEL_COST_MAP", "True")
|
|
monkeypatch.setattr(litellm, "model_cost", litellm.get_model_cost_map(url=""))
|
|
|
|
|
|
@pytest.fixture
|
|
def zai_response():
|
|
"""Mock response from Z.AI API"""
|
|
return {
|
|
"id": "chatcmpl-zai-123",
|
|
"object": "chat.completion",
|
|
"created": 1677652288,
|
|
"model": "glm-4.6",
|
|
"choices": [
|
|
{
|
|
"index": 0,
|
|
"message": {
|
|
"role": "assistant",
|
|
"content": "Hello! How can I help you today?",
|
|
},
|
|
"finish_reason": "stop",
|
|
}
|
|
],
|
|
"usage": {"prompt_tokens": 10, "completion_tokens": 15, "total_tokens": 25},
|
|
}
|
|
|
|
|
|
def test_get_llm_provider_zai():
|
|
"""Test that get_llm_provider correctly identifies zai provider"""
|
|
from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider
|
|
|
|
model, provider, api_key, api_base = get_llm_provider("zai/glm-4.6")
|
|
assert model == "glm-4.6"
|
|
assert provider == "zai"
|
|
assert api_base == "https://api.z.ai/api/paas/v4"
|
|
|
|
|
|
def test_zai_in_provider_lists():
|
|
"""Test that zai is registered in all necessary provider lists"""
|
|
assert "zai" in litellm.openai_compatible_providers
|
|
assert "zai" in litellm.provider_list
|
|
|
|
|
|
def test_zai_models_in_model_cost(local_model_cost_map):
|
|
"""Test that ZAI models are in the model cost map"""
|
|
|
|
zai_models = [
|
|
"zai/glm-4.7",
|
|
"zai/glm-4.6",
|
|
"zai/glm-4.5",
|
|
"zai/glm-4.5v",
|
|
"zai/glm-4.5-x",
|
|
"zai/glm-4.5-air",
|
|
"zai/glm-4.5-airx",
|
|
"zai/glm-4-32b-0414-128k",
|
|
"zai/glm-4.5-flash",
|
|
]
|
|
|
|
for model in zai_models:
|
|
assert model in litellm.model_cost, f"Model {model} not found in model_cost"
|
|
assert litellm.model_cost[model]["litellm_provider"] == "zai"
|
|
|
|
|
|
def test_zai_glm46_cost_calculation(local_model_cost_map):
|
|
"""Test the cost calculation for glm-4.6"""
|
|
|
|
key = "zai/glm-4.6"
|
|
info = litellm.model_cost[key]
|
|
|
|
prompt_cost, completion_cost = cost_per_token(
|
|
model="zai/glm-4.6",
|
|
prompt_tokens=1000000, # 1M tokens
|
|
completion_tokens=1000000,
|
|
)
|
|
|
|
# GLM-4.6: $0.6/M input, $2.2/M output
|
|
assert math.isclose(prompt_cost, 0.6, rel_tol=1e-6)
|
|
assert math.isclose(completion_cost, 2.2, rel_tol=1e-6)
|
|
|
|
|
|
def test_zai_flash_model_is_free(local_model_cost_map):
|
|
"""Test that glm-4.5-flash has zero cost"""
|
|
|
|
key = "zai/glm-4.5-flash"
|
|
info = litellm.model_cost[key]
|
|
|
|
assert info["input_cost_per_token"] == 0
|
|
assert info["output_cost_per_token"] == 0
|
|
|
|
|
|
def test_glm47_supports_reasoning(local_model_cost_map):
|
|
"""Test that GLM-4.7 supports reasoning"""
|
|
|
|
key = "zai/glm-4.7"
|
|
assert key in litellm.model_cost, f"Model {key} not found in model_cost"
|
|
|
|
info = litellm.model_cost[key]
|
|
assert info["supports_reasoning"] is True
|
|
|
|
|
|
def test_glm47_cost_calculation(local_model_cost_map):
|
|
"""Test cost calculation for GLM-4.7"""
|
|
|
|
prompt_cost, completion_cost = cost_per_token(
|
|
model="zai/glm-4.7",
|
|
prompt_tokens=1000000, # 1M tokens
|
|
completion_tokens=1000000,
|
|
)
|
|
|
|
# GLM-4.7: $0.6/M input, $2.2/M output (same as GLM-4.6)
|
|
assert math.isclose(prompt_cost, 0.6, rel_tol=1e-6)
|
|
assert math.isclose(completion_cost, 2.2, rel_tol=1e-6)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_zai_completion_call(respx_mock, zai_response, monkeypatch):
|
|
"""Test completion call with zai provider using mocked response"""
|
|
monkeypatch.setenv("ZAI_API_KEY", "test-api-key")
|
|
monkeypatch.setattr(litellm, "disable_aiohttp_transport", True)
|
|
|
|
respx_mock.post("https://api.z.ai/api/paas/v4/chat/completions").respond(
|
|
json=zai_response
|
|
)
|
|
|
|
response = await litellm.acompletion(
|
|
model="zai/glm-4.6",
|
|
messages=[{"role": "user", "content": "Hello"}],
|
|
max_tokens=20,
|
|
)
|
|
|
|
assert response.choices[0].message.content == "Hello! How can I help you today?"
|
|
assert response.usage.total_tokens == 25
|
|
|
|
assert len(respx_mock.calls) == 1
|
|
request = respx_mock.calls[0].request
|
|
assert request.method == "POST"
|
|
assert "api.z.ai" in str(request.url)
|
|
assert "Authorization" in request.headers
|
|
assert request.headers["Authorization"] == "Bearer test-api-key"
|
|
|
|
|
|
def test_zai_sync_completion(respx_mock, zai_response, monkeypatch):
|
|
"""Test synchronous completion call"""
|
|
monkeypatch.setenv("ZAI_API_KEY", "test-api-key")
|
|
monkeypatch.setattr(litellm, "disable_aiohttp_transport", True)
|
|
|
|
respx_mock.post("https://api.z.ai/api/paas/v4/chat/completions").respond(
|
|
json=zai_response
|
|
)
|
|
|
|
response = completion(
|
|
model="zai/glm-4.6",
|
|
messages=[{"role": "user", "content": "Hello"}],
|
|
max_tokens=20,
|
|
)
|
|
|
|
assert response.choices[0].message.content == "Hello! How can I help you today?"
|
|
assert response.usage.total_tokens == 25
|