opencode: Model updates + thinking levels (#54880)
Leftovers after https://github.com/zed-industries/zed/pull/53651 Updated models: - **Zen**: GPT 5.5 and GPT 5.5 Pro - not tested because I don't have a Zen subscription and I stubbornly refuse to get one - **Go**: DeepSeek V4 Pro and DeepSeek V4 Flash - failing due to https://github.com/anomalyco/opencode/issues/24224 - **Go**: MiMo V2.5 and MiMo V2.5 Pro - tested, confirmed working - **Free**: Ling 2.6 Flash, [available for "a limited time"](https://x.com/opencode/status/2046717718028513694) - tested, confirmed working - **Free**: Hy3 Preview, [available until May 8](https://x.com/opencode/status/2047328981435756824) - tested, confirmed working When testing the new models and comparing with OpenCode CLI, I realized the [variants](https://opencode.ai/docs/models/#built-in-variants)/thinking effort configuration was not supported by the Zed Agent implementation. I added that for OpenCode Go models, after manually checking what each model supports in OpenCode. Reasoning levels and everything seems to work (UI looks good, model works) but I have no idea how to specifically test reasoning levels without doing a full benchmark 🤷 I did not add the same thing for OpenCode Zen models because I could not figure out a way to get the supported variants. @benbrandt let me know if you want me to take this out of this PR and to keep just the model updates! Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Release Notes: - OpenCode: add new models (GPT 5.5, DeepSeek V4, MiMo V2.5, Ling 2.6, Hy3) - OpenCode Go: add support for configurable reasoning effort levels --------- Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
This commit is contained in:
1 parent
d47e73c1ff
commit
2b0f1fa68c
6 files changed
+201
-19
No files matched your search
Generated
+1
@@ -11872,6 +11872,7 @@ dependencies = [
|
||||
"futures 0.3.32",
|
||||
"google_ai",
|
||||
"http_client",
|
||||
"language_model_core",
|
||||
"schemars 1.0.4",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
||||
@@ -7,9 +7,10 @@ use gpui::{AnyView, App, AsyncApp, Context, Entity, SharedString, Task, Window};
|
||||
use http_client::{AsyncBody, HttpClient, http};
|
||||
use language_model::{
|
||||
ApiKeyState, AuthenticateError, EnvVar, IconOrSvg, LanguageModel, LanguageModelCompletionError,
|
||||
LanguageModelCompletionEvent, LanguageModelId, LanguageModelName, LanguageModelProvider,
|
||||
LanguageModelProviderId, LanguageModelProviderName, LanguageModelProviderState,
|
||||
LanguageModelRequest, LanguageModelToolChoice, RateLimiter, env_var,
|
||||
LanguageModelCompletionEvent, LanguageModelEffortLevel, LanguageModelId, LanguageModelName,
|
||||
LanguageModelProvider, LanguageModelProviderId, LanguageModelProviderName,
|
||||
LanguageModelProviderState, LanguageModelRequest, LanguageModelToolChoice, RateLimiter,
|
||||
ReasoningEffort, env_var,
|
||||
};
|
||||
use opencode::{ApiProtocol, OPENCODE_API_URL, OpenCodeSubscription};
|
||||
pub use settings::OpenCodeAvailableModel as AvailableModel;
|
||||
@@ -29,6 +30,27 @@ use crate::provider::open_ai::{
|
||||
OpenAiEventMapper, OpenAiResponseEventMapper, into_open_ai, into_open_ai_response,
|
||||
};
|
||||
|
||||
fn normalize_reasoning_effort(effort: &str) -> Option<ReasoningEffort> {
|
||||
match effort.trim().to_ascii_lowercase().as_str() {
|
||||
"minimal" => Some(ReasoningEffort::Minimal),
|
||||
"low" => Some(ReasoningEffort::Low),
|
||||
"medium" => Some(ReasoningEffort::Medium),
|
||||
"high" => Some(ReasoningEffort::High),
|
||||
"max" | "xhigh" => Some(ReasoningEffort::XHigh),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn reasoning_effort_display(effort: ReasoningEffort) -> (&'static str, &'static str) {
|
||||
match effort {
|
||||
ReasoningEffort::Minimal => ("Minimal", "minimal"),
|
||||
ReasoningEffort::Low => ("Low", "low"),
|
||||
ReasoningEffort::Medium => ("Medium", "medium"),
|
||||
ReasoningEffort::High => ("High", "high"),
|
||||
ReasoningEffort::XHigh => ("Max", "max"),
|
||||
}
|
||||
}
|
||||
|
||||
const PROVIDER_ID: LanguageModelProviderId = LanguageModelProviderId::new("opencode");
|
||||
const PROVIDER_NAME: LanguageModelProviderName = LanguageModelProviderName::new("OpenCode");
|
||||
|
||||
@@ -254,6 +276,7 @@ impl LanguageModelProvider for OpenCodeLanguageModelProvider {
|
||||
max_tokens: model.max_tokens,
|
||||
max_output_tokens: model.max_output_tokens,
|
||||
protocol,
|
||||
reasoning_effort_levels: model.reasoning_effort_levels.clone(),
|
||||
custom_model_api_url: model.custom_model_api_url.clone(),
|
||||
};
|
||||
let key = format!("{}/{}", subscription.id_prefix(), model.name);
|
||||
@@ -522,6 +545,36 @@ impl LanguageModel for OpenCodeLanguageModel {
|
||||
self.model.supports_images()
|
||||
}
|
||||
|
||||
fn supports_thinking(&self) -> bool {
|
||||
self.model
|
||||
.supported_reasoning_effort_levels()
|
||||
.is_some_and(|levels| !levels.is_empty())
|
||||
}
|
||||
|
||||
fn supported_effort_levels(&self) -> Vec<LanguageModelEffortLevel> {
|
||||
self.model
|
||||
.supported_reasoning_effort_levels()
|
||||
.map(|levels| {
|
||||
if levels.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
let default_index = levels.len() - 1;
|
||||
levels
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, effort)| {
|
||||
let (name, value) = reasoning_effort_display(effort);
|
||||
LanguageModelEffortLevel {
|
||||
name: name.into(),
|
||||
value: value.into(),
|
||||
is_default: i == default_index,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn supports_tool_choice(&self, choice: LanguageModelToolChoice) -> bool {
|
||||
match choice {
|
||||
LanguageModelToolChoice::Auto | LanguageModelToolChoice::Any => true,
|
||||
@@ -576,12 +629,17 @@ impl LanguageModel for OpenCodeLanguageModel {
|
||||
|
||||
match self.model.protocol(self.subscription) {
|
||||
ApiProtocol::Anthropic => {
|
||||
let mode = if self.supports_thinking() && request.thinking_allowed {
|
||||
anthropic::AnthropicModelMode::AdaptiveThinking
|
||||
} else {
|
||||
anthropic::AnthropicModelMode::Default
|
||||
};
|
||||
let anthropic_request = into_anthropic(
|
||||
request,
|
||||
self.model.id().to_string(),
|
||||
1.0,
|
||||
self.model.max_output_tokens().unwrap_or(8192),
|
||||
anthropic::AnthropicModelMode::Default,
|
||||
mode,
|
||||
);
|
||||
let stream = self.stream_anthropic(anthropic_request, http_client, cx);
|
||||
async move {
|
||||
@@ -591,13 +649,21 @@ impl LanguageModel for OpenCodeLanguageModel {
|
||||
.boxed()
|
||||
}
|
||||
ApiProtocol::OpenAiChat => {
|
||||
let reasoning_effort = if request.thinking_allowed {
|
||||
request
|
||||
.thinking_effort
|
||||
.as_deref()
|
||||
.and_then(normalize_reasoning_effort)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let openai_request = into_open_ai(
|
||||
request,
|
||||
self.model.id(),
|
||||
false,
|
||||
false,
|
||||
self.model.max_output_tokens(),
|
||||
None,
|
||||
reasoning_effort,
|
||||
false,
|
||||
);
|
||||
let stream = self.stream_openai_chat(openai_request, http_client, cx);
|
||||
@@ -608,13 +674,21 @@ impl LanguageModel for OpenCodeLanguageModel {
|
||||
.boxed()
|
||||
}
|
||||
ApiProtocol::OpenAiResponses => {
|
||||
let reasoning_effort = if request.thinking_allowed {
|
||||
request
|
||||
.thinking_effort
|
||||
.as_deref()
|
||||
.and_then(normalize_reasoning_effort)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let response_request = into_open_ai_response(
|
||||
request,
|
||||
self.model.id(),
|
||||
false,
|
||||
false,
|
||||
self.model.max_output_tokens(),
|
||||
None,
|
||||
reasoning_effort,
|
||||
);
|
||||
let stream = self.stream_openai_response(response_request, http_client, cx);
|
||||
async move {
|
||||
|
||||
@@ -21,6 +21,7 @@ anyhow.workspace = true
|
||||
futures.workspace = true
|
||||
google_ai.workspace = true
|
||||
http_client.workspace = true
|
||||
language_model_core.workspace = true
|
||||
schemars = { workspace = true, optional = true }
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
||||
+114
-13
@@ -1,6 +1,7 @@
|
||||
use anyhow::{Result, anyhow};
|
||||
use futures::{AsyncBufReadExt, AsyncReadExt, StreamExt, io::BufReader, stream::BoxStream};
|
||||
use http_client::{AsyncBody, HttpClient, Method, Request as HttpRequest};
|
||||
use language_model_core::ReasoningEffort;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::EnumIter;
|
||||
|
||||
@@ -76,6 +77,10 @@ pub enum Model {
|
||||
Claude3_5Haiku,
|
||||
|
||||
// -- OpenAI Responses API models --
|
||||
#[serde(rename = "gpt-5.5")]
|
||||
Gpt5_5,
|
||||
#[serde(rename = "gpt-5.5-pro")]
|
||||
Gpt5_5Pro,
|
||||
#[serde(rename = "gpt-5.4")]
|
||||
Gpt5_4,
|
||||
#[serde(rename = "gpt-5.4-pro")]
|
||||
@@ -114,6 +119,14 @@ pub enum Model {
|
||||
Gemini3Flash,
|
||||
|
||||
// -- OpenAI Chat Completions protocol models --
|
||||
#[serde(rename = "deepseek-v4-pro")]
|
||||
DeepSeekV4Pro,
|
||||
#[serde(rename = "deepseek-v4-flash")]
|
||||
DeepSeekV4Flash,
|
||||
#[serde(rename = "ling-2.6-flash-free")]
|
||||
Ling2_6FlashFree,
|
||||
#[serde(rename = "hy3-preview-free")]
|
||||
Hy3PreviewFree,
|
||||
#[serde(rename = "minimax-m2.5")]
|
||||
MiniMaxM2_5,
|
||||
#[serde(rename = "minimax-m2.5-free")]
|
||||
@@ -132,6 +145,10 @@ pub enum Model {
|
||||
MimoV2Pro,
|
||||
#[serde(rename = "mimo-v2-omni")]
|
||||
MimoV2Omni,
|
||||
#[serde(rename = "mimo-v2.5-pro")]
|
||||
MimoV2_5Pro,
|
||||
#[serde(rename = "mimo-v2.5")]
|
||||
MimoV2_5,
|
||||
#[serde(rename = "big-pickle")]
|
||||
BigPickle,
|
||||
#[serde(rename = "nemotron-3-super-free")]
|
||||
@@ -149,6 +166,7 @@ pub enum Model {
|
||||
max_tokens: u64,
|
||||
max_output_tokens: Option<u64>,
|
||||
protocol: ApiProtocol,
|
||||
reasoning_effort_levels: Option<Vec<ReasoningEffort>>,
|
||||
custom_model_api_url: Option<String>,
|
||||
},
|
||||
}
|
||||
@@ -186,12 +204,20 @@ impl Model {
|
||||
| Self::Qwen3_6Plus => &[OpenCodeSubscription::Zen, OpenCodeSubscription::Go],
|
||||
|
||||
// Go-only models
|
||||
Self::MiniMaxM2_7 | Self::MimoV2Pro | Self::MimoV2Omni => &[OpenCodeSubscription::Go],
|
||||
Self::MiniMaxM2_7
|
||||
| Self::MimoV2_5Pro
|
||||
| Self::MimoV2_5
|
||||
| Self::MimoV2Pro
|
||||
| Self::MimoV2Omni
|
||||
| Self::DeepSeekV4Pro
|
||||
| Self::DeepSeekV4Flash => &[OpenCodeSubscription::Go],
|
||||
|
||||
// Free models
|
||||
Self::MiniMaxM2_5Free | Self::Nemotron3SuperFree | Self::BigPickle => {
|
||||
&[OpenCodeSubscription::Free]
|
||||
}
|
||||
Self::MiniMaxM2_5Free
|
||||
| Self::Nemotron3SuperFree
|
||||
| Self::BigPickle
|
||||
| Self::Ling2_6FlashFree
|
||||
| Self::Hy3PreviewFree => &[OpenCodeSubscription::Free],
|
||||
|
||||
// Custom models get their subscription from settings, not from here
|
||||
Self::Custom { .. } => &[],
|
||||
@@ -213,6 +239,8 @@ impl Model {
|
||||
Self::ClaudeHaiku4_5 => "claude-haiku-4-5",
|
||||
Self::Claude3_5Haiku => "claude-3-5-haiku",
|
||||
|
||||
Self::Gpt5_5 => "gpt-5.5",
|
||||
Self::Gpt5_5Pro => "gpt-5.5-pro",
|
||||
Self::Gpt5_4 => "gpt-5.4",
|
||||
Self::Gpt5_4Pro => "gpt-5.4-pro",
|
||||
Self::Gpt5_4Mini => "gpt-5.4-mini",
|
||||
@@ -232,6 +260,10 @@ impl Model {
|
||||
Self::Gemini3_1Pro => "gemini-3.1-pro",
|
||||
Self::Gemini3Flash => "gemini-3-flash",
|
||||
|
||||
Self::DeepSeekV4Pro => "deepseek-v4-pro",
|
||||
Self::DeepSeekV4Flash => "deepseek-v4-flash",
|
||||
Self::Ling2_6FlashFree => "ling-2.6-flash-free",
|
||||
Self::Hy3PreviewFree => "hy3-preview-free",
|
||||
Self::MiniMaxM2_5 => "minimax-m2.5",
|
||||
Self::MiniMaxM2_5Free => "minimax-m2.5-free",
|
||||
Self::Glm5 => "glm-5",
|
||||
@@ -241,6 +273,8 @@ impl Model {
|
||||
Self::MiniMaxM2_7 => "minimax-m2.7",
|
||||
Self::MimoV2Pro => "mimo-v2-pro",
|
||||
Self::MimoV2Omni => "mimo-v2-omni",
|
||||
Self::MimoV2_5Pro => "mimo-v2.5-pro",
|
||||
Self::MimoV2_5 => "mimo-v2.5",
|
||||
Self::Qwen3_5Plus => "qwen3.5-plus",
|
||||
Self::Qwen3_6Plus => "qwen3.6-plus",
|
||||
Self::BigPickle => "big-pickle",
|
||||
@@ -262,6 +296,8 @@ impl Model {
|
||||
Self::ClaudeHaiku4_5 => "Claude Haiku 4.5",
|
||||
Self::Claude3_5Haiku => "Claude Haiku 3.5",
|
||||
|
||||
Self::Gpt5_5 => "GPT 5.5",
|
||||
Self::Gpt5_5Pro => "GPT 5.5 Pro",
|
||||
Self::Gpt5_4 => "GPT 5.4",
|
||||
Self::Gpt5_4Pro => "GPT 5.4 Pro",
|
||||
Self::Gpt5_4Mini => "GPT 5.4 Mini",
|
||||
@@ -281,6 +317,10 @@ impl Model {
|
||||
Self::Gemini3_1Pro => "Gemini 3.1 Pro",
|
||||
Self::Gemini3Flash => "Gemini 3 Flash",
|
||||
|
||||
Self::DeepSeekV4Pro => "DeepSeek V4 Pro",
|
||||
Self::DeepSeekV4Flash => "DeepSeek V4 Flash",
|
||||
Self::Ling2_6FlashFree => "Ling 2.6 Flash Free",
|
||||
Self::Hy3PreviewFree => "Hy3 Preview Free",
|
||||
Self::MiniMaxM2_5 => "MiniMax M2.5",
|
||||
Self::MiniMaxM2_5Free => "MiniMax M2.5 Free",
|
||||
Self::Glm5 => "GLM 5",
|
||||
@@ -290,6 +330,8 @@ impl Model {
|
||||
Self::MiniMaxM2_7 => "MiniMax M2.7",
|
||||
Self::MimoV2Pro => "MiMo V2 Pro",
|
||||
Self::MimoV2Omni => "MiMo V2 Omni",
|
||||
Self::MimoV2_5Pro => "MiMo V2.5 Pro",
|
||||
Self::MimoV2_5 => "MiMo V2.5",
|
||||
Self::Qwen3_5Plus => "Qwen3.5 Plus",
|
||||
Self::Qwen3_6Plus => "Qwen3.6 Plus",
|
||||
Self::BigPickle => "Big Pickle",
|
||||
@@ -323,7 +365,9 @@ impl Model {
|
||||
| Self::ClaudeHaiku4_5
|
||||
| Self::Claude3_5Haiku => ApiProtocol::Anthropic,
|
||||
|
||||
Self::Gpt5_4
|
||||
Self::Gpt5_5
|
||||
| Self::Gpt5_5Pro
|
||||
| Self::Gpt5_4
|
||||
| Self::Gpt5_4Pro
|
||||
| Self::Gpt5_4Mini
|
||||
| Self::Gpt5_4Nano
|
||||
@@ -341,6 +385,8 @@ impl Model {
|
||||
|
||||
Self::Gemini3_1Pro | Self::Gemini3Flash => ApiProtocol::Google,
|
||||
|
||||
Self::DeepSeekV4Pro | Self::DeepSeekV4Flash => ApiProtocol::Anthropic,
|
||||
|
||||
Self::MiniMaxM2_5Free
|
||||
| Self::Glm5
|
||||
| Self::Glm5_1
|
||||
@@ -348,10 +394,14 @@ impl Model {
|
||||
| Self::KimiK2_6
|
||||
| Self::MimoV2Pro
|
||||
| Self::MimoV2Omni
|
||||
| Self::MimoV2_5Pro
|
||||
| Self::MimoV2_5
|
||||
| Self::Qwen3_5Plus
|
||||
| Self::Qwen3_6Plus
|
||||
| Self::BigPickle
|
||||
| Self::Nemotron3SuperFree => ApiProtocol::OpenAiChat,
|
||||
| Self::Nemotron3SuperFree
|
||||
| Self::Ling2_6FlashFree
|
||||
| Self::Hy3PreviewFree => ApiProtocol::OpenAiChat,
|
||||
|
||||
Self::Custom { protocol, .. } => *protocol,
|
||||
}
|
||||
@@ -369,6 +419,7 @@ impl Model {
|
||||
Self::Claude3_5Haiku => 200_000,
|
||||
|
||||
// OpenAI models
|
||||
Self::Gpt5_5 | Self::Gpt5_5Pro => 1_050_000,
|
||||
Self::Gpt5_4 | Self::Gpt5_4Pro => 1_050_000,
|
||||
Self::Gpt5_4Mini | Self::Gpt5_4Nano => 400_000,
|
||||
Self::Gpt5_3Codex => 400_000,
|
||||
@@ -386,13 +437,17 @@ impl Model {
|
||||
// OpenAI-compatible models
|
||||
Self::MiniMaxM2_7 => 204_800,
|
||||
Self::MiniMaxM2_5 | Self::MiniMaxM2_5Free => 204_800,
|
||||
Self::Glm5 | Self::Glm5_1 => 204_800,
|
||||
Self::Glm5 | Self::Glm5_1 => 202_725,
|
||||
Self::KimiK2_6 | Self::KimiK2_5 => 262_144,
|
||||
Self::MimoV2Pro => 1_048_576,
|
||||
Self::MimoV2_5Pro | Self::MimoV2Pro => 1_048_576,
|
||||
Self::MimoV2_5 => 1_000_000,
|
||||
Self::MimoV2Omni => 262_144,
|
||||
Self::Qwen3_5Plus | Self::Qwen3_6Plus => 262_144,
|
||||
Self::BigPickle => 200_000,
|
||||
Self::Nemotron3SuperFree => 204_800,
|
||||
Self::DeepSeekV4Pro | Self::DeepSeekV4Flash => 1_000_000,
|
||||
Self::Ling2_6FlashFree => 262_100,
|
||||
Self::Hy3PreviewFree => 256_000,
|
||||
|
||||
Self::Custom { max_tokens, .. } => *max_tokens,
|
||||
}
|
||||
@@ -411,7 +466,9 @@ impl Model {
|
||||
Self::Claude3_5Haiku => Some(8_192),
|
||||
|
||||
// OpenAI models
|
||||
Self::Gpt5_4
|
||||
Self::Gpt5_5
|
||||
| Self::Gpt5_5Pro
|
||||
| Self::Gpt5_4
|
||||
| Self::Gpt5_4Pro
|
||||
| Self::Gpt5_4Mini
|
||||
| Self::Gpt5_4Nano
|
||||
@@ -430,15 +487,22 @@ impl Model {
|
||||
// Google models
|
||||
Self::Gemini3_1Pro | Self::Gemini3Flash => Some(65_536),
|
||||
|
||||
// Anthropic-compatible models
|
||||
Self::DeepSeekV4Pro | Self::DeepSeekV4Flash => Some(384_000),
|
||||
|
||||
// OpenAI-compatible models
|
||||
Self::MiniMaxM2_7 => Some(131_072),
|
||||
Self::MiniMaxM2_5 | Self::MiniMaxM2_5Free => Some(131_072),
|
||||
Self::Glm5 | Self::Glm5_1 => Some(131_072),
|
||||
Self::Glm5 | Self::Glm5_1 => Some(32_768),
|
||||
Self::BigPickle => Some(128_000),
|
||||
Self::KimiK2_6 | Self::KimiK2_5 => Some(65_536),
|
||||
Self::Qwen3_5Plus | Self::Qwen3_6Plus => Some(65_536),
|
||||
Self::Nemotron3SuperFree => Some(128_000),
|
||||
Self::MimoV2Pro | Self::MimoV2Omni => Some(64_000),
|
||||
Self::MimoV2_5Pro | Self::MimoV2_5 | Self::MimoV2Pro | Self::MimoV2Omni => {
|
||||
Some(128_000)
|
||||
}
|
||||
Self::Ling2_6FlashFree => Some(32_800),
|
||||
Self::Hy3PreviewFree => Some(64_000),
|
||||
|
||||
Self::Custom {
|
||||
max_output_tokens, ..
|
||||
@@ -464,7 +528,9 @@ impl Model {
|
||||
| Self::Claude3_5Haiku => true,
|
||||
|
||||
// OpenAI models support images
|
||||
Self::Gpt5_4
|
||||
Self::Gpt5_5
|
||||
| Self::Gpt5_5Pro
|
||||
| Self::Gpt5_4
|
||||
| Self::Gpt5_4Pro
|
||||
| Self::Gpt5_4Mini
|
||||
| Self::Gpt5_4Nano
|
||||
@@ -487,6 +553,7 @@ impl Model {
|
||||
Self::KimiK2_6
|
||||
| Self::KimiK2_5
|
||||
| Self::MimoV2Omni
|
||||
| Self::MimoV2_5
|
||||
| Self::Qwen3_5Plus
|
||||
| Self::Qwen3_6Plus => true,
|
||||
|
||||
@@ -497,8 +564,14 @@ impl Model {
|
||||
| Self::Glm5_1
|
||||
| Self::MiniMaxM2_7
|
||||
| Self::MimoV2Pro
|
||||
| Self::MimoV2_5Pro
|
||||
| Self::BigPickle
|
||||
| Self::Nemotron3SuperFree => false,
|
||||
| Self::Nemotron3SuperFree
|
||||
| Self::Ling2_6FlashFree
|
||||
| Self::Hy3PreviewFree => false,
|
||||
|
||||
// DeepSeek models (Anthropic protocol) don't support images
|
||||
Self::DeepSeekV4Pro | Self::DeepSeekV4Flash => false,
|
||||
|
||||
Self::Custom { protocol, .. } => matches!(
|
||||
protocol,
|
||||
@@ -509,6 +582,34 @@ impl Model {
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn supported_reasoning_effort_levels(&self) -> Option<Vec<ReasoningEffort>> {
|
||||
match self {
|
||||
Self::MimoV2_5Pro
|
||||
| Self::MimoV2_5
|
||||
| Self::MimoV2Pro
|
||||
| Self::MimoV2Omni
|
||||
| Self::Hy3PreviewFree => Some(vec![
|
||||
ReasoningEffort::Low,
|
||||
ReasoningEffort::Medium,
|
||||
ReasoningEffort::High,
|
||||
]),
|
||||
|
||||
Self::DeepSeekV4Pro | Self::DeepSeekV4Flash => Some(vec![
|
||||
ReasoningEffort::Low,
|
||||
ReasoningEffort::Medium,
|
||||
ReasoningEffort::High,
|
||||
ReasoningEffort::XHigh,
|
||||
]),
|
||||
|
||||
Self::Custom {
|
||||
reasoning_effort_levels,
|
||||
..
|
||||
} => reasoning_effort_levels.clone(),
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Stream generate content for Google models via OpenCode.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::merge_from::MergeFrom;
|
||||
use collections::HashMap;
|
||||
use language_model_core::ReasoningEffort;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings_macros::{MergeFrom, with_fallible_options};
|
||||
@@ -179,6 +180,8 @@ pub struct OpenCodeAvailableModel {
|
||||
pub subscription: Option<OpenCodeModelSubscription>,
|
||||
/// Custom Model API URL to use for this model.
|
||||
pub custom_model_api_url: Option<String>,
|
||||
/// Supported reasoning effort levels, for example `["low", "medium", "high"].
|
||||
pub reasoning_effort_levels: Option<Vec<ReasoningEffort>>,
|
||||
}
|
||||
|
||||
#[with_fallible_options]
|
||||
|
||||
@@ -663,6 +663,7 @@ The Zed agent comes pre-configured with OpenCode models. If you wish to use newe
|
||||
"max_tokens": 123456,
|
||||
"max_output_tokens": 98765,
|
||||
"protocol": "openai_chat",
|
||||
"reasoning_effort_levels": ["low", "medium", "high"],
|
||||
"subscription": "go",
|
||||
"custom_model_api_url": "https://example.com/zen"
|
||||
}
|
||||
@@ -679,6 +680,7 @@ The available configuration options for custom models are:
|
||||
- `max_tokens` (required): maximum model context window size, for example `1000000`
|
||||
- `max_output_tokens` (optional): maximum tokens the model can generate, for example `64000`
|
||||
- `protocol` (required): model API protocol, one of `"anthropic"`, `"openai_responses"`, `"openai_chat"`, or `"google"`
|
||||
- `reasoning_effort_levels` (optional): list of supported reasoning effort levels, for example `["low", "medium", "high"]`. The latest value in the list is used as the default
|
||||
- `subscription` (optional): `"zen"`, `"go"`, or `"free"` (defaults to `"zen"`)
|
||||
- `custom_model_api_url` (optional): custom API base URL to use instead of the default OpenCode API
|
||||
|
||||
|
||||
Reference in new issue
Block a user