feat: add DeepSeek V4 model support with thinking mode and reasoning effort (#5522) * fix: align DeepSeek provider with V4 API * Fix DeepSeek beta routing for standard chat completions * feat: add DeepSeek V4 model support with thinking mode and reasoning effort * Address DeepSeek review feedback * Set DeepSeek default model to v4 flash * fix: clean-up deprecated models, add migration * fix: move reasoning effort mapping to resolveReasoningEffort * fix: lint empty line * fix: remove duplicate code * fix: add coder model to migration logic --------- Co-authored-by: dclef <drclef233@gmail.com> Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
Signed| @@ -2130,12 +2130,12 @@ | ||
| 2130 | 2130 | <span data-i18n="Allows the model to return its thinking process."> |
| 2131 | 2131 | Allows the model to return its thinking process. |
| 2132 | 2132 | </span> |
| 2133 | 2133 | <strong data-i18n="This setting affects visibility only." data-source-mode="except" data-source="zai,moonshot,openrouter,deepseek"> |
| 2134 | 2134 | This setting affects visibility only. |
| 2135 | 2135 | </strong> |
| 2136 | 2136 | </div> |
| 2137 | 2137 | </div> |
| 2138 | 2138 | <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,claude,xai,makersuite,vertexai,aimlapi,openrouter,pollinations,perplexity,cometapi,electronhub,azure_openai,chutes,nanogpt,deepseek"> |
| 2139 | 2139 | <div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response." data-i18n="[title]Constrains effort on reasoning for reasoning models."> |
| 2140 | 2140 | <label for="openai_reasoning_effort"> |
| 2141 | 2141 | <span data-i18n="Reasoning Effort">Reasoning Effort</span> |
| @@ -3735,9 +3735,7 @@ | ||
| 3735 | 3735 | <div> |
| 3736 | 3736 | <h4 data-i18n="DeepSeek Model">DeepSeek Model</h4> |
| 3737 | 3737 | <select id="model_deepseek_select"> |
| 3738 | - <option value="deepseek-chat">deepseek-chat</option> | |
| 3738 | + <option value="" data-i18n="-- Connect to the API --">-- Connect to the API --</option> | |
| 3739 | - <option value="deepseek-coder">deepseek-coder</option> | |
| 3740 | - <option value="deepseek-reasoner">deepseek-reasoner</option> | |
| 3741 | 3739 | </select> |
| 3742 | 3740 | </div> |
| 3743 | 3741 | </div> |
| @@ -446,7 +446,7 @@ const default_settings = { | ||
| 446 | 446 | electronhub_sort_models: 'alphabetically', |
| 447 | 447 | electronhub_group_models: false, |
| 448 | 448 | nanogpt_model: 'gpt-4o-mini', |
| 449 | 449 | deepseek_model: 'deepseek-chatv4-flash', |
| 450 | 450 | aimlapi_model: 'chatgpt-4o-latest', |
| 451 | 451 | xai_model: 'grok-3-beta', |
| 452 | 452 | pollinations_model: 'openai', |
| @@ -2501,6 +2501,7 @@ function getReasoningEffort(settings = null, model = null) { | ||
| 2501 | 2501 | chat_completion_sources.COMETAPI, |
| 2502 | 2502 | chat_completion_sources.ELECTRONHUB, |
| 2503 | 2503 | chat_completion_sources.CHUTES, |
| 2504 | + chat_completion_sources.DEEPSEEK, | |
| 2504 | 2505 | ]; |
| 2505 | 2506 | |
| 2506 | 2507 | if (!reasoningEffortSources.includes(settings.chat_completion_source)) { |
| @@ -2508,6 +2509,17 @@ function getReasoningEffort(settings = null, model = null) { | ||
| 2508 | 2509 | } |
| 2509 | 2510 | |
| 2510 | 2511 | function resolveReasoningEffort() { |
| 2512 | + if (settings.chat_completion_source === chat_completion_sources.DEEPSEEK) { | |
| 2513 | + switch (settings.reasoning_effort) { | |
| 2514 | + case reasoning_effort_types.auto: | |
| 2515 | + return undefined; | |
| 2516 | + case reasoning_effort_types.max: | |
| 2517 | + return reasoning_effort_types.max; | |
| 2518 | + default: | |
| 2519 | + return reasoning_effort_types.high; | |
| 2520 | + } | |
| 2521 | + } | |
| 2522 | + | |
| 2511 | 2523 | switch (settings.reasoning_effort) { |
| 2512 | 2524 | case reasoning_effort_types.auto: |
| 2513 | 2525 | return undefined; |
| @@ -4110,6 +4122,7 @@ function migrateChatCompletionSettings(settings) { | ||
| 4110 | 4122 | { oldKey: 'claude_use_sysprompt', oldValue: true, newKey: 'use_sysprompt', newValue: true }, |
| 4111 | 4123 | { oldKey: 'use_makersuite_sysprompt', oldValue: true, newKey: 'use_sysprompt', newValue: true }, |
| 4112 | 4124 | { oldKey: 'mistralai_model', oldValue: /^(mistral-medium|mistral-small)$/, newKey: 'mistralai_model', newValue: (settings.mistralai_model + '-latest') }, |
| 4125 | + { oldKey: 'deepseek_model', oldValue: /^deepseek-(chat|reasoner|coder)$/, newKey: 'deepseek_model', newValue: 'deepseek-v4-flash' }, | |
| 4113 | 4126 | ]; |
| 4114 | 4127 | |
| 4115 | 4128 | for (const migration of migrateMap) { |
| @@ -5622,16 +5635,8 @@ async function onModelChange() { | ||
| 5622 | 5635 | } |
| 5623 | 5636 | |
| 5624 | 5637 | if (oai_settings.chat_completion_source === chat_completion_sources.DEEPSEEK) { |
| 5625 | - if (oai_settings.max_context_unlocked) { | |
| 5638 | + const maxContext = oai_settings.max_context_unlocked ? unlocked_max : max_1mil; | |
| 5626 | 5639 | $('#openai_max_context').attr('max', unlocked_maxmaxContext); |
| 5627 | - } else if (['deepseek-reasoner', 'deepseek-chat'].includes(oai_settings.deepseek_model)) { | |
| 5628 | - $('#openai_max_context').attr('max', max_128k); | |
| 5629 | - } else if (oai_settings.deepseek_model == 'deepseek-coder') { | |
| 5630 | - $('#openai_max_context').attr('max', max_16k); | |
| 5631 | - } else { | |
| 5632 | - $('#openai_max_context').attr('max', max_64k); | |
| 5633 | - } | |
| 5634 | - | |
| 5635 | 5640 | oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context); |
| 5636 | 5641 | $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input'); |
| 5637 | 5642 | $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); |
| @@ -1074,9 +1074,10 @@ async function sendDeepSeekRequest(request, response) { | ||
| 1074 | 1074 | } |
| 1075 | 1075 | |
| 1076 | 1076 | const processedMessages = addAssistantPrefix(postProcessPrompt(request.body.messages, PROMPT_PROCESSING_TYPE.SEMI_TOOLS, getPromptNames(request)), bodyParams.tools, 'prefix'); |
| 1077 | + addReasoningContentToToolCalls(processedMessages); | |
| 1077 | 1078 | |
| 1078 | 1079 | if (/-reasoner/request.test(body.include_reasoning && request.body.model)reasoning_effort) { |
| 1079 | - addReasoningContentToToolCalls(processedMessages); | |
| 1080 | + bodyParams['reasoning_effort'] = request.body.reasoning_effort; | |
| 1080 | 1081 | } |
| 1081 | 1082 | |
| 1082 | 1083 | const requestBody = { |
| @@ -1090,6 +1091,7 @@ async function sendDeepSeekRequest(request, response) { | ||
| 1090 | 1091 | 'top_p': request.body.top_p, |
| 1091 | 1092 | 'stop': request.body.stop, |
| 1092 | 1093 | 'seed': request.body.seed, |
| 1094 | + 'thinking': { type: request.body.include_reasoning ? 'enabled' : 'disabled' }, | |
| 1093 | 1095 | ...bodyParams, |
| 1094 | 1096 | }; |
| 1095 | 1097 | |