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>

77cbcd877453d66f8069ff8bbae31b494395df73

Dclef <42974381+Dclef@users.noreply.github.com>

Signed
3 files changed, +23 -18Showing whitespace changes
public/index.html+3 -5
@@ -2130,12 +2130,12 @@
2130 <span data-i18n="Allows the model to return its thinking process.">2130 <span data-i18n="Allows the model to return its thinking process.">
2131 Allows the model to return its thinking process.2131 Allows the model to return its thinking process.
2132 </span>2132 </span>
2133 <strong data-i18n="This setting affects visibility only." data-source-mode="except" data-source="zai,moonshot,openrouter">2133 <strong data-i18n="This setting affects visibility only." data-source-mode="except" data-source="zai,moonshot,openrouter,deepseek">
2134 This setting affects visibility only.2134 This setting affects visibility only.
2135 </strong>2135 </strong>
2136 </div>2136 </div>
2137 </div>2137 </div>
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">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 <div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models.&#10;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.">2139 <div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models.&#10;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 <label for="openai_reasoning_effort">2140 <label for="openai_reasoning_effort">
2141 <span data-i18n="Reasoning Effort">Reasoning Effort</span>2141 <span data-i18n="Reasoning Effort">Reasoning Effort</span>
@@ -3735,9 +3735,7 @@
3735 <div>3735 <div>
3736 <h4 data-i18n="DeepSeek Model">DeepSeek Model</h4>3736 <h4 data-i18n="DeepSeek Model">DeepSeek Model</h4>
3737 <select id="model_deepseek_select">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 </select>3739 </select>
3742 </div>3740 </div>
3743 </div>3741 </div>
public/scripts/openai.js+16 -11
@@ -446,7 +446,7 @@ const default_settings = {
446 electronhub_sort_models: 'alphabetically',446 electronhub_sort_models: 'alphabetically',
447 electronhub_group_models: false,447 electronhub_group_models: false,
448 nanogpt_model: 'gpt-4o-mini',448 nanogpt_model: 'gpt-4o-mini',
449 deepseek_model: 'deepseek-chat',449 deepseek_model: 'deepseek-v4-flash',
450 aimlapi_model: 'chatgpt-4o-latest',450 aimlapi_model: 'chatgpt-4o-latest',
451 xai_model: 'grok-3-beta',451 xai_model: 'grok-3-beta',
452 pollinations_model: 'openai',452 pollinations_model: 'openai',
@@ -2501,6 +2501,7 @@ function getReasoningEffort(settings = null, model = null) {
2501 chat_completion_sources.COMETAPI,2501 chat_completion_sources.COMETAPI,
2502 chat_completion_sources.ELECTRONHUB,2502 chat_completion_sources.ELECTRONHUB,
2503 chat_completion_sources.CHUTES,2503 chat_completion_sources.CHUTES,
2504 chat_completion_sources.DEEPSEEK,
2504 ];2505 ];
25052506
2506 if (!reasoningEffortSources.includes(settings.chat_completion_source)) {2507 if (!reasoningEffortSources.includes(settings.chat_completion_source)) {
@@ -2508,6 +2509,17 @@ function getReasoningEffort(settings = null, model = null) {
2508 }2509 }
25092510
2510 function resolveReasoningEffort() {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 switch (settings.reasoning_effort) {2523 switch (settings.reasoning_effort) {
2512 case reasoning_effort_types.auto:2524 case reasoning_effort_types.auto:
2513 return undefined;2525 return undefined;
@@ -4110,6 +4122,7 @@ function migrateChatCompletionSettings(settings) {
4110 { oldKey: 'claude_use_sysprompt', oldValue: true, newKey: 'use_sysprompt', newValue: true },4122 { oldKey: 'claude_use_sysprompt', oldValue: true, newKey: 'use_sysprompt', newValue: true },
4111 { oldKey: 'use_makersuite_sysprompt', oldValue: true, newKey: 'use_sysprompt', newValue: true },4123 { oldKey: 'use_makersuite_sysprompt', oldValue: true, newKey: 'use_sysprompt', newValue: true },
4112 { oldKey: 'mistralai_model', oldValue: /^(mistral-medium|mistral-small)$/, newKey: 'mistralai_model', newValue: (settings.mistralai_model + '-latest') },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 ];
41144127
4115 for (const migration of migrateMap) {4128 for (const migration of migrateMap) {
@@ -5622,16 +5635,8 @@ async function onModelChange() {
5622 }5635 }
56235636
5624 if (oai_settings.chat_completion_source === chat_completion_sources.DEEPSEEK) {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 $('#openai_max_context').attr('max', unlocked_max);5639 $('#openai_max_context').attr('max', maxContext);
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 oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context);5640 oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context);
5636 $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input');5641 $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input');
5637 $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input');5642 $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input');
src/endpoints/backends/chat-completions.js+4 -2
@@ -1074,9 +1074,10 @@ async function sendDeepSeekRequest(request, response) {
1074 }1074 }
10751075
1076 const processedMessages = addAssistantPrefix(postProcessPrompt(request.body.messages, PROMPT_PROCESSING_TYPE.SEMI_TOOLS, getPromptNames(request)), bodyParams.tools, 'prefix');1076 const processedMessages = addAssistantPrefix(postProcessPrompt(request.body.messages, PROMPT_PROCESSING_TYPE.SEMI_TOOLS, getPromptNames(request)), bodyParams.tools, 'prefix');
1077
1078 if (/-reasoner/.test(request.body.model)) {
1079 addReasoningContentToToolCalls(processedMessages);1077 addReasoningContentToToolCalls(processedMessages);
1078
1079 if (request.body.include_reasoning && request.body.reasoning_effort) {
1080 bodyParams['reasoning_effort'] = request.body.reasoning_effort;
1080 }1081 }
10811082
1082 const requestBody = {1083 const requestBody = {
@@ -1090,6 +1091,7 @@ async function sendDeepSeekRequest(request, response) {
1090 'top_p': request.body.top_p,1091 'top_p': request.body.top_p,
1091 'stop': request.body.stop,1092 'stop': request.body.stop,
1092 'seed': request.body.seed,1093 'seed': request.body.seed,
1094 'thinking': { type: request.body.include_reasoning ? 'enabled' : 'disabled' },
1093 ...bodyParams,1095 ...bodyParams,
1094 };1096 };
10951097