fix: rename the mainland China brand to Qianwen AI Platform

This commit is contained in:
mateo-berri 2026-09-21 12:13:43 -07:00
parent a83773cfa5
commit cf00ab1bf8
10 changed files with 82 additions and 10 deletions

View file

@ -356,7 +356,7 @@ For MCP OAuth, an upstream may advertise dynamic client registration but refuse
| [Petals (`petals`)](https://docs.litellm.ai/docs/providers/petals) | ✅ | ✅ | ✅ | | | | | | | |
| [Pinstripes (`pinstripes`)](https://docs.litellm.ai/docs/providers/pinstripes) | ✅ | ✅ | ✅ | | | | | | | |
| [Predibase (`predibase`)](https://docs.litellm.ai/docs/providers/predibase) | ✅ | ✅ | ✅ | | | | | | | |
| [Qwen AI Platform (`qwen_ai_platform`)](https://docs.litellm.ai/docs/providers/qwencloud) | ✅ | ✅ | ✅ | ✅ | ✅ | | | | | ✅ |
| [Qianwen AI Platform (`qwen_ai_platform`)](https://docs.litellm.ai/docs/providers/qwencloud) | ✅ | ✅ | ✅ | ✅ | ✅ | | | | | ✅ |
| [QwenCloud (`qwencloud`)](https://docs.litellm.ai/docs/providers/qwencloud) | ✅ | ✅ | ✅ | ✅ | ✅ | | | | | ✅ |
| [Recraft (`recraft`)](https://docs.litellm.ai/docs/providers/recraft) | | | | | ✅ | | | | | |
| [Replicate (`replicate`)](https://docs.litellm.ai/docs/providers/replicate) | ✅ | ✅ | ✅ | | | | | | | |

View file

@ -103,7 +103,7 @@ def missing_dashscope_family_key_message(custom_llm_provider: str) -> str:
)
if custom_llm_provider == "qwen_ai_platform":
return (
"Missing API key for Qwen AI Platform. Set QWEN_AI_PLATFORM_API_KEY or "
"Missing API key for Qianwen AI Platform. Set QWEN_AI_PLATFORM_API_KEY or "
"DASHSCOPE_API_KEY environment variable or pass api_key parameter."
)
return "Missing API key for DashScope. Set DASHSCOPE_API_KEY environment variable or pass api_key parameter."

View file

@ -23,7 +23,7 @@ def _require_qwen_ai_platform_api_key(api_key: str | None) -> str:
resolved: Final = _resolve_qwen_ai_platform_api_key(api_key)
if resolved is None:
raise ValueError(
"Qwen AI Platform API key is required. Set 'QWEN_AI_PLATFORM_API_KEY' or 'DASHSCOPE_API_KEY' env var "
"Qianwen AI Platform API key is required. Set 'QWEN_AI_PLATFORM_API_KEY' or 'DASHSCOPE_API_KEY' env var "
"or pass api_key explicitly."
)
return resolved

View file

@ -691,7 +691,7 @@
}
},
"qwen_ai_platform": {
"display_name": "Qwen AI Platform (`qwen_ai_platform`)",
"display_name": "Qianwen AI Platform (`qwen_ai_platform`)",
"url": "https://docs.litellm.ai/docs/providers/qwencloud",
"endpoints": {
"chat_completions": true,

View file

@ -1129,12 +1129,12 @@
},
{
"provider": "Qwen_AI_Platform",
"provider_display_name": "Qwen AI Platform",
"provider_display_name": "Qianwen AI Platform",
"litellm_provider": "qwen_ai_platform",
"credential_fields": [
{
"key": "api_key",
"label": "Qwen AI Platform API Key",
"label": "Qianwen AI Platform API Key",
"placeholder": null,
"tooltip": null,
"required": true,
@ -1146,7 +1146,7 @@
"key": "api_base",
"label": "API Base",
"placeholder": "https://dashscope.aliyuncs.com/compatible-mode/v1",
"tooltip": "The base URL for Qwen AI Platform. Defaults to https://dashscope.aliyuncs.com/compatible-mode/v1 if not specified.",
"tooltip": "The base URL for Qianwen AI Platform. Defaults to https://dashscope.aliyuncs.com/compatible-mode/v1 if not specified.",
"required": true,
"field_type": "text",
"options": null,

View file

@ -744,7 +744,7 @@
}
},
"qwen_ai_platform": {
"display_name": "Qwen AI Platform (`qwen_ai_platform`)",
"display_name": "Qianwen AI Platform (`qwen_ai_platform`)",
"url": "https://docs.litellm.ai/docs/providers/qwencloud",
"endpoints": {
"chat_completions": true,

View file

@ -1,10 +1,14 @@
import json
import math
import re
from pathlib import Path
import pytest
import litellm
from litellm import completion, get_llm_provider
from litellm.llms.dashscope.chat.transformation import DashScopeChatConfig
from litellm.llms.dashscope.common_utils import missing_dashscope_family_key_message
from litellm.llms.dashscope.cost_calculator import (
cost_per_token as dashscope_cost_per_token,
)
@ -53,6 +57,7 @@ BRAND_CASES = [
pytest.param(
{
"provider": "qwencloud",
"display_name": "QwenCloud",
"enum": LlmProviders.QWENCLOUD,
"key_env": "QWENCLOUD_API_KEY",
"base_env": "QWENCLOUD_API_BASE",
@ -69,6 +74,7 @@ BRAND_CASES = [
pytest.param(
{
"provider": "qwen_ai_platform",
"display_name": "Qianwen AI Platform",
"enum": LlmProviders.QWEN_AI_PLATFORM,
"key_env": "QWEN_AI_PLATFORM_API_KEY",
"base_env": "QWEN_AI_PLATFORM_API_BASE",
@ -250,6 +256,48 @@ class TestQwenBrandDefaultUrls:
)
class TestQwenBrandUserFacingNames:
RETIRED_MAINLAND_NAME = "Qwen AI Platform"
@pytest.mark.parametrize("brand", BRAND_CASES)
def test_missing_key_message_names_brand(self, brand):
message = missing_dashscope_family_key_message(brand["provider"])
assert brand["display_name"] in message
assert brand["key_env"] in message
assert self.RETIRED_MAINLAND_NAME not in message
@pytest.mark.parametrize("brand", BRAND_CASES)
def test_embedding_without_key_names_brand(self, brand):
with pytest.raises(litellm.APIConnectionError, match=re.escape(brand["display_name"])) as exc_info:
litellm.embedding(model=f"{brand['provider']}/text-embedding-v4", input=["hello"])
assert self.RETIRED_MAINLAND_NAME not in str(exc_info.value)
@pytest.mark.parametrize("brand", BRAND_CASES)
def test_rerank_without_key_names_brand(self, brand):
with pytest.raises(litellm.APIConnectionError, match=re.escape(brand["display_name"])) as exc_info:
litellm.rerank(model=f"{brand['provider']}/gte-rerank-v2", query="q", documents=["a", "b"])
assert self.RETIRED_MAINLAND_NAME not in str(exc_info.value)
@pytest.mark.parametrize("brand", BRAND_CASES)
def test_image_generation_without_key_names_brand(self, brand):
with pytest.raises(litellm.APIConnectionError, match=re.escape(brand["display_name"])) as exc_info:
litellm.image_generation(model=f"{brand['provider']}/qwen-image", prompt="a cup of coffee")
assert self.RETIRED_MAINLAND_NAME not in str(exc_info.value)
@pytest.mark.parametrize("brand", BRAND_CASES)
@pytest.mark.parametrize(
"matrix_path",
[
Path(litellm.__file__).parent / "provider_endpoints_support_backup.json",
Path(litellm.__file__).parent.parent / "provider_endpoints_support.json",
],
ids=["backup", "root"],
)
def test_supported_endpoints_matrix_display_name(self, brand, matrix_path):
matrix = json.loads(matrix_path.read_text())
assert matrix["providers"][brand["provider"]]["display_name"] == f"{brand['display_name']} (`{brand['provider']}`)"
class TestQwenBrandCostParity:
@pytest.fixture(autouse=True)
def setup_model_cost_map(self, monkeypatch):

View file

@ -1,3 +1,4 @@
import json
import re
from datetime import datetime, timezone
from typing import Final
@ -339,7 +340,23 @@ def test_cognition_provider_fields():
assert fields_by_key["api_base"]["required"] is False
def test_chatgpt_provider_fields():
def test_qwen_mainland_provider_fields_carry_the_qianwen_brand():
app_instance = FastAPI()
app_instance.include_router(router)
test_client = TestClient(app_instance)
providers = test_client.get("/public/providers/fields").json()
mainland = next(p for p in providers if p["litellm_provider"] == "qwen_ai_platform")
international = next(p for p in providers if p["litellm_provider"] == "qwencloud")
assert mainland["provider_display_name"] == "Qianwen AI Platform"
assert international["provider_display_name"] == "QwenCloud"
mainland_fields = {f["key"]: f for f in mainland["credential_fields"]}
assert mainland_fields["api_key"]["label"] == "Qianwen AI Platform API Key"
assert "Qianwen AI Platform" in mainland_fields["api_base"]["tooltip"]
assert "Qwen AI Platform" not in json.dumps(mainland)
app_instance = FastAPI()
app_instance.include_router(router)
test_client = TestClient(app_instance)

View file

@ -133,6 +133,13 @@ describe("provider_info_helpers", () => {
expect(result.logo).toBeTruthy();
});
it("should resolve the qwen_ai_platform slug and Qwen_AI_Platform enum key to the Qianwen AI Platform display name", () => {
expect(getProviderLogoAndName("qwen_ai_platform").displayName).toBe("Qianwen AI Platform");
expect(getProviderLogoAndName("Qwen_AI_Platform").displayName).toBe("Qianwen AI Platform");
expect(getProviderLogoAndName("qwencloud").displayName).toBe("QwenCloud");
expect(getProviderLogoAndName("qwen_ai_platform").logo).toBe(providerLogoMap[Providers.Qwen_AI_Platform]);
});
it("should return provider value as display name when no mapping exists", () => {
const unknownProvider = "unknown_provider";
const result = getProviderLogoAndName(unknownProvider);

View file

@ -152,7 +152,7 @@ export enum Providers {
PETALS = "Petals",
PG_VECTOR = "Pg Vector",
PREDIBASE = "Predibase",
Qwen_AI_Platform = "Qwen AI Platform",
Qwen_AI_Platform = "Qianwen AI Platform",
QwenCloud = "QwenCloud",
RECRAFT = "Recraft",
REPLICATE = "Replicate",