diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index dd367e875de..89f4dc0a8a4 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -44353,6 +44353,36 @@ "supports_tool_choice": true, "source": "https://docs.z.ai/guides/overview/pricing" }, + "zai/glm-5.3": { + "cache_creation_input_token_cost": 0, + "cache_read_input_token_cost": 2.6e-07, + "input_cost_per_token": 1.4e-06, + "output_cost_per_token": 4.4e-06, + "litellm_provider": "zai", + "max_input_tokens": 1048576, + "max_output_tokens": 131072, + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-5.2": { + "cache_creation_input_token_cost": 0, + "cache_read_input_token_cost": 2.6e-07, + "input_cost_per_token": 1.4e-06, + "output_cost_per_token": 4.4e-06, + "litellm_provider": "zai", + "max_input_tokens": 1048576, + "max_output_tokens": 131072, + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, "zai/glm-5.1": { "cache_creation_input_token_cost": 0, "cache_read_input_token_cost": 2.6e-07, @@ -44368,6 +44398,37 @@ "supports_tool_choice": true, "source": "https://docs.z.ai/guides/overview/pricing" }, + "zai/glm-5-turbo": { + "cache_creation_input_token_cost": 0, + "cache_read_input_token_cost": 2.4e-07, + "input_cost_per_token": 1.2e-06, + "output_cost_per_token": 4e-06, + "litellm_provider": "zai", + "max_input_tokens": 200000, + "max_output_tokens": 131072, + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-5v-turbo": { + "cache_creation_input_token_cost": 0, + "cache_read_input_token_cost": 2.4e-07, + "input_cost_per_token": 1.2e-06, + "output_cost_per_token": 4e-06, + "litellm_provider": "zai", + "max_input_tokens": 200000, + "max_output_tokens": 131072, + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_tool_choice": true, + "supports_vision": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, "zai/glm-5-code": { "cache_creation_input_token_cost": 0, "cache_read_input_token_cost": 3e-07, @@ -44413,6 +44474,21 @@ "supports_tool_choice": true, "source": "https://docs.z.ai/guides/overview/pricing" }, + "zai/glm-4.7-flashx": { + "cache_creation_input_token_cost": 0, + "cache_read_input_token_cost": 1e-08, + "input_cost_per_token": 7e-08, + "output_cost_per_token": 4e-07, + "litellm_provider": "zai", + "max_input_tokens": 200000, + "max_output_tokens": 131072, + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, "zai/glm-4.6": { "cache_creation_input_token_cost": 0, "cache_read_input_token_cost": 1.1e-07, @@ -44428,6 +44504,22 @@ "supports_tool_choice": true, "source": "https://docs.z.ai/guides/overview/pricing" }, + "zai/glm-4.6v": { + "cache_creation_input_token_cost": 0, + "cache_read_input_token_cost": 5e-08, + "input_cost_per_token": 3e-07, + "output_cost_per_token": 9e-07, + "litellm_provider": "zai", + "max_input_tokens": 128000, + "max_output_tokens": 32768, + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_tool_choice": true, + "supports_vision": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, "zai/glm-4.5": { "input_cost_per_token": 6e-07, "output_cost_per_token": 2.2e-06, diff --git a/litellm/proxy/public_endpoints/provider_create_fields.json b/litellm/proxy/public_endpoints/provider_create_fields.json index 4652719a23b..553ad42f937 100644 --- a/litellm/proxy/public_endpoints/provider_create_fields.json +++ b/litellm/proxy/public_endpoints/provider_create_fields.json @@ -3296,6 +3296,34 @@ ], "default_model_placeholder": "gpt-3.5-turbo" }, + { + "provider": "ZAI", + "provider_display_name": "Z.AI", + "litellm_provider": "zai", + "credential_fields": [ + { + "key": "api_key", + "label": "API Key", + "placeholder": "your-zai-api-key", + "tooltip": "Z.AI API Key from https://z.ai/manage-apikey/apikey-list", + "required": true, + "field_type": "password", + "options": null, + "default_value": null + }, + { + "key": "api_base", + "label": "API Base", + "placeholder": "https://api.z.ai/api/paas/v4", + "tooltip": "General: https://api.z.ai/api/paas/v4. GLM Coding Plan: https://api.z.ai/api/coding/paas/v4. Override for self-hosted endpoints.", + "required": false, + "field_type": "text", + "options": null, + "default_value": "https://api.z.ai/api/paas/v4" + } + ], + "default_model_placeholder": "zai/glm-4.6" + }, { "provider": "CURSOR", "provider_display_name": "Cursor", diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index dd367e875de..89f4dc0a8a4 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -44353,6 +44353,36 @@ "supports_tool_choice": true, "source": "https://docs.z.ai/guides/overview/pricing" }, + "zai/glm-5.3": { + "cache_creation_input_token_cost": 0, + "cache_read_input_token_cost": 2.6e-07, + "input_cost_per_token": 1.4e-06, + "output_cost_per_token": 4.4e-06, + "litellm_provider": "zai", + "max_input_tokens": 1048576, + "max_output_tokens": 131072, + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-5.2": { + "cache_creation_input_token_cost": 0, + "cache_read_input_token_cost": 2.6e-07, + "input_cost_per_token": 1.4e-06, + "output_cost_per_token": 4.4e-06, + "litellm_provider": "zai", + "max_input_tokens": 1048576, + "max_output_tokens": 131072, + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, "zai/glm-5.1": { "cache_creation_input_token_cost": 0, "cache_read_input_token_cost": 2.6e-07, @@ -44368,6 +44398,37 @@ "supports_tool_choice": true, "source": "https://docs.z.ai/guides/overview/pricing" }, + "zai/glm-5-turbo": { + "cache_creation_input_token_cost": 0, + "cache_read_input_token_cost": 2.4e-07, + "input_cost_per_token": 1.2e-06, + "output_cost_per_token": 4e-06, + "litellm_provider": "zai", + "max_input_tokens": 200000, + "max_output_tokens": 131072, + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, + "zai/glm-5v-turbo": { + "cache_creation_input_token_cost": 0, + "cache_read_input_token_cost": 2.4e-07, + "input_cost_per_token": 1.2e-06, + "output_cost_per_token": 4e-06, + "litellm_provider": "zai", + "max_input_tokens": 200000, + "max_output_tokens": 131072, + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_tool_choice": true, + "supports_vision": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, "zai/glm-5-code": { "cache_creation_input_token_cost": 0, "cache_read_input_token_cost": 3e-07, @@ -44413,6 +44474,21 @@ "supports_tool_choice": true, "source": "https://docs.z.ai/guides/overview/pricing" }, + "zai/glm-4.7-flashx": { + "cache_creation_input_token_cost": 0, + "cache_read_input_token_cost": 1e-08, + "input_cost_per_token": 7e-08, + "output_cost_per_token": 4e-07, + "litellm_provider": "zai", + "max_input_tokens": 200000, + "max_output_tokens": 131072, + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_tool_choice": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, "zai/glm-4.6": { "cache_creation_input_token_cost": 0, "cache_read_input_token_cost": 1.1e-07, @@ -44428,6 +44504,22 @@ "supports_tool_choice": true, "source": "https://docs.z.ai/guides/overview/pricing" }, + "zai/glm-4.6v": { + "cache_creation_input_token_cost": 0, + "cache_read_input_token_cost": 5e-08, + "input_cost_per_token": 3e-07, + "output_cost_per_token": 9e-07, + "litellm_provider": "zai", + "max_input_tokens": 128000, + "max_output_tokens": 32768, + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_tool_choice": true, + "supports_vision": true, + "source": "https://docs.z.ai/guides/overview/pricing" + }, "zai/glm-4.5": { "input_cost_per_token": 6e-07, "output_cost_per_token": 2.2e-06, diff --git a/tests/test_litellm/proxy/public_endpoints/test_public_endpoints.py b/tests/test_litellm/proxy/public_endpoints/test_public_endpoints.py index 31430da71e8..408d0e21a6a 100644 --- a/tests/test_litellm/proxy/public_endpoints/test_public_endpoints.py +++ b/tests/test_litellm/proxy/public_endpoints/test_public_endpoints.py @@ -60,6 +60,28 @@ def test_get_provider_create_fields(): ), "Expected at least one provider to have detailed credential fields" +def test_zai_provider_fields(): + app_instance = FastAPI() + app_instance.include_router(router) + client = TestClient(app_instance) + + response = client.get("/public/providers/fields") + assert response.status_code == 200 + + providers = response.json() + zai = next((provider for provider in providers if provider["provider"] == "ZAI"), None) + + assert zai is not None + assert zai["provider_display_name"] == "Z.AI" + assert zai["litellm_provider"] == "zai" + assert zai["default_model_placeholder"] == "zai/glm-4.6" + + credential_fields = {field["key"]: field for field in zai["credential_fields"]} + assert credential_fields["api_key"]["required"] is True + assert credential_fields["api_key"]["field_type"] == "password" + assert credential_fields["api_base"]["default_value"] == "https://api.z.ai/api/paas/v4" + + def test_get_litellm_model_cost_map_returns_cost_map(): app = FastAPI() app.include_router(router) diff --git a/tests/test_litellm/test_zai_model_metadata.py b/tests/test_litellm/test_zai_model_metadata.py new file mode 100644 index 00000000000..06864baa604 --- /dev/null +++ b/tests/test_litellm/test_zai_model_metadata.py @@ -0,0 +1,91 @@ +import json +from pathlib import Path + + +CURRENT_ZAI_MODELS = { + "zai/glm-5.3", + "zai/glm-5.2", + "zai/glm-5.1", + "zai/glm-5", + "zai/glm-5-turbo", + "zai/glm-5v-turbo", + "zai/glm-4.7", + "zai/glm-4.7-flash", + "zai/glm-4.7-flashx", + "zai/glm-4.6", + "zai/glm-4.6v", + "zai/glm-4.5", + "zai/glm-4.5v", + "zai/glm-4.5-air", + "zai/glm-4.5-flash", +} + +ZAI_NEW_MODEL_METADATA = { + "zai/glm-5.3": { + "input_cost_per_token": 1.4e-06, + "output_cost_per_token": 4.4e-06, + "max_input_tokens": 1048576, + "max_output_tokens": 131072, + }, + "zai/glm-5.2": { + "input_cost_per_token": 1.4e-06, + "output_cost_per_token": 4.4e-06, + "max_input_tokens": 1048576, + "max_output_tokens": 131072, + }, + "zai/glm-5-turbo": { + "input_cost_per_token": 1.2e-06, + "output_cost_per_token": 4e-06, + "max_input_tokens": 200000, + "max_output_tokens": 131072, + }, + "zai/glm-5v-turbo": { + "input_cost_per_token": 1.2e-06, + "output_cost_per_token": 4e-06, + "max_input_tokens": 200000, + "max_output_tokens": 131072, + "supports_vision": True, + }, + "zai/glm-4.7-flashx": { + "input_cost_per_token": 7e-08, + "output_cost_per_token": 4e-07, + "max_input_tokens": 200000, + "max_output_tokens": 131072, + }, + "zai/glm-4.6v": { + "input_cost_per_token": 3e-07, + "output_cost_per_token": 9e-07, + "max_input_tokens": 128000, + "max_output_tokens": 32768, + "supports_vision": True, + }, +} + + +def test_zai_model_metadata(): + json_path = Path(__file__).parents[2] / "model_prices_and_context_window.json" + model_cost = json.loads(json_path.read_text()) + + assert CURRENT_ZAI_MODELS.issubset(model_cost) + + for model, expected_metadata in ZAI_NEW_MODEL_METADATA.items(): + assert model in model_cost, f"{model} missing from model_prices_and_context_window.json" + metadata = model_cost[model] + assert metadata["litellm_provider"] == "zai" + assert metadata["mode"] == "chat" + assert metadata["supports_function_calling"] is True + assert metadata["supports_reasoning"] is True + assert metadata["supports_tool_choice"] is True + assert metadata["supports_prompt_caching"] is True + + for key, value in expected_metadata.items(): + assert metadata[key] == value + + +def test_zai_model_metadata_backup_matches_main(): + repo_root = Path(__file__).parents[2] + model_cost = json.loads((repo_root / "model_prices_and_context_window.json").read_text()) + backup_model_cost = json.loads((repo_root / "litellm" / "model_prices_and_context_window_backup.json").read_text()) + + for model in ZAI_NEW_MODEL_METADATA: + assert backup_model_cost[model] == model_cost[model] diff --git a/ui/litellm-dashboard/src/components/add_model/AddModelForm.test.tsx b/ui/litellm-dashboard/src/components/add_model/AddModelForm.test.tsx index 340fd811e97..f18250866c0 100644 --- a/ui/litellm-dashboard/src/components/add_model/AddModelForm.test.tsx +++ b/ui/litellm-dashboard/src/components/add_model/AddModelForm.test.tsx @@ -340,6 +340,35 @@ describe("AddModelForm", () => { }); }); + it("should allow searching providers by their LiteLLM provider slug", async () => { + const mockUseAuthorized = vi.mocked(await import("@/app/(dashboard)/hooks/useAuthorized")); + const mockUseProviderFields = vi.mocked(await import("@/app/(dashboard)/hooks/providers/useProviderFields")); + mockUseAuthorized.default.mockReturnValue(mockAuthorizedUser("proxy_admin", "user-1", true)); + mockUseProviderFields.useProviderFields.mockReturnValue({ + data: [ + { + provider: "ZAI", + provider_display_name: "Z.AI", + litellm_provider: "zai", + default_model_placeholder: "zai/glm-4.6", + credential_fields: [], + }, + ], + isLoading: false, + error: null, + }); + + const props = createTestProps(); + const user = userEvent.setup({ pointerEventsCheck: PointerEventsCheckLevel.Never }); + renderWithProviders(); + + const providerSelect = await screen.findByRole("combobox", { name: /provider/i }); + await user.click(providerSelect); + await user.type(providerSelect, "zai"); + + expect(await screen.findByText("Z.AI")).toBeInTheDocument(); + }); + describe("cache control bindings reach the parent form store", () => { const renderWithForm = async () => { const mockUseAuthorized = vi.mocked(await import("@/app/(dashboard)/hooks/useAuthorized")); diff --git a/ui/litellm-dashboard/src/components/add_model/AddModelForm.tsx b/ui/litellm-dashboard/src/components/add_model/AddModelForm.tsx index b6884327a3c..7a12c20bfdb 100644 --- a/ui/litellm-dashboard/src/components/add_model/AddModelForm.tsx +++ b/ui/litellm-dashboard/src/components/add_model/AddModelForm.tsx @@ -123,6 +123,7 @@ const AddModelForm: React.FC = ({ () => sortedProviderMetadata.map((providerInfo) => ({ label: providerInfo.provider_display_name, + sublabel: providerInfo.litellm_provider, value: providerInfo.provider, icon: , })),