feat(models): add recent large OpenRouter models (#2461)
This commit is contained in:
@@ -218,6 +218,8 @@ codewhale --provider wanjie-ark --model deepseek-reasoner
|
||||
# OpenRouter
|
||||
codewhale auth set --provider openrouter --api-key "YOUR_OPENROUTER_API_KEY"
|
||||
codewhale --provider openrouter --model deepseek/deepseek-v4-pro
|
||||
codewhale --provider openrouter --model arcee-ai/trinity-large-thinking
|
||||
codewhale --provider openrouter --model qwen/qwen3.7-max
|
||||
|
||||
# Xiaomi MiMo
|
||||
codewhale auth set --provider xiaomi-mimo --api-key "YOUR_XIAOMI_MIMO_API_KEY"
|
||||
|
||||
@@ -315,6 +315,8 @@ codewhale --provider wanjie-ark --model deepseek-reasoner
|
||||
# OpenRouter
|
||||
codewhale auth set --provider openrouter --api-key "YOUR_OPENROUTER_API_KEY"
|
||||
codewhale --provider openrouter --model deepseek/deepseek-v4-pro
|
||||
codewhale --provider openrouter --model arcee-ai/trinity-large-thinking
|
||||
codewhale --provider openrouter --model qwen/qwen3.7-max
|
||||
|
||||
# Xiaomi MiMo
|
||||
codewhale auth set --provider xiaomi-mimo --api-key "YOUR_XIAOMI_MIMO_API_KEY"
|
||||
|
||||
@@ -262,6 +262,8 @@ codewhale --provider wanjie-ark --model deepseek-reasoner
|
||||
# OpenRouter
|
||||
codewhale auth set --provider openrouter --api-key "YOUR_OPENROUTER_API_KEY"
|
||||
codewhale --provider openrouter --model deepseek/deepseek-v4-pro
|
||||
codewhale --provider openrouter --model arcee-ai/trinity-large-thinking
|
||||
codewhale --provider openrouter --model qwen/qwen3.7-max
|
||||
|
||||
# Xiaomi MiMo
|
||||
codewhale auth set --provider xiaomi-mimo --api-key "YOUR_XIAOMI_MIMO_API_KEY"
|
||||
|
||||
+10
-1
@@ -36,6 +36,11 @@ base_url = "https://api.deepseek.com/beta"
|
||||
# deepseek-v4-flash — fast, cost-efficient (legacy aliases: deepseek-chat, deepseek-reasoner)
|
||||
# deepseek-ai/deepseek-v4-pro — NVIDIA NIM-hosted Pro model ID
|
||||
# deepseek-ai/deepseek-v4-flash — NVIDIA NIM-hosted Flash model ID
|
||||
# deepseek/deepseek-v4-pro — default OpenRouter DeepSeek model ID
|
||||
# arcee-ai/trinity-large-thinking — OpenRouter Arcee Trinity Large Thinking
|
||||
# qwen/qwen3.7-max — OpenRouter Qwen 3.7 Max
|
||||
# xiaomi/mimo-v2.5-pro — OpenRouter Xiaomi MiMo 2.5 Pro
|
||||
# xiaomi/mimo-v2.5 — OpenRouter Xiaomi MiMo 2.5
|
||||
# gpt-4.1 — default generic OpenAI-compatible model ID
|
||||
# deepseek-ai/deepseek-v4-flash — default AtlasCloud model ID
|
||||
# deepseek-reasoner — default Wanjie Ark model ID
|
||||
@@ -255,7 +260,11 @@ max_subagents = 10 # optional (1-20)
|
||||
[providers.openrouter]
|
||||
# api_key = "YOUR_OPENROUTER_API_KEY"
|
||||
# base_url = "https://openrouter.ai/api/v1"
|
||||
# model = "deepseek/deepseek-v4-pro" # or deepseek/deepseek-v4-flash
|
||||
# model = "deepseek/deepseek-v4-pro"
|
||||
# Recent large model IDs also accepted here include arcee-ai/trinity-large-thinking,
|
||||
# qwen/qwen3.7-max, xiaomi/mimo-v2.5-pro, qwen/qwen3.6-35b-a3b,
|
||||
# google/gemma-4-31b-it, z-ai/glm-5.1, moonshotai/kimi-k2.6, and
|
||||
# nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free.
|
||||
|
||||
# Xiaomi MiMo OpenAI-compatible endpoint (https://platform.xiaomimimo.com)
|
||||
[providers.xiaomi_mimo]
|
||||
|
||||
@@ -186,6 +186,109 @@ impl Default for ModelRegistry {
|
||||
supports_tools: true,
|
||||
supports_reasoning: true,
|
||||
},
|
||||
ModelInfo {
|
||||
id: "arcee-ai/trinity-large-thinking".to_string(),
|
||||
provider: ProviderKind::Openrouter,
|
||||
aliases: vec![
|
||||
"trinity".to_string(),
|
||||
"trinity-large-thinking".to_string(),
|
||||
"arcee-trinity-large-thinking".to_string(),
|
||||
],
|
||||
supports_tools: true,
|
||||
supports_reasoning: true,
|
||||
},
|
||||
ModelInfo {
|
||||
id: "qwen/qwen3.7-max".to_string(),
|
||||
provider: ProviderKind::Openrouter,
|
||||
aliases: vec!["qwen3.7-max".to_string(), "qwen-3.7-max".to_string()],
|
||||
supports_tools: true,
|
||||
supports_reasoning: true,
|
||||
},
|
||||
ModelInfo {
|
||||
id: "xiaomi/mimo-v2.5-pro".to_string(),
|
||||
provider: ProviderKind::Openrouter,
|
||||
aliases: vec![
|
||||
"openrouter-mimo-v2.5-pro".to_string(),
|
||||
"openrouter-xiaomi-mimo-v2.5-pro".to_string(),
|
||||
],
|
||||
supports_tools: true,
|
||||
supports_reasoning: true,
|
||||
},
|
||||
ModelInfo {
|
||||
id: "xiaomi/mimo-v2.5".to_string(),
|
||||
provider: ProviderKind::Openrouter,
|
||||
aliases: vec![
|
||||
"openrouter-mimo-v2.5".to_string(),
|
||||
"openrouter-xiaomi-mimo-v2.5".to_string(),
|
||||
],
|
||||
supports_tools: true,
|
||||
supports_reasoning: true,
|
||||
},
|
||||
ModelInfo {
|
||||
id: "qwen/qwen3.6-35b-a3b".to_string(),
|
||||
provider: ProviderKind::Openrouter,
|
||||
aliases: vec![
|
||||
"qwen3.6-35b-a3b".to_string(),
|
||||
"qwen-3.6-35b-a3b".to_string(),
|
||||
],
|
||||
supports_tools: true,
|
||||
supports_reasoning: true,
|
||||
},
|
||||
ModelInfo {
|
||||
id: "qwen/qwen3.6-27b".to_string(),
|
||||
provider: ProviderKind::Openrouter,
|
||||
aliases: vec!["qwen3.6-27b".to_string(), "qwen-3.6-27b".to_string()],
|
||||
supports_tools: true,
|
||||
supports_reasoning: true,
|
||||
},
|
||||
ModelInfo {
|
||||
id: "moonshotai/kimi-k2.6".to_string(),
|
||||
provider: ProviderKind::Openrouter,
|
||||
aliases: vec!["openrouter-kimi-k2.6".to_string()],
|
||||
supports_tools: true,
|
||||
supports_reasoning: true,
|
||||
},
|
||||
ModelInfo {
|
||||
id: "z-ai/glm-5.1".to_string(),
|
||||
provider: ProviderKind::Openrouter,
|
||||
aliases: vec!["glm-5.1".to_string(), "zai-glm-5.1".to_string()],
|
||||
supports_tools: true,
|
||||
supports_reasoning: true,
|
||||
},
|
||||
ModelInfo {
|
||||
id: "tencent/hy3-preview".to_string(),
|
||||
provider: ProviderKind::Openrouter,
|
||||
aliases: vec!["hy3-preview".to_string(), "tencent-hy3-preview".to_string()],
|
||||
supports_tools: true,
|
||||
supports_reasoning: true,
|
||||
},
|
||||
ModelInfo {
|
||||
id: "google/gemma-4-31b-it".to_string(),
|
||||
provider: ProviderKind::Openrouter,
|
||||
aliases: vec!["gemma-4-31b".to_string(), "gemma-4-31b-it".to_string()],
|
||||
supports_tools: true,
|
||||
supports_reasoning: true,
|
||||
},
|
||||
ModelInfo {
|
||||
id: "google/gemma-4-26b-a4b-it".to_string(),
|
||||
provider: ProviderKind::Openrouter,
|
||||
aliases: vec![
|
||||
"gemma-4-26b-a4b".to_string(),
|
||||
"gemma-4-26b-a4b-it".to_string(),
|
||||
],
|
||||
supports_tools: true,
|
||||
supports_reasoning: true,
|
||||
},
|
||||
ModelInfo {
|
||||
id: "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free".to_string(),
|
||||
provider: ProviderKind::Openrouter,
|
||||
aliases: vec![
|
||||
"nemotron-3-nano-omni".to_string(),
|
||||
"nemotron-3-nano-omni-reasoning".to_string(),
|
||||
],
|
||||
supports_tools: true,
|
||||
supports_reasoning: true,
|
||||
},
|
||||
ModelInfo {
|
||||
id: "mimo-v2.5-pro".to_string(),
|
||||
provider: ProviderKind::XiaomiMimo,
|
||||
@@ -619,6 +722,28 @@ mod tests {
|
||||
assert_eq!(resolved.resolved.id, "deepseek/deepseek-v4-flash");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recent_openrouter_large_model_aliases_resolve_when_provider_hinted() {
|
||||
let registry = ModelRegistry::default();
|
||||
|
||||
for (alias, expected) in [
|
||||
("trinity-large-thinking", "arcee-ai/trinity-large-thinking"),
|
||||
("qwen3.7-max", "qwen/qwen3.7-max"),
|
||||
("qwen3.6-35b-a3b", "qwen/qwen3.6-35b-a3b"),
|
||||
("gemma-4-31b-it", "google/gemma-4-31b-it"),
|
||||
("glm-5.1", "z-ai/glm-5.1"),
|
||||
("openrouter-mimo-v2.5-pro", "xiaomi/mimo-v2.5-pro"),
|
||||
("openrouter-kimi-k2.6", "moonshotai/kimi-k2.6"),
|
||||
] {
|
||||
let resolved = registry.resolve(Some(alias), Some(ProviderKind::Openrouter));
|
||||
|
||||
assert_eq!(resolved.resolved.provider, ProviderKind::Openrouter);
|
||||
assert_eq!(resolved.resolved.id, expected);
|
||||
assert!(resolved.resolved.supports_tools);
|
||||
assert!(resolved.resolved.supports_reasoning);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deepseek_v4_flash_alias_resolves_to_novita_when_provider_hinted() {
|
||||
let registry = ModelRegistry::default();
|
||||
|
||||
@@ -29,6 +29,19 @@ const DEFAULT_VOLCENGINE_MODEL: &str = "DeepSeek-V4-Pro";
|
||||
const DEFAULT_VOLCENGINE_BASE_URL: &str = "https://ark.cn-beijing.volces.com/api/coding/v3";
|
||||
const DEFAULT_OPENROUTER_MODEL: &str = "deepseek/deepseek-v4-pro";
|
||||
const DEFAULT_OPENROUTER_FLASH_MODEL: &str = "deepseek/deepseek-v4-flash";
|
||||
const OPENROUTER_ARCEE_TRINITY_LARGE_THINKING_MODEL: &str = "arcee-ai/trinity-large-thinking";
|
||||
const OPENROUTER_GEMMA_4_31B_MODEL: &str = "google/gemma-4-31b-it";
|
||||
const OPENROUTER_GEMMA_4_26B_A4B_MODEL: &str = "google/gemma-4-26b-a4b-it";
|
||||
const OPENROUTER_GLM_5_1_MODEL: &str = "z-ai/glm-5.1";
|
||||
const OPENROUTER_KIMI_K2_6_MODEL: &str = "moonshotai/kimi-k2.6";
|
||||
const OPENROUTER_NEMOTRON_3_NANO_OMNI_MODEL: &str =
|
||||
"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free";
|
||||
const OPENROUTER_QWEN_3_7_MAX_MODEL: &str = "qwen/qwen3.7-max";
|
||||
const OPENROUTER_QWEN_3_6_35B_A3B_MODEL: &str = "qwen/qwen3.6-35b-a3b";
|
||||
const OPENROUTER_QWEN_3_6_27B_MODEL: &str = "qwen/qwen3.6-27b";
|
||||
const OPENROUTER_TENCENT_HY3_PREVIEW_MODEL: &str = "tencent/hy3-preview";
|
||||
const OPENROUTER_XIAOMI_MIMO_V2_5_PRO_MODEL: &str = "xiaomi/mimo-v2.5-pro";
|
||||
const OPENROUTER_XIAOMI_MIMO_V2_5_MODEL: &str = "xiaomi/mimo-v2.5";
|
||||
const DEFAULT_XIAOMI_MIMO_MODEL: &str = "mimo-v2.5-pro";
|
||||
const DEFAULT_NOVITA_MODEL: &str = "deepseek/deepseek-v4-pro";
|
||||
const DEFAULT_NOVITA_FLASH_MODEL: &str = "deepseek/deepseek-v4-flash";
|
||||
@@ -1426,6 +1439,11 @@ fn normalize_model_for_provider(provider: ProviderKind, model: &str) -> String {
|
||||
}
|
||||
|
||||
let normalized = model.trim().to_ascii_lowercase();
|
||||
if provider == ProviderKind::Openrouter
|
||||
&& let Some(canonical) = canonical_openrouter_recent_model_id(&normalized)
|
||||
{
|
||||
return canonical.to_string();
|
||||
}
|
||||
match (provider, normalized.as_str()) {
|
||||
(ProviderKind::NvidiaNim, "deepseek-v4-pro" | "deepseek-v4pro") => {
|
||||
DEFAULT_NVIDIA_NIM_MODEL.to_string()
|
||||
@@ -1483,6 +1501,57 @@ fn normalize_model_for_provider(provider: ProviderKind, model: &str) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
fn canonical_openrouter_recent_model_id(model: &str) -> Option<&'static str> {
|
||||
let normalized = model.trim().to_ascii_lowercase();
|
||||
let normalized = normalized.replace(['_', ' '], "-");
|
||||
match normalized.as_str() {
|
||||
OPENROUTER_ARCEE_TRINITY_LARGE_THINKING_MODEL
|
||||
| "trinity"
|
||||
| "trinity-large-thinking"
|
||||
| "arcee-trinity"
|
||||
| "arcee-trinity-large-thinking" => Some(OPENROUTER_ARCEE_TRINITY_LARGE_THINKING_MODEL),
|
||||
OPENROUTER_GEMMA_4_31B_MODEL | "gemma-4-31b" | "gemma-4-31b-it" => {
|
||||
Some(OPENROUTER_GEMMA_4_31B_MODEL)
|
||||
}
|
||||
OPENROUTER_GEMMA_4_26B_A4B_MODEL | "gemma-4-26b-a4b" | "gemma-4-26b-a4b-it" => {
|
||||
Some(OPENROUTER_GEMMA_4_26B_A4B_MODEL)
|
||||
}
|
||||
OPENROUTER_GLM_5_1_MODEL | "glm-5.1" | "glm-5-1" | "zai-glm-5.1" | "zai-glm-5-1" => {
|
||||
Some(OPENROUTER_GLM_5_1_MODEL)
|
||||
}
|
||||
OPENROUTER_KIMI_K2_6_MODEL | "kimi-k2.6" | "kimi-k2-6" | "moonshot-kimi-k2.6" => {
|
||||
Some(OPENROUTER_KIMI_K2_6_MODEL)
|
||||
}
|
||||
OPENROUTER_NEMOTRON_3_NANO_OMNI_MODEL
|
||||
| "nemotron-3-nano-omni"
|
||||
| "nemotron-3-nano-omni-reasoning" => Some(OPENROUTER_NEMOTRON_3_NANO_OMNI_MODEL),
|
||||
OPENROUTER_QWEN_3_7_MAX_MODEL | "qwen3.7-max" | "qwen-3.7-max" | "qwen3-7-max" => {
|
||||
Some(OPENROUTER_QWEN_3_7_MAX_MODEL)
|
||||
}
|
||||
OPENROUTER_QWEN_3_6_35B_A3B_MODEL
|
||||
| "qwen3.6-35b-a3b"
|
||||
| "qwen-3.6-35b-a3b"
|
||||
| "qwen3-6-35b-a3b" => Some(OPENROUTER_QWEN_3_6_35B_A3B_MODEL),
|
||||
OPENROUTER_QWEN_3_6_27B_MODEL | "qwen3.6-27b" | "qwen-3.6-27b" | "qwen3-6-27b" => {
|
||||
Some(OPENROUTER_QWEN_3_6_27B_MODEL)
|
||||
}
|
||||
OPENROUTER_TENCENT_HY3_PREVIEW_MODEL | "hy3-preview" | "tencent-hy3-preview" => {
|
||||
Some(OPENROUTER_TENCENT_HY3_PREVIEW_MODEL)
|
||||
}
|
||||
OPENROUTER_XIAOMI_MIMO_V2_5_PRO_MODEL
|
||||
| "mimo-v2.5-pro"
|
||||
| "mimo-v2-5-pro"
|
||||
| "xiaomi-mimo-v2.5-pro"
|
||||
| "xiaomi-mimo-v2-5-pro" => Some(OPENROUTER_XIAOMI_MIMO_V2_5_PRO_MODEL),
|
||||
OPENROUTER_XIAOMI_MIMO_V2_5_MODEL
|
||||
| "mimo-v2.5"
|
||||
| "mimo-v2-5"
|
||||
| "xiaomi-mimo-v2.5"
|
||||
| "xiaomi-mimo-v2-5" => Some(OPENROUTER_XIAOMI_MIMO_V2_5_MODEL),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn default_model_for_provider(provider: ProviderKind) -> &'static str {
|
||||
match provider {
|
||||
ProviderKind::Deepseek => DEFAULT_DEEPSEEK_MODEL,
|
||||
@@ -3758,6 +3827,36 @@ unix_socket_path = "/tmp/cw-hooks.sock"
|
||||
assert_eq!(resolved.model, DEFAULT_OPENROUTER_FLASH_MODEL);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn openrouter_provider_normalizes_recent_large_model_aliases() {
|
||||
let _lock = env_lock();
|
||||
let _env = EnvGuard::without_deepseek_runtime_overrides();
|
||||
|
||||
for (alias, expected) in [
|
||||
(
|
||||
"trinity-large-thinking",
|
||||
OPENROUTER_ARCEE_TRINITY_LARGE_THINKING_MODEL,
|
||||
),
|
||||
("qwen3.7-max", OPENROUTER_QWEN_3_7_MAX_MODEL),
|
||||
("qwen3.6-35b-a3b", OPENROUTER_QWEN_3_6_35B_A3B_MODEL),
|
||||
("mimo-v2.5-pro", OPENROUTER_XIAOMI_MIMO_V2_5_PRO_MODEL),
|
||||
("kimi-k2.6", OPENROUTER_KIMI_K2_6_MODEL),
|
||||
("gemma-4-31b-it", OPENROUTER_GEMMA_4_31B_MODEL),
|
||||
("glm-5.1", OPENROUTER_GLM_5_1_MODEL),
|
||||
] {
|
||||
let cli = CliRuntimeOverrides {
|
||||
provider: Some(ProviderKind::Openrouter),
|
||||
model: Some(alias.to_string()),
|
||||
..CliRuntimeOverrides::default()
|
||||
};
|
||||
|
||||
let resolved = ConfigToml::default().resolve_runtime_options(&cli);
|
||||
|
||||
assert_eq!(resolved.provider, ProviderKind::Openrouter);
|
||||
assert_eq!(resolved.model, expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn novita_provider_normalizes_flash_aliases() {
|
||||
let _lock = env_lock();
|
||||
|
||||
+161
-3
@@ -48,6 +48,33 @@ pub const DEFAULT_VOLCENGINE_BASE_URL: &str = "https://ark.cn-beijing.volces.com
|
||||
pub const DEFAULT_WANJIE_ARK_BASE_URL: &str = "https://maas-openapi.wanjiedata.com/api/v1";
|
||||
pub const DEFAULT_OPENROUTER_MODEL: &str = "deepseek/deepseek-v4-pro";
|
||||
pub const DEFAULT_OPENROUTER_FLASH_MODEL: &str = "deepseek/deepseek-v4-flash";
|
||||
pub const OPENROUTER_ARCEE_TRINITY_LARGE_THINKING_MODEL: &str = "arcee-ai/trinity-large-thinking";
|
||||
pub const OPENROUTER_GEMMA_4_31B_MODEL: &str = "google/gemma-4-31b-it";
|
||||
pub const OPENROUTER_GEMMA_4_26B_A4B_MODEL: &str = "google/gemma-4-26b-a4b-it";
|
||||
pub const OPENROUTER_GLM_5_1_MODEL: &str = "z-ai/glm-5.1";
|
||||
pub const OPENROUTER_KIMI_K2_6_MODEL: &str = "moonshotai/kimi-k2.6";
|
||||
pub const OPENROUTER_NEMOTRON_3_NANO_OMNI_MODEL: &str =
|
||||
"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free";
|
||||
pub const OPENROUTER_QWEN_3_7_MAX_MODEL: &str = "qwen/qwen3.7-max";
|
||||
pub const OPENROUTER_QWEN_3_6_35B_A3B_MODEL: &str = "qwen/qwen3.6-35b-a3b";
|
||||
pub const OPENROUTER_QWEN_3_6_27B_MODEL: &str = "qwen/qwen3.6-27b";
|
||||
pub const OPENROUTER_TENCENT_HY3_PREVIEW_MODEL: &str = "tencent/hy3-preview";
|
||||
pub const OPENROUTER_XIAOMI_MIMO_V2_5_PRO_MODEL: &str = "xiaomi/mimo-v2.5-pro";
|
||||
pub const OPENROUTER_XIAOMI_MIMO_V2_5_MODEL: &str = "xiaomi/mimo-v2.5";
|
||||
pub const RECENT_OPENROUTER_LARGE_MODELS: &[&str] = &[
|
||||
OPENROUTER_ARCEE_TRINITY_LARGE_THINKING_MODEL,
|
||||
OPENROUTER_QWEN_3_7_MAX_MODEL,
|
||||
OPENROUTER_XIAOMI_MIMO_V2_5_PRO_MODEL,
|
||||
OPENROUTER_XIAOMI_MIMO_V2_5_MODEL,
|
||||
OPENROUTER_QWEN_3_6_35B_A3B_MODEL,
|
||||
OPENROUTER_QWEN_3_6_27B_MODEL,
|
||||
OPENROUTER_KIMI_K2_6_MODEL,
|
||||
OPENROUTER_GLM_5_1_MODEL,
|
||||
OPENROUTER_TENCENT_HY3_PREVIEW_MODEL,
|
||||
OPENROUTER_GEMMA_4_31B_MODEL,
|
||||
OPENROUTER_GEMMA_4_26B_A4B_MODEL,
|
||||
OPENROUTER_NEMOTRON_3_NANO_OMNI_MODEL,
|
||||
];
|
||||
pub const DEFAULT_OPENROUTER_BASE_URL: &str = "https://openrouter.ai/api/v1";
|
||||
pub const DEFAULT_XIAOMI_MIMO_MODEL: &str = "mimo-v2.5-pro";
|
||||
pub const DEFAULT_XIAOMI_MIMO_BASE_URL: &str = "https://api.xiaomimimo.com/v1";
|
||||
@@ -339,12 +366,15 @@ pub fn provider_capability(provider: ApiProvider, resolved_model: &str) -> Provi
|
||||
let max_output = if is_v4_pro || is_v4_flash {
|
||||
384_000
|
||||
} else {
|
||||
4096
|
||||
crate::models::max_output_tokens_for_model(resolved_model).unwrap_or(4096)
|
||||
};
|
||||
|
||||
// Thinking support: V4 models support thinking on all providers, but
|
||||
// only when the model name matches the V4 family.
|
||||
let thinking_supported = is_v4_pro || is_v4_flash || is_reasoner;
|
||||
let thinking_supported = is_v4_pro
|
||||
|| is_v4_flash
|
||||
|| is_reasoner
|
||||
|| crate::models::model_supports_reasoning(resolved_model);
|
||||
|
||||
// Cache telemetry: returned only by DeepSeek-native and NVIDIA NIM endpoints.
|
||||
let cache_telemetry_supported = matches!(
|
||||
@@ -457,6 +487,57 @@ fn canonical_official_deepseek_model_id(model: &str) -> Option<&'static str> {
|
||||
}
|
||||
}
|
||||
|
||||
fn canonical_openrouter_recent_model_id(model: &str) -> Option<&'static str> {
|
||||
let normalized = model.trim().to_ascii_lowercase();
|
||||
let normalized = normalized.replace(['_', ' '], "-");
|
||||
match normalized.as_str() {
|
||||
OPENROUTER_ARCEE_TRINITY_LARGE_THINKING_MODEL
|
||||
| "trinity"
|
||||
| "trinity-large-thinking"
|
||||
| "arcee-trinity"
|
||||
| "arcee-trinity-large-thinking" => Some(OPENROUTER_ARCEE_TRINITY_LARGE_THINKING_MODEL),
|
||||
OPENROUTER_GEMMA_4_31B_MODEL | "gemma-4-31b" | "gemma-4-31b-it" => {
|
||||
Some(OPENROUTER_GEMMA_4_31B_MODEL)
|
||||
}
|
||||
OPENROUTER_GEMMA_4_26B_A4B_MODEL | "gemma-4-26b-a4b" | "gemma-4-26b-a4b-it" => {
|
||||
Some(OPENROUTER_GEMMA_4_26B_A4B_MODEL)
|
||||
}
|
||||
OPENROUTER_GLM_5_1_MODEL | "glm-5.1" | "glm-5-1" | "zai-glm-5.1" | "zai-glm-5-1" => {
|
||||
Some(OPENROUTER_GLM_5_1_MODEL)
|
||||
}
|
||||
OPENROUTER_KIMI_K2_6_MODEL | "kimi-k2.6" | "kimi-k2-6" | "moonshot-kimi-k2.6" => {
|
||||
Some(OPENROUTER_KIMI_K2_6_MODEL)
|
||||
}
|
||||
OPENROUTER_NEMOTRON_3_NANO_OMNI_MODEL
|
||||
| "nemotron-3-nano-omni"
|
||||
| "nemotron-3-nano-omni-reasoning" => Some(OPENROUTER_NEMOTRON_3_NANO_OMNI_MODEL),
|
||||
OPENROUTER_QWEN_3_7_MAX_MODEL | "qwen3.7-max" | "qwen-3.7-max" | "qwen3-7-max" => {
|
||||
Some(OPENROUTER_QWEN_3_7_MAX_MODEL)
|
||||
}
|
||||
OPENROUTER_QWEN_3_6_35B_A3B_MODEL
|
||||
| "qwen3.6-35b-a3b"
|
||||
| "qwen-3.6-35b-a3b"
|
||||
| "qwen3-6-35b-a3b" => Some(OPENROUTER_QWEN_3_6_35B_A3B_MODEL),
|
||||
OPENROUTER_QWEN_3_6_27B_MODEL | "qwen3.6-27b" | "qwen-3.6-27b" | "qwen3-6-27b" => {
|
||||
Some(OPENROUTER_QWEN_3_6_27B_MODEL)
|
||||
}
|
||||
OPENROUTER_TENCENT_HY3_PREVIEW_MODEL | "hy3-preview" | "tencent-hy3-preview" => {
|
||||
Some(OPENROUTER_TENCENT_HY3_PREVIEW_MODEL)
|
||||
}
|
||||
OPENROUTER_XIAOMI_MIMO_V2_5_PRO_MODEL
|
||||
| "mimo-v2.5-pro"
|
||||
| "mimo-v2-5-pro"
|
||||
| "xiaomi-mimo-v2.5-pro"
|
||||
| "xiaomi-mimo-v2-5-pro" => Some(OPENROUTER_XIAOMI_MIMO_V2_5_PRO_MODEL),
|
||||
OPENROUTER_XIAOMI_MIMO_V2_5_MODEL
|
||||
| "mimo-v2.5"
|
||||
| "mimo-v2-5"
|
||||
| "xiaomi-mimo-v2.5"
|
||||
| "xiaomi-mimo-v2-5" => Some(OPENROUTER_XIAOMI_MIMO_V2_5_MODEL),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Normalize a model selected through the TUI for the active provider.
|
||||
///
|
||||
/// Official DeepSeek endpoints require bare model IDs. Provider-prefixed
|
||||
@@ -469,6 +550,12 @@ fn canonical_official_deepseek_model_id(model: &str) -> Option<&'static str> {
|
||||
/// aliases like `deepseek-v4pro` → `deepseek-v4-pro`.
|
||||
#[must_use]
|
||||
pub fn normalize_model_name_for_provider(provider: ApiProvider, model: &str) -> Option<String> {
|
||||
if matches!(provider, ApiProvider::Openrouter)
|
||||
&& let Some(canonical) = canonical_openrouter_recent_model_id(model)
|
||||
{
|
||||
return Some(canonical.to_string());
|
||||
}
|
||||
|
||||
let normalized = normalize_model_name(model)?;
|
||||
if matches!(provider, ApiProvider::Deepseek | ApiProvider::DeepseekCN)
|
||||
&& let Some(canonical) = canonical_official_deepseek_model_id(&normalized)
|
||||
@@ -500,7 +587,11 @@ pub fn model_completion_names_for_provider(provider: ApiProvider) -> Vec<&'stati
|
||||
match provider {
|
||||
ApiProvider::Deepseek | ApiProvider::DeepseekCN => OFFICIAL_DEEPSEEK_MODELS.to_vec(),
|
||||
ApiProvider::NvidiaNim => vec![DEFAULT_NVIDIA_NIM_MODEL, DEFAULT_NVIDIA_NIM_FLASH_MODEL],
|
||||
ApiProvider::Openrouter => vec![DEFAULT_OPENROUTER_MODEL, DEFAULT_OPENROUTER_FLASH_MODEL],
|
||||
ApiProvider::Openrouter => {
|
||||
let mut models = vec![DEFAULT_OPENROUTER_MODEL, DEFAULT_OPENROUTER_FLASH_MODEL];
|
||||
models.extend_from_slice(RECENT_OPENROUTER_LARGE_MODELS);
|
||||
models
|
||||
}
|
||||
ApiProvider::XiaomiMimo => vec![DEFAULT_XIAOMI_MIMO_MODEL, "mimo-v2.5"],
|
||||
ApiProvider::Novita => vec![DEFAULT_NOVITA_MODEL, DEFAULT_NOVITA_FLASH_MODEL],
|
||||
ApiProvider::Fireworks => vec![DEFAULT_FIREWORKS_MODEL],
|
||||
@@ -3368,6 +3459,11 @@ fn normalize_model_config(config: &mut Config) {
|
||||
}
|
||||
|
||||
fn normalize_model_for_provider(provider: ApiProvider, model: &str) -> Option<String> {
|
||||
if matches!(provider, ApiProvider::Openrouter)
|
||||
&& let Some(canonical) = canonical_openrouter_recent_model_id(model)
|
||||
{
|
||||
return Some(canonical.to_string());
|
||||
}
|
||||
if provider_passes_model_through(provider) {
|
||||
return None;
|
||||
}
|
||||
@@ -6099,6 +6195,27 @@ api_key = "old-openrouter-key"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normalize_model_name_for_provider_maps_recent_openrouter_aliases() {
|
||||
for (alias, expected) in [
|
||||
(
|
||||
"trinity-large-thinking",
|
||||
OPENROUTER_ARCEE_TRINITY_LARGE_THINKING_MODEL,
|
||||
),
|
||||
("qwen3.7-max", OPENROUTER_QWEN_3_7_MAX_MODEL),
|
||||
("qwen3.6-35b-a3b", OPENROUTER_QWEN_3_6_35B_A3B_MODEL),
|
||||
("mimo-v2.5-pro", OPENROUTER_XIAOMI_MIMO_V2_5_PRO_MODEL),
|
||||
("kimi-k2.6", OPENROUTER_KIMI_K2_6_MODEL),
|
||||
("gemma-4-31b-it", OPENROUTER_GEMMA_4_31B_MODEL),
|
||||
("glm-5.1", OPENROUTER_GLM_5_1_MODEL),
|
||||
] {
|
||||
assert_eq!(
|
||||
normalize_model_name_for_provider(ApiProvider::Openrouter, alias).as_deref(),
|
||||
Some(expected)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn model_completion_names_for_deepseek_api_are_deduplicated_bare_ids() {
|
||||
assert_eq!(
|
||||
@@ -6107,6 +6224,23 @@ api_key = "old-openrouter-key"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn model_completion_names_for_openrouter_include_recent_large_models() {
|
||||
let models = model_completion_names_for_provider(ApiProvider::Openrouter);
|
||||
|
||||
for expected in [
|
||||
DEFAULT_OPENROUTER_MODEL,
|
||||
DEFAULT_OPENROUTER_FLASH_MODEL,
|
||||
OPENROUTER_ARCEE_TRINITY_LARGE_THINKING_MODEL,
|
||||
OPENROUTER_QWEN_3_7_MAX_MODEL,
|
||||
OPENROUTER_XIAOMI_MIMO_V2_5_PRO_MODEL,
|
||||
OPENROUTER_QWEN_3_6_35B_A3B_MODEL,
|
||||
OPENROUTER_GEMMA_4_31B_MODEL,
|
||||
] {
|
||||
assert!(models.contains(&expected), "missing {expected}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn model_completion_names_for_moonshot_excludes_oauth_only_kimi_code_model() {
|
||||
assert_eq!(
|
||||
@@ -8181,6 +8315,30 @@ model = "deepseek-ai/deepseek-v4-pro"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn provider_capability_openrouter_recent_large_models_are_reasoning_aware() {
|
||||
for (model, expected_window, expected_output) in [
|
||||
(
|
||||
OPENROUTER_ARCEE_TRINITY_LARGE_THINKING_MODEL,
|
||||
262_144,
|
||||
262_144,
|
||||
),
|
||||
(OPENROUTER_QWEN_3_7_MAX_MODEL, 1_000_000, 65_536),
|
||||
(OPENROUTER_XIAOMI_MIMO_V2_5_PRO_MODEL, 1_000_000, 131_072),
|
||||
] {
|
||||
let cap = provider_capability(ApiProvider::Openrouter, model);
|
||||
|
||||
assert_eq!(cap.context_window, expected_window);
|
||||
assert_eq!(cap.max_output, expected_output);
|
||||
assert!(cap.thinking_supported);
|
||||
assert!(!cap.cache_telemetry_supported);
|
||||
assert_eq!(
|
||||
cap.request_payload_mode,
|
||||
RequestPayloadMode::ChatCompletions
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn provider_capability_xiaomi_mimo_has_thinking_no_cache() {
|
||||
let cap = provider_capability(ApiProvider::XiaomiMimo, DEFAULT_XIAOMI_MIMO_MODEL);
|
||||
|
||||
@@ -229,12 +229,79 @@ pub fn context_window_for_model(model: &str) -> Option<u32> {
|
||||
}
|
||||
return Some(LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS);
|
||||
}
|
||||
if let Some(window) = known_context_window_for_model(&lower) {
|
||||
return Some(window);
|
||||
}
|
||||
if lower.contains("claude") {
|
||||
return Some(200_000);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn known_context_window_for_model(model_lower: &str) -> Option<u32> {
|
||||
match model_lower {
|
||||
"arcee-ai/trinity-large-thinking" => Some(262_144),
|
||||
"google/gemma-4-31b-it"
|
||||
| "google/gemma-4-31b-it:free"
|
||||
| "google/gemma-4-26b-a4b-it"
|
||||
| "google/gemma-4-26b-a4b-it:free"
|
||||
| "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free"
|
||||
| "qwen/qwen3.6-35b-a3b"
|
||||
| "qwen/qwen3.6-27b"
|
||||
| "tencent/hy3-preview"
|
||||
| "moonshotai/kimi-k2.6"
|
||||
| "moonshotai/kimi-k2.6:free" => Some(262_144),
|
||||
"z-ai/glm-5.1" | "z-ai/glm-5v-turbo" => Some(202_752),
|
||||
"qwen/qwen3.7-max" | "xiaomi/mimo-v2.5-pro" | "xiaomi/mimo-v2.5" | "qwen/qwen3.6-plus" => {
|
||||
Some(1_000_000)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn max_output_tokens_for_model(model: &str) -> Option<u32> {
|
||||
let lower = model.to_lowercase();
|
||||
if lower.contains("deepseek") && lower.contains("v4") {
|
||||
return Some(384_000);
|
||||
}
|
||||
match lower.as_str() {
|
||||
"arcee-ai/trinity-large-thinking" | "moonshotai/kimi-k2.6" => Some(262_144),
|
||||
"qwen/qwen3.6-35b-a3b" | "qwen/qwen3.6-27b" => Some(262_140),
|
||||
"xiaomi/mimo-v2.5-pro" | "xiaomi/mimo-v2.5" => Some(131_072),
|
||||
"qwen/qwen3.7-max" | "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free" => Some(65_536),
|
||||
"google/gemma-4-31b-it" => Some(16_384),
|
||||
"google/gemma-4-31b-it:free" | "google/gemma-4-26b-a4b-it:free" => Some(32_768),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn model_supports_reasoning(model: &str) -> bool {
|
||||
let lower = model.to_lowercase();
|
||||
if lower.contains("deepseek") && lower.contains("v4") {
|
||||
return true;
|
||||
}
|
||||
matches!(
|
||||
lower.as_str(),
|
||||
"arcee-ai/trinity-large-thinking"
|
||||
| "google/gemma-4-31b-it"
|
||||
| "google/gemma-4-31b-it:free"
|
||||
| "google/gemma-4-26b-a4b-it"
|
||||
| "google/gemma-4-26b-a4b-it:free"
|
||||
| "moonshotai/kimi-k2.6"
|
||||
| "moonshotai/kimi-k2.6:free"
|
||||
| "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free"
|
||||
| "qwen/qwen3.7-max"
|
||||
| "qwen/qwen3.6-35b-a3b"
|
||||
| "qwen/qwen3.6-27b"
|
||||
| "tencent/hy3-preview"
|
||||
| "xiaomi/mimo-v2.5-pro"
|
||||
| "xiaomi/mimo-v2.5"
|
||||
| "z-ai/glm-5.1"
|
||||
)
|
||||
}
|
||||
|
||||
/// Parse an explicit `_Nk` context-window hint from a model name (vendor
|
||||
/// agnostic). Returns the window in tokens for `N` in `8..=1024`.
|
||||
fn explicit_context_window_hint(model_lower: &str) -> Option<u32> {
|
||||
@@ -419,6 +486,38 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recent_openrouter_large_models_have_static_windows() {
|
||||
for (model, expected_window) in [
|
||||
("arcee-ai/trinity-large-thinking", 262_144),
|
||||
(concat!("qwen/", "qwen3.7-max"), 1_000_000),
|
||||
(concat!("qwen/", "qwen3.6-35b-a3b"), 262_144),
|
||||
(concat!("xiaomi/", "mimo-v2.5-pro"), 1_000_000),
|
||||
("moonshotai/kimi-k2.6", 262_144),
|
||||
("google/gemma-4-31b-it", 262_144),
|
||||
("z-ai/glm-5.1", 202_752),
|
||||
] {
|
||||
assert_eq!(context_window_for_model(model), Some(expected_window));
|
||||
assert!(model_supports_reasoning(model));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recent_openrouter_large_models_have_known_output_caps() {
|
||||
assert_eq!(
|
||||
max_output_tokens_for_model("arcee-ai/trinity-large-thinking"),
|
||||
Some(262_144)
|
||||
);
|
||||
assert_eq!(
|
||||
max_output_tokens_for_model(concat!("qwen/", "qwen3.7-max")),
|
||||
Some(65_536)
|
||||
);
|
||||
assert_eq!(
|
||||
max_output_tokens_for_model(concat!("xiaomi/", "mimo-v2.5-pro")),
|
||||
Some(131_072)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deepseek_models_with_k_suffix_use_hint() {
|
||||
assert_eq!(context_window_for_model("deepseek-v3.2-32k"), Some(32_000));
|
||||
|
||||
@@ -546,7 +546,7 @@ If you are upgrading from older releases:
|
||||
- `provider` (string, optional): `deepseek` (default), `nvidia-nim`, `openai`, `atlascloud`, `wanjie-ark`, `openrouter`, `xiaomi-mimo`, `novita`, `fireworks`, `siliconflow`, `moonshot`, `sglang`, `vllm`, or `ollama`. Legacy `deepseek-cn` configs are still accepted as an alias for `deepseek`; DeepSeek uses the same official host [`https://api.deepseek.com`](https://api-docs.deepseek.com/) worldwide. `nvidia-nim` targets NVIDIA's NIM-hosted DeepSeek endpoints through `https://integrate.api.nvidia.com/v1`; `openai` targets a generic OpenAI-compatible endpoint, defaulting to `https://api.openai.com/v1`; `atlascloud` targets AtlasCloud's OpenAI-compatible endpoint at `https://api.atlascloud.ai/v1`; `wanjie-ark` targets Wanjie Ark's OpenAI-compatible endpoint at `https://maas-openapi.wanjiedata.com/api/v1`; `openrouter` targets `https://openrouter.ai/api/v1`; `xiaomi-mimo` targets Xiaomi MiMo's OpenAI-compatible endpoint at `https://api.xiaomimimo.com/v1`; `novita` targets `https://api.novita.ai/v1`; `fireworks` targets `https://api.fireworks.ai/inference/v1`; `siliconflow` targets SiliconFlow, defaulting to `https://api.siliconflow.com/v1`; `moonshot` targets Moonshot/Kimi, defaulting to `https://api.moonshot.ai/v1`; `sglang` targets a self-hosted OpenAI-compatible endpoint, defaulting to `http://localhost:30000/v1`; `vllm` targets a self-hosted vLLM OpenAI-compatible endpoint, defaulting to `http://localhost:8000/v1`; `ollama` targets Ollama's OpenAI-compatible endpoint, defaulting to `http://localhost:11434/v1`.
|
||||
- `api_key` (string, required for hosted providers): must be non-empty for DeepSeek/hosted providers (or set the provider API key env var). Self-hosted SGLang, vLLM, and Ollama can omit it.
|
||||
- `base_url` (string, optional): defaults to `https://api.deepseek.com/beta` for DeepSeek's OpenAI-compatible Chat Completions API, including legacy `provider = "deepseek-cn"` configs. Other defaults are `https://integrate.api.nvidia.com/v1` for `nvidia-nim`, `https://api.openai.com/v1` for `openai`, `https://api.atlascloud.ai/v1` for `atlascloud`, `https://maas-openapi.wanjiedata.com/api/v1` for `wanjie-ark`, `https://openrouter.ai/api/v1` for `openrouter`, `https://api.xiaomimimo.com/v1` for `xiaomi-mimo`, `https://api.novita.ai/v1` for `novita`, `https://api.fireworks.ai/inference/v1` for `fireworks`, `https://api.siliconflow.com/v1` for `siliconflow`, `https://api.moonshot.ai/v1` for `moonshot`, `http://localhost:30000/v1` for `sglang`, `http://localhost:8000/v1` for `vllm`, and `http://localhost:11434/v1` for `ollama`. Set `https://api.deepseek.com` or `https://api.deepseek.com/v1` explicitly to opt out of DeepSeek beta features.
|
||||
- `default_text_model` (string, optional): defaults to `deepseek-v4-pro` for DeepSeek and generic OpenAI-compatible endpoints, `deepseek-ai/deepseek-v4-pro` for NVIDIA NIM, `deepseek-ai/deepseek-v4-flash` for AtlasCloud, `deepseek-reasoner` for Wanjie Ark, `deepseek/deepseek-v4-pro` for OpenRouter and Novita, `mimo-v2.5-pro` for Xiaomi MiMo, `accounts/fireworks/models/deepseek-v4-pro` for Fireworks, `deepseek-ai/DeepSeek-V4-Pro` for SiliconFlow, `kimi-k2.6` for Moonshot, `deepseek-ai/DeepSeek-V4-Pro` for SGLang/vLLM, and `deepseek-coder:1.3b` for Ollama. Current public DeepSeek IDs are `deepseek-v4-pro` and `deepseek-v4-flash`, both with 1M context windows, 384K max output, and thinking mode enabled by default. Legacy `deepseek-chat` and `deepseek-reasoner` remain compatibility aliases for `deepseek-v4-flash` until July 24, 2026, except SiliconFlow maps `deepseek-reasoner` and `deepseek-r1` to its Pro model while `deepseek-chat` and `deepseek-v3` map to Flash. Provider-specific mappings translate `deepseek-v4-pro` / `deepseek-v4-flash` to each provider's model ID where supported. Generic `openai`, `atlascloud`, `wanjie-ark`, `xiaomi-mimo`, and Ollama model IDs are passed through unchanged. OpenRouter and SiliconFlow provider configs with a custom `base_url` also preserve explicit model values, which lets OpenAI-compatible gateways accept bare model IDs. Use `/models` or `codewhale models` to discover live IDs from your configured endpoint. `CODEWHALE_MODEL` overrides this for a single process; `DEEPSEEK_MODEL` is the legacy alias.
|
||||
- `default_text_model` (string, optional): defaults to `deepseek-v4-pro` for DeepSeek and generic OpenAI-compatible endpoints, `deepseek-ai/deepseek-v4-pro` for NVIDIA NIM, `deepseek-ai/deepseek-v4-flash` for AtlasCloud, `deepseek-reasoner` for Wanjie Ark, `deepseek/deepseek-v4-pro` for OpenRouter and Novita, `mimo-v2.5-pro` for Xiaomi MiMo, `accounts/fireworks/models/deepseek-v4-pro` for Fireworks, `deepseek-ai/DeepSeek-V4-Pro` for SiliconFlow, `kimi-k2.6` for Moonshot, `deepseek-ai/DeepSeek-V4-Pro` for SGLang/vLLM, and `deepseek-coder:1.3b` for Ollama. Current public DeepSeek IDs are `deepseek-v4-pro` and `deepseek-v4-flash`, both with 1M context windows, 384K max output, and thinking mode enabled by default. Legacy `deepseek-chat` and `deepseek-reasoner` remain compatibility aliases for `deepseek-v4-flash` until July 24, 2026, except SiliconFlow maps `deepseek-reasoner` and `deepseek-r1` to its Pro model while `deepseek-chat` and `deepseek-v3` map to Flash. Provider-specific mappings translate `deepseek-v4-pro` / `deepseek-v4-flash` to each provider's model ID where supported. OpenRouter also recognizes recent large IDs such as `arcee-ai/trinity-large-thinking`, `qwen/qwen3.7-max`, `xiaomi/mimo-v2.5-pro`, `qwen/qwen3.6-35b-a3b`, `google/gemma-4-31b-it`, and `moonshotai/kimi-k2.6`. Generic `openai`, `atlascloud`, `wanjie-ark`, `xiaomi-mimo`, and Ollama model IDs are passed through unchanged. OpenRouter and SiliconFlow provider configs with a custom `base_url` also preserve explicit model values, which lets OpenAI-compatible gateways accept bare model IDs. Use `/models` or `codewhale models` to discover live IDs from your configured endpoint. `CODEWHALE_MODEL` overrides this for a single process; `DEEPSEEK_MODEL` is the legacy alias.
|
||||
- `reasoning_effort` (string, optional): `off`, `low`, `medium`, `high`, or `max`; defaults to the configured UI tier. DeepSeek Platform receives top-level `thinking` / `reasoning_effort` fields. NVIDIA NIM receives equivalent settings through `chat_template_kwargs`.
|
||||
- `allow_shell` (bool, optional): defaults to `true` (sandboxed).
|
||||
- `approval_policy` (string, optional): `on-request`, `untrusted`, or `never`. Runtime `approval_mode` editing in `/config` also accepts `on-request` and `untrusted` aliases.
|
||||
|
||||
+14
-2
@@ -117,7 +117,7 @@ endpoint.
|
||||
| `atlascloud` | `[providers.atlascloud]` | `ATLASCLOUD_API_KEY` | `ATLASCLOUD_BASE_URL`; default `https://api.atlascloud.ai/v1` | `deepseek-ai/deepseek-v4-flash`, `deepseek-ai/deepseek-v4-pro` | OpenAI-compatible hosted route. `ATLASCLOUD_MODEL` is accepted by the TUI config path, and the static `ModelRegistry` includes AtlasCloud fallback rows for CLI model resolution. |
|
||||
| `wanjie-ark` | `[providers.wanjie_ark]` | `WANJIE_ARK_API_KEY`, `WANJIE_API_KEY`, `WANJIE_MAAS_API_KEY` | `WANJIE_ARK_BASE_URL`, `WANJIE_BASE_URL`, `WANJIE_MAAS_BASE_URL`; default `https://maas-openapi.wanjiedata.com/api/v1` | `deepseek-reasoner` | OpenAI-compatible hosted route. `WANJIE_ARK_MODEL`, `WANJIE_MODEL`, and `WANJIE_MAAS_MODEL` are accepted. |
|
||||
| `volcengine` | `[providers.volcengine]` | `VOLCENGINE_API_KEY`, `VOLCENGINE_ARK_API_KEY`, `ARK_API_KEY` | `VOLCENGINE_BASE_URL`, `VOLCENGINE_ARK_BASE_URL`, `ARK_BASE_URL`; default `https://ark.cn-beijing.volces.com/api/coding/v3` | `DeepSeek-V4-Pro`, `DeepSeek-V4-Flash` | Volcengine/Volcano Engine Ark OpenAI-compatible coding endpoint. `VOLCENGINE_MODEL` and `VOLCENGINE_ARK_MODEL` are accepted. |
|
||||
| `openrouter` | `[providers.openrouter]` | `OPENROUTER_API_KEY` | `OPENROUTER_BASE_URL`; default `https://openrouter.ai/api/v1` | `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash` | Additive open-model routing layer. It does not replace DeepSeek; it lets users route supported model IDs through OpenRouter when they choose it. |
|
||||
| `openrouter` | `[providers.openrouter]` | `OPENROUTER_API_KEY` | `OPENROUTER_BASE_URL`; default `https://openrouter.ai/api/v1` | `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash`; recent large IDs include `arcee-ai/trinity-large-thinking`, `qwen/qwen3.7-max`, `xiaomi/mimo-v2.5-pro`, `qwen/qwen3.6-35b-a3b`, `google/gemma-4-31b-it`, `z-ai/glm-5.1`, `moonshotai/kimi-k2.6` | Additive open-model routing layer. It does not replace DeepSeek; it lets users route supported model IDs through OpenRouter when they choose it. |
|
||||
| `xiaomi-mimo` | `[providers.xiaomi_mimo]` | `XIAOMI_MIMO_API_KEY`, `MIMO_API_KEY` | `XIAOMI_MIMO_BASE_URL`, `MIMO_BASE_URL`; default `https://api.xiaomimimo.com/v1` | `mimo-v2.5-pro`, `mimo-v2.5` | Xiaomi MiMo OpenAI-compatible chat completions route. It sends `max_completion_tokens` and uses MiMo's `thinking` field for reasoning control. |
|
||||
| `novita` | `[providers.novita]` | `NOVITA_API_KEY` | `NOVITA_BASE_URL`; default `https://api.novita.ai/v1` | `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash` | OpenAI-compatible hosted route for DeepSeek model IDs. Use config or `CODEWHALE_MODEL` / `DEEPSEEK_MODEL` for model overrides. |
|
||||
| `fireworks` | `[providers.fireworks]` | `FIREWORKS_API_KEY` | `FIREWORKS_BASE_URL`; default `https://api.fireworks.ai/inference/v1` | `accounts/fireworks/models/deepseek-v4-pro` | OpenAI-compatible hosted route. Use config or `CODEWHALE_MODEL` / `DEEPSEEK_MODEL` for model overrides. |
|
||||
@@ -136,6 +136,18 @@ includes `mimo-v2.5` for image input. CodeWhale exposes image analysis through t
|
||||
separate `[vision_model]` / `image_analyze` path; set that model to
|
||||
`mimo-v2.5` when using MiMo for vision.
|
||||
|
||||
### Recent OpenRouter Large Models
|
||||
|
||||
OpenRouter completions and static registry rows include the April 2026 onward
|
||||
large open-weight or open-labeled models verified through OpenRouter's model
|
||||
metadata: `arcee-ai/trinity-large-thinking`, `qwen/qwen3.6-35b-a3b`,
|
||||
`qwen/qwen3.6-27b`, `xiaomi/mimo-v2.5-pro`, `xiaomi/mimo-v2.5`,
|
||||
`moonshotai/kimi-k2.6`, `z-ai/glm-5.1`, `tencent/hy3-preview`,
|
||||
`google/gemma-4-31b-it`, `google/gemma-4-26b-a4b-it`, and
|
||||
`nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free`. `qwen/qwen3.7-max`
|
||||
is also included because it is a current user-requested large OpenRouter model,
|
||||
but it is treated as a hosted Qwen model rather than documented as open-weight.
|
||||
|
||||
## Static Model Registry
|
||||
|
||||
`codewhale model list` and `codewhale model resolve` use the static registry in
|
||||
@@ -151,7 +163,7 @@ endpoint when the endpoint supports model listing.
|
||||
| `atlascloud` | `deepseek-ai/deepseek-v4-flash`, `deepseek-ai/deepseek-v4-pro` | yes | yes |
|
||||
| `wanjie-ark` | `deepseek-reasoner` | yes | yes |
|
||||
| `volcengine` | `DeepSeek-V4-Pro`, `DeepSeek-V4-Flash` | yes | yes |
|
||||
| `openrouter` | `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash` | yes | yes |
|
||||
| `openrouter` | `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash`, `arcee-ai/trinity-large-thinking`, `qwen/qwen3.7-max`, `xiaomi/mimo-v2.5-pro`, `xiaomi/mimo-v2.5`, `qwen/qwen3.6-35b-a3b`, `qwen/qwen3.6-27b`, `moonshotai/kimi-k2.6`, `z-ai/glm-5.1`, `tencent/hy3-preview`, `google/gemma-4-31b-it`, `google/gemma-4-26b-a4b-it`, `nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free` | yes | yes |
|
||||
| `xiaomi-mimo` | `mimo-v2.5-pro`, `mimo-v2.5` | yes | yes |
|
||||
| `novita` | `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash` | yes | yes |
|
||||
| `fireworks` | `accounts/fireworks/models/deepseek-v4-pro` | yes | yes |
|
||||
|
||||
Reference in New Issue
Block a user