mirror of
https://github.com/zed-industries/zed.git
synced 2026-06-01 03:14:56 +07:00
opencode: Support interleaved_reasoning and fix DeepSeek (#55574)
OpenCode API endpoints for DeepSeek were [moved from Anthropic-compatible to OpenAI-compatible](https://github.com/anomalyco/opencode/pull/24500) and DeepSeek requires interleaved reasoning enabled to work. I ran a _"rename this variable to potato"_ test and I can confirm DeepSeek V4 Flash and Pro both work now 🎉 Some other OpenCode Go models were marked [on models.dev](https://github.com/anomalyco/models.dev/tree/dev/providers/opencode-go/models) as supporting `interleaved_reasoning` so they too got that enabled. Kimi K2.5 and Kimi K2.6 continue to fail with https://github.com/zed-industries/zed/issues/51743 (https://github.com/zed-industries/zed/pull/55085 seems to hint at this being [an OpenCode issue](https://github.com/zed-industries/zed/issues/51743#issuecomment-4336785765)?), but all other models seem to work fine both with `interleaved_reasoning` and without it 🤷 I assume it's better to have that turned on? Again, the intersection of OpenAI Chat Completions API, different models, different inference providers, how they all work together is something I know nothing about! 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 Go: use correct DeepSeek endpoints - OpenCode: add support for interleaved_reasoning
This commit is contained in:
parent
646672c35a
commit
a42374250f
4 changed files with 34 additions and 9 deletions
|
|
@ -278,6 +278,7 @@ impl LanguageModelProvider for OpenCodeLanguageModelProvider {
|
||||||
protocol,
|
protocol,
|
||||||
reasoning_effort_levels: model.reasoning_effort_levels.clone(),
|
reasoning_effort_levels: model.reasoning_effort_levels.clone(),
|
||||||
custom_model_api_url: model.custom_model_api_url.clone(),
|
custom_model_api_url: model.custom_model_api_url.clone(),
|
||||||
|
interleaved_reasoning: model.interleaved_reasoning,
|
||||||
};
|
};
|
||||||
let key = format!("{}/{}", subscription.id_prefix(), model.name);
|
let key = format!("{}/{}", subscription.id_prefix(), model.name);
|
||||||
models.insert(key, (custom_model, subscription));
|
models.insert(key, (custom_model, subscription));
|
||||||
|
|
@ -664,7 +665,7 @@ impl LanguageModel for OpenCodeLanguageModel {
|
||||||
false,
|
false,
|
||||||
self.model.max_output_tokens(),
|
self.model.max_output_tokens(),
|
||||||
reasoning_effort,
|
reasoning_effort,
|
||||||
false,
|
self.model.interleaved_reasoning(),
|
||||||
);
|
);
|
||||||
let stream = self.stream_openai_chat(openai_request, http_client, cx);
|
let stream = self.stream_openai_chat(openai_request, http_client, cx);
|
||||||
async move {
|
async move {
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,7 @@ pub enum Model {
|
||||||
protocol: ApiProtocol,
|
protocol: ApiProtocol,
|
||||||
reasoning_effort_levels: Option<Vec<ReasoningEffort>>,
|
reasoning_effort_levels: Option<Vec<ReasoningEffort>>,
|
||||||
custom_model_api_url: Option<String>,
|
custom_model_api_url: Option<String>,
|
||||||
|
interleaved_reasoning: bool,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -385,8 +386,6 @@ impl Model {
|
||||||
|
|
||||||
Self::Gemini3_1Pro | Self::Gemini3Flash => ApiProtocol::Google,
|
Self::Gemini3_1Pro | Self::Gemini3Flash => ApiProtocol::Google,
|
||||||
|
|
||||||
Self::DeepSeekV4Pro | Self::DeepSeekV4Flash => ApiProtocol::Anthropic,
|
|
||||||
|
|
||||||
Self::MiniMaxM2_5Free
|
Self::MiniMaxM2_5Free
|
||||||
| Self::Glm5
|
| Self::Glm5
|
||||||
| Self::Glm5_1
|
| Self::Glm5_1
|
||||||
|
|
@ -398,6 +397,8 @@ impl Model {
|
||||||
| Self::MimoV2_5
|
| Self::MimoV2_5
|
||||||
| Self::Qwen3_5Plus
|
| Self::Qwen3_5Plus
|
||||||
| Self::Qwen3_6Plus
|
| Self::Qwen3_6Plus
|
||||||
|
| Self::DeepSeekV4Pro
|
||||||
|
| Self::DeepSeekV4Flash
|
||||||
| Self::BigPickle
|
| Self::BigPickle
|
||||||
| Self::Nemotron3SuperFree
|
| Self::Nemotron3SuperFree
|
||||||
| Self::Ling2_6FlashFree
|
| Self::Ling2_6FlashFree
|
||||||
|
|
@ -407,6 +408,27 @@ impl Model {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn interleaved_reasoning(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::DeepSeekV4Pro
|
||||||
|
| Self::DeepSeekV4Flash
|
||||||
|
| Self::KimiK2_5
|
||||||
|
| Self::KimiK2_6
|
||||||
|
| Self::MimoV2Omni
|
||||||
|
| Self::MimoV2_5
|
||||||
|
| Self::MimoV2_5Pro
|
||||||
|
| Self::Glm5
|
||||||
|
| Self::Glm5_1 => true,
|
||||||
|
|
||||||
|
Self::Custom {
|
||||||
|
interleaved_reasoning,
|
||||||
|
..
|
||||||
|
} => *interleaved_reasoning,
|
||||||
|
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn max_token_count(&self) -> u64 {
|
pub fn max_token_count(&self) -> u64 {
|
||||||
match self {
|
match self {
|
||||||
// Anthropic models
|
// Anthropic models
|
||||||
|
|
@ -487,9 +509,6 @@ impl Model {
|
||||||
// Google models
|
// Google models
|
||||||
Self::Gemini3_1Pro | Self::Gemini3Flash => Some(65_536),
|
Self::Gemini3_1Pro | Self::Gemini3Flash => Some(65_536),
|
||||||
|
|
||||||
// Anthropic-compatible models
|
|
||||||
Self::DeepSeekV4Pro | Self::DeepSeekV4Flash => Some(384_000),
|
|
||||||
|
|
||||||
// OpenAI-compatible models
|
// OpenAI-compatible models
|
||||||
Self::MiniMaxM2_7 => Some(131_072),
|
Self::MiniMaxM2_7 => Some(131_072),
|
||||||
Self::MiniMaxM2_5 | Self::MiniMaxM2_5Free => Some(131_072),
|
Self::MiniMaxM2_5 | Self::MiniMaxM2_5Free => Some(131_072),
|
||||||
|
|
@ -497,6 +516,7 @@ impl Model {
|
||||||
Self::BigPickle => Some(128_000),
|
Self::BigPickle => Some(128_000),
|
||||||
Self::KimiK2_6 | Self::KimiK2_5 => Some(65_536),
|
Self::KimiK2_6 | Self::KimiK2_5 => Some(65_536),
|
||||||
Self::Qwen3_5Plus | Self::Qwen3_6Plus => Some(65_536),
|
Self::Qwen3_5Plus | Self::Qwen3_6Plus => Some(65_536),
|
||||||
|
Self::DeepSeekV4Pro | Self::DeepSeekV4Flash => Some(384_000),
|
||||||
Self::Nemotron3SuperFree => Some(128_000),
|
Self::Nemotron3SuperFree => Some(128_000),
|
||||||
Self::MimoV2_5Pro | Self::MimoV2_5 | Self::MimoV2Pro | Self::MimoV2Omni => {
|
Self::MimoV2_5Pro | Self::MimoV2_5 | Self::MimoV2Pro | Self::MimoV2Omni => {
|
||||||
Some(128_000)
|
Some(128_000)
|
||||||
|
|
@ -565,14 +585,13 @@ impl Model {
|
||||||
| Self::MiniMaxM2_7
|
| Self::MiniMaxM2_7
|
||||||
| Self::MimoV2Pro
|
| Self::MimoV2Pro
|
||||||
| Self::MimoV2_5Pro
|
| Self::MimoV2_5Pro
|
||||||
|
| Self::DeepSeekV4Pro
|
||||||
|
| Self::DeepSeekV4Flash
|
||||||
| Self::BigPickle
|
| Self::BigPickle
|
||||||
| Self::Nemotron3SuperFree
|
| Self::Nemotron3SuperFree
|
||||||
| Self::Ling2_6FlashFree
|
| Self::Ling2_6FlashFree
|
||||||
| Self::Hy3PreviewFree => false,
|
| Self::Hy3PreviewFree => false,
|
||||||
|
|
||||||
// DeepSeek models (Anthropic protocol) don't support images
|
|
||||||
Self::DeepSeekV4Pro | Self::DeepSeekV4Flash => false,
|
|
||||||
|
|
||||||
Self::Custom { protocol, .. } => matches!(
|
Self::Custom { protocol, .. } => matches!(
|
||||||
protocol,
|
protocol,
|
||||||
ApiProtocol::Anthropic
|
ApiProtocol::Anthropic
|
||||||
|
|
|
||||||
|
|
@ -181,6 +181,9 @@ pub struct OpenCodeAvailableModel {
|
||||||
pub custom_model_api_url: Option<String>,
|
pub custom_model_api_url: Option<String>,
|
||||||
/// Supported reasoning effort levels, for example `["low", "medium", "high"].
|
/// Supported reasoning effort levels, for example `["low", "medium", "high"].
|
||||||
pub reasoning_effort_levels: Option<Vec<ReasoningEffort>>,
|
pub reasoning_effort_levels: Option<Vec<ReasoningEffort>>,
|
||||||
|
/// When using OpenAiChat protocol, whether thinking tokens are sent as a dedicated `reasoning_content` field or inline in message text.
|
||||||
|
#[serde(default)]
|
||||||
|
pub interleaved_reasoning: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[with_fallible_options]
|
#[with_fallible_options]
|
||||||
|
|
|
||||||
|
|
@ -663,6 +663,7 @@ The Zed agent comes pre-configured with OpenCode models. If you wish to use newe
|
||||||
"max_output_tokens": 98765,
|
"max_output_tokens": 98765,
|
||||||
"protocol": "openai_chat",
|
"protocol": "openai_chat",
|
||||||
"reasoning_effort_levels": ["low", "medium", "high"],
|
"reasoning_effort_levels": ["low", "medium", "high"],
|
||||||
|
"interleaved_reasoning": false,
|
||||||
"subscription": "go",
|
"subscription": "go",
|
||||||
"custom_model_api_url": "https://example.com/zen"
|
"custom_model_api_url": "https://example.com/zen"
|
||||||
}
|
}
|
||||||
|
|
@ -680,6 +681,7 @@ The available configuration options for custom models are:
|
||||||
- `max_output_tokens` (optional): maximum tokens the model can generate, for example `64000`
|
- `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"`
|
- `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
|
- `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
|
||||||
|
- `interleaved_reasoning` (optional, default `false`): if thinking tokens are sent as a dedicated `reasoning_content` field (`true`) or inline in message text (`false`). Applies only when using the `openai_chat` protocol
|
||||||
- `subscription` (optional): `"zen"`, `"go"`, or `"free"` (defaults to `"zen"`)
|
- `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
|
- `custom_model_api_url` (optional): custom API base URL to use instead of the default OpenCode API
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue