fix(config): default deepseek-cn to official api.deepseek.com (#1084)
Sets the `deepseek-cn` provider preset's default `base_url` to the official host (`https://api.deepseek.com`) per [api-docs.deepseek.com](https://api-docs.deepseek.com/). Keeps recognizing `api.deepseeki.com` in URL heuristics and chat-client normalization so existing configs continue to work, and updates the `doctor` strict-tool-mode endpoint hint, docs, and examples accordingly. Closes #1079. Thanks to @Jefsky for the fix.
This commit is contained in:
+2
-3
@@ -6,10 +6,9 @@
|
||||
# Get an API key from DeepSeek, then keep it local in `.env`.
|
||||
# DEEPSEEK_API_KEY=
|
||||
|
||||
# Global endpoint:
|
||||
# Official DeepSeek Platform host (see api-docs.deepseek.com); `deepseek-cn` uses the same host.
|
||||
# DEEPSEEK_BASE_URL=https://api.deepseek.com
|
||||
# China endpoint:
|
||||
# DEEPSEEK_BASE_URL=https://api.deepseeki.com
|
||||
# DEEPSEEK_PROVIDER=deepseek-cn
|
||||
|
||||
# V4 model selection. Compatibility aliases such as `deepseek-chat` normalize
|
||||
# to the current V4 flash model in the TUI.
|
||||
|
||||
@@ -56,7 +56,7 @@ See README.md for project overview, docs/ARCHITECTURE.md for internals.
|
||||
- **Thinking Tokens**: DeepSeek models output thinking blocks (`ContentBlock::Thinking`) before final answers. The TUI streams and displays these with visual distinction.
|
||||
- **Reasoning Models**: `deepseek-v4-pro` and `deepseek-v4-flash` are the documented V4 model IDs. Legacy `deepseek-chat` and `deepseek-reasoner` are compatibility aliases for `deepseek-v4-flash`.
|
||||
- **Large Context Window**: DeepSeek V4 models have 1M-token context windows. Use search tools to navigate efficiently.
|
||||
- **API**: OpenAI-compatible Chat Completions (`/chat/completions`) is the documented DeepSeek API path. Base URL configurable for global (`api.deepseek.com`) or China (`api.deepseeki.com`); `/v1` is accepted for OpenAI SDK compatibility, and `/beta` is only needed for beta features such as strict tool mode, chat prefix completion, and FIM completion.
|
||||
- **API**: OpenAI-compatible Chat Completions (`/chat/completions`) is the documented DeepSeek API path. Base URL uses the official host `api.deepseek.com` for both global and `deepseek-cn` presets; legacy typo host `api.deepseeki.com` remains recognized for backward compatibility. `/v1` is accepted for OpenAI SDK compatibility, and `/beta` is only needed for beta features such as strict tool mode, chat prefix completion, and FIM completion.
|
||||
- **Thinking + Tool Calls**: In V4 thinking mode, assistant messages that contain tool calls must replay their `reasoning_content` in all subsequent requests or the API returns HTTP 400.
|
||||
|
||||
## GitHub Operations
|
||||
|
||||
+2
-2
@@ -19,8 +19,8 @@
|
||||
provider = "deepseek" # deepseek | deepseek-cn | nvidia-nim | openai | openrouter | novita | fireworks | sglang | vllm | ollama
|
||||
api_key = "YOUR_DEEPSEEK_API_KEY" # must be non-empty
|
||||
base_url = "https://api.deepseek.com/beta"
|
||||
# base_url = "https://api.deepseeki.com" # China users
|
||||
# base_url = "https://api.deepseek.com" # opt out of DeepSeek beta features
|
||||
# provider = "deepseek-cn" # mainland China preset (official https://api.deepseek.com)
|
||||
# base_url = "https://api.deepseek.com" # opt out of DeepSeek beta features
|
||||
# Optional custom model request headers for OpenAI-compatible gateways.
|
||||
# Authorization and Content-Type are managed by the client and cannot be overridden here.
|
||||
# http_headers = { "X-Model-Provider-Id" = "your-model-provider" }
|
||||
|
||||
@@ -1526,13 +1526,13 @@ mod tests {
|
||||
..ConfigToml::default()
|
||||
};
|
||||
config.providers.deepseek.api_key = Some("provider-key".to_string());
|
||||
config.providers.deepseek.base_url = Some("https://api.deepseeki.com".to_string());
|
||||
config.providers.deepseek.base_url = Some("https://gateway.example/v1".to_string());
|
||||
config.providers.deepseek.model = Some("deepseek-v4-flash".to_string());
|
||||
|
||||
let resolved = config.resolve_runtime_options(&CliRuntimeOverrides::default());
|
||||
|
||||
assert_eq!(resolved.api_key.as_deref(), Some("provider-key"));
|
||||
assert_eq!(resolved.base_url, "https://api.deepseeki.com");
|
||||
assert_eq!(resolved.base_url, "https://gateway.example/v1");
|
||||
assert_eq!(resolved.model, "deepseek-v4-flash");
|
||||
}
|
||||
|
||||
@@ -1547,7 +1547,7 @@ mod tests {
|
||||
..ConfigToml::default()
|
||||
};
|
||||
config.providers.deepseek.api_key = Some("provider-key".to_string());
|
||||
config.providers.deepseek.base_url = Some("https://api.deepseeki.com".to_string());
|
||||
config.providers.deepseek.base_url = Some("https://gateway.example/v1".to_string());
|
||||
config.providers.deepseek.model = Some("deepseek-v4-flash".to_string());
|
||||
config
|
||||
.http_headers
|
||||
@@ -1566,7 +1566,7 @@ mod tests {
|
||||
let resolved = config.resolve_runtime_options(&CliRuntimeOverrides::default());
|
||||
|
||||
assert_eq!(resolved.api_key.as_deref(), Some("provider-key"));
|
||||
assert_eq!(resolved.base_url, "https://api.deepseeki.com");
|
||||
assert_eq!(resolved.base_url, "https://gateway.example/v1");
|
||||
assert_eq!(resolved.model, "deepseek-v4-flash");
|
||||
assert_eq!(
|
||||
resolved
|
||||
|
||||
@@ -42,7 +42,9 @@ pub const DEFAULT_VLLM_FLASH_MODEL: &str = "deepseek-ai/DeepSeek-V4-Flash";
|
||||
pub const DEFAULT_VLLM_BASE_URL: &str = "http://localhost:8000/v1";
|
||||
pub const DEFAULT_OLLAMA_MODEL: &str = "deepseek-coder:1.3b";
|
||||
pub const DEFAULT_OLLAMA_BASE_URL: &str = "http://localhost:11434/v1";
|
||||
pub const DEFAULT_DEEPSEEKCN_BASE_URL: &str = "https://api.deepseeki.com";
|
||||
/// Official DeepSeek API host per https://api-docs.deepseek.com/ (`deepseek-cn` preset defaults here).
|
||||
/// Legacy typo hostname `api.deepseeki.com` remains recognized in URL heuristics for backward compatibility.
|
||||
pub const DEFAULT_DEEPSEEKCN_BASE_URL: &str = "https://api.deepseek.com";
|
||||
const API_KEYRING_SENTINEL: &str = "__KEYRING__";
|
||||
pub const COMMON_DEEPSEEK_MODELS: &[&str] = &[
|
||||
"deepseek-v4-pro",
|
||||
|
||||
+5
-13
@@ -2438,16 +2438,8 @@ fn known_deepseek_base_url_kind(base_url: &str) -> Option<DeepSeekBaseUrlKind> {
|
||||
}
|
||||
}
|
||||
|
||||
fn recommended_strict_base_url(config: &Config, base_url: &str) -> &'static str {
|
||||
if matches!(
|
||||
config.api_provider(),
|
||||
crate::config::ApiProvider::DeepseekCN
|
||||
) || base_url.to_ascii_lowercase().contains("api.deepseeki.com")
|
||||
{
|
||||
"https://api.deepseeki.com/beta"
|
||||
} else {
|
||||
crate::config::DEFAULT_DEEPSEEK_BASE_URL
|
||||
}
|
||||
fn recommended_strict_base_url(_config: &Config, _base_url: &str) -> &'static str {
|
||||
crate::config::DEFAULT_DEEPSEEK_BASE_URL
|
||||
}
|
||||
|
||||
fn doctor_timeout_recovery_lines(config: &Config) -> Vec<String> {
|
||||
@@ -2463,7 +2455,7 @@ fn doctor_timeout_recovery_lines(config: &Config) -> Vec<String> {
|
||||
&& !target.base_url.contains("api.deepseeki.com") =>
|
||||
{
|
||||
lines.push(
|
||||
"If you are in mainland China, set `provider = \"deepseek-cn\"` or `base_url = \"https://api.deepseeki.com\"` in ~/.deepseek/config.toml, then rerun `deepseek doctor`."
|
||||
"If you are in mainland China, set `provider = \"deepseek-cn\"` or `base_url = \"https://api.deepseek.com\"` in ~/.deepseek/config.toml, then rerun `deepseek doctor`."
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
@@ -4456,7 +4448,7 @@ mod doctor_endpoint_tests {
|
||||
assert!(!status.function_strict_sent);
|
||||
assert_eq!(
|
||||
status.recommended_base_url.as_deref(),
|
||||
Some("https://api.deepseeki.com/beta")
|
||||
Some(crate::config::DEFAULT_DEEPSEEK_BASE_URL)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4516,7 +4508,7 @@ mod doctor_endpoint_tests {
|
||||
|
||||
let text = doctor_timeout_recovery_lines(&config).join("\n");
|
||||
|
||||
assert!(text.contains("api.deepseeki.com"));
|
||||
assert!(text.contains("api.deepseek.com"));
|
||||
assert!(text.contains("provider = \"deepseek-cn\""));
|
||||
assert!(text.contains("deepseek doctor --json"));
|
||||
}
|
||||
|
||||
@@ -1119,7 +1119,7 @@ impl App {
|
||||
} = options;
|
||||
|
||||
// If no provider is explicitly configured AND the system locale
|
||||
// indicates Chinese (zh-*), suggest DeepseekCN (api.deepseeki.com)
|
||||
// indicates Chinese (zh-*), suggest DeepseekCN (official api.deepseek.com preset)
|
||||
// as the appropriate default.
|
||||
let provider = if config.provider.is_none() && is_chinese_system_locale() {
|
||||
let cn_base_url = crate::config::DEFAULT_DEEPSEEKCN_BASE_URL.to_string();
|
||||
|
||||
@@ -356,9 +356,9 @@ If you are upgrading from older releases:
|
||||
|
||||
### Core keys (used by the TUI/engine)
|
||||
|
||||
- `provider` (string, optional): `deepseek` (default), `deepseek-cn`, `nvidia-nim`, `openai`, `openrouter`, `novita`, `fireworks`, `sglang`, `vllm`, or `ollama`. `deepseek-cn` uses DeepSeek's mainland China endpoint (`https://api.deepseeki.com`); `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`; `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), `deepseek-cn`, `nvidia-nim`, `openai`, `openrouter`, `novita`, `fireworks`, `sglang`, `vllm`, or `ollama`. `deepseek-cn` presets DeepSeek Platform for mainland China with the documented host [`https://api.deepseek.com`](https://api-docs.deepseek.com/) (distinct from typo `api.deepseeki.com`, which older configs may still carry and the client accepts as a DeepSeek-compatible host); `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`; `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 in v0.8.16, `https://api.deepseeki.com` for `provider = "deepseek-cn"`, `https://api.openai.com/v1` for `provider = "openai"`, 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.
|
||||
- `base_url` (string, optional): defaults to `https://api.deepseek.com/beta` for DeepSeek's OpenAI-compatible Chat Completions API in v0.8.16, `https://api.deepseek.com` for `provider = "deepseek-cn"`, `https://api.openai.com/v1` for `provider = "openai"`, 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, `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` and Ollama model IDs are passed through unchanged. 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).
|
||||
|
||||
Reference in New Issue
Block a user