feat(provider): add Wanjie Ark support
This commit is contained in:
@@ -255,6 +255,10 @@ deepseek --provider nvidia-nim
|
||||
deepseek auth set --provider atlascloud --api-key "YOUR_ATLASCLOUD_API_KEY"
|
||||
deepseek --provider atlascloud
|
||||
|
||||
# Wanjie Ark
|
||||
deepseek auth set --provider wanjie-ark --api-key "YOUR_WANJIE_API_KEY"
|
||||
deepseek --provider wanjie-ark --model deepseek-reasoner
|
||||
|
||||
# OpenRouter
|
||||
deepseek auth set --provider openrouter --api-key "YOUR_OPENROUTER_API_KEY"
|
||||
deepseek --provider openrouter --model deepseek/deepseek-v4-pro
|
||||
@@ -283,10 +287,9 @@ deepseek --provider ollama --model deepseek-coder:1.3b
|
||||
```
|
||||
|
||||
Inside the TUI, `/provider` opens the provider picker and `/model` opens the
|
||||
model picker. `/provider openrouter` and `/model <id>` switch directly, while
|
||||
`/models` lists live API models. The `/model` picker uses the active provider's
|
||||
live model catalog when the provider exposes one, with provider-aware defaults
|
||||
as a fallback.
|
||||
local model/thinking picker. `/provider openrouter` and `/model <id>` switch
|
||||
directly, while `/models` explicitly fetches and lists live API models when the
|
||||
active provider supports model listing.
|
||||
|
||||
---
|
||||
|
||||
@@ -411,13 +414,14 @@ Key environment variables:
|
||||
| `DEEPSEEK_HTTP_HEADERS` | Optional custom model request headers, e.g. `X-Model-Provider-Id=your-model-provider` |
|
||||
| `DEEPSEEK_MODEL` | Default model |
|
||||
| `DEEPSEEK_STREAM_IDLE_TIMEOUT_SECS` | Stream idle timeout in seconds, default `300`, clamped to `1..=3600` |
|
||||
| `DEEPSEEK_PROVIDER` | `deepseek` (default), `nvidia-nim`, `openai`, `atlascloud`, `openrouter`, `novita`, `fireworks`, `sglang`, `vllm`, `ollama` |
|
||||
| `DEEPSEEK_PROVIDER` | `deepseek` (default), `nvidia-nim`, `openai`, `atlascloud`, `wanjie-ark`, `openrouter`, `novita`, `fireworks`, `sglang`, `vllm`, `ollama` |
|
||||
| `DEEPSEEK_PROFILE` | Config profile name |
|
||||
| `DEEPSEEK_MEMORY` | Set to `on` to enable user memory |
|
||||
| `DEEPSEEK_ALLOW_INSECURE_HTTP=1` | Allow non-local `http://` API base URLs on trusted networks |
|
||||
| `NVIDIA_API_KEY` / `OPENAI_API_KEY` / `ATLASCLOUD_API_KEY` / `OPENROUTER_API_KEY` / `NOVITA_API_KEY` / `FIREWORKS_API_KEY` / `SGLANG_API_KEY` / `VLLM_API_KEY` / `OLLAMA_API_KEY` | Provider auth |
|
||||
| `NVIDIA_API_KEY` / `OPENAI_API_KEY` / `ATLASCLOUD_API_KEY` / `WANJIE_ARK_API_KEY` / `OPENROUTER_API_KEY` / `NOVITA_API_KEY` / `FIREWORKS_API_KEY` / `SGLANG_API_KEY` / `VLLM_API_KEY` / `OLLAMA_API_KEY` | Provider auth |
|
||||
| `OPENAI_BASE_URL` / `OPENAI_MODEL` | Generic OpenAI-compatible endpoint and model ID |
|
||||
| `ATLASCLOUD_BASE_URL` / `ATLASCLOUD_MODEL` | AtlasCloud endpoint and model override |
|
||||
| `WANJIE_ARK_BASE_URL` / `WANJIE_ARK_MODEL` | Wanjie Ark endpoint and model override |
|
||||
| `OPENROUTER_BASE_URL` | OpenRouter endpoint override |
|
||||
| `NOVITA_BASE_URL` | Novita endpoint override |
|
||||
| `FIREWORKS_BASE_URL` | Fireworks endpoint override |
|
||||
|
||||
+15
-6
@@ -12,11 +12,12 @@
|
||||
# Choose which provider to use by default. Per-provider credentials live in the
|
||||
# `[providers.*]` sections near the bottom of
|
||||
# this file — keeping both stored at once means `/provider deepseek` and
|
||||
# `/provider nvidia-nim` (or `--provider openai`, `--provider fireworks`,
|
||||
# `/provider sglang`, `/provider vllm`, `/provider ollama`) toggle without having to
|
||||
# re-enter keys. Top-level `api_key` / `base_url` are still read as DeepSeek
|
||||
# defaults when `[providers.deepseek]` is absent (backward compatibility).
|
||||
provider = "deepseek" # deepseek | deepseek-cn | nvidia-nim | openai | atlascloud | openrouter | novita | fireworks | sglang | vllm | ollama
|
||||
# `/provider nvidia-nim` (or `--provider openai`, `--provider wanjie-ark`,
|
||||
# `--provider fireworks`, `/provider sglang`, `/provider vllm`, `/provider ollama`)
|
||||
# toggle without having to re-enter keys. Top-level `api_key` / `base_url` are
|
||||
# still read as DeepSeek defaults when `[providers.deepseek]` is absent
|
||||
# (backward compatibility).
|
||||
provider = "deepseek" # deepseek | deepseek-cn | nvidia-nim | openai | atlascloud | wanjie-ark | openrouter | novita | fireworks | sglang | vllm | ollama
|
||||
api_key = "YOUR_DEEPSEEK_API_KEY" # must be non-empty
|
||||
base_url = "https://api.deepseek.com/beta"
|
||||
# provider = "deepseek-cn" # legacy alias (official host is still https://api.deepseek.com)
|
||||
@@ -35,6 +36,7 @@ base_url = "https://api.deepseek.com/beta"
|
||||
# deepseek-ai/deepseek-v4-flash — NVIDIA NIM-hosted Flash model ID
|
||||
# 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
|
||||
# accounts/fireworks/models/deepseek-v4-pro — Fireworks AI Pro model ID
|
||||
# deepseek-ai/DeepSeek-V4-Pro — SGLang self-hosted Pro model ID
|
||||
# deepseek-ai/DeepSeek-V4-Flash — SGLang self-hosted Flash model ID
|
||||
@@ -154,12 +156,13 @@ max_subagents = 10 # optional (1-20)
|
||||
# ─────────────────────────────────────────────────────────────────────────────────
|
||||
# Providers can be stored at once; `provider = "..."` (top of file) or
|
||||
# `/provider deepseek` / `/provider nvidia-nim` / `--provider openai` /
|
||||
# `/provider fireworks` switches between them without
|
||||
# `--provider wanjie-ark` / `/provider fireworks` switches between them without
|
||||
# having to re-enter keys. Env vars override anything set here:
|
||||
# DeepSeek: DEEPSEEK_API_KEY, DEEPSEEK_BASE_URL, DEEPSEEK_MODEL
|
||||
# NIM: NVIDIA_API_KEY (or NVIDIA_NIM_API_KEY), NIM_BASE_URL
|
||||
# (or NVIDIA_NIM_BASE_URL / NVIDIA_BASE_URL), NVIDIA_NIM_MODEL
|
||||
# OpenAI-compatible: OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_MODEL
|
||||
# Wanjie Ark: WANJIE_ARK_API_KEY (or WANJIE_API_KEY), WANJIE_ARK_BASE_URL, WANJIE_ARK_MODEL
|
||||
# Fireworks: FIREWORKS_API_KEY, FIREWORKS_BASE_URL
|
||||
# SGLang: SGLANG_BASE_URL, SGLANG_MODEL, optional SGLANG_API_KEY
|
||||
# vLLM: VLLM_BASE_URL, VLLM_MODEL, optional VLLM_API_KEY
|
||||
@@ -193,6 +196,12 @@ max_subagents = 10 # optional (1-20)
|
||||
# base_url = "https://api.atlascloud.ai/v1"
|
||||
# model = "deepseek-ai/deepseek-v4-flash"
|
||||
|
||||
# Wanjie Ark / 万界方舟 OpenAI-compatible endpoint
|
||||
[providers.wanjie_ark]
|
||||
# api_key = "YOUR_WANJIE_API_KEY"
|
||||
# base_url = "https://maas-openapi.wanjiedata.com/api/v1"
|
||||
# model = "deepseek-reasoner" # or the exact model ID enabled on your Wanjie account
|
||||
|
||||
# Fireworks AI-hosted DeepSeek V4 (https://fireworks.ai)
|
||||
[providers.fireworks]
|
||||
# api_key = "YOUR_FIREWORKS_API_KEY"
|
||||
|
||||
@@ -87,6 +87,16 @@ impl Default for ModelRegistry {
|
||||
supports_tools: true,
|
||||
supports_reasoning: false,
|
||||
},
|
||||
ModelInfo {
|
||||
id: "deepseek-reasoner".to_string(),
|
||||
provider: ProviderKind::WanjieArk,
|
||||
aliases: vec![
|
||||
"wanjie-deepseek-reasoner".to_string(),
|
||||
"ark-wanjie-deepseek-reasoner".to_string(),
|
||||
],
|
||||
supports_tools: true,
|
||||
supports_reasoning: true,
|
||||
},
|
||||
ModelInfo {
|
||||
id: "deepseek/deepseek-v4-pro".to_string(),
|
||||
provider: ProviderKind::Openrouter,
|
||||
@@ -361,6 +371,16 @@ mod tests {
|
||||
assert_eq!(resolved.resolved.id, "deepseek/deepseek-v4-pro");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wanjie_ark_default_uses_reasoner_model_id() {
|
||||
let registry = ModelRegistry::default();
|
||||
let resolved = registry.resolve(None, Some(ProviderKind::WanjieArk));
|
||||
|
||||
assert_eq!(resolved.resolved.provider, ProviderKind::WanjieArk);
|
||||
assert_eq!(resolved.resolved.id, "deepseek-reasoner");
|
||||
assert!(resolved.resolved.supports_reasoning);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn novita_default_uses_namespaced_model_id() {
|
||||
let registry = ModelRegistry::default();
|
||||
|
||||
+30
-2
@@ -27,6 +27,7 @@ enum ProviderArg {
|
||||
NvidiaNim,
|
||||
Openai,
|
||||
Atlascloud,
|
||||
WanjieArk,
|
||||
Openrouter,
|
||||
Novita,
|
||||
Fireworks,
|
||||
@@ -42,6 +43,7 @@ impl From<ProviderArg> for ProviderKind {
|
||||
ProviderArg::NvidiaNim => ProviderKind::NvidiaNim,
|
||||
ProviderArg::Openai => ProviderKind::Openai,
|
||||
ProviderArg::Atlascloud => ProviderKind::Atlascloud,
|
||||
ProviderArg::WanjieArk => ProviderKind::WanjieArk,
|
||||
ProviderArg::Openrouter => ProviderKind::Openrouter,
|
||||
ProviderArg::Novita => ProviderKind::Novita,
|
||||
ProviderArg::Fireworks => ProviderKind::Fireworks,
|
||||
@@ -685,6 +687,7 @@ fn provider_slot(provider: ProviderKind) -> &'static str {
|
||||
ProviderKind::NvidiaNim => "nvidia-nim",
|
||||
ProviderKind::Openai => "openai",
|
||||
ProviderKind::Atlascloud => "atlascloud",
|
||||
ProviderKind::WanjieArk => "wanjie-ark",
|
||||
ProviderKind::Openrouter => "openrouter",
|
||||
ProviderKind::Novita => "novita",
|
||||
ProviderKind::Fireworks => "fireworks",
|
||||
@@ -695,11 +698,12 @@ fn provider_slot(provider: ProviderKind) -> &'static str {
|
||||
}
|
||||
|
||||
/// Provider order used by the `auth list` and `auth status` outputs.
|
||||
const PROVIDER_LIST: [ProviderKind; 10] = [
|
||||
const PROVIDER_LIST: [ProviderKind; 11] = [
|
||||
ProviderKind::Deepseek,
|
||||
ProviderKind::NvidiaNim,
|
||||
ProviderKind::Openai,
|
||||
ProviderKind::Atlascloud,
|
||||
ProviderKind::WanjieArk,
|
||||
ProviderKind::Openrouter,
|
||||
ProviderKind::Novita,
|
||||
ProviderKind::Fireworks,
|
||||
@@ -762,6 +766,11 @@ fn provider_env_vars(provider: ProviderKind) -> &'static [&'static str] {
|
||||
ProviderKind::Ollama => &["OLLAMA_API_KEY"],
|
||||
ProviderKind::Openai => &["OPENAI_API_KEY"],
|
||||
ProviderKind::Atlascloud => &["ATLASCLOUD_API_KEY"],
|
||||
ProviderKind::WanjieArk => &[
|
||||
"WANJIE_ARK_API_KEY",
|
||||
"WANJIE_API_KEY",
|
||||
"WANJIE_MAAS_API_KEY",
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1405,6 +1414,7 @@ fn build_tui_command(
|
||||
| ProviderKind::NvidiaNim
|
||||
| ProviderKind::Openai
|
||||
| ProviderKind::Atlascloud
|
||||
| ProviderKind::WanjieArk
|
||||
| ProviderKind::Openrouter
|
||||
| ProviderKind::Novita
|
||||
| ProviderKind::Fireworks
|
||||
@@ -1413,7 +1423,7 @@ fn build_tui_command(
|
||||
| ProviderKind::Ollama
|
||||
) {
|
||||
bail!(
|
||||
"The interactive TUI supports DeepSeek, NVIDIA NIM, OpenAI-compatible, AtlasCloud, OpenRouter, Novita, Fireworks, SGLang, vLLM, and Ollama providers. Remove --provider {} or use `deepseek model ...` for provider registry inspection.",
|
||||
"The interactive TUI supports DeepSeek, NVIDIA NIM, OpenAI-compatible, AtlasCloud, Wanjie Ark, OpenRouter, Novita, Fireworks, SGLang, vLLM, and Ollama providers. Remove --provider {} or use `deepseek model ...` for provider registry inspection.",
|
||||
resolved_runtime.provider.as_str()
|
||||
);
|
||||
}
|
||||
@@ -1438,6 +1448,9 @@ fn build_tui_command(
|
||||
if resolved_runtime.provider == ProviderKind::Atlascloud {
|
||||
cmd.env("ATLASCLOUD_API_KEY", api_key);
|
||||
}
|
||||
if resolved_runtime.provider == ProviderKind::WanjieArk {
|
||||
cmd.env("WANJIE_ARK_API_KEY", api_key);
|
||||
}
|
||||
let source = resolved_runtime
|
||||
.api_key_source
|
||||
.unwrap_or(RuntimeApiKeySource::Env)
|
||||
@@ -1474,6 +1487,9 @@ fn build_tui_command(
|
||||
if resolved_runtime.provider == ProviderKind::Atlascloud {
|
||||
cmd.env("ATLASCLOUD_API_KEY", api_key);
|
||||
}
|
||||
if resolved_runtime.provider == ProviderKind::WanjieArk {
|
||||
cmd.env("WANJIE_ARK_API_KEY", api_key);
|
||||
}
|
||||
cmd.env("DEEPSEEK_API_KEY_SOURCE", "cli");
|
||||
}
|
||||
if let Some(base_url) = cli.base_url.as_ref() {
|
||||
@@ -2062,6 +2078,18 @@ mod tests {
|
||||
}))
|
||||
));
|
||||
|
||||
let cli = parse_ok(&["deepseek", "auth", "set", "--provider", "wanjie-ark"]);
|
||||
assert!(matches!(
|
||||
cli.command,
|
||||
Some(Commands::Auth(AuthArgs {
|
||||
command: AuthCommand::Set {
|
||||
provider: ProviderArg::WanjieArk,
|
||||
api_key: None,
|
||||
api_key_stdin: false,
|
||||
}
|
||||
}))
|
||||
));
|
||||
|
||||
let cli = parse_ok(&["deepseek", "auth", "get", "--provider", "sglang"]);
|
||||
assert!(matches!(
|
||||
cli.command,
|
||||
|
||||
+164
-1
@@ -23,6 +23,8 @@ const DEFAULT_NVIDIA_NIM_BASE_URL: &str = "https://integrate.api.nvidia.com/v1";
|
||||
const DEFAULT_OPENAI_BASE_URL: &str = "https://api.openai.com/v1";
|
||||
const DEFAULT_ATLASCLOUD_MODEL: &str = "deepseek-ai/deepseek-v4-flash";
|
||||
const DEFAULT_ATLASCLOUD_BASE_URL: &str = "https://api.atlascloud.ai/v1";
|
||||
const DEFAULT_WANJIE_ARK_MODEL: &str = "deepseek-reasoner";
|
||||
const DEFAULT_WANJIE_ARK_BASE_URL: &str = "https://maas-openapi.wanjiedata.com/api/v1";
|
||||
const DEFAULT_OPENROUTER_MODEL: &str = "deepseek/deepseek-v4-pro";
|
||||
const DEFAULT_OPENROUTER_FLASH_MODEL: &str = "deepseek/deepseek-v4-flash";
|
||||
const DEFAULT_NOVITA_MODEL: &str = "deepseek/deepseek-v4-pro";
|
||||
@@ -54,6 +56,15 @@ pub enum ProviderKind {
|
||||
NvidiaNim,
|
||||
Openai,
|
||||
Atlascloud,
|
||||
#[serde(
|
||||
alias = "wanjie",
|
||||
alias = "wanjie_ark",
|
||||
alias = "ark-wanjie",
|
||||
alias = "ark_wanjie",
|
||||
alias = "wanjie-maas",
|
||||
alias = "wanjie_maas"
|
||||
)]
|
||||
WanjieArk,
|
||||
Openrouter,
|
||||
Novita,
|
||||
Fireworks,
|
||||
@@ -70,6 +81,7 @@ impl ProviderKind {
|
||||
Self::NvidiaNim => "nvidia-nim",
|
||||
Self::Openai => "openai",
|
||||
Self::Atlascloud => "atlascloud",
|
||||
Self::WanjieArk => "wanjie-ark",
|
||||
Self::Openrouter => "openrouter",
|
||||
Self::Novita => "novita",
|
||||
Self::Fireworks => "fireworks",
|
||||
@@ -87,6 +99,8 @@ impl ProviderKind {
|
||||
"nvidia" | "nvidia-nim" | "nvidia_nim" | "nim" => Some(Self::NvidiaNim),
|
||||
"openai" | "open-ai" => Some(Self::Openai),
|
||||
"atlascloud" | "atlas-cloud" | "atlas_cloud" | "atlas" => Some(Self::Atlascloud),
|
||||
"wanjie" | "wanjie-ark" | "wanjie_ark" | "ark-wanjie" | "ark_wanjie" | "wanjieark"
|
||||
| "wanjie-maas" | "wanjie_maas" | "wanjiemaas" => Some(Self::WanjieArk),
|
||||
"openrouter" | "open_router" => Some(Self::Openrouter),
|
||||
"novita" => Some(Self::Novita),
|
||||
"fireworks" | "fireworks-ai" => Some(Self::Fireworks),
|
||||
@@ -118,6 +132,8 @@ pub struct ProvidersToml {
|
||||
#[serde(default)]
|
||||
pub atlascloud: ProviderConfigToml,
|
||||
#[serde(default)]
|
||||
pub wanjie_ark: ProviderConfigToml,
|
||||
#[serde(default)]
|
||||
pub openrouter: ProviderConfigToml,
|
||||
#[serde(default)]
|
||||
pub novita: ProviderConfigToml,
|
||||
@@ -139,6 +155,7 @@ impl ProvidersToml {
|
||||
ProviderKind::NvidiaNim => &self.nvidia_nim,
|
||||
ProviderKind::Openai => &self.openai,
|
||||
ProviderKind::Atlascloud => &self.atlascloud,
|
||||
ProviderKind::WanjieArk => &self.wanjie_ark,
|
||||
ProviderKind::Openrouter => &self.openrouter,
|
||||
ProviderKind::Novita => &self.novita,
|
||||
ProviderKind::Fireworks => &self.fireworks,
|
||||
@@ -154,6 +171,7 @@ impl ProvidersToml {
|
||||
ProviderKind::NvidiaNim => &mut self.nvidia_nim,
|
||||
ProviderKind::Openai => &mut self.openai,
|
||||
ProviderKind::Atlascloud => &mut self.atlascloud,
|
||||
ProviderKind::WanjieArk => &mut self.wanjie_ark,
|
||||
ProviderKind::Openrouter => &mut self.openrouter,
|
||||
ProviderKind::Novita => &mut self.novita,
|
||||
ProviderKind::Fireworks => &mut self.fireworks,
|
||||
@@ -369,6 +387,10 @@ impl ConfigToml {
|
||||
&mut self.providers.atlascloud,
|
||||
&project.providers.atlascloud,
|
||||
);
|
||||
merge_provider_config(
|
||||
&mut self.providers.wanjie_ark,
|
||||
&project.providers.wanjie_ark,
|
||||
);
|
||||
merge_provider_config(
|
||||
&mut self.providers.openrouter,
|
||||
&project.providers.openrouter,
|
||||
@@ -437,6 +459,12 @@ impl ConfigToml {
|
||||
"providers.atlascloud.http_headers" => {
|
||||
serialize_http_headers(&self.providers.atlascloud.http_headers)
|
||||
}
|
||||
"providers.wanjie_ark.api_key" => self.providers.wanjie_ark.api_key.clone(),
|
||||
"providers.wanjie_ark.base_url" => self.providers.wanjie_ark.base_url.clone(),
|
||||
"providers.wanjie_ark.model" => self.providers.wanjie_ark.model.clone(),
|
||||
"providers.wanjie_ark.http_headers" => {
|
||||
serialize_http_headers(&self.providers.wanjie_ark.http_headers)
|
||||
}
|
||||
"providers.openrouter.api_key" => self.providers.openrouter.api_key.clone(),
|
||||
"providers.openrouter.base_url" => self.providers.openrouter.base_url.clone(),
|
||||
"providers.openrouter.model" => self.providers.openrouter.model.clone(),
|
||||
@@ -547,6 +575,18 @@ impl ConfigToml {
|
||||
"providers.atlascloud.http_headers" => {
|
||||
self.providers.atlascloud.http_headers = parse_http_headers(value)?;
|
||||
}
|
||||
"providers.wanjie_ark.api_key" => {
|
||||
self.providers.wanjie_ark.api_key = Some(value.to_string());
|
||||
}
|
||||
"providers.wanjie_ark.base_url" => {
|
||||
self.providers.wanjie_ark.base_url = Some(value.to_string());
|
||||
}
|
||||
"providers.wanjie_ark.model" => {
|
||||
self.providers.wanjie_ark.model = Some(value.to_string());
|
||||
}
|
||||
"providers.wanjie_ark.http_headers" => {
|
||||
self.providers.wanjie_ark.http_headers = parse_http_headers(value)?;
|
||||
}
|
||||
"providers.nvidia_nim.api_key" => {
|
||||
self.providers.nvidia_nim.api_key = Some(value.to_string());
|
||||
}
|
||||
@@ -679,6 +719,12 @@ impl ConfigToml {
|
||||
"providers.atlascloud.base_url" => self.providers.atlascloud.base_url = None,
|
||||
"providers.atlascloud.model" => self.providers.atlascloud.model = None,
|
||||
"providers.atlascloud.http_headers" => self.providers.atlascloud.http_headers.clear(),
|
||||
"providers.wanjie_ark.api_key" => self.providers.wanjie_ark.api_key = None,
|
||||
"providers.wanjie_ark.base_url" => self.providers.wanjie_ark.base_url = None,
|
||||
"providers.wanjie_ark.model" => self.providers.wanjie_ark.model = None,
|
||||
"providers.wanjie_ark.http_headers" => {
|
||||
self.providers.wanjie_ark.http_headers.clear();
|
||||
}
|
||||
"providers.nvidia_nim.api_key" => self.providers.nvidia_nim.api_key = None,
|
||||
"providers.nvidia_nim.base_url" => self.providers.nvidia_nim.base_url = None,
|
||||
"providers.nvidia_nim.model" => self.providers.nvidia_nim.model = None,
|
||||
@@ -794,6 +840,18 @@ impl ConfigToml {
|
||||
if let Some(v) = serialize_http_headers(&self.providers.atlascloud.http_headers) {
|
||||
out.insert("providers.atlascloud.http_headers".to_string(), v);
|
||||
}
|
||||
if let Some(v) = self.providers.wanjie_ark.api_key.as_ref() {
|
||||
out.insert("providers.wanjie_ark.api_key".to_string(), redact_secret(v));
|
||||
}
|
||||
if let Some(v) = self.providers.wanjie_ark.base_url.as_ref() {
|
||||
out.insert("providers.wanjie_ark.base_url".to_string(), v.clone());
|
||||
}
|
||||
if let Some(v) = self.providers.wanjie_ark.model.as_ref() {
|
||||
out.insert("providers.wanjie_ark.model".to_string(), v.clone());
|
||||
}
|
||||
if let Some(v) = serialize_http_headers(&self.providers.wanjie_ark.http_headers) {
|
||||
out.insert("providers.wanjie_ark.http_headers".to_string(), v);
|
||||
}
|
||||
if let Some(v) = self.providers.nvidia_nim.api_key.as_ref() {
|
||||
out.insert("providers.nvidia_nim.api_key".to_string(), redact_secret(v));
|
||||
}
|
||||
@@ -932,6 +990,7 @@ impl ConfigToml {
|
||||
ProviderKind::NvidiaNim => DEFAULT_NVIDIA_NIM_BASE_URL.to_string(),
|
||||
ProviderKind::Openai => DEFAULT_OPENAI_BASE_URL.to_string(),
|
||||
ProviderKind::Atlascloud => DEFAULT_ATLASCLOUD_BASE_URL.to_string(),
|
||||
ProviderKind::WanjieArk => DEFAULT_WANJIE_ARK_BASE_URL.to_string(),
|
||||
ProviderKind::Openrouter => DEFAULT_OPENROUTER_BASE_URL.to_string(),
|
||||
ProviderKind::Novita => DEFAULT_NOVITA_BASE_URL.to_string(),
|
||||
ProviderKind::Fireworks => DEFAULT_FIREWORKS_BASE_URL.to_string(),
|
||||
@@ -974,6 +1033,7 @@ impl ConfigToml {
|
||||
|
||||
let explicit_model = cli.model.is_some()
|
||||
|| env.model.is_some()
|
||||
|| env.model_for(provider).is_some()
|
||||
|| provider_cfg.model.is_some()
|
||||
|| root_deepseek_model.is_some()
|
||||
|| self.model.is_some();
|
||||
@@ -981,6 +1041,7 @@ impl ConfigToml {
|
||||
.model
|
||||
.clone()
|
||||
.or_else(|| env.model.clone())
|
||||
.or_else(|| env.model_for(provider))
|
||||
.or_else(|| provider_cfg.model.clone())
|
||||
.or(root_deepseek_model)
|
||||
.or_else(|| self.model.clone())
|
||||
@@ -1071,7 +1132,10 @@ pub fn load_project_config(workspace: &Path) -> Option<ConfigToml> {
|
||||
}
|
||||
|
||||
fn normalize_model_for_provider(provider: ProviderKind, model: &str) -> String {
|
||||
if matches!(provider, ProviderKind::Atlascloud | ProviderKind::Ollama) {
|
||||
if matches!(
|
||||
provider,
|
||||
ProviderKind::Atlascloud | ProviderKind::WanjieArk | ProviderKind::Ollama
|
||||
) {
|
||||
return model.to_string();
|
||||
}
|
||||
|
||||
@@ -1130,6 +1194,7 @@ fn default_model_for_provider(provider: ProviderKind) -> &'static str {
|
||||
ProviderKind::NvidiaNim => DEFAULT_NVIDIA_NIM_MODEL,
|
||||
ProviderKind::Openai => DEFAULT_OPENAI_MODEL,
|
||||
ProviderKind::Atlascloud => DEFAULT_ATLASCLOUD_MODEL,
|
||||
ProviderKind::WanjieArk => DEFAULT_WANJIE_ARK_MODEL,
|
||||
ProviderKind::Openrouter => DEFAULT_OPENROUTER_MODEL,
|
||||
ProviderKind::Novita => DEFAULT_NOVITA_MODEL,
|
||||
ProviderKind::Fireworks => DEFAULT_FIREWORKS_MODEL,
|
||||
@@ -1145,6 +1210,7 @@ fn default_base_url_for_provider(provider: ProviderKind) -> &'static str {
|
||||
ProviderKind::NvidiaNim => DEFAULT_NVIDIA_NIM_BASE_URL,
|
||||
ProviderKind::Openai => DEFAULT_OPENAI_BASE_URL,
|
||||
ProviderKind::Atlascloud => DEFAULT_ATLASCLOUD_BASE_URL,
|
||||
ProviderKind::WanjieArk => DEFAULT_WANJIE_ARK_BASE_URL,
|
||||
ProviderKind::Openrouter => DEFAULT_OPENROUTER_BASE_URL,
|
||||
ProviderKind::Novita => DEFAULT_NOVITA_BASE_URL,
|
||||
ProviderKind::Fireworks => DEFAULT_FIREWORKS_BASE_URL,
|
||||
@@ -1491,6 +1557,7 @@ fn normalize_config_file_path(path: PathBuf) -> Result<PathBuf> {
|
||||
struct EnvRuntimeOverrides {
|
||||
provider: Option<ProviderKind>,
|
||||
model: Option<String>,
|
||||
wanjie_ark_model: Option<String>,
|
||||
output_mode: Option<String>,
|
||||
auth_mode: Option<String>,
|
||||
log_level: Option<String>,
|
||||
@@ -1503,6 +1570,7 @@ struct EnvRuntimeOverrides {
|
||||
nvidia_base_url: Option<String>,
|
||||
openai_base_url: Option<String>,
|
||||
atlascloud_base_url: Option<String>,
|
||||
wanjie_ark_base_url: Option<String>,
|
||||
openrouter_base_url: Option<String>,
|
||||
novita_base_url: Option<String>,
|
||||
fireworks_base_url: Option<String>,
|
||||
@@ -1518,6 +1586,11 @@ impl EnvRuntimeOverrides {
|
||||
.ok()
|
||||
.and_then(|v| ProviderKind::parse(&v)),
|
||||
model: std::env::var("DEEPSEEK_MODEL").ok(),
|
||||
wanjie_ark_model: std::env::var("WANJIE_ARK_MODEL")
|
||||
.or_else(|_| std::env::var("WANJIE_MODEL"))
|
||||
.or_else(|_| std::env::var("WANJIE_MAAS_MODEL"))
|
||||
.ok()
|
||||
.filter(|v| !v.trim().is_empty()),
|
||||
output_mode: std::env::var("DEEPSEEK_OUTPUT_MODE").ok(),
|
||||
auth_mode: std::env::var("DEEPSEEK_AUTH_MODE").ok(),
|
||||
log_level: std::env::var("DEEPSEEK_LOG_LEVEL").ok(),
|
||||
@@ -1547,6 +1620,11 @@ impl EnvRuntimeOverrides {
|
||||
atlascloud_base_url: std::env::var("ATLASCLOUD_BASE_URL")
|
||||
.ok()
|
||||
.filter(|v| !v.trim().is_empty()),
|
||||
wanjie_ark_base_url: std::env::var("WANJIE_ARK_BASE_URL")
|
||||
.or_else(|_| std::env::var("WANJIE_BASE_URL"))
|
||||
.or_else(|_| std::env::var("WANJIE_MAAS_BASE_URL"))
|
||||
.ok()
|
||||
.filter(|v| !v.trim().is_empty()),
|
||||
openrouter_base_url: std::env::var("OPENROUTER_BASE_URL")
|
||||
.ok()
|
||||
.filter(|v| !v.trim().is_empty()),
|
||||
@@ -1576,6 +1654,7 @@ impl EnvRuntimeOverrides {
|
||||
ProviderKind::NvidiaNim => self.nvidia_base_url.clone(),
|
||||
ProviderKind::Openai => self.openai_base_url.clone(),
|
||||
ProviderKind::Atlascloud => self.atlascloud_base_url.clone(),
|
||||
ProviderKind::WanjieArk => self.wanjie_ark_base_url.clone(),
|
||||
ProviderKind::Openrouter => self.openrouter_base_url.clone(),
|
||||
ProviderKind::Novita => self.novita_base_url.clone(),
|
||||
ProviderKind::Fireworks => self.fireworks_base_url.clone(),
|
||||
@@ -1584,6 +1663,13 @@ impl EnvRuntimeOverrides {
|
||||
ProviderKind::Ollama => self.ollama_base_url.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn model_for(&self, provider: ProviderKind) -> Option<String> {
|
||||
match provider {
|
||||
ProviderKind::WanjieArk => self.wanjie_ark_model.clone(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -1628,6 +1714,13 @@ mod tests {
|
||||
nvidia_nim_base_url: Option<OsString>,
|
||||
openrouter_api_key: Option<OsString>,
|
||||
openrouter_base_url: Option<OsString>,
|
||||
wanjie_ark_api_key: Option<OsString>,
|
||||
wanjie_ark_base_url: Option<OsString>,
|
||||
wanjie_base_url: Option<OsString>,
|
||||
wanjie_maas_base_url: Option<OsString>,
|
||||
wanjie_ark_model: Option<OsString>,
|
||||
wanjie_model: Option<OsString>,
|
||||
wanjie_maas_model: Option<OsString>,
|
||||
novita_api_key: Option<OsString>,
|
||||
novita_base_url: Option<OsString>,
|
||||
fireworks_api_key: Option<OsString>,
|
||||
@@ -1656,6 +1749,13 @@ mod tests {
|
||||
nvidia_nim_base_url: env::var_os("NVIDIA_NIM_BASE_URL"),
|
||||
openrouter_api_key: env::var_os("OPENROUTER_API_KEY"),
|
||||
openrouter_base_url: env::var_os("OPENROUTER_BASE_URL"),
|
||||
wanjie_ark_api_key: env::var_os("WANJIE_ARK_API_KEY"),
|
||||
wanjie_ark_base_url: env::var_os("WANJIE_ARK_BASE_URL"),
|
||||
wanjie_base_url: env::var_os("WANJIE_BASE_URL"),
|
||||
wanjie_maas_base_url: env::var_os("WANJIE_MAAS_BASE_URL"),
|
||||
wanjie_ark_model: env::var_os("WANJIE_ARK_MODEL"),
|
||||
wanjie_model: env::var_os("WANJIE_MODEL"),
|
||||
wanjie_maas_model: env::var_os("WANJIE_MAAS_MODEL"),
|
||||
novita_api_key: env::var_os("NOVITA_API_KEY"),
|
||||
novita_base_url: env::var_os("NOVITA_BASE_URL"),
|
||||
fireworks_api_key: env::var_os("FIREWORKS_API_KEY"),
|
||||
@@ -1682,6 +1782,13 @@ mod tests {
|
||||
env::remove_var("NVIDIA_NIM_BASE_URL");
|
||||
env::remove_var("OPENROUTER_API_KEY");
|
||||
env::remove_var("OPENROUTER_BASE_URL");
|
||||
env::remove_var("WANJIE_ARK_API_KEY");
|
||||
env::remove_var("WANJIE_ARK_BASE_URL");
|
||||
env::remove_var("WANJIE_BASE_URL");
|
||||
env::remove_var("WANJIE_MAAS_BASE_URL");
|
||||
env::remove_var("WANJIE_ARK_MODEL");
|
||||
env::remove_var("WANJIE_MODEL");
|
||||
env::remove_var("WANJIE_MAAS_MODEL");
|
||||
env::remove_var("NOVITA_API_KEY");
|
||||
env::remove_var("NOVITA_BASE_URL");
|
||||
env::remove_var("FIREWORKS_API_KEY");
|
||||
@@ -1722,6 +1829,13 @@ mod tests {
|
||||
Self::restore_var("NVIDIA_NIM_BASE_URL", self.nvidia_nim_base_url.take());
|
||||
Self::restore_var("OPENROUTER_API_KEY", self.openrouter_api_key.take());
|
||||
Self::restore_var("OPENROUTER_BASE_URL", self.openrouter_base_url.take());
|
||||
Self::restore_var("WANJIE_ARK_API_KEY", self.wanjie_ark_api_key.take());
|
||||
Self::restore_var("WANJIE_ARK_BASE_URL", self.wanjie_ark_base_url.take());
|
||||
Self::restore_var("WANJIE_BASE_URL", self.wanjie_base_url.take());
|
||||
Self::restore_var("WANJIE_MAAS_BASE_URL", self.wanjie_maas_base_url.take());
|
||||
Self::restore_var("WANJIE_ARK_MODEL", self.wanjie_ark_model.take());
|
||||
Self::restore_var("WANJIE_MODEL", self.wanjie_model.take());
|
||||
Self::restore_var("WANJIE_MAAS_MODEL", self.wanjie_maas_model.take());
|
||||
Self::restore_var("NOVITA_API_KEY", self.novita_api_key.take());
|
||||
Self::restore_var("NOVITA_BASE_URL", self.novita_base_url.take());
|
||||
Self::restore_var("FIREWORKS_API_KEY", self.fireworks_api_key.take());
|
||||
@@ -2136,6 +2250,18 @@ mod tests {
|
||||
ProviderKind::parse("ollama-local"),
|
||||
Some(ProviderKind::Ollama)
|
||||
);
|
||||
assert_eq!(
|
||||
ProviderKind::parse("wanjie-ark"),
|
||||
Some(ProviderKind::WanjieArk)
|
||||
);
|
||||
assert_eq!(
|
||||
ProviderKind::parse("ark_wanjie"),
|
||||
Some(ProviderKind::WanjieArk)
|
||||
);
|
||||
|
||||
let parsed: ConfigToml =
|
||||
toml::from_str("provider = \"ark-wanjie\"").expect("wanjie provider alias");
|
||||
assert_eq!(parsed.provider, ProviderKind::WanjieArk);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2202,6 +2328,22 @@ mod tests {
|
||||
assert_eq!(resolved.model, DEFAULT_FIREWORKS_MODEL);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wanjie_ark_provider_defaults_to_openai_compatible_endpoint_and_model() {
|
||||
let _lock = env_lock();
|
||||
let _env = EnvGuard::without_deepseek_runtime_overrides();
|
||||
let config = ConfigToml {
|
||||
provider: ProviderKind::WanjieArk,
|
||||
..ConfigToml::default()
|
||||
};
|
||||
|
||||
let resolved = config.resolve_runtime_options(&CliRuntimeOverrides::default());
|
||||
|
||||
assert_eq!(resolved.provider, ProviderKind::WanjieArk);
|
||||
assert_eq!(resolved.base_url, DEFAULT_WANJIE_ARK_BASE_URL);
|
||||
assert_eq!(resolved.model, DEFAULT_WANJIE_ARK_MODEL);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sglang_provider_defaults_to_local_endpoint_and_model() {
|
||||
let _lock = env_lock();
|
||||
@@ -2412,6 +2554,27 @@ mod tests {
|
||||
assert_eq!(resolved.base_url, DEFAULT_FIREWORKS_BASE_URL);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wanjie_ark_env_api_key_and_base_url_fall_back_when_config_missing() {
|
||||
let _lock = env_lock();
|
||||
let _env = EnvGuard::without_deepseek_runtime_overrides();
|
||||
// Safety: test-only environment mutation guarded by a module mutex.
|
||||
unsafe {
|
||||
env::set_var("DEEPSEEK_PROVIDER", "wanjie-ark");
|
||||
env::set_var("WANJIE_ARK_API_KEY", "wanjie-env-key");
|
||||
env::set_var("WANJIE_ARK_BASE_URL", "https://wanjie.example/api/v1");
|
||||
env::set_var("WANJIE_ARK_MODEL", "account-model-id");
|
||||
}
|
||||
|
||||
let resolved =
|
||||
ConfigToml::default().resolve_runtime_options(&CliRuntimeOverrides::default());
|
||||
|
||||
assert_eq!(resolved.provider, ProviderKind::WanjieArk);
|
||||
assert_eq!(resolved.api_key.as_deref(), Some("wanjie-env-key"));
|
||||
assert_eq!(resolved.base_url, "https://wanjie.example/api/v1");
|
||||
assert_eq!(resolved.model, "account-model-id");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn openrouter_provider_normalizes_flash_aliases() {
|
||||
let _lock = env_lock();
|
||||
|
||||
@@ -540,6 +540,12 @@ pub fn env_for(name: &str) -> Option<String> {
|
||||
"ollama" | "ollama-local" => &["OLLAMA_API_KEY"],
|
||||
"openai" => &["OPENAI_API_KEY"],
|
||||
"atlascloud" | "atlas-cloud" | "atlas_cloud" | "atlas" => &["ATLASCLOUD_API_KEY"],
|
||||
"wanjie" | "wanjie-ark" | "wanjie_ark" | "ark-wanjie" | "ark_wanjie" | "wanjieark"
|
||||
| "wanjie-maas" | "wanjie_maas" | "wanjiemaas" => &[
|
||||
"WANJIE_ARK_API_KEY",
|
||||
"WANJIE_API_KEY",
|
||||
"WANJIE_MAAS_API_KEY",
|
||||
],
|
||||
_ => return None,
|
||||
};
|
||||
for var in candidates {
|
||||
@@ -579,6 +585,9 @@ mod tests {
|
||||
"OLLAMA_API_KEY",
|
||||
"OPENAI_API_KEY",
|
||||
"ATLASCLOUD_API_KEY",
|
||||
"WANJIE_ARK_API_KEY",
|
||||
"WANJIE_API_KEY",
|
||||
"WANJIE_MAAS_API_KEY",
|
||||
SECRET_BACKEND_ENV,
|
||||
] {
|
||||
// Safety: tests serialise on env_lock(); the broader
|
||||
@@ -743,6 +752,19 @@ mod tests {
|
||||
clear_known_envs();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wanjie_ark_env_aliases_resolve() {
|
||||
let _guard = env_lock();
|
||||
clear_known_envs();
|
||||
unsafe { std::env::set_var("WANJIE_API_KEY", "wanjie-key") };
|
||||
|
||||
assert_eq!(env_for("wanjie-ark").as_deref(), Some("wanjie-key"));
|
||||
assert_eq!(env_for("ark_wanjie").as_deref(), Some("wanjie-key"));
|
||||
assert_eq!(env_for("wanjie-maas").as_deref(), Some("wanjie-key"));
|
||||
|
||||
clear_known_envs();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fireworks_env_aliases_resolve() {
|
||||
let _lock = env_lock();
|
||||
|
||||
@@ -905,7 +905,10 @@ pub(super) fn apply_reasoning_effort(
|
||||
"enable_thinking": false,
|
||||
});
|
||||
}
|
||||
ApiProvider::Openai | ApiProvider::Atlascloud | ApiProvider::Ollama => {}
|
||||
ApiProvider::Openai
|
||||
| ApiProvider::Atlascloud
|
||||
| ApiProvider::WanjieArk
|
||||
| ApiProvider::Ollama => {}
|
||||
ApiProvider::NvidiaNim => {
|
||||
body["chat_template_kwargs"] = json!({
|
||||
"thinking": false,
|
||||
@@ -930,7 +933,10 @@ pub(super) fn apply_reasoning_effort(
|
||||
});
|
||||
body["reasoning_effort"] = json!("high");
|
||||
}
|
||||
ApiProvider::Openai | ApiProvider::Atlascloud | ApiProvider::Ollama => {}
|
||||
ApiProvider::Openai
|
||||
| ApiProvider::Atlascloud
|
||||
| ApiProvider::WanjieArk
|
||||
| ApiProvider::Ollama => {}
|
||||
ApiProvider::NvidiaNim => {
|
||||
body["chat_template_kwargs"] = json!({
|
||||
"thinking": true,
|
||||
@@ -956,7 +962,10 @@ pub(super) fn apply_reasoning_effort(
|
||||
});
|
||||
body["reasoning_effort"] = json!("max");
|
||||
}
|
||||
ApiProvider::Openai | ApiProvider::Atlascloud | ApiProvider::Ollama => {}
|
||||
ApiProvider::Openai
|
||||
| ApiProvider::Atlascloud
|
||||
| ApiProvider::WanjieArk
|
||||
| ApiProvider::Ollama => {}
|
||||
ApiProvider::NvidiaNim => {
|
||||
body["chat_template_kwargs"] = json!({
|
||||
"thinking": true,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//! `/provider` with no args opens the picker modal (#52). `/provider <name>`
|
||||
//! keeps the v0.6.6 CLI form for muscle-memory + scripted use.
|
||||
|
||||
use crate::config::{ApiProvider, normalize_model_name};
|
||||
use crate::config::{ApiProvider, normalize_model_name, provider_passes_model_through};
|
||||
use crate::tui::app::{App, AppAction};
|
||||
|
||||
use super::CommandResult;
|
||||
@@ -27,13 +27,13 @@ pub fn provider(app: &mut App, args: Option<&str>) -> CommandResult {
|
||||
|
||||
let Some(target) = ApiProvider::parse(name) else {
|
||||
return CommandResult::error(format!(
|
||||
"Unknown provider '{name}'. Expected: deepseek, nvidia-nim, openai, atlascloud, openrouter, novita, fireworks, sglang, vllm, or ollama."
|
||||
"Unknown provider '{name}'. Expected: deepseek, nvidia-nim, openai, atlascloud, wanjie-ark, openrouter, novita, fireworks, sglang, vllm, or ollama."
|
||||
));
|
||||
};
|
||||
|
||||
let model = match model_arg {
|
||||
None => None,
|
||||
Some(raw) if target == ApiProvider::Ollama => Some(raw.trim().to_string()),
|
||||
Some(raw) if provider_passes_model_through(target) => Some(raw.trim().to_string()),
|
||||
Some(raw) => match normalize_model_name(&expand_model_alias(raw)) {
|
||||
Some(normalized) => Some(normalized),
|
||||
None => {
|
||||
@@ -142,6 +142,19 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn switch_to_wanjie_ark_preserves_model_id() {
|
||||
let mut app = create_test_app();
|
||||
let result = provider(&mut app, Some("ark-wanjie account-model-id"));
|
||||
match result.action {
|
||||
Some(AppAction::SwitchProvider { provider, model }) => {
|
||||
assert_eq!(provider, ApiProvider::WanjieArk);
|
||||
assert_eq!(model.as_deref(), Some("account-model-id"));
|
||||
}
|
||||
other => panic!("expected SwitchProvider, got {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn switch_to_novita_emits_action() {
|
||||
let mut app = create_test_app();
|
||||
|
||||
+242
-4
@@ -28,6 +28,8 @@ pub const DEFAULT_OPENAI_MODEL: &str = "gpt-4.1";
|
||||
pub const DEFAULT_OPENAI_BASE_URL: &str = "https://api.openai.com/v1";
|
||||
pub const DEFAULT_ATLASCLOUD_MODEL: &str = "deepseek-ai/deepseek-v4-flash";
|
||||
pub const DEFAULT_ATLASCLOUD_BASE_URL: &str = "https://api.atlascloud.ai/v1";
|
||||
pub const DEFAULT_WANJIE_ARK_MODEL: &str = "deepseek-reasoner";
|
||||
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 DEFAULT_OPENROUTER_BASE_URL: &str = "https://openrouter.ai/api/v1";
|
||||
@@ -70,6 +72,7 @@ pub enum ApiProvider {
|
||||
NvidiaNim,
|
||||
Openai,
|
||||
Atlascloud,
|
||||
WanjieArk,
|
||||
Openrouter,
|
||||
Novita,
|
||||
Fireworks,
|
||||
@@ -89,6 +92,8 @@ impl ApiProvider {
|
||||
"nvidia" | "nvidia-nim" | "nvidia_nim" | "nim" => Some(Self::NvidiaNim),
|
||||
"openai" | "open-ai" => Some(Self::Openai),
|
||||
"atlascloud" | "atlas-cloud" | "atlas_cloud" | "atlas" => Some(Self::Atlascloud),
|
||||
"wanjie" | "wanjie-ark" | "wanjie_ark" | "ark-wanjie" | "ark_wanjie" | "wanjieark"
|
||||
| "wanjie-maas" | "wanjie_maas" | "wanjiemaas" => Some(Self::WanjieArk),
|
||||
"openrouter" | "open_router" => Some(Self::Openrouter),
|
||||
"novita" => Some(Self::Novita),
|
||||
"fireworks" | "fireworks-ai" => Some(Self::Fireworks),
|
||||
@@ -107,6 +112,7 @@ impl ApiProvider {
|
||||
Self::NvidiaNim => "nvidia-nim",
|
||||
Self::Openai => "openai",
|
||||
Self::Atlascloud => "atlascloud",
|
||||
Self::WanjieArk => "wanjie-ark",
|
||||
Self::Openrouter => "openrouter",
|
||||
Self::Novita => "novita",
|
||||
Self::Fireworks => "fireworks",
|
||||
@@ -125,6 +131,7 @@ impl ApiProvider {
|
||||
Self::NvidiaNim => "NVIDIA NIM",
|
||||
Self::Openai => "OpenAI-compatible",
|
||||
Self::Atlascloud => "AtlasCloud",
|
||||
Self::WanjieArk => "Wanjie Ark",
|
||||
Self::Openrouter => "OpenRouter",
|
||||
Self::Novita => "Novita AI",
|
||||
Self::Fireworks => "Fireworks AI",
|
||||
@@ -142,6 +149,7 @@ impl ApiProvider {
|
||||
Self::NvidiaNim,
|
||||
Self::Openai,
|
||||
Self::Atlascloud,
|
||||
Self::WanjieArk,
|
||||
Self::Openrouter,
|
||||
Self::Novita,
|
||||
Self::Fireworks,
|
||||
@@ -250,6 +258,8 @@ pub fn provider_capability(provider: ApiProvider, resolved_model: &str) -> Provi
|
||||
|| model_lower == "deepseek-v4flash"
|
||||
|| model_lower == "deepseek-v4"
|
||||
|| alias_deprecation.is_some();
|
||||
let is_reasoner = matches!(provider, ApiProvider::WanjieArk)
|
||||
&& (model_lower.contains("reasoner") || model_lower.contains("r1"));
|
||||
|
||||
// Context window: V4-class models get 1M, everything else falls through
|
||||
// to the model's own lookup or a default.
|
||||
@@ -270,7 +280,7 @@ pub fn provider_capability(provider: ApiProvider, resolved_model: &str) -> Provi
|
||||
|
||||
// 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;
|
||||
let thinking_supported = is_v4_pro || is_v4_flash || is_reasoner;
|
||||
|
||||
// Cache telemetry: returned only by DeepSeek-native and NVIDIA NIM endpoints.
|
||||
let cache_telemetry_supported = matches!(
|
||||
@@ -398,6 +408,7 @@ pub fn model_completion_names_for_provider(provider: ApiProvider) -> Vec<&'stati
|
||||
ApiProvider::Openrouter => vec![DEFAULT_OPENROUTER_MODEL, DEFAULT_OPENROUTER_FLASH_MODEL],
|
||||
ApiProvider::Novita => vec![DEFAULT_NOVITA_MODEL, DEFAULT_NOVITA_FLASH_MODEL],
|
||||
ApiProvider::Fireworks => vec![DEFAULT_FIREWORKS_MODEL],
|
||||
ApiProvider::WanjieArk => vec![DEFAULT_WANJIE_ARK_MODEL],
|
||||
ApiProvider::Sglang => vec![DEFAULT_SGLANG_MODEL, DEFAULT_SGLANG_FLASH_MODEL],
|
||||
ApiProvider::Vllm => vec![DEFAULT_VLLM_MODEL, DEFAULT_VLLM_FLASH_MODEL],
|
||||
ApiProvider::Openai | ApiProvider::Atlascloud | ApiProvider::Ollama => {
|
||||
@@ -1194,6 +1205,8 @@ pub struct ProvidersConfig {
|
||||
#[serde(default)]
|
||||
pub atlascloud: ProviderConfig,
|
||||
#[serde(default)]
|
||||
pub wanjie_ark: ProviderConfig,
|
||||
#[serde(default)]
|
||||
pub openrouter: ProviderConfig,
|
||||
#[serde(default)]
|
||||
pub novita: ProviderConfig,
|
||||
@@ -1306,6 +1319,7 @@ impl Config {
|
||||
let table = match provider {
|
||||
ApiProvider::Openai => "providers.openai",
|
||||
ApiProvider::Atlascloud => "providers.atlascloud",
|
||||
ApiProvider::WanjieArk => "providers.wanjie_ark",
|
||||
ApiProvider::Openrouter => "providers.openrouter",
|
||||
ApiProvider::Novita => "providers.novita",
|
||||
ApiProvider::Fireworks => "providers.fireworks",
|
||||
@@ -1328,7 +1342,7 @@ impl Config {
|
||||
&& ApiProvider::parse(provider).is_none()
|
||||
{
|
||||
anyhow::bail!(
|
||||
"Invalid provider '{provider}': expected deepseek, deepseek-cn, nvidia-nim, openai, atlascloud, openrouter, novita, fireworks, sglang, vllm, or ollama."
|
||||
"Invalid provider '{provider}': expected deepseek, deepseek-cn, nvidia-nim, openai, atlascloud, wanjie-ark, openrouter, novita, fireworks, sglang, vllm, or ollama."
|
||||
);
|
||||
}
|
||||
if let Some(ref key) = self.api_key
|
||||
@@ -1446,6 +1460,7 @@ impl Config {
|
||||
ApiProvider::NvidiaNim => &providers.nvidia_nim,
|
||||
ApiProvider::Openai => &providers.openai,
|
||||
ApiProvider::Atlascloud => &providers.atlascloud,
|
||||
ApiProvider::WanjieArk => &providers.wanjie_ark,
|
||||
ApiProvider::Openrouter => &providers.openrouter,
|
||||
ApiProvider::Novita => &providers.novita,
|
||||
ApiProvider::Fireworks => &providers.fireworks,
|
||||
@@ -1521,6 +1536,7 @@ impl Config {
|
||||
ApiProvider::NvidiaNim => DEFAULT_NVIDIA_NIM_MODEL,
|
||||
ApiProvider::Openai => DEFAULT_OPENAI_MODEL,
|
||||
ApiProvider::Atlascloud => DEFAULT_ATLASCLOUD_MODEL,
|
||||
ApiProvider::WanjieArk => DEFAULT_WANJIE_ARK_MODEL,
|
||||
ApiProvider::Openrouter => DEFAULT_OPENROUTER_MODEL,
|
||||
ApiProvider::Novita => DEFAULT_NOVITA_MODEL,
|
||||
ApiProvider::Fireworks => DEFAULT_FIREWORKS_MODEL,
|
||||
@@ -1551,6 +1567,7 @@ impl Config {
|
||||
.cloned(),
|
||||
ApiProvider::Openai
|
||||
| ApiProvider::Atlascloud
|
||||
| ApiProvider::WanjieArk
|
||||
| ApiProvider::Openrouter
|
||||
| ApiProvider::Novita
|
||||
| ApiProvider::Fireworks
|
||||
@@ -1565,6 +1582,7 @@ impl Config {
|
||||
ApiProvider::NvidiaNim => DEFAULT_NVIDIA_NIM_BASE_URL,
|
||||
ApiProvider::Openai => DEFAULT_OPENAI_BASE_URL,
|
||||
ApiProvider::Atlascloud => DEFAULT_ATLASCLOUD_BASE_URL,
|
||||
ApiProvider::WanjieArk => DEFAULT_WANJIE_ARK_BASE_URL,
|
||||
ApiProvider::Openrouter => DEFAULT_OPENROUTER_BASE_URL,
|
||||
ApiProvider::Novita => DEFAULT_NOVITA_BASE_URL,
|
||||
ApiProvider::Fireworks => DEFAULT_FIREWORKS_BASE_URL,
|
||||
@@ -1597,6 +1615,7 @@ impl Config {
|
||||
ApiProvider::NvidiaNim => "nvidia-nim",
|
||||
ApiProvider::Openai => "openai",
|
||||
ApiProvider::Atlascloud => "atlascloud",
|
||||
ApiProvider::WanjieArk => "wanjie-ark",
|
||||
ApiProvider::Openrouter => "openrouter",
|
||||
ApiProvider::Novita => "novita",
|
||||
ApiProvider::Fireworks => "fireworks",
|
||||
@@ -1665,6 +1684,11 @@ impl Config {
|
||||
"AtlasCloud API key not found. Run 'deepseek auth set --provider atlascloud', \
|
||||
set ATLASCLOUD_API_KEY, or add [providers.atlascloud] api_key in ~/.deepseek/config.toml."
|
||||
),
|
||||
ApiProvider::WanjieArk => anyhow::bail!(
|
||||
"Wanjie Ark API key not found. Run 'deepseek auth set --provider wanjie-ark', \
|
||||
set WANJIE_ARK_API_KEY/WANJIE_API_KEY/WANJIE_MAAS_API_KEY, or add \
|
||||
[providers.wanjie_ark] api_key in ~/.deepseek/config.toml."
|
||||
),
|
||||
ApiProvider::Openrouter => anyhow::bail!(
|
||||
"OpenRouter API key not found. Run 'deepseek auth set --provider openrouter', \
|
||||
set OPENROUTER_API_KEY, or add [providers.openrouter] api_key in ~/.deepseek/config.toml."
|
||||
@@ -2177,6 +2201,13 @@ fn apply_env_overrides(config: &mut Config) {
|
||||
.openrouter
|
||||
.base_url = Some(value);
|
||||
}
|
||||
ApiProvider::WanjieArk => {
|
||||
config
|
||||
.providers
|
||||
.get_or_insert_with(ProvidersConfig::default)
|
||||
.wanjie_ark
|
||||
.base_url = Some(value);
|
||||
}
|
||||
ApiProvider::Novita => {
|
||||
config
|
||||
.providers
|
||||
@@ -2265,6 +2296,18 @@ fn apply_env_overrides(config: &mut Config) {
|
||||
.openrouter
|
||||
.base_url = Some(value);
|
||||
}
|
||||
if matches!(config.api_provider(), ApiProvider::WanjieArk)
|
||||
&& let Ok(value) = std::env::var("WANJIE_ARK_BASE_URL")
|
||||
.or_else(|_| std::env::var("WANJIE_BASE_URL"))
|
||||
.or_else(|_| std::env::var("WANJIE_MAAS_BASE_URL"))
|
||||
&& !value.trim().is_empty()
|
||||
{
|
||||
config
|
||||
.providers
|
||||
.get_or_insert_with(ProvidersConfig::default)
|
||||
.wanjie_ark
|
||||
.base_url = Some(value);
|
||||
}
|
||||
if matches!(config.api_provider(), ApiProvider::Novita)
|
||||
&& let Ok(value) = std::env::var("NOVITA_BASE_URL")
|
||||
&& !value.trim().is_empty()
|
||||
@@ -2323,6 +2366,7 @@ fn apply_env_overrides(config: &mut Config) {
|
||||
ApiProvider::NvidiaNim => &mut providers.nvidia_nim,
|
||||
ApiProvider::Openai => &mut providers.openai,
|
||||
ApiProvider::Atlascloud => &mut providers.atlascloud,
|
||||
ApiProvider::WanjieArk => &mut providers.wanjie_ark,
|
||||
ApiProvider::Openrouter => &mut providers.openrouter,
|
||||
ApiProvider::Novita => &mut providers.novita,
|
||||
ApiProvider::Fireworks => &mut providers.fireworks,
|
||||
@@ -2373,6 +2417,17 @@ fn apply_env_overrides(config: &mut Config) {
|
||||
{
|
||||
config.default_text_model = Some(value);
|
||||
}
|
||||
if matches!(config.api_provider(), ApiProvider::WanjieArk)
|
||||
&& let Ok(value) = std::env::var("WANJIE_ARK_MODEL")
|
||||
.or_else(|_| std::env::var("WANJIE_MODEL"))
|
||||
.or_else(|_| std::env::var("WANJIE_MAAS_MODEL"))
|
||||
{
|
||||
config
|
||||
.providers
|
||||
.get_or_insert_with(ProvidersConfig::default)
|
||||
.wanjie_ark
|
||||
.model = Some(value);
|
||||
}
|
||||
if let Ok(value) =
|
||||
std::env::var("DEEPSEEK_MODEL").or_else(|_| std::env::var("DEEPSEEK_DEFAULT_TEXT_MODEL"))
|
||||
{
|
||||
@@ -2398,6 +2453,7 @@ fn apply_env_overrides(config: &mut Config) {
|
||||
ApiProvider::NvidiaNim => &mut providers.nvidia_nim,
|
||||
ApiProvider::Openai => &mut providers.openai,
|
||||
ApiProvider::Atlascloud => &mut providers.atlascloud,
|
||||
ApiProvider::WanjieArk => &mut providers.wanjie_ark,
|
||||
ApiProvider::Openrouter => &mut providers.openrouter,
|
||||
ApiProvider::Novita => &mut providers.novita,
|
||||
ApiProvider::Fireworks => &mut providers.fireworks,
|
||||
@@ -2653,7 +2709,10 @@ fn normalize_model_for_provider(provider: ApiProvider, model: &str) -> Option<St
|
||||
pub(crate) fn provider_passes_model_through(provider: ApiProvider) -> bool {
|
||||
matches!(
|
||||
provider,
|
||||
ApiProvider::Openai | ApiProvider::Atlascloud | ApiProvider::Ollama
|
||||
ApiProvider::Openai
|
||||
| ApiProvider::Atlascloud
|
||||
| ApiProvider::WanjieArk
|
||||
| ApiProvider::Ollama
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2671,6 +2730,7 @@ fn default_base_url_for_provider(provider: ApiProvider) -> &'static str {
|
||||
ApiProvider::NvidiaNim => DEFAULT_NVIDIA_NIM_BASE_URL,
|
||||
ApiProvider::Openai => DEFAULT_OPENAI_BASE_URL,
|
||||
ApiProvider::Atlascloud => DEFAULT_ATLASCLOUD_BASE_URL,
|
||||
ApiProvider::WanjieArk => DEFAULT_WANJIE_ARK_BASE_URL,
|
||||
ApiProvider::Openrouter => DEFAULT_OPENROUTER_BASE_URL,
|
||||
ApiProvider::Novita => DEFAULT_NOVITA_BASE_URL,
|
||||
ApiProvider::Fireworks => DEFAULT_FIREWORKS_BASE_URL,
|
||||
@@ -2901,6 +2961,7 @@ fn merge_providers(
|
||||
nvidia_nim: merge_provider_config(base.nvidia_nim, override_cfg.nvidia_nim),
|
||||
openai: merge_provider_config(base.openai, override_cfg.openai),
|
||||
atlascloud: merge_provider_config(base.atlascloud, override_cfg.atlascloud),
|
||||
wanjie_ark: merge_provider_config(base.wanjie_ark, override_cfg.wanjie_ark),
|
||||
openrouter: merge_provider_config(base.openrouter, override_cfg.openrouter),
|
||||
novita: merge_provider_config(base.novita, override_cfg.novita),
|
||||
fireworks: merge_provider_config(base.fireworks, override_cfg.fireworks),
|
||||
@@ -3306,6 +3367,11 @@ pub fn active_provider_has_env_api_key(config: &Config) -> bool {
|
||||
ApiProvider::Atlascloud => {
|
||||
std::env::var("ATLASCLOUD_API_KEY").is_ok_and(|k| !k.trim().is_empty())
|
||||
}
|
||||
ApiProvider::WanjieArk => {
|
||||
std::env::var("WANJIE_ARK_API_KEY").is_ok_and(|k| !k.trim().is_empty())
|
||||
|| std::env::var("WANJIE_API_KEY").is_ok_and(|k| !k.trim().is_empty())
|
||||
|| std::env::var("WANJIE_MAAS_API_KEY").is_ok_and(|k| !k.trim().is_empty())
|
||||
}
|
||||
ApiProvider::Openrouter => {
|
||||
std::env::var("OPENROUTER_API_KEY").is_ok_and(|k| !k.trim().is_empty())
|
||||
}
|
||||
@@ -3334,6 +3400,7 @@ pub fn has_api_key_for(config: &Config, provider: ApiProvider) -> bool {
|
||||
ApiProvider::NvidiaNim => "NVIDIA_API_KEY",
|
||||
ApiProvider::Openai => "OPENAI_API_KEY",
|
||||
ApiProvider::Atlascloud => "ATLASCLOUD_API_KEY",
|
||||
ApiProvider::WanjieArk => "WANJIE_ARK_API_KEY",
|
||||
ApiProvider::Openrouter => "OPENROUTER_API_KEY",
|
||||
ApiProvider::Novita => "NOVITA_API_KEY",
|
||||
ApiProvider::Fireworks => "FIREWORKS_API_KEY",
|
||||
@@ -3349,6 +3416,12 @@ pub fn has_api_key_for(config: &Config, provider: ApiProvider) -> bool {
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if matches!(provider, ApiProvider::WanjieArk)
|
||||
&& (std::env::var("WANJIE_API_KEY").is_ok_and(|k| !k.trim().is_empty())
|
||||
|| std::env::var("WANJIE_MAAS_API_KEY").is_ok_and(|k| !k.trim().is_empty()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Self-hosted providers typically run without authentication.
|
||||
if matches!(
|
||||
@@ -3407,6 +3480,7 @@ pub fn save_api_key_for(provider: ApiProvider, api_key: &str) -> Result<PathBuf>
|
||||
ApiProvider::NvidiaNim => "providers.nvidia_nim",
|
||||
ApiProvider::Openai => "providers.openai",
|
||||
ApiProvider::Atlascloud => "providers.atlascloud",
|
||||
ApiProvider::WanjieArk => "providers.wanjie_ark",
|
||||
ApiProvider::Openrouter => "providers.openrouter",
|
||||
ApiProvider::Novita => "providers.novita",
|
||||
ApiProvider::Fireworks => "providers.fireworks",
|
||||
@@ -3442,6 +3516,7 @@ pub fn save_api_key_for(provider: ApiProvider, api_key: &str) -> Result<PathBuf>
|
||||
ApiProvider::NvidiaNim => "nvidia_nim",
|
||||
ApiProvider::Openai => "openai",
|
||||
ApiProvider::Atlascloud => "atlascloud",
|
||||
ApiProvider::WanjieArk => "wanjie_ark",
|
||||
ApiProvider::Openrouter => "openrouter",
|
||||
ApiProvider::Novita => "novita",
|
||||
ApiProvider::Fireworks => "fireworks",
|
||||
@@ -3610,6 +3685,15 @@ mod tests {
|
||||
atlascloud_api_key: Option<OsString>,
|
||||
atlascloud_base_url: Option<OsString>,
|
||||
atlascloud_model: Option<OsString>,
|
||||
wanjie_ark_api_key: Option<OsString>,
|
||||
wanjie_api_key: Option<OsString>,
|
||||
wanjie_maas_api_key: Option<OsString>,
|
||||
wanjie_ark_base_url: Option<OsString>,
|
||||
wanjie_base_url: Option<OsString>,
|
||||
wanjie_maas_base_url: Option<OsString>,
|
||||
wanjie_ark_model: Option<OsString>,
|
||||
wanjie_model: Option<OsString>,
|
||||
wanjie_maas_model: Option<OsString>,
|
||||
openrouter_api_key: Option<OsString>,
|
||||
openrouter_base_url: Option<OsString>,
|
||||
novita_api_key: Option<OsString>,
|
||||
@@ -3653,6 +3737,15 @@ mod tests {
|
||||
let atlascloud_api_key_prev = env::var_os("ATLASCLOUD_API_KEY");
|
||||
let atlascloud_base_url_prev = env::var_os("ATLASCLOUD_BASE_URL");
|
||||
let atlascloud_model_prev = env::var_os("ATLASCLOUD_MODEL");
|
||||
let wanjie_ark_api_key_prev = env::var_os("WANJIE_ARK_API_KEY");
|
||||
let wanjie_api_key_prev = env::var_os("WANJIE_API_KEY");
|
||||
let wanjie_maas_api_key_prev = env::var_os("WANJIE_MAAS_API_KEY");
|
||||
let wanjie_ark_base_url_prev = env::var_os("WANJIE_ARK_BASE_URL");
|
||||
let wanjie_base_url_prev = env::var_os("WANJIE_BASE_URL");
|
||||
let wanjie_maas_base_url_prev = env::var_os("WANJIE_MAAS_BASE_URL");
|
||||
let wanjie_ark_model_prev = env::var_os("WANJIE_ARK_MODEL");
|
||||
let wanjie_model_prev = env::var_os("WANJIE_MODEL");
|
||||
let wanjie_maas_model_prev = env::var_os("WANJIE_MAAS_MODEL");
|
||||
let openrouter_api_key_prev = env::var_os("OPENROUTER_API_KEY");
|
||||
let openrouter_base_url_prev = env::var_os("OPENROUTER_BASE_URL");
|
||||
let novita_api_key_prev = env::var_os("NOVITA_API_KEY");
|
||||
@@ -3691,6 +3784,15 @@ mod tests {
|
||||
env::remove_var("ATLASCLOUD_API_KEY");
|
||||
env::remove_var("ATLASCLOUD_BASE_URL");
|
||||
env::remove_var("ATLASCLOUD_MODEL");
|
||||
env::remove_var("WANJIE_ARK_API_KEY");
|
||||
env::remove_var("WANJIE_API_KEY");
|
||||
env::remove_var("WANJIE_MAAS_API_KEY");
|
||||
env::remove_var("WANJIE_ARK_BASE_URL");
|
||||
env::remove_var("WANJIE_BASE_URL");
|
||||
env::remove_var("WANJIE_MAAS_BASE_URL");
|
||||
env::remove_var("WANJIE_ARK_MODEL");
|
||||
env::remove_var("WANJIE_MODEL");
|
||||
env::remove_var("WANJIE_MAAS_MODEL");
|
||||
env::remove_var("OPENROUTER_API_KEY");
|
||||
env::remove_var("OPENROUTER_BASE_URL");
|
||||
env::remove_var("NOVITA_API_KEY");
|
||||
@@ -3729,6 +3831,15 @@ mod tests {
|
||||
atlascloud_api_key: atlascloud_api_key_prev,
|
||||
atlascloud_base_url: atlascloud_base_url_prev,
|
||||
atlascloud_model: atlascloud_model_prev,
|
||||
wanjie_ark_api_key: wanjie_ark_api_key_prev,
|
||||
wanjie_api_key: wanjie_api_key_prev,
|
||||
wanjie_maas_api_key: wanjie_maas_api_key_prev,
|
||||
wanjie_ark_base_url: wanjie_ark_base_url_prev,
|
||||
wanjie_base_url: wanjie_base_url_prev,
|
||||
wanjie_maas_base_url: wanjie_maas_base_url_prev,
|
||||
wanjie_ark_model: wanjie_ark_model_prev,
|
||||
wanjie_model: wanjie_model_prev,
|
||||
wanjie_maas_model: wanjie_maas_model_prev,
|
||||
openrouter_api_key: openrouter_api_key_prev,
|
||||
openrouter_base_url: openrouter_base_url_prev,
|
||||
novita_api_key: novita_api_key_prev,
|
||||
@@ -3776,6 +3887,15 @@ mod tests {
|
||||
Self::restore_var("ATLASCLOUD_API_KEY", self.atlascloud_api_key.take());
|
||||
Self::restore_var("ATLASCLOUD_BASE_URL", self.atlascloud_base_url.take());
|
||||
Self::restore_var("ATLASCLOUD_MODEL", self.atlascloud_model.take());
|
||||
Self::restore_var("WANJIE_ARK_API_KEY", self.wanjie_ark_api_key.take());
|
||||
Self::restore_var("WANJIE_API_KEY", self.wanjie_api_key.take());
|
||||
Self::restore_var("WANJIE_MAAS_API_KEY", self.wanjie_maas_api_key.take());
|
||||
Self::restore_var("WANJIE_ARK_BASE_URL", self.wanjie_ark_base_url.take());
|
||||
Self::restore_var("WANJIE_BASE_URL", self.wanjie_base_url.take());
|
||||
Self::restore_var("WANJIE_MAAS_BASE_URL", self.wanjie_maas_base_url.take());
|
||||
Self::restore_var("WANJIE_ARK_MODEL", self.wanjie_ark_model.take());
|
||||
Self::restore_var("WANJIE_MODEL", self.wanjie_model.take());
|
||||
Self::restore_var("WANJIE_MAAS_MODEL", self.wanjie_maas_model.take());
|
||||
Self::restore_var("OPENROUTER_API_KEY", self.openrouter_api_key.take());
|
||||
Self::restore_var("OPENROUTER_BASE_URL", self.openrouter_base_url.take());
|
||||
Self::restore_var("NOVITA_API_KEY", self.novita_api_key.take());
|
||||
@@ -4061,6 +4181,9 @@ mod tests {
|
||||
"openai" => {
|
||||
providers.openai.api_key = Some(api_key.to_string());
|
||||
}
|
||||
"wanjie-ark" => {
|
||||
providers.wanjie_ark.api_key = Some(api_key.to_string());
|
||||
}
|
||||
"openrouter" => {
|
||||
providers.openrouter.api_key = Some(api_key.to_string());
|
||||
}
|
||||
@@ -4091,7 +4214,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn has_api_key_uses_active_provider_scoped_config_key() {
|
||||
for provider in ["openai", "openrouter", "novita", "fireworks"] {
|
||||
for provider in ["openai", "wanjie-ark", "openrouter", "novita", "fireworks"] {
|
||||
let config = config_with_provider_scoped_key(provider, "provider-config-key");
|
||||
|
||||
assert!(
|
||||
@@ -4106,6 +4229,7 @@ mod tests {
|
||||
let _lock = lock_test_env();
|
||||
for (provider, env_var) in [
|
||||
("openai", "OPENAI_API_KEY"),
|
||||
("wanjie-ark", "WANJIE_ARK_API_KEY"),
|
||||
("openrouter", "OPENROUTER_API_KEY"),
|
||||
("novita", "NOVITA_API_KEY"),
|
||||
("fireworks", "FIREWORKS_API_KEY"),
|
||||
@@ -5101,6 +5225,89 @@ http_headers = { "X-Model-Provider-Id" = "from-file" }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wanjie_ark_provider_uses_documented_defaults() -> Result<()> {
|
||||
let config = Config {
|
||||
provider: Some("wanjie-ark".to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
config.validate()?;
|
||||
assert_eq!(config.api_provider(), ApiProvider::WanjieArk);
|
||||
assert_eq!(config.default_model(), DEFAULT_WANJIE_ARK_MODEL);
|
||||
assert_eq!(config.deepseek_base_url(), DEFAULT_WANJIE_ARK_BASE_URL);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wanjie_ark_env_overrides_provider_base_url_model_and_key() -> Result<()> {
|
||||
let _lock = lock_test_env();
|
||||
let nanos = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_nanos();
|
||||
let temp_root = env::temp_dir().join(format!(
|
||||
"deepseek-tui-wanjie-env-test-{}-{}",
|
||||
std::process::id(),
|
||||
nanos
|
||||
));
|
||||
fs::create_dir_all(&temp_root)?;
|
||||
let _guard = EnvGuard::new(&temp_root);
|
||||
|
||||
unsafe {
|
||||
env::set_var("DEEPSEEK_PROVIDER", "ark-wanjie");
|
||||
env::set_var("WANJIE_ARK_API_KEY", "wanjie-env-key");
|
||||
env::set_var("WANJIE_ARK_BASE_URL", "https://wanjie.example/api/v1");
|
||||
env::set_var("WANJIE_ARK_MODEL", "wanjie-model-id");
|
||||
}
|
||||
|
||||
let config = Config::load(None, None)?;
|
||||
assert_eq!(config.api_provider(), ApiProvider::WanjieArk);
|
||||
assert_eq!(config.deepseek_api_key()?, "wanjie-env-key");
|
||||
assert_eq!(config.deepseek_base_url(), "https://wanjie.example/api/v1");
|
||||
assert_eq!(config.default_model(), "wanjie-model-id");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wanjie_ark_provider_accepts_custom_model_and_table_key() -> Result<()> {
|
||||
let _lock = lock_test_env();
|
||||
let nanos = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_nanos();
|
||||
let temp_root = env::temp_dir().join(format!(
|
||||
"deepseek-tui-wanjie-table-{}-{}",
|
||||
std::process::id(),
|
||||
nanos
|
||||
));
|
||||
fs::create_dir_all(&temp_root)?;
|
||||
let _guard = EnvGuard::new(&temp_root);
|
||||
|
||||
let config_path = temp_root.join(".deepseek").join("config.toml");
|
||||
ensure_parent_dir(&config_path)?;
|
||||
fs::write(
|
||||
&config_path,
|
||||
r#"provider = "wanjie-ark"
|
||||
|
||||
[providers.wanjie_ark]
|
||||
api_key = "wanjie-table-key"
|
||||
base_url = "https://maas-openapi.wanjiedata.com/api/v1"
|
||||
model = "account-model-id"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
let config = Config::load(None, None)?;
|
||||
assert_eq!(config.api_provider(), ApiProvider::WanjieArk);
|
||||
assert_eq!(config.deepseek_api_key()?, "wanjie-table-key");
|
||||
assert_eq!(
|
||||
config.deepseek_base_url(),
|
||||
"https://maas-openapi.wanjiedata.com/api/v1"
|
||||
);
|
||||
assert_eq!(config.default_model(), "account-model-id");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn openai_provider_accepts_custom_model_and_base_url() -> Result<()> {
|
||||
let _lock = lock_test_env();
|
||||
@@ -5699,6 +5906,7 @@ api_key = "novita-table-key"
|
||||
|
||||
let mut config = Config::default();
|
||||
assert!(!has_api_key_for(&config, ApiProvider::Openai));
|
||||
assert!(!has_api_key_for(&config, ApiProvider::WanjieArk));
|
||||
assert!(!has_api_key_for(&config, ApiProvider::Openrouter));
|
||||
assert!(
|
||||
has_api_key_for(&config, ApiProvider::Sglang),
|
||||
@@ -5713,8 +5921,10 @@ api_key = "novita-table-key"
|
||||
unsafe {
|
||||
env::set_var("OPENROUTER_API_KEY", "or-env");
|
||||
env::set_var("OPENAI_API_KEY", "openai-env");
|
||||
env::set_var("WANJIE_API_KEY", "wanjie-env");
|
||||
}
|
||||
assert!(has_api_key_for(&config, ApiProvider::Openai));
|
||||
assert!(has_api_key_for(&config, ApiProvider::WanjieArk));
|
||||
assert!(has_api_key_for(&config, ApiProvider::Openrouter));
|
||||
assert!(!has_api_key_for(&config, ApiProvider::Novita));
|
||||
|
||||
@@ -5722,12 +5932,15 @@ api_key = "novita-table-key"
|
||||
unsafe {
|
||||
env::remove_var("OPENROUTER_API_KEY");
|
||||
env::remove_var("OPENAI_API_KEY");
|
||||
env::remove_var("WANJIE_API_KEY");
|
||||
}
|
||||
let mut providers = ProvidersConfig::default();
|
||||
providers.openai.api_key = Some("file-openai".to_string());
|
||||
providers.wanjie_ark.api_key = Some("file-wanjie".to_string());
|
||||
providers.novita.api_key = Some("file-novita".to_string());
|
||||
config.providers = Some(providers);
|
||||
assert!(has_api_key_for(&config, ApiProvider::Openai));
|
||||
assert!(has_api_key_for(&config, ApiProvider::WanjieArk));
|
||||
assert!(has_api_key_for(&config, ApiProvider::Novita));
|
||||
assert!(!has_api_key_for(&config, ApiProvider::Openrouter));
|
||||
Ok(())
|
||||
@@ -5818,6 +6031,7 @@ api_key = "novita-table-key"
|
||||
Some("novita-saved-key")
|
||||
);
|
||||
save_api_key_for(ApiProvider::Openai, "openai-saved-key")?;
|
||||
save_api_key_for(ApiProvider::WanjieArk, "wanjie-saved-key")?;
|
||||
save_api_key_for(ApiProvider::Fireworks, "fireworks-saved-key")?;
|
||||
save_api_key_for(ApiProvider::Sglang, "sglang-saved-key")?;
|
||||
let contents = fs::read_to_string(&path)?;
|
||||
@@ -5830,6 +6044,14 @@ api_key = "novita-table-key"
|
||||
.and_then(toml::Value::as_str),
|
||||
Some("openai-saved-key")
|
||||
);
|
||||
assert_eq!(
|
||||
parsed
|
||||
.get("providers")
|
||||
.and_then(|p| p.get("wanjie_ark"))
|
||||
.and_then(|t| t.get("api_key"))
|
||||
.and_then(toml::Value::as_str),
|
||||
Some("wanjie-saved-key")
|
||||
);
|
||||
assert_eq!(
|
||||
parsed
|
||||
.get("providers")
|
||||
@@ -6141,6 +6363,22 @@ model = "deepseek-ai/deepseek-v4-pro"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn provider_capability_wanjie_ark_reasoner_has_thinking_no_cache() {
|
||||
let cap = provider_capability(ApiProvider::WanjieArk, DEFAULT_WANJIE_ARK_MODEL);
|
||||
assert_eq!(
|
||||
cap.context_window,
|
||||
crate::models::LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS
|
||||
);
|
||||
assert_eq!(cap.max_output, 4096);
|
||||
assert!(cap.thinking_supported);
|
||||
assert!(!cap.cache_telemetry_supported);
|
||||
assert_eq!(
|
||||
cap.request_payload_mode,
|
||||
RequestPayloadMode::ChatCompletions
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn provider_capability_ollama_is_openai_compatible_without_thinking() {
|
||||
let cap = provider_capability(ApiProvider::Ollama, "deepseek-v3.1:671b");
|
||||
|
||||
@@ -359,6 +359,7 @@ impl Engine {
|
||||
ApiProvider::NvidiaNim => "NVIDIA_API_KEY/NVIDIA_NIM_API_KEY",
|
||||
ApiProvider::Openai => "OPENAI_API_KEY",
|
||||
ApiProvider::Atlascloud => "ATLASCLOUD_API_KEY",
|
||||
ApiProvider::WanjieArk => "WANJIE_ARK_API_KEY/WANJIE_API_KEY/WANJIE_MAAS_API_KEY",
|
||||
ApiProvider::Openrouter => "OPENROUTER_API_KEY",
|
||||
ApiProvider::Novita => "NOVITA_API_KEY",
|
||||
ApiProvider::Fireworks => "FIREWORKS_API_KEY",
|
||||
|
||||
@@ -1473,6 +1473,10 @@ fn run_setup_status(config: &Config, workspace: &Path) -> Result<()> {
|
||||
"ATLASCLOUD_API_KEY",
|
||||
"deepseek auth set --provider atlascloud --api-key \"...\"",
|
||||
),
|
||||
crate::config::ApiProvider::WanjieArk => (
|
||||
"WANJIE_ARK_API_KEY",
|
||||
"deepseek auth set --provider wanjie-ark --api-key \"...\"",
|
||||
),
|
||||
crate::config::ApiProvider::Openrouter => (
|
||||
"OPENROUTER_API_KEY",
|
||||
"deepseek auth set --provider openrouter --api-key \"...\"",
|
||||
@@ -1507,6 +1511,7 @@ fn run_setup_status(config: &Config, workspace: &Path) -> Result<()> {
|
||||
crate::config::ApiProvider::NvidiaNim => "nvidia_nim",
|
||||
crate::config::ApiProvider::Openai => "openai",
|
||||
crate::config::ApiProvider::Atlascloud => "atlascloud",
|
||||
crate::config::ApiProvider::WanjieArk => "wanjie_ark",
|
||||
crate::config::ApiProvider::Openrouter => "openrouter",
|
||||
crate::config::ApiProvider::Novita => "novita",
|
||||
crate::config::ApiProvider::Fireworks => "fireworks",
|
||||
@@ -1718,6 +1723,25 @@ async fn run_doctor(config: &Config, workspace: &Path, config_path_override: Opt
|
||||
"nvidia-nim",
|
||||
&["NVIDIA_API_KEY", "NVIDIA_NIM_API_KEY"][..],
|
||||
),
|
||||
(
|
||||
crate::config::ApiProvider::Openai,
|
||||
"openai",
|
||||
&["OPENAI_API_KEY"][..],
|
||||
),
|
||||
(
|
||||
crate::config::ApiProvider::Atlascloud,
|
||||
"atlascloud",
|
||||
&["ATLASCLOUD_API_KEY"][..],
|
||||
),
|
||||
(
|
||||
crate::config::ApiProvider::WanjieArk,
|
||||
"wanjie-ark",
|
||||
&[
|
||||
"WANJIE_ARK_API_KEY",
|
||||
"WANJIE_API_KEY",
|
||||
"WANJIE_MAAS_API_KEY",
|
||||
][..],
|
||||
),
|
||||
(
|
||||
crate::config::ApiProvider::Openrouter,
|
||||
"openrouter",
|
||||
|
||||
@@ -90,6 +90,7 @@ impl ProviderPickerView {
|
||||
ApiProvider::NvidiaNim => "NVIDIA_API_KEY",
|
||||
ApiProvider::Openai => "OPENAI_API_KEY",
|
||||
ApiProvider::Atlascloud => "ATLASCLOUD_API_KEY",
|
||||
ApiProvider::WanjieArk => "WANJIE_ARK_API_KEY",
|
||||
ApiProvider::Openrouter => "OPENROUTER_API_KEY",
|
||||
ApiProvider::Novita => "NOVITA_API_KEY",
|
||||
ApiProvider::Fireworks => "FIREWORKS_API_KEY",
|
||||
@@ -395,6 +396,7 @@ mod tests {
|
||||
"NVIDIA NIM",
|
||||
"OpenAI-compatible",
|
||||
"AtlasCloud",
|
||||
"Wanjie Ark",
|
||||
"OpenRouter",
|
||||
"Novita AI",
|
||||
"Fireworks AI",
|
||||
|
||||
@@ -5431,6 +5431,7 @@ fn render(f: &mut Frame, app: &mut App) {
|
||||
crate::config::ApiProvider::NvidiaNim => Some("NIM"),
|
||||
crate::config::ApiProvider::Openai => Some("OpenAI"),
|
||||
crate::config::ApiProvider::Atlascloud => Some("Atlas"),
|
||||
crate::config::ApiProvider::WanjieArk => Some("Wanjie"),
|
||||
crate::config::ApiProvider::Openrouter => Some("OR"),
|
||||
crate::config::ApiProvider::Novita => Some("Novita"),
|
||||
crate::config::ApiProvider::Fireworks => Some("Fireworks"),
|
||||
@@ -6194,6 +6195,7 @@ async fn apply_provider_picker_api_key(
|
||||
ApiProvider::NvidiaNim => &mut providers.nvidia_nim,
|
||||
ApiProvider::Openai => &mut providers.openai,
|
||||
ApiProvider::Atlascloud => &mut providers.atlascloud,
|
||||
ApiProvider::WanjieArk => &mut providers.wanjie_ark,
|
||||
ApiProvider::Openrouter => &mut providers.openrouter,
|
||||
ApiProvider::Novita => &mut providers.novita,
|
||||
ApiProvider::Fireworks => &mut providers.fireworks,
|
||||
|
||||
+14
-6
@@ -62,19 +62,24 @@ label without printing the key itself. The command only probes the active
|
||||
provider's keyring entry.
|
||||
|
||||
For hosted, generic OpenAI-compatible, or self-hosted providers, set
|
||||
`provider = "nvidia-nim"`, `"openai"`, `"atlascloud"`, `"fireworks"`,
|
||||
`provider = "nvidia-nim"`, `"openai"`, `"atlascloud"`, `"wanjie-ark"`, `"fireworks"`,
|
||||
`"sglang"`, `"vllm"`, or `"ollama"` or pass `deepseek --provider <name>`. The facade saves provider
|
||||
credentials to the shared user config and forwards the resolved key, base URL,
|
||||
provider, and model to the TUI process. Use
|
||||
`deepseek auth set --provider nvidia-nim --api-key "YOUR_NVIDIA_API_KEY"` or
|
||||
`deepseek auth set --provider openai --api-key "YOUR_OPENAI_COMPATIBLE_API_KEY"` or
|
||||
`deepseek auth set --provider atlascloud --api-key "YOUR_ATLASCLOUD_API_KEY"` or
|
||||
`deepseek auth set --provider wanjie-ark --api-key "YOUR_WANJIE_API_KEY"` or
|
||||
`deepseek auth set --provider fireworks --api-key "YOUR_FIREWORKS_API_KEY"` to
|
||||
save provider keys through the facade. The generic `openai` provider defaults
|
||||
to `https://api.openai.com/v1`, accepts `OPENAI_BASE_URL`, and passes model IDs
|
||||
through unchanged for OpenAI-compatible gateways. `atlascloud` defaults to
|
||||
`https://api.atlascloud.ai/v1`, accepts `ATLASCLOUD_BASE_URL`, and uses
|
||||
`deepseek-ai/deepseek-v4-flash` as its default model. SGLang, vLLM, and Ollama are
|
||||
`deepseek-ai/deepseek-v4-flash` as its default model. `wanjie-ark` targets
|
||||
Wanjie Ark's OpenAI-compatible endpoint at
|
||||
`https://maas-openapi.wanjiedata.com/api/v1`, defaults to `deepseek-reasoner`,
|
||||
and passes model IDs through unchanged because Wanjie model access is
|
||||
account-scoped. SGLang, vLLM, and Ollama are
|
||||
self-hosted and can run without an API key by default. Ollama defaults to
|
||||
`http://localhost:11434/v1` and sends model tags such as `deepseek-coder:1.3b`
|
||||
or `qwen2.5-coder:7b` unchanged. Self-hosted providers and loopback custom
|
||||
@@ -197,7 +202,7 @@ fallbacks after saved config and keyring credentials:
|
||||
- `DEEPSEEK_API_KEY`
|
||||
- `DEEPSEEK_BASE_URL`
|
||||
- `DEEPSEEK_HTTP_HEADERS` (custom model request headers, comma-separated `name=value` pairs)
|
||||
- `DEEPSEEK_PROVIDER` (`deepseek|nvidia-nim|openai|atlascloud|openrouter|novita|fireworks|sglang|vllm|ollama`)
|
||||
- `DEEPSEEK_PROVIDER` (`deepseek|nvidia-nim|openai|atlascloud|wanjie-ark|openrouter|novita|fireworks|sglang|vllm|ollama`)
|
||||
- `DEEPSEEK_MODEL` or `DEEPSEEK_DEFAULT_TEXT_MODEL`
|
||||
- `DEEPSEEK_STREAM_IDLE_TIMEOUT_SECS` (stream idle timeout in seconds; default `300`, clamped to `1..=3600`)
|
||||
- `DEEPSEEK_STREAM_OPEN_TIMEOUT_SECS` (connection setup + response-header wait in seconds; default `45`, clamped to `5..=300`; distinct from the per-chunk idle timeout)
|
||||
@@ -210,6 +215,9 @@ fallbacks after saved config and keyring credentials:
|
||||
- `ATLASCLOUD_API_KEY`
|
||||
- `ATLASCLOUD_BASE_URL`
|
||||
- `ATLASCLOUD_MODEL`
|
||||
- `WANJIE_ARK_API_KEY`, `WANJIE_API_KEY`, or `WANJIE_MAAS_API_KEY`
|
||||
- `WANJIE_ARK_BASE_URL`, `WANJIE_BASE_URL`, or `WANJIE_MAAS_BASE_URL`
|
||||
- `WANJIE_ARK_MODEL`, `WANJIE_MODEL`, or `WANJIE_MAAS_MODEL`
|
||||
- `OPENROUTER_API_KEY`
|
||||
- `OPENROUTER_BASE_URL`
|
||||
- `NOVITA_API_KEY`
|
||||
@@ -418,10 +426,10 @@ If you are upgrading from older releases:
|
||||
|
||||
### Core keys (used by the TUI/engine)
|
||||
|
||||
- `provider` (string, optional): `deepseek` (default), `nvidia-nim`, `openai`, `atlascloud`, `openrouter`, `novita`, `fireworks`, `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`; `fireworks` targets `https://api.fireworks.ai/inference/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`.
|
||||
- `provider` (string, optional): `deepseek` (default), `nvidia-nim`, `openai`, `atlascloud`, `wanjie-ark`, `openrouter`, `novita`, `fireworks`, `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`; `fireworks` targets `https://api.fireworks.ai/inference/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, `https://api.openai.com/v1` for `provider = "openai"`, `https://api.atlascloud.ai/v1` for `provider = "atlascloud"`, or the provider-specific endpoint for hosted/self-hosted providers. 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, `deepseek-ai/deepseek-v4-pro` for NVIDIA NIM, `gpt-4.1` for generic OpenAI-compatible endpoints, `deepseek-ai/deepseek-v4-flash` for AtlasCloud, `accounts/fireworks/models/deepseek-v4-pro` for Fireworks, `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. Provider-specific mappings translate `deepseek-v4-pro` / `deepseek-v4-flash` to each provider's model ID where supported. Generic `openai`, `atlascloud`, and Ollama model IDs are passed through unchanged. OpenRouter provider configs with a custom `base_url` also preserve explicit model values, which lets OpenAI-compatible gateways accept bare model IDs. Use `/models` or `deepseek models` to discover live IDs from your configured endpoint. `DEEPSEEK_MODEL` overrides this for a single process.
|
||||
- `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, `https://api.openai.com/v1` for `provider = "openai"`, `https://api.atlascloud.ai/v1` for `provider = "atlascloud"`, `https://maas-openapi.wanjiedata.com/api/v1` for `provider = "wanjie-ark"`, or the provider-specific endpoint for hosted/self-hosted providers. 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, `deepseek-ai/deepseek-v4-pro` for NVIDIA NIM, `gpt-4.1` for generic OpenAI-compatible endpoints, `deepseek-ai/deepseek-v4-flash` for AtlasCloud, `deepseek-reasoner` for Wanjie Ark, `accounts/fireworks/models/deepseek-v4-pro` for Fireworks, `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. Provider-specific mappings translate `deepseek-v4-pro` / `deepseek-v4-flash` to each provider's model ID where supported. Generic `openai`, `atlascloud`, `wanjie-ark`, and Ollama model IDs are passed through unchanged. OpenRouter provider configs with a custom `base_url` also preserve explicit model values, which lets OpenAI-compatible gateways accept bare model IDs. Use `/models` or `deepseek models` to discover live IDs from your configured endpoint. `DEEPSEEK_MODEL` overrides this for a single process.
|
||||
- `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.
|
||||
|
||||
Reference in New Issue
Block a user