From 0d1eaef4e4c7d6709826c3a6528f5f1e22a7636c Mon Sep 17 00:00:00 2001 From: ExDevilLee Date: Wed, 19 Aug 2026 12:09:16 +0800 Subject: [PATCH] fix(ui): add Z.AI provider to Add Model --- .../provider_create_fields.json | 28 ++++++++++++++++++ .../public_endpoints/test_public_endpoints.py | 22 ++++++++++++++ .../add_model/AddModelForm.test.tsx | 29 +++++++++++++++++++ .../src/components/add_model/AddModelForm.tsx | 1 + 4 files changed, 80 insertions(+) diff --git a/litellm/proxy/public_endpoints/provider_create_fields.json b/litellm/proxy/public_endpoints/provider_create_fields.json index ab13773614a..835bf2a6ad1 100644 --- a/litellm/proxy/public_endpoints/provider_create_fields.json +++ b/litellm/proxy/public_endpoints/provider_create_fields.json @@ -3240,6 +3240,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/tests/test_litellm/proxy/public_endpoints/test_public_endpoints.py b/tests/test_litellm/proxy/public_endpoints/test_public_endpoints.py index 03d228cc732..8b58e960f05 100644 --- a/tests/test_litellm/proxy/public_endpoints/test_public_endpoints.py +++ b/tests/test_litellm/proxy/public_endpoints/test_public_endpoints.py @@ -63,6 +63,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/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 7e084a532f4..a8e332c5d5f 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: , })),