feat(models): add new models for SiliconFlow and OpenRouter providers

test(models): update tests to validate new providers and registered models
This commit is contained in:
X-iZhang
2026-02-27 14:38:22 +00:00
parent c9e5d925b8
commit d81d41f756
3 changed files with 43 additions and 58 deletions
+22 -55
View File
@@ -422,9 +422,9 @@ def _step_provider(config: EvoScientistConfig) -> str:
Choice(title="Anthropic (Claude models)", value="anthropic"),
Choice(title="OpenAI (GPT models)", value="openai"),
Choice(title="Google GenAI (Gemini models)", value="google-genai"),
Choice(title="NVIDIA (DeepSeek, Kimi, GLM, MiniMax, Step, etc.)", value="nvidia"),
Choice(title="SiliconFlow (third party)", value="siliconflow"),
Choice(title="OpenRouter (third party)", value="openrouter"),
Choice(title="NVIDIA (third party — limited free requests)", value="nvidia"),
Choice(title="SiliconFlow (third party — GLM, Kimi, MiniMax, etc.)", value="siliconflow"),
Choice(title="OpenRouter (third party — Grok, Gemini, Qwen, etc.)", value="openrouter"),
Choice(title="Ollama (local models)", value="ollama"),
Choice(title="Other (OpenAI-compatible)", value="custom"),
]
@@ -545,18 +545,6 @@ def _step_provider_api_key(
)
_THIRD_PARTY_EXAMPLES: dict[str, list[tuple[str, str]]] = {
"openrouter": [
("minimax/minimax-m2.5", "MiniMax M2.5"),
("x-ai/grok-4.1-fast", "Grok 4.1 Fast"),
],
"siliconflow": [
("Pro/zai-org/GLM-5", "GLM 5"),
("Pro/moonshotai/Kimi-K2.5", "Kimi K2.5"),
],
}
def _step_base_url(config: EvoScientistConfig) -> str:
"""Prompt for custom provider base URL.
@@ -678,44 +666,6 @@ def _step_model(
console.print(f" [dim]Using default: {model}[/dim]")
return model
# Third-party providers: select from examples or type custom model name
if provider in _THIRD_PARTY_EXAMPLES:
examples = _THIRD_PARTY_EXAMPLES[provider]
_CUSTOM_SENTINEL = "__custom__"
choices = [
Choice(title=f"{label} ({mid})", value=mid)
for mid, label in examples
]
choices.append(Choice(title="Customize your model...", value=_CUSTOM_SENTINEL))
selected = questionary.select(
"Select model:",
choices=choices,
default=choices[0].value,
style=WIZARD_STYLE,
qmark=QMARK,
use_indicator=True,
).ask()
if selected is None:
raise KeyboardInterrupt()
if selected != _CUSTOM_SENTINEL:
return selected
model = questionary.text(
"Model name:",
style=WIZARD_STYLE,
qmark=QMARK,
placeholder=FormattedText([("fg:#858585", " e.g. owner/model-name")]),
).ask()
if model is None:
raise KeyboardInterrupt()
model = model.strip()
if not model:
model = examples[0][0]
console.print(f" [dim]Using default: {model}[/dim]")
return model
# Get models for the selected provider
entries = get_models_for_provider(provider)
@@ -734,9 +684,11 @@ def _step_model(
provider_models = [name for name, _ in entries]
# Create choices with model IDs as hints
_CUSTOM_SENTINEL = "__custom__"
choices = []
for name, model_id in entries:
choices.append(Choice(title=f"{name} ({model_id})", value=name))
choices.append(Choice(title="Type a model name...", value=_CUSTOM_SENTINEL))
# Determine default
if config.model in provider_models:
@@ -744,7 +696,7 @@ def _step_model(
else:
default = provider_models[0]
model = questionary.select(
selected = questionary.select(
"Select model:",
choices=choices,
default=default,
@@ -753,9 +705,24 @@ def _step_model(
use_indicator=True,
).ask()
if model is None:
if selected is None:
raise KeyboardInterrupt()
if selected != _CUSTOM_SENTINEL:
return selected
model = questionary.text(
"Model name:",
style=WIZARD_STYLE,
qmark=QMARK,
placeholder=FormattedText([("fg:#858585", " e.g. owner/model-name")]),
).ask()
if model is None:
raise KeyboardInterrupt()
model = model.strip()
if not model:
model = provider_models[0]
console.print(f" [dim]Using default: {model}[/dim]")
return model
+16
View File
@@ -46,9 +46,22 @@ _MODEL_ENTRIES: list[tuple[str, str, str]] = [
("deepseek-v3.1", "deepseek-ai/deepseek-v3.1-terminus", "nvidia"),
("kimi-k2.5", "moonshotai/kimi-k2.5", "nvidia"),
("kimi-k2-thinking", "moonshotai/kimi-k2-thinking", "nvidia"),
("minimax-m2.5", "minimaxai/minimax-m2.5", "nvidia"),
("minimax-m2.1", "minimaxai/minimax-m2.1", "nvidia"),
("qwen3.5-397b", "qwen/qwen3.5-397b-a17b", "nvidia"),
("step-3.5-flash", "stepfun-ai/step-3.5-flash", "nvidia"),
("nemotron-nano", "nvidia/nemotron-3-nano-30b-a3b", "nvidia"),
# SiliconFlow
("minimax-m2.5", "Pro/MiniMaxAI/MiniMax-M2.5", "siliconflow"),
("glm-5", "Pro/zai-org/GLM-5", "siliconflow"),
("kimi-k2.5", "Pro/moonshotai/Kimi-K2.5", "siliconflow"),
("glm-4.7", "Pro/zai-org/GLM-4.7", "siliconflow"),
# OpenRouter
("minimax-m2.5", "minimax/minimax-m2.5", "openrouter"),
("grok-4.1-fast", "x-ai/grok-4.1-fast", "openrouter"),
("qwen3.5-122b", "qwen/qwen3.5-122b-a10b", "openrouter"),
("gemini-3-flash", "google/gemini-3-flash-preview", "openrouter"),
("claude-sonnet-4.6", "anthropic/claude-sonnet-4.6", "openrouter"),
]
# Public dict for simple lookups (last entry wins for duplicate names).
@@ -147,6 +160,9 @@ def get_chat_model(
api_key = os.environ.get("SILICONFLOW_API_KEY", "")
if api_key:
kwargs["api_key"] = api_key
# Disable thinking — LangChain drops reasoning_content from history,
# causing SiliconFlow to reject multi-turn requests (error 20015).
kwargs.setdefault("extra_body", {})["enable_thinking"] = False
provider = "openai"
elif provider == "openrouter":
kwargs["base_url"] = _OPENROUTER_BASE_URL
+5 -3
View File
@@ -33,7 +33,7 @@ class TestModelsRegistry:
def test_entries_are_valid_tuples(self):
"""Test that _MODEL_ENTRIES contains valid (name, model_id, provider) tuples."""
valid_providers = {"anthropic", "openai", "google-genai", "nvidia"}
valid_providers = {"anthropic", "openai", "google-genai", "nvidia", "siliconflow", "openrouter"}
for entry in _MODEL_ENTRIES:
assert len(entry) == 3, f"Entry {entry} doesn't have 3 elements"
name, model_id, provider = entry
@@ -49,9 +49,11 @@ class TestModelsRegistry:
assert isinstance(name, str)
assert isinstance(model_id, str)
# Third-party providers have no registered models (user types model name)
# Third-party providers now have registered models
openrouter_models = get_models_for_provider("openrouter")
assert len(openrouter_models) == 0
assert len(openrouter_models) > 0
siliconflow_models = get_models_for_provider("siliconflow")
assert len(siliconflow_models) > 0
# =============================================================================