mirror of
https://github.com/zed-industries/zed.git
synced 2026-05-31 19:05:00 +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,
|
||||
reasoning_effort_levels: model.reasoning_effort_levels.clone(),
|
||||
custom_model_api_url: model.custom_model_api_url.clone(),
|
||||
interleaved_reasoning: model.interleaved_reasoning,
|
||||
};
|
||||
let key = format!("{}/{}", subscription.id_prefix(), model.name);
|
||||
models.insert(key, (custom_model, subscription));
|
||||
|
|
@ -664,7 +665,7 @@ impl LanguageModel for OpenCodeLanguageModel {
|
|||
false,
|
||||
self.model.max_output_tokens(),
|
||||
reasoning_effort,
|
||||
false,
|
||||
self.model.interleaved_reasoning(),
|
||||
);
|
||||
let stream = self.stream_openai_chat(openai_request, http_client, cx);
|
||||
async move {
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@ pub enum Model {
|
|||
protocol: ApiProtocol,
|
||||
reasoning_effort_levels: Option<Vec<ReasoningEffort>>,
|
||||
custom_model_api_url: Option<String>,
|
||||
interleaved_reasoning: bool,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -385,8 +386,6 @@ impl Model {
|
|||
|
||||
Self::Gemini3_1Pro | Self::Gemini3Flash => ApiProtocol::Google,
|
||||
|
||||
Self::DeepSeekV4Pro | Self::DeepSeekV4Flash => ApiProtocol::Anthropic,
|
||||
|
||||
Self::MiniMaxM2_5Free
|
||||
| Self::Glm5
|
||||
| Self::Glm5_1
|
||||
|
|
@ -398,6 +397,8 @@ impl Model {
|
|||
| Self::MimoV2_5
|
||||
| Self::Qwen3_5Plus
|
||||
| Self::Qwen3_6Plus
|
||||
| Self::DeepSeekV4Pro
|
||||
| Self::DeepSeekV4Flash
|
||||
| Self::BigPickle
|
||||
| Self::Nemotron3SuperFree
|
||||
| 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 {
|
||||
match self {
|
||||
// Anthropic models
|
||||
|
|
@ -487,9 +509,6 @@ 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),
|
||||
|
|
@ -497,6 +516,7 @@ impl Model {
|
|||
Self::BigPickle => Some(128_000),
|
||||
Self::KimiK2_6 | Self::KimiK2_5 => 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::MimoV2_5Pro | Self::MimoV2_5 | Self::MimoV2Pro | Self::MimoV2Omni => {
|
||||
Some(128_000)
|
||||
|
|
@ -565,14 +585,13 @@ impl Model {
|
|||
| Self::MiniMaxM2_7
|
||||
| Self::MimoV2Pro
|
||||
| Self::MimoV2_5Pro
|
||||
| Self::DeepSeekV4Pro
|
||||
| Self::DeepSeekV4Flash
|
||||
| Self::BigPickle
|
||||
| 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,
|
||||
ApiProtocol::Anthropic
|
||||
|
|
|
|||
|
|
@ -181,6 +181,9 @@ pub struct OpenCodeAvailableModel {
|
|||
pub custom_model_api_url: Option<String>,
|
||||
/// Supported reasoning effort levels, for example `["low", "medium", "high"].
|
||||
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]
|
||||
|
|
|
|||
|
|
@ -663,6 +663,7 @@ The Zed agent comes pre-configured with OpenCode models. If you wish to use newe
|
|||
"max_output_tokens": 98765,
|
||||
"protocol": "openai_chat",
|
||||
"reasoning_effort_levels": ["low", "medium", "high"],
|
||||
"interleaved_reasoning": false,
|
||||
"subscription": "go",
|
||||
"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`
|
||||
- `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
|
||||
- `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"`)
|
||||
- `custom_model_api_url` (optional): custom API base URL to use instead of the default OpenCode API
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue