fix(llm): support Volcengine Coding model aliases (#411)

* fix(llm): support Volcengine Coding model aliases

* refactor(llm): add Volcengine Coding provider

* style: format Volcengine Coding test
This commit is contained in:
Ziheng Zhang
2026-08-07 14:30:23 +08:00
committed by GitHub
parent 3c5cc831c0
commit 33979e5371
9 changed files with 51 additions and 0 deletions
+1
View File
@@ -21,6 +21,7 @@ VALID_PROVIDERS: frozenset[str] = frozenset(
"zhipu",
"zhipu-code",
"volcengine",
"volcengine-code",
"dashscope",
"dashscope-code",
"deepseek",
+5
View File
@@ -102,6 +102,11 @@ def _provider_key_info(config: EvoScientistConfig, provider: str):
config.volcengine_api_key or os.environ.get("VOLCENGINE_API_KEY", ""),
validate_volcengine_key,
),
"volcengine-code": (
"Volcengine Coding Plan",
config.volcengine_api_key or os.environ.get("VOLCENGINE_API_KEY", ""),
validate_volcengine_key,
),
"dashscope": (
"DashScope",
config.dashscope_api_key or os.environ.get("DASHSCOPE_API_KEY", ""),
+4
View File
@@ -278,6 +278,10 @@ def _step_provider(
title="Volcengine (火山引擎 — Doubao models)",
value="volcengine",
),
Choice(
title="Volcengine Coding Plan (火山引擎代码计划 — coding models)",
value="volcengine-code",
),
Choice(
title="DashScope (阿里云 — Qwen models)",
value="dashscope",
@@ -475,6 +475,9 @@ def validate_zhipu_key(api_key: str) -> tuple[bool, str]:
def validate_volcengine_key(api_key: str) -> tuple[bool, str]:
"""Validate a Volcengine API key by making a test request.
Uses the general endpoint for validation; volcengine and volcengine-code
share the same API key and only differ in their runtime base URL.
Returns:
Tuple of (is_valid, message).
"""
+1
View File
@@ -124,6 +124,7 @@ _PROVIDER_KEY_ATTR = {
"zhipu": "zhipu_api_key",
"zhipu-code": "zhipu_api_key",
"volcengine": "volcengine_api_key",
"volcengine-code": "volcengine_api_key",
"dashscope": "dashscope_api_key",
"dashscope-code": "dashscope_api_key",
"moonshot": "moonshot_api_key",
+2
View File
@@ -32,6 +32,8 @@ _KNOWN_MODEL_CONTEXT_WINDOWS: dict[str, int] = {
# Zhipu GLM-5.2 — 1M context, an exception to the ``glm-5`` family (203K).
# Matches OpenRouter ``z-ai/glm-5.2`` via split('/')[-1].
"glm-5.2": 1_000_000,
# Volcengine Coding Plan's OpenAI-compatible alias for GLM-5.2.
"glm-5-2": 1_000_000,
# Tencent Hunyuan HY3 — 262K context (OpenRouter ``tencent/hy3``).
"hy3": 262_000,
}
+6
View File
@@ -43,6 +43,7 @@ _SILICONFLOW_BASE_URL = "https://api.siliconflow.cn/v1"
_ZHIPU_BASE_URL = "https://open.bigmodel.cn/api/paas/v4"
_ZHIPU_CODE_BASE_URL = "https://open.bigmodel.cn/api/coding/paas/v4"
_VOLCENGINE_BASE_URL = "https://ark.cn-beijing.volces.com/api/v3"
_VOLCENGINE_CODE_BASE_URL = "https://ark.cn-beijing.volces.com/api/coding/v3"
_DASHSCOPE_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1"
_DASHSCOPE_CODE_BASE_URL = "https://coding.dashscope.aliyuncs.com/v1"
@@ -114,6 +115,7 @@ _OPENAI_ROUTED_PROVIDERS: dict[str, tuple[str | None, str]] = {
"zhipu": (_ZHIPU_BASE_URL, "ZHIPU_API_KEY"),
"zhipu-code": (_ZHIPU_CODE_BASE_URL, "ZHIPU_API_KEY"),
"volcengine": (_VOLCENGINE_BASE_URL, "VOLCENGINE_API_KEY"),
"volcengine-code": (_VOLCENGINE_CODE_BASE_URL, "VOLCENGINE_API_KEY"),
"dashscope": (_DASHSCOPE_BASE_URL, "DASHSCOPE_API_KEY"),
"dashscope-code": (_DASHSCOPE_CODE_BASE_URL, "DASHSCOPE_API_KEY"),
"requesty": (_REQUESTY_BASE_URL, "REQUESTY_API_KEY"),
@@ -283,6 +285,10 @@ _MODEL_ENTRIES: list[tuple[str, str, str]] = [
("qwen3.5-122b", "qwen/qwen3.5-122b-a10b", "openrouter"),
("deepseek-v4-pro", "deepseek/deepseek-v4-pro", "openrouter"),
("deepseek-v4-flash", "deepseek/deepseek-v4-flash", "openrouter"),
# Volcengine Coding Plan (火山引擎代码计划 — coding-only endpoint)
# Listed before Zhipu so simple GLM lookups keep their existing default.
("glm-5.2", "glm-5-2", "volcengine-code"),
("kimi-k2.5", "kimi-k2-5", "volcengine-code"),
# Zhipu CodePlan (智谱代码计划 — coding-only endpoint)
("glm-5.2", "glm-5.2", "zhipu-code"),
("glm-5.1", "glm-5.1", "zhipu-code"),
+5
View File
@@ -202,3 +202,8 @@ def test_lookup_is_case_insensitive():
# GLM-5 capitalized variant
glm = SimpleNamespace(model_name="Pro/zai-org/GLM-5", profile=None)
assert get_context_window(glm) == 203_000
def test_volcengine_glm_5_2_alias_keeps_exact_context_window():
model = SimpleNamespace(model_name="glm-5-2", profile=None)
assert get_context_window(model) == 1_000_000
+24
View File
@@ -41,6 +41,7 @@ class TestModelsRegistry:
assert "zhipu" in providers
assert "zhipu-code" in providers
assert "volcengine" in providers
assert "volcengine-code" in providers
assert "dashscope" in providers
assert "dashscope-code" in providers
assert "deepseek" in providers
@@ -62,6 +63,7 @@ class TestModelsRegistry:
"zhipu",
"zhipu-code",
"volcengine",
"volcengine-code",
"dashscope",
"dashscope-code",
"custom-openai",
@@ -1128,6 +1130,28 @@ class TestThirdPartyRouting:
assert call_kwargs["base_url"] == "https://ark.cn-beijing.volces.com/api/v3"
assert call_kwargs["api_key"] == "ve-key-123"
@pytest.mark.parametrize(
("configured_model", "api_model"),
[("glm-5.2", "glm-5-2"), ("kimi-k2.5", "kimi-k2-5")],
)
@patch("EvoScientist.llm.models.init_chat_model")
def test_volcengine_code_routes_through_openai(
self, mock_init, configured_model, api_model, monkeypatch
):
"""Volcengine Coding Plan uses its endpoint, IDs, and vendor API key."""
mock_init.return_value = "mock_model"
monkeypatch.setenv("VOLCENGINE_API_KEY", "ve-code-key-123")
get_chat_model(configured_model, provider="volcengine-code")
call_kwargs = mock_init.call_args[1]
assert call_kwargs["model_provider"] == "openai"
assert call_kwargs["model"] == api_model
assert (
call_kwargs["base_url"] == "https://ark.cn-beijing.volces.com/api/coding/v3"
)
assert call_kwargs["api_key"] == "ve-code-key-123"
@patch("EvoScientist.llm.models.init_chat_model")
def test_dashscope_routes_through_openai(self, mock_init, monkeypatch):
"""DashScope provider should route through OpenAI with correct base_url."""