hotfix(models): add DeepSeek V4+ model support with reasoning effort (#14551)

### What this PR does

Adds wildcard detection and reasoning effort support for DeepSeek V4+
models (`deepseek-v4-flash`, `deepseek-v4-pro`, and future versions like
V5+).

Before this PR: DeepSeek V4 models are not recognized as reasoning
models, so the thinking toggle and effort selector don't appear in the
UI.

After this PR: V4+ models are auto-detected via a generic regex
(`deepseek-v{N>=4}`), with proper reasoning effort control (`high` /
`max`).

### Why we need it and why it was done in this way

DeepSeek released V4 models with a new reasoning effort API
(`reasoning_effort: "high" | "max"`) alongside the existing `thinking: {
type: "enabled" }` control. The existing
`isDeepSeekHybridInferenceModel()` regex only matched V3.x patterns and
`deepseek-chat`, missing V4 entirely.

Key design decisions:
- **Wildcard regex** (`deepseek-v([4-9]|\d{2,})`) instead of hardcoding
V4 — future versions (V5, V6...) are automatically covered
- **V3 regex unchanged** — `deepseek-v3` (plain) doesn't support
thinking on some third-party providers, so the existing suffix
requirement is preserved
- **UI uses `xhigh` → API maps to `max`** — reuses existing
`ReasoningEffortOption` type without extending it, since `max` is not in
`OpenAI.ReasoningEffort`
- **V4+ defaults to thinking enabled** — unlike V3.x which defaults to
non-thinking, V4 requires explicit `{ thinking: { type: 'disabled' } }`
to turn off

### Changes (3 files)

1. **`src/renderer/src/types/index.ts`** — Add `'deepseek_v4'` to
`ThinkModelTypes`

2. **`src/renderer/src/config/models/reasoning.ts`**:
   - New `isDeepSeekV4PlusModel()` — generic regex for V4+ model IDs
- `isDeepSeekHybridInferenceModel()` now includes V4+ via `||
isDeepSeekV4PlusModel(model)`
- `_getThinkModelType()` returns `'deepseek_v4'` (checked before
`deepseek_hybrid`)
   - `MODEL_SUPPORTED_REASONING_EFFORT.deepseek_v4`: `['high', 'xhigh']`
- `MODEL_SUPPORTED_OPTIONS.deepseek_v4`: `['default', 'none', 'high',
'xhigh']`

3. **`src/renderer/src/aiCore/utils/reasoning.ts`**:
- V4+ effort params: `{ thinking: { type: 'enabled' }, reasoning_effort:
'high' | 'max' }`
- `none` handling: `{ thinking: { type: 'disabled' } }` (V4 defaults to
thinking on)

### Breaking changes

None.

### Checklist

- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: Write code that humans can understand and Keep it simple
- [x] Refactor: You have left the code cleaner than you found it (Boy
Scout Rule)
- [x] Self-review: I have reviewed my own code before requesting review
from others

### Release note

```release-note
Support DeepSeek V4+ models (deepseek-v4-flash, deepseek-v4-pro) with reasoning effort control (high/max)
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Signed-off-by: Siin Xu <31815270+SiinXu@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Siin Xu
2026-04-23 23:30:23 -07:00
committed by GitHub
parent 19f2ed674d
commit e17d573755
3 changed files with 35 additions and 2 deletions

View File

@@ -12,6 +12,7 @@ import {
getModelSupportedReasoningEffortOptions,
isClaude46SeriesModel,
isDeepSeekHybridInferenceModel,
isDeepSeekV4PlusModel,
isDoubaoSeed18Model,
isDoubaoSeedAfter251015,
isDoubaoThinkingAutoModel,
@@ -185,7 +186,12 @@ export function getReasoningEffort(assistant: Assistant, model: Model): Reasonin
return { thinking: { type: 'disabled' } }
}
// Deepseek, default behavior is non-thinking
// DeepSeek V4+ defaults to thinking enabled, explicitly disable it
if (isDeepSeekV4PlusModel(model)) {
return { thinking: { type: 'disabled' } }
}
// DeepSeek V3.x hybrid, default behavior is non-thinking
if (isDeepSeekHybridInferenceModel(model)) {
return {}
}
@@ -341,6 +347,15 @@ export function getReasoningEffort(assistant: Assistant, model: Model): Reasonin
return {}
}
// DeepSeek V4+ models support reasoning_effort: "high" | "max" alongside thinking control
// UI uses "xhigh" which maps to API's "max"; all other effort levels map to "high"
if (isDeepSeekV4PlusModel(model)) {
return {
thinking: { type: 'enabled' as const },
reasoning_effort: reasoningEffort === 'xhigh' ? ('max' as OpenAIReasoningEffort) : 'high'
}
}
// DeepSeek hybrid inference models, v3.1 and maybe more in the future
// 不同的 provider 有不同的思考控制方式,在这里统一解决
if (isDeepSeekHybridInferenceModel(model)) {

View File

@@ -79,6 +79,7 @@ export const MODEL_SUPPORTED_REASONING_EFFORT = {
zhipu: ['auto'] as const,
perplexity: ['low', 'medium', 'high'] as const,
deepseek_hybrid: ['auto'] as const,
deepseek_v4: ['high', 'xhigh'] as const,
kimi_k2_5: ['none', 'auto'] as const,
// Claude 3.7, 4.0, 4.5 reasoning models
claude: ['low', 'medium', 'high'] as const,
@@ -118,6 +119,7 @@ export const MODEL_SUPPORTED_OPTIONS: ThinkingOptionConfig = {
zhipu: ['default', 'none', ...MODEL_SUPPORTED_REASONING_EFFORT.zhipu] as const,
perplexity: ['default', ...MODEL_SUPPORTED_REASONING_EFFORT.perplexity] as const,
deepseek_hybrid: ['default', 'none', ...MODEL_SUPPORTED_REASONING_EFFORT.deepseek_hybrid] as const,
deepseek_v4: ['default', 'none', ...MODEL_SUPPORTED_REASONING_EFFORT.deepseek_v4] as const,
kimi_k2_5: ['default', ...MODEL_SUPPORTED_REASONING_EFFORT.kimi_k2_5] as const,
claude: ['default', 'none', ...MODEL_SUPPORTED_REASONING_EFFORT.claude] as const,
claude46: ['default', 'none', ...MODEL_SUPPORTED_REASONING_EFFORT.claude46] as const
@@ -202,6 +204,8 @@ const _getThinkModelType = (model: Model): ThinkingModelType => {
thinkingModelType = 'perplexity'
} else if (isSupportedThinkingTokenZhipuModel(model)) {
thinkingModelType = 'zhipu'
} else if (isDeepSeekV4PlusModel(model)) {
thinkingModelType = 'deepseek_v4'
} else if (isDeepSeekHybridInferenceModel(model)) {
thinkingModelType = 'deepseek_hybrid'
} else if (isSupportedThinkingTokenMiMoModel(model)) {
@@ -630,6 +634,19 @@ export const isSupportedThinkingTokenKimiModel = (model: Model): boolean => {
return idResult || nameResult
}
/**
* Matches DeepSeek V4+ models (e.g., deepseek-v4-flash, deepseek-v4-pro, deepseek-v5-xxx).
* V4+ models default to thinking enabled and support reasoning_effort: "high" | "max".
*/
export const isDeepSeekV4PlusModel = (model: Model) => {
const { idResult, nameResult } = withModelIdAndNameAsId(model, (model) => {
const modelId = getLowerBaseModelName(model.id)
// Match deepseek-v{N} where N >= 4, with any optional suffix
return /(\w+-)?deepseek-v([4-9]|\d{2,})([.-]\w+)*$/.test(modelId)
})
return idResult || nameResult
}
export const isDeepSeekHybridInferenceModel = (model: Model) => {
const { idResult, nameResult } = withModelIdAndNameAsId(model, (model) => {
const modelId = getLowerBaseModelName(model.id)
@@ -647,7 +664,7 @@ export const isDeepSeekHybridInferenceModel = (model: Model) => {
modelId.includes('deepseek-chat')
)
})
return idResult || nameResult
return idResult || nameResult || isDeepSeekV4PlusModel(model)
}
export const isLingReasoningModel = (model?: Model): boolean => {

View File

@@ -126,6 +126,7 @@ const ThinkModelTypes = [
'zhipu',
'perplexity',
'deepseek_hybrid',
'deepseek_v4',
'kimi_k2_5',
'claude',
'claude46'