mirror of
https://github.com/zed-industries/zed.git
synced 2026-06-01 03:14:56 +07:00
deepseek: Add deepseek-v4-pro & deepseek-v4-flash (#54731)
reference: https://api-docs.deepseek.com/ Release Notes: - Added deepseek-v4-pro and deepseek-v4-flash models --------- Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com> Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com> Co-authored-by: MrSubidubi <dev@bahn.sh>
This commit is contained in:
parent
0e5da4cbd4
commit
4c27cee963
3 changed files with 118 additions and 33 deletions
|
|
@ -48,11 +48,11 @@ impl From<Role> for String {
|
|||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
||||
pub enum Model {
|
||||
#[serde(rename = "deepseek-chat")]
|
||||
#[serde(rename = "deepseek-v4-flash")]
|
||||
V4Flash,
|
||||
#[serde(rename = "deepseek-v4-pro")]
|
||||
#[default]
|
||||
Chat,
|
||||
#[serde(rename = "deepseek-reasoner")]
|
||||
Reasoner,
|
||||
V4Pro,
|
||||
#[serde(rename = "custom")]
|
||||
Custom {
|
||||
name: String,
|
||||
|
|
@ -65,29 +65,29 @@ pub enum Model {
|
|||
|
||||
impl Model {
|
||||
pub fn default_fast() -> Self {
|
||||
Model::Chat
|
||||
Model::V4Flash
|
||||
}
|
||||
|
||||
pub fn from_id(id: &str) -> Result<Self> {
|
||||
match id {
|
||||
"deepseek-chat" => Ok(Self::Chat),
|
||||
"deepseek-reasoner" => Ok(Self::Reasoner),
|
||||
"deepseek-v4-flash" => Ok(Self::V4Flash),
|
||||
"deepseek-v4-pro" => Ok(Self::V4Pro),
|
||||
_ => anyhow::bail!("invalid model id {id}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn id(&self) -> &str {
|
||||
match self {
|
||||
Self::Chat => "deepseek-chat",
|
||||
Self::Reasoner => "deepseek-reasoner",
|
||||
Self::V4Flash => "deepseek-v4-flash",
|
||||
Self::V4Pro => "deepseek-v4-pro",
|
||||
Self::Custom { name, .. } => name,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn display_name(&self) -> &str {
|
||||
match self {
|
||||
Self::Chat => "DeepSeek Chat",
|
||||
Self::Reasoner => "DeepSeek Reasoner",
|
||||
Self::V4Flash => "DeepSeek V4 Flash",
|
||||
Self::V4Pro => "DeepSeek V4 Pro",
|
||||
Self::Custom {
|
||||
name, display_name, ..
|
||||
} => display_name.as_ref().unwrap_or(name).as_str(),
|
||||
|
|
@ -96,16 +96,14 @@ impl Model {
|
|||
|
||||
pub fn max_token_count(&self) -> u64 {
|
||||
match self {
|
||||
Self::Chat | Self::Reasoner => 128_000,
|
||||
Self::V4Flash | Self::V4Pro => 1_000_000,
|
||||
Self::Custom { max_tokens, .. } => *max_tokens,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max_output_tokens(&self) -> Option<u64> {
|
||||
match self {
|
||||
// Their API treats this max against the context window, which means we hit the limit a lot
|
||||
// Using the default value of None in the API instead
|
||||
Self::Chat | Self::Reasoner => None,
|
||||
Self::V4Flash | Self::V4Pro => Some(384_000),
|
||||
Self::Custom {
|
||||
max_output_tokens, ..
|
||||
} => *max_output_tokens,
|
||||
|
|
@ -123,11 +121,35 @@ pub struct Request {
|
|||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub temperature: Option<f32>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub thinking: Option<Thinking>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub reasoning_effort: Option<ReasoningEffort>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub response_format: Option<ResponseFormat>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub tools: Vec<ToolDefinition>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Thinking {
|
||||
#[serde(rename = "type")]
|
||||
pub kind: ThinkingType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Eq, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum ThinkingType {
|
||||
Enabled,
|
||||
Disabled,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Eq, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum ReasoningEffort {
|
||||
High,
|
||||
Max,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ResponseFormat {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use anyhow::{Result, anyhow};
|
||||
use collections::{BTreeMap, HashMap};
|
||||
use collections::{HashMap, IndexMap};
|
||||
use credentials_provider::CredentialsProvider;
|
||||
use deepseek::DEEPSEEK_API_URL;
|
||||
|
||||
|
|
@ -9,10 +9,11 @@ use gpui::{AnyView, App, AsyncApp, Context, Entity, SharedString, Task, Window};
|
|||
use http_client::HttpClient;
|
||||
use language_model::{
|
||||
ApiKeyState, AuthenticateError, EnvVar, IconOrSvg, LanguageModel, LanguageModelCompletionError,
|
||||
LanguageModelCompletionEvent, LanguageModelId, LanguageModelName, LanguageModelProvider,
|
||||
LanguageModelProviderId, LanguageModelProviderName, LanguageModelProviderState,
|
||||
LanguageModelRequest, LanguageModelToolChoice, LanguageModelToolResultContent,
|
||||
LanguageModelToolUse, MessageContent, RateLimiter, Role, StopReason, TokenUsage, env_var,
|
||||
LanguageModelCompletionEvent, LanguageModelEffortLevel, LanguageModelId, LanguageModelName,
|
||||
LanguageModelProvider, LanguageModelProviderId, LanguageModelProviderName,
|
||||
LanguageModelProviderState, LanguageModelRequest, LanguageModelToolChoice,
|
||||
LanguageModelToolResultContent, LanguageModelToolUse, MessageContent, RateLimiter, Role,
|
||||
StopReason, TokenUsage, env_var,
|
||||
};
|
||||
pub use settings::DeepseekAvailableModel as AvailableModel;
|
||||
use settings::{Settings, SettingsStore};
|
||||
|
|
@ -164,10 +165,10 @@ impl LanguageModelProvider for DeepSeekLanguageModelProvider {
|
|||
}
|
||||
|
||||
fn provided_models(&self, cx: &App) -> Vec<Arc<dyn LanguageModel>> {
|
||||
let mut models = BTreeMap::default();
|
||||
let mut models = IndexMap::default();
|
||||
|
||||
models.insert("deepseek-chat", deepseek::Model::Chat);
|
||||
models.insert("deepseek-reasoner", deepseek::Model::Reasoner);
|
||||
models.insert("deepseek-v4-flash", deepseek::Model::V4Flash);
|
||||
models.insert("deepseek-v4-pro", deepseek::Model::V4Pro);
|
||||
|
||||
for available_model in &Self::settings(cx).available_models {
|
||||
models.insert(
|
||||
|
|
@ -273,6 +274,32 @@ impl LanguageModel for DeepSeekLanguageModel {
|
|||
true
|
||||
}
|
||||
|
||||
fn supports_thinking(&self) -> bool {
|
||||
matches!(
|
||||
self.model,
|
||||
deepseek::Model::V4Flash | deepseek::Model::V4Pro
|
||||
)
|
||||
}
|
||||
|
||||
fn supported_effort_levels(&self) -> Vec<LanguageModelEffortLevel> {
|
||||
if !self.supports_thinking() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
vec![
|
||||
LanguageModelEffortLevel {
|
||||
name: "High".into(),
|
||||
value: "high".into(),
|
||||
is_default: true,
|
||||
},
|
||||
LanguageModelEffortLevel {
|
||||
name: "Max".into(),
|
||||
value: "max".into(),
|
||||
is_default: false,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn supports_tool_choice(&self, _choice: LanguageModelToolChoice) -> bool {
|
||||
true
|
||||
}
|
||||
|
|
@ -320,7 +347,10 @@ pub fn into_deepseek(
|
|||
model: &deepseek::Model,
|
||||
max_output_tokens: Option<u64>,
|
||||
) -> deepseek::Request {
|
||||
let is_reasoner = model == &deepseek::Model::Reasoner;
|
||||
let thinking = deepseek_thinking(model, request.thinking_allowed);
|
||||
let thinking_enabled = thinking
|
||||
.as_ref()
|
||||
.is_some_and(|thinking| thinking.kind == deepseek::ThinkingType::Enabled);
|
||||
|
||||
let mut messages = Vec::new();
|
||||
let mut current_reasoning: Option<String> = None;
|
||||
|
|
@ -408,11 +438,17 @@ pub fn into_deepseek(
|
|||
messages,
|
||||
stream: true,
|
||||
max_tokens: max_output_tokens,
|
||||
temperature: if is_reasoner {
|
||||
temperature: if thinking_enabled {
|
||||
None
|
||||
} else {
|
||||
request.temperature
|
||||
},
|
||||
thinking,
|
||||
reasoning_effort: if thinking_enabled {
|
||||
into_deepseek_reasoning_effort(request.thinking_effort.as_deref())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
response_format: None,
|
||||
tools: request
|
||||
.tools
|
||||
|
|
@ -428,6 +464,32 @@ pub fn into_deepseek(
|
|||
}
|
||||
}
|
||||
|
||||
fn deepseek_thinking(
|
||||
model: &deepseek::Model,
|
||||
thinking_allowed: bool,
|
||||
) -> Option<deepseek::Thinking> {
|
||||
let kind = match model {
|
||||
deepseek::Model::V4Flash | deepseek::Model::V4Pro => {
|
||||
if thinking_allowed {
|
||||
deepseek::ThinkingType::Enabled
|
||||
} else {
|
||||
deepseek::ThinkingType::Disabled
|
||||
}
|
||||
}
|
||||
deepseek::Model::Custom { .. } => return None,
|
||||
};
|
||||
|
||||
Some(deepseek::Thinking { kind })
|
||||
}
|
||||
|
||||
fn into_deepseek_reasoning_effort(effort: Option<&str>) -> Option<deepseek::ReasoningEffort> {
|
||||
match effort {
|
||||
Some("high") => Some(deepseek::ReasoningEffort::High),
|
||||
Some("max") => Some(deepseek::ReasoningEffort::Max),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DeepSeekEventMapper {
|
||||
tool_calls_by_index: HashMap<usize, RawToolCall>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ Zed will also use the `DEEPSEEK_API_KEY` environment variable if it's defined.
|
|||
|
||||
#### Custom Models {#deepseek-custom-models}
|
||||
|
||||
The Zed agent comes pre-configured to use the latest version for common models (DeepSeek Chat, DeepSeek Reasoner).
|
||||
The Zed agent comes pre-configured to use DeepSeek V4 Flash and DeepSeek V4 Pro.
|
||||
If you wish to use alternate models or customize the API endpoint, you can do so by adding the following to your Zed settings file ([how to edit](../configuring-zed.md#settings-files)):
|
||||
|
||||
```json [settings]
|
||||
|
|
@ -252,15 +252,16 @@ If you wish to use alternate models or customize the API endpoint, you can do so
|
|||
"api_url": "https://api.deepseek.com",
|
||||
"available_models": [
|
||||
{
|
||||
"name": "deepseek-chat",
|
||||
"display_name": "DeepSeek Chat",
|
||||
"max_tokens": 64000
|
||||
"name": "deepseek-v4-flash",
|
||||
"display_name": "DeepSeek V4 Flash",
|
||||
"max_tokens": 1000000,
|
||||
"max_output_tokens": 384000
|
||||
},
|
||||
{
|
||||
"name": "deepseek-reasoner",
|
||||
"display_name": "DeepSeek Reasoner",
|
||||
"max_tokens": 64000,
|
||||
"max_output_tokens": 4096
|
||||
"name": "deepseek-v4-pro",
|
||||
"display_name": "DeepSeek V4 Pro",
|
||||
"max_tokens": 1000000,
|
||||
"max_output_tokens": 384000
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue