feat: add siliconflow chat provider (#4764) * feat: add siliconflow chat provider * fix: remove siliconflow seed handling * fix: enable SiliconFlow image inlining from shared vision list * fix: handle SiliconFlow model context limits and sizing * fix: drop SiliconFlow reasoning effort handling since controls are hidden * fix: parse SiliconFlow reasoning in streaming and non-streaming * fix: add missing comma in supported models list * Remove seed from HTML template * Combine streamed reasoning parsing blocks * Update logo image * Unhide image inlining controls --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>

5c974bd14810a56b762c606681e7bfd995d88340

QiyuanChen <72334646+qychen2001@users.noreply.github.com>

Signed
11 files changed, +166 -8Showing whitespace changes
public/img/siliconflow.svg+4 -0
@@ -0,0 +1,4 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="142.22" height="68.010002" viewBox="0 0 142.22 68.010002" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
3 <path d="M 136.05,0 H 74.21 c -3.42,0 -6.18,2.77 -6.18,6.18 v 18.55 c 0,3.42 -2.77,6.18 -6.18,6.18 H 6.18 C 2.76,30.91 0,33.68 0,37.09 v 24.74 c 0,3.42 2.77,6.18 6.18,6.18 h 61.84 c 3.42,0 6.18,-2.77 6.18,-6.18 V 43.28 c 0,-3.42 2.77,-6.18 6.18,-6.18 h 55.66 c 3.42,0 6.18,-2.77 6.18,-6.18 V 6.18 C 142.22,2.76 139.45,0 136.04,0 Z" />
4</svg>
public/index.html+22 -7
@@ -693,7 +693,7 @@
693 </span>693 </span>
694 </div>694 </div>
695 </div>695 </div>
696 <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai,zai">696 <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,siliconflow,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai,zai">
697 <div class="range-block-title" data-i18n="Temperature">697 <div class="range-block-title" data-i18n="Temperature">
698 Temperature698 Temperature
699 </div>699 </div>
@@ -706,7 +706,7 @@
706 </div>706 </div>
707 </div>707 </div>
708 </div>708 </div>
709 <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,mistralai,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai">709 <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,siliconflow,mistralai,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai">
710 <div class="range-block-title" data-i18n="Frequency Penalty">710 <div class="range-block-title" data-i18n="Frequency Penalty">
711 Frequency Penalty711 Frequency Penalty
712 </div>712 </div>
@@ -719,7 +719,7 @@
719 </div>719 </div>
720 </div>720 </div>
721 </div>721 </div>
722 <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,mistralai,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai">722 <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,siliconflow,mistralai,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai">
723 <div class="range-block-title" data-i18n="Presence Penalty">723 <div class="range-block-title" data-i18n="Presence Penalty">
724 Presence Penalty724 Presence Penalty
725 </div>725 </div>
@@ -745,7 +745,7 @@
745 </div>745 </div>
746 </div>746 </div>
747 </div>747 </div>
748 <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai,zai">748 <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,siliconflow,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai,zai">
749 <div class="range-block-title" data-i18n="Top P">749 <div class="range-block-title" data-i18n="Top P">
750 Top P750 Top P
751 </div>751 </div>
@@ -1965,7 +1965,7 @@
1965 </b>1965 </b>
1966 </div>1966 </div>
1967 </div>1967 </div>
1968 <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,aimlapi,openrouter,groq,deepseek,makersuite,vertexai,ai21,xai,pollinations,moonshot,fireworks,cometapi,electronhub,azure_openai,zai">1968 <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,aimlapi,openrouter,groq,siliconflow,deepseek,makersuite,vertexai,ai21,xai,pollinations,moonshot,fireworks,cometapi,electronhub,azure_openai,zai">
1969 <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand">1969 <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand">
1970 <input id="openai_function_calling" type="checkbox" />1970 <input id="openai_function_calling" type="checkbox" />
1971 <span data-i18n="Enable function calling">Enable function calling</span>1971 <span data-i18n="Enable function calling">Enable function calling</span>
@@ -1980,7 +1980,7 @@
1980 <strong data-i18n="enable_functions_desc_4">Not supported when Prompt Post-Processing with "no tools" is used!</strong>1980 <strong data-i18n="enable_functions_desc_4">Not supported when Prompt Post-Processing with "no tools" is used!</strong>
1981 </div>1981 </div>
1982 </div>1982 </div>
1983 <div class="range-block" data-source="openai,aimlapi,openrouter,mistralai,makersuite,vertexai,claude,custom,xai,pollinations,moonshot,cohere,cometapi,nanogpt,electronhub,azure_openai,zai">1983 <div class="range-block" data-source="openai,aimlapi,openrouter,mistralai,makersuite,vertexai,claude,custom,xai,pollinations,moonshot,cohere,cometapi,nanogpt,electronhub,azure_openai,zai,siliconflow">
1984 <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand">1984 <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand">
1985 <input id="openai_image_inlining" type="checkbox" />1985 <input id="openai_image_inlining" type="checkbox" />
1986 <span data-i18n="Send inline images">Send inline images</span>1986 <span data-i18n="Send inline images">Send inline images</span>
@@ -1992,7 +1992,7 @@
1992 <div id="image_inlining_hint" class="flexBasis100p toggle-description justifyLeft">1992 <div id="image_inlining_hint" class="flexBasis100p toggle-description justifyLeft">
1993 <span data-i18n="image_inlining_hint_1">Sends images in prompts if the model supports it.</span>1993 <span data-i18n="image_inlining_hint_1">Sends images in prompts if the model supports it.</span>
1994 </div>1994 </div>
1995 <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,xai,pollinations,cohere,cometapi,nanogpt,moonshot,aimlapi,openrouter,mistralai,electronhub,azure_openai,zai">1995 <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,xai,pollinations,cohere,cometapi,nanogpt,moonshot,aimlapi,openrouter,mistralai,electronhub,azure_openai,zai,siliconflow">
1996 <div class="flex-container oneline-dropdown">1996 <div class="flex-container oneline-dropdown">
1997 <label for="openai_inline_image_quality" data-i18n="Inline Image Quality">1997 <label for="openai_inline_image_quality" data-i18n="Inline Image Quality">
1998 Inline Image Quality1998 Inline Image Quality
@@ -2806,6 +2806,7 @@
2806 <option value="openrouter">OpenRouter</option>2806 <option value="openrouter">OpenRouter</option>
2807 <option value="perplexity">Perplexity</option>2807 <option value="perplexity">Perplexity</option>
2808 <option value="pollinations">Pollinations</option>2808 <option value="pollinations">Pollinations</option>
2809 <option value="siliconflow">SiliconFlow</option>
2809 <option value="xai">xAI (Grok)</option>2810 <option value="xai">xAI (Grok)</option>
2810 <option value="zai">Z.AI (GLM)</option>2811 <option value="zai">Z.AI (GLM)</option>
2811 </optgroup>2812 </optgroup>
@@ -3397,6 +3398,20 @@
3397 <option value="mistral-saba-24b">mistral-saba-24b</option>3398 <option value="mistral-saba-24b">mistral-saba-24b</option>
3398 </select>3399 </select>
3399 </div>3400 </div>
3401 <div id="siliconflow_form" data-source="siliconflow">
3402 <h4>SiliconFlow API Key</h4>
3403 <div class="flex-container">
3404 <input id="api_key_siliconflow" name="api_key_siliconflow" class="text_pole flex1" value="" type="text" autocomplete="off">
3405 <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_siliconflow"></div>
3406 </div>
3407 <div data-for="api_key_siliconflow" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'.">
3408 For privacy reasons, your API key will be hidden after you click 'Connect'.
3409 </div>
3410 <h4>SiliconFlow Model</h4>
3411 <select id="model_siliconflow_select">
3412 <option value="" data-i18n="-- Connect to the API --">-- Connect to the API --</option>
3413 </select>
3414 </div>
3400 <div id="electronhub_form" data-source="electronhub">3415 <div id="electronhub_form" data-source="electronhub">
3401 <h4 data-i18n="Electron Hub API Key">Electron Hub API Key</h4>3416 <h4 data-i18n="Electron Hub API Key">Electron Hub API Key</h4>
3402 <div>3417 <div>
public/scripts/RossAscends-mods.js+1 -0
@@ -403,6 +403,7 @@ function RA_autoconnect(PrevApi) {
403 || (secret_state[SECRET_KEYS.COHERE] && oai_settings.chat_completion_source == chat_completion_sources.COHERE)403 || (secret_state[SECRET_KEYS.COHERE] && oai_settings.chat_completion_source == chat_completion_sources.COHERE)
404 || (secret_state[SECRET_KEYS.PERPLEXITY] && oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY)404 || (secret_state[SECRET_KEYS.PERPLEXITY] && oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY)
405 || (secret_state[SECRET_KEYS.GROQ] && oai_settings.chat_completion_source == chat_completion_sources.GROQ)405 || (secret_state[SECRET_KEYS.GROQ] && oai_settings.chat_completion_source == chat_completion_sources.GROQ)
406 || (secret_state[SECRET_KEYS.SILICONFLOW] && oai_settings.chat_completion_source == chat_completion_sources.SILICONFLOW)
406 || (secret_state[SECRET_KEYS.ELECTRONHUB] && oai_settings.chat_completion_source == chat_completion_sources.ELECTRONHUB)407 || (secret_state[SECRET_KEYS.ELECTRONHUB] && oai_settings.chat_completion_source == chat_completion_sources.ELECTRONHUB)
407 || (secret_state[SECRET_KEYS.NANOGPT] && oai_settings.chat_completion_source == chat_completion_sources.NANOGPT)408 || (secret_state[SECRET_KEYS.NANOGPT] && oai_settings.chat_completion_source == chat_completion_sources.NANOGPT)
408 || (secret_state[SECRET_KEYS.DEEPSEEK] && oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK)409 || (secret_state[SECRET_KEYS.DEEPSEEK] && oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK)
public/scripts/openai.js+118 -1
@@ -194,6 +194,7 @@ export const chat_completion_sources = {
194 COMETAPI: 'cometapi',194 COMETAPI: 'cometapi',
195 AZURE_OPENAI: 'azure_openai',195 AZURE_OPENAI: 'azure_openai',
196 ZAI: 'zai',196 ZAI: 'zai',
197 SILICONFLOW: 'siliconflow',
197};198};
198199
199const character_names_behavior = {200const character_names_behavior = {
@@ -280,6 +281,7 @@ export const settingsToUpdate = {
280 cohere_model: ['#model_cohere_select', 'cohere_model', false, true],281 cohere_model: ['#model_cohere_select', 'cohere_model', false, true],
281 perplexity_model: ['#model_perplexity_select', 'perplexity_model', false, true],282 perplexity_model: ['#model_perplexity_select', 'perplexity_model', false, true],
282 groq_model: ['#model_groq_select', 'groq_model', false, true],283 groq_model: ['#model_groq_select', 'groq_model', false, true],
284 siliconflow_model: ['#model_siliconflow_select', 'siliconflow_model', false, true],
283 electronhub_model: ['#model_electronhub_select', 'electronhub_model', false, true],285 electronhub_model: ['#model_electronhub_select', 'electronhub_model', false, true],
284 electronhub_sort_models: ['#electronhub_sort_models', 'electronhub_sort_models', false, true],286 electronhub_sort_models: ['#electronhub_sort_models', 'electronhub_sort_models', false, true],
285 electronhub_group_models: ['#electronhub_group_models', 'electronhub_group_models', false, true],287 electronhub_group_models: ['#electronhub_group_models', 'electronhub_group_models', false, true],
@@ -387,6 +389,7 @@ const default_settings = {
387 cohere_model: 'command-r-plus',389 cohere_model: 'command-r-plus',
388 perplexity_model: 'sonar-pro',390 perplexity_model: 'sonar-pro',
389 groq_model: 'llama-3.3-70b-versatile',391 groq_model: 'llama-3.3-70b-versatile',
392 siliconflow_model: 'deepseek-ai/DeepSeek-V3',
390 electronhub_model: 'gpt-4o-mini',393 electronhub_model: 'gpt-4o-mini',
391 electronhub_sort_models: 'alphabetically',394 electronhub_sort_models: 'alphabetically',
392 electronhub_group_models: false,395 electronhub_group_models: false,
@@ -1587,6 +1590,8 @@ export function getChatCompletionModel(source = null) {
1587 return oai_settings.perplexity_model;1590 return oai_settings.perplexity_model;
1588 case chat_completion_sources.GROQ:1591 case chat_completion_sources.GROQ:
1589 return oai_settings.groq_model;1592 return oai_settings.groq_model;
1593 case chat_completion_sources.SILICONFLOW:
1594 return oai_settings.siliconflow_model;
1590 case chat_completion_sources.ELECTRONHUB:1595 case chat_completion_sources.ELECTRONHUB:
1591 return oai_settings.electronhub_model;1596 return oai_settings.electronhub_model;
1592 case chat_completion_sources.NANOGPT:1597 case chat_completion_sources.NANOGPT:
@@ -1920,6 +1925,24 @@ function saveModelList(data) {
1920 $('#model_groq_select').val(oai_settings.groq_model).trigger('change');1925 $('#model_groq_select').val(oai_settings.groq_model).trigger('change');
1921 }1926 }
19221927
1928 if (oai_settings.chat_completion_source === chat_completion_sources.SILICONFLOW) {
1929 $('#model_siliconflow_select').empty();
1930 model_list.forEach((model) => {
1931 $('#model_siliconflow_select').append(
1932 $('<option>', {
1933 value: model.id,
1934 text: model.id,
1935 }));
1936 });
1937
1938 const selectedModel = model_list.find(model => model.id === oai_settings.siliconflow_model);
1939 if (model_list.length > 0 && (!selectedModel || !oai_settings.siliconflow_model)) {
1940 oai_settings.siliconflow_model = model_list[0].id;
1941 }
1942
1943 $('#model_siliconflow_select').val(oai_settings.siliconflow_model).trigger('change');
1944 }
1945
1923 if (oai_settings.chat_completion_source === chat_completion_sources.FIREWORKS) {1946 if (oai_settings.chat_completion_source === chat_completion_sources.FIREWORKS) {
1924 $('#model_fireworks_select').empty();1947 $('#model_fireworks_select').empty();
1925 model_list.forEach((model) => {1948 model_list.forEach((model) => {
@@ -2654,7 +2677,7 @@ export function getStreamingReply(data, state, { chatCompletionSource = null, ov
2654 state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning)?.[0]?.delta?.reasoning || '');2677 state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning)?.[0]?.delta?.reasoning || '');
2655 }2678 }
2656 return data.choices?.[0]?.delta?.content ?? data.choices?.[0]?.message?.content ?? data.choices?.[0]?.text ?? '';2679 return data.choices?.[0]?.delta?.content ?? data.choices?.[0]?.message?.content ?? data.choices?.[0]?.text ?? '';
2657 } else if ([chat_completion_sources.CUSTOM, chat_completion_sources.POLLINATIONS, chat_completion_sources.AIMLAPI, chat_completion_sources.MOONSHOT, chat_completion_sources.COMETAPI, chat_completion_sources.ELECTRONHUB, chat_completion_sources.NANOGPT, chat_completion_sources.ZAI].includes(chat_completion_source)) {2680 } else if ([chat_completion_sources.CUSTOM, chat_completion_sources.POLLINATIONS, chat_completion_sources.AIMLAPI, chat_completion_sources.MOONSHOT, chat_completion_sources.COMETAPI, chat_completion_sources.ELECTRONHUB, chat_completion_sources.NANOGPT, chat_completion_sources.ZAI, chat_completion_sources.SILICONFLOW].includes(chat_completion_source)) {
2658 if (show_thoughts) {2681 if (show_thoughts) {
2659 state.reasoning +=2682 state.reasoning +=
2660 data.choices?.filter(x => x?.delta?.reasoning_content)?.[0]?.delta?.reasoning_content ??2683 data.choices?.filter(x => x?.delta?.reasoning_content)?.[0]?.delta?.reasoning_content ??
@@ -3665,6 +3688,7 @@ function loadOpenAISettings(data, settings) {
3665 oai_settings.cohere_model = settings.cohere_model ?? default_settings.cohere_model;3688 oai_settings.cohere_model = settings.cohere_model ?? default_settings.cohere_model;
3666 oai_settings.perplexity_model = settings.perplexity_model ?? default_settings.perplexity_model;3689 oai_settings.perplexity_model = settings.perplexity_model ?? default_settings.perplexity_model;
3667 oai_settings.groq_model = settings.groq_model ?? default_settings.groq_model;3690 oai_settings.groq_model = settings.groq_model ?? default_settings.groq_model;
3691 oai_settings.siliconflow_model = settings.siliconflow_model ?? default_settings.siliconflow_model;
3668 oai_settings.electronhub_model = settings.electronhub_model ?? default_settings.electronhub_model;3692 oai_settings.electronhub_model = settings.electronhub_model ?? default_settings.electronhub_model;
3669 oai_settings.electronhub_sort_models = settings.electronhub_sort_models ?? default_settings.electronhub_sort_models;3693 oai_settings.electronhub_sort_models = settings.electronhub_sort_models ?? default_settings.electronhub_sort_models;
3670 oai_settings.electronhub_group_models = settings.electronhub_group_models ?? default_settings.electronhub_group_models;3694 oai_settings.electronhub_group_models = settings.electronhub_group_models ?? default_settings.electronhub_group_models;
@@ -3770,6 +3794,8 @@ function loadOpenAISettings(data, settings) {
3770 $(`#model_perplexity_select option[value="${oai_settings.perplexity_model}"`).prop('selected', true);3794 $(`#model_perplexity_select option[value="${oai_settings.perplexity_model}"`).prop('selected', true);
3771 $('#model_groq_select').val(oai_settings.groq_model);3795 $('#model_groq_select').val(oai_settings.groq_model);
3772 $(`#model_groq_select option[value="${oai_settings.groq_model}"`).prop('selected', true);3796 $(`#model_groq_select option[value="${oai_settings.groq_model}"`).prop('selected', true);
3797 $('#model_siliconflow_select').val(oai_settings.siliconflow_model);
3798 $(`#model_siliconflow_select option[value="${oai_settings.siliconflow_model}"`).prop('selected', true);
3773 $('#model_electronhub_select').val(oai_settings.electronhub_model);3799 $('#model_electronhub_select').val(oai_settings.electronhub_model);
3774 $(`#model_electronhub_select option[value="${oai_settings.electronhub_model}"`).prop('selected', true);3800 $(`#model_electronhub_select option[value="${oai_settings.electronhub_model}"`).prop('selected', true);
3775 $('#model_nanogpt_select').val(oai_settings.nanogpt_model);3801 $('#model_nanogpt_select').val(oai_settings.nanogpt_model);
@@ -4077,6 +4103,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
4077 cohere_model: settings.cohere_model,4103 cohere_model: settings.cohere_model,
4078 perplexity_model: settings.perplexity_model,4104 perplexity_model: settings.perplexity_model,
4079 groq_model: settings.groq_model,4105 groq_model: settings.groq_model,
4106 siliconflow_model: settings.siliconflow_model,
4080 xai_model: settings.xai_model,4107 xai_model: settings.xai_model,
4081 pollinations_model: settings.pollinations_model,4108 pollinations_model: settings.pollinations_model,
4082 aimlapi_model: settings.aimlapi_model,4109 aimlapi_model: settings.aimlapi_model,
@@ -4766,6 +4793,65 @@ function getZaiMaxContext(model, isUnlocked) {
4766}4793}
47674794
4768/**4795/**
4796 * Get the maximum context size for the SiliconFlow model
4797 * @param {string} model Model identifier
4798 * @param {boolean} isUnlocked Whether context limits are unlocked
4799 * @returns {number} Maximum context size in tokens
4800 */
4801function getSiliconflowMaxContext(model, isUnlocked) {
4802 if (isUnlocked) {
4803 return unlocked_max;
4804 }
4805
4806 const contextMap = {
4807 'baidu/ERNIE-4.5-300B-A47B': max_128k,
4808 'ByteDance-Seed/Seed-OSS-36B-Instruct': max_256k,
4809 'deepseek-ai/DeepSeek-R1': max_128k,
4810 'deepseek-ai/DeepSeek-V3': max_128k,
4811 'deepseek-ai/DeepSeek-V3.1': max_128k,
4812 'deepseek-ai/DeepSeek-V3.1-Terminus': max_128k,
4813 'deepseek-ai/DeepSeek-V3.2-Exp': max_128k,
4814 'deepseek-ai/deepseek-vl2': max_4k,
4815 'inclusionAI/Ling-1T': max_128k,
4816 'inclusionAI/Ling-flash-2.0': max_128k,
4817 'inclusionAI/Ling-mini-2.0': max_128k,
4818 'inclusionAI/Ring-1T': max_128k,
4819 'inclusionAI/Ring-flash-2.0': max_128k,
4820 'meta-llama/Llama-3.3-70B-Instruct': max_32k,
4821 'meta-llama/Meta-Llama-3.1-8B-Instruct': max_32k,
4822 'MiniMaxAI/MiniMax-M1-80k': max_128k,
4823 'MiniMaxAI/MiniMax-M2': max_128k,
4824 'moonshotai/Kimi-K2-Instruct': max_128k,
4825 'moonshotai/Kimi-K2-Instruct-0905': max_256k,
4826 'moonshotai/Kimi-K2-Thinking': max_256k,
4827 'openai/gpt-oss-120b': max_128k,
4828 'openai/gpt-oss-20b': max_128k,
4829 'Qwen/Qwen3-235B-A22B-Instruct-2507': max_256k,
4830 'Qwen/Qwen3-235B-A22B-Thinking-2507': max_256k,
4831 'Qwen/Qwen3-30B-A3B-Instruct-2507': max_256k,
4832 'Qwen/Qwen3-30B-A3B-Thinking-2507': max_256k,
4833 'Qwen/Qwen3-VL-235B-A22B-Instruct': max_256k,
4834 'Qwen/Qwen3-VL-235B-A22B-Thinking': max_256k,
4835 'Qwen/Qwen3-VL-30B-A3B-Instruct': max_256k,
4836 'Qwen/Qwen3-VL-30B-A3B-Thinking': max_256k,
4837 'Qwen/Qwen3-VL-32B-Instruct': max_256k,
4838 'Qwen/Qwen3-VL-32B-Thinking': max_256k,
4839 'Qwen/Qwen3-VL-8B-Instruct': max_256k,
4840 'Qwen/Qwen3-VL-8B-Thinking': max_256k,
4841 'stepfun-ai/step3': max_64k,
4842 'tencent/Hunyuan-A13B-Instruct': max_128k,
4843 'zai-org/GLM-4.5': max_128k,
4844 'zai-org/GLM-4.5-Air': max_128k,
4845 'zai-org/GLM-4.5V': max_64k,
4846 'zai-org/GLM-4.6': max_200k,
4847 };
4848
4849 // Return context size if model found, otherwise default to 32k
4850 return Object.entries(contextMap).find(([key]) => model.includes(key))?.[1] || max_32k;
4851
4852}
4853
4854/**
4769 * Get the maximum context size for the Moonshot model4855 * Get the maximum context size for the Moonshot model
4770 * @param {string} model Model identifier4856 * @param {string} model Model identifier
4771 * @param {boolean} isUnlocked If context limits are unlocked4857 * @param {boolean} isUnlocked If context limits are unlocked
@@ -4956,6 +5042,15 @@ async function onModelChange() {
4956 oai_settings.groq_model = value;5042 oai_settings.groq_model = value;
4957 }5043 }
49585044
5045 if ($(this).is('#model_siliconflow_select')) {
5046 if (!value) {
5047 console.debug('Null SiliconFlow model selected. Ignoring.');
5048 return;
5049 }
5050 console.log('SiliconFlow model changed to', value);
5051 oai_settings.siliconflow_model = value;
5052 }
5053
4959 if ($(this).is('#model_electronhub_select')) {5054 if ($(this).is('#model_electronhub_select')) {
4960 if (!value) {5055 if (!value) {
4961 console.debug('Null ElectronHub model selected. Ignoring.');5056 console.debug('Null ElectronHub model selected. Ignoring.');
@@ -5356,6 +5451,15 @@ async function onModelChange() {
5356 $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input');5451 $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input');
5357 }5452 }
53585453
5454 if (oai_settings.chat_completion_source === chat_completion_sources.SILICONFLOW) {
5455 const maxContext = getSiliconflowMaxContext(oai_settings.siliconflow_model, oai_settings.max_context_unlocked);
5456 $('#openai_max_context').attr('max', maxContext);
5457 oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context);
5458 $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input');
5459 oai_settings.temp_openai = Math.min(oai_max_temp, oai_settings.temp_openai);
5460 $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input');
5461 }
5462
5359 if (oai_settings.chat_completion_source == chat_completion_sources.ZAI) {5463 if (oai_settings.chat_completion_source == chat_completion_sources.ZAI) {
5360 const maxContext = getZaiMaxContext(oai_settings.zai_model, oai_settings.max_context_unlocked);5464 const maxContext = getZaiMaxContext(oai_settings.zai_model, oai_settings.max_context_unlocked);
5361 $('#openai_max_context').attr('max', maxContext);5465 $('#openai_max_context').attr('max', maxContext);
@@ -5411,6 +5515,7 @@ async function onConnectButtonClick(e) {
5411 [chat_completion_sources.COHERE]: { key: SECRET_KEYS.COHERE, selector: '#api_key_cohere', proxy: false },5515 [chat_completion_sources.COHERE]: { key: SECRET_KEYS.COHERE, selector: '#api_key_cohere', proxy: false },
5412 [chat_completion_sources.PERPLEXITY]: { key: SECRET_KEYS.PERPLEXITY, selector: '#api_key_perplexity', proxy: false },5516 [chat_completion_sources.PERPLEXITY]: { key: SECRET_KEYS.PERPLEXITY, selector: '#api_key_perplexity', proxy: false },
5413 [chat_completion_sources.GROQ]: { key: SECRET_KEYS.GROQ, selector: '#api_key_groq', proxy: false },5517 [chat_completion_sources.GROQ]: { key: SECRET_KEYS.GROQ, selector: '#api_key_groq', proxy: false },
5518 [chat_completion_sources.SILICONFLOW]: { key: SECRET_KEYS.SILICONFLOW, selector: '#api_key_siliconflow', proxy: false },
5414 [chat_completion_sources.ELECTRONHUB]: { key: SECRET_KEYS.ELECTRONHUB, selector: '#api_key_electronhub', proxy: false },5519 [chat_completion_sources.ELECTRONHUB]: { key: SECRET_KEYS.ELECTRONHUB, selector: '#api_key_electronhub', proxy: false },
5415 [chat_completion_sources.NANOGPT]: { key: SECRET_KEYS.NANOGPT, selector: '#api_key_nanogpt', proxy: false },5520 [chat_completion_sources.NANOGPT]: { key: SECRET_KEYS.NANOGPT, selector: '#api_key_nanogpt', proxy: false },
5416 [chat_completion_sources.DEEPSEEK]: { key: SECRET_KEYS.DEEPSEEK, selector: '#api_key_deepseek', proxy: true },5521 [chat_completion_sources.DEEPSEEK]: { key: SECRET_KEYS.DEEPSEEK, selector: '#api_key_deepseek', proxy: true },
@@ -5493,6 +5598,9 @@ function toggleChatCompletionForms() {
5493 else if (oai_settings.chat_completion_source == chat_completion_sources.GROQ) {5598 else if (oai_settings.chat_completion_source == chat_completion_sources.GROQ) {
5494 $('#model_groq_select').trigger('change');5599 $('#model_groq_select').trigger('change');
5495 }5600 }
5601 else if (oai_settings.chat_completion_source == chat_completion_sources.SILICONFLOW) {
5602 $('#model_siliconflow_select').trigger('change');
5603 }
5496 else if (oai_settings.chat_completion_source == chat_completion_sources.ELECTRONHUB) {5604 else if (oai_settings.chat_completion_source == chat_completion_sources.ELECTRONHUB) {
5497 $('#model_electronhub_select').trigger('change');5605 $('#model_electronhub_select').trigger('change');
5498 }5606 }
@@ -5647,6 +5755,12 @@ export function isImageInliningSupported() {
5647 'moonshot-v1-128k-vision-preview',5755 'moonshot-v1-128k-vision-preview',
5648 // Z.AI (GLM)5756 // Z.AI (GLM)
5649 'glm-4.5v',5757 'glm-4.5v',
5758 // SiliconFlow
5759 'Qwen/Qwen3-VL-32B-Instruct',
5760 'Qwen/Qwen3-VL-8B-Instruct',
5761 'Qwen/Qwen3-VL-235B-A22B-Instruct',
5762 'Qwen/Qwen3-VL-30B-A3B-Instruct',
5763 'zai-org/GLM-4.5V',
5650 ];5764 ];
56515765
5652 switch (oai_settings.chat_completion_source) {5766 switch (oai_settings.chat_completion_source) {
@@ -5691,6 +5805,8 @@ export function isImageInliningSupported() {
5691 return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.nanogpt_model)?.capabilities?.vision);5805 return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.nanogpt_model)?.capabilities?.vision);
5692 case chat_completion_sources.ZAI:5806 case chat_completion_sources.ZAI:
5693 return visionSupportedModels.some(model => oai_settings.zai_model.includes(model));5807 return visionSupportedModels.some(model => oai_settings.zai_model.includes(model));
5808 case chat_completion_sources.SILICONFLOW:
5809 return visionSupportedModels.some(model => oai_settings.siliconflow_model.includes(model));
5694 default:5810 default:
5695 return false;5811 return false;
5696 }5812 }
@@ -6571,6 +6687,7 @@ export function initOpenAI() {
6571 $('#model_cohere_select').on('change', onModelChange);6687 $('#model_cohere_select').on('change', onModelChange);
6572 $('#model_perplexity_select').on('change', onModelChange);6688 $('#model_perplexity_select').on('change', onModelChange);
6573 $('#model_groq_select').on('change', onModelChange);6689 $('#model_groq_select').on('change', onModelChange);
6690 $('#model_siliconflow_select').on('change', onModelChange);
6574 $('#model_electronhub_select').on('change', onModelChange);6691 $('#model_electronhub_select').on('change', onModelChange);
6575 $('#model_nanogpt_select').on('change', onModelChange);6692 $('#model_nanogpt_select').on('change', onModelChange);
6576 $('#model_deepseek_select').on('change', onModelChange);6693 $('#model_deepseek_select').on('change', onModelChange);
public/scripts/reasoning.js+1 -0
@@ -127,6 +127,7 @@ export function extractReasoningFromData(data, {
127 case chat_completion_sources.COMETAPI:127 case chat_completion_sources.COMETAPI:
128 case chat_completion_sources.ELECTRONHUB:128 case chat_completion_sources.ELECTRONHUB:
129 case chat_completion_sources.NANOGPT:129 case chat_completion_sources.NANOGPT:
130 case chat_completion_sources.SILICONFLOW:
130 case chat_completion_sources.ZAI:131 case chat_completion_sources.ZAI:
131 case chat_completion_sources.CUSTOM: {132 case chat_completion_sources.CUSTOM: {
132 return data?.choices?.[0]?.message?.reasoning_content133 return data?.choices?.[0]?.message?.reasoning_content
public/scripts/secrets.js+3 -0
@@ -69,6 +69,7 @@ export const SECRET_KEYS = {
69 MOONSHOT: 'api_key_moonshot',69 MOONSHOT: 'api_key_moonshot',
70 COMETAPI: 'api_key_cometapi',70 COMETAPI: 'api_key_cometapi',
71 ZAI: 'api_key_zai',71 ZAI: 'api_key_zai',
72 SILICONFLOW: 'api_key_siliconflow',
72};73};
7374
74const FRIENDLY_NAMES = {75const FRIENDLY_NAMES = {
@@ -126,6 +127,7 @@ const FRIENDLY_NAMES = {
126 [SECRET_KEYS.COMETAPI]: 'CometAPI',127 [SECRET_KEYS.COMETAPI]: 'CometAPI',
127 [SECRET_KEYS.AZURE_OPENAI]: 'Azure OpenAI',128 [SECRET_KEYS.AZURE_OPENAI]: 'Azure OpenAI',
128 [SECRET_KEYS.ZAI]: 'Z.AI',129 [SECRET_KEYS.ZAI]: 'Z.AI',
130 [SECRET_KEYS.SILICONFLOW]: 'SiliconFlow',
129};131};
130132
131const INPUT_MAP = {133const INPUT_MAP = {
@@ -166,6 +168,7 @@ const INPUT_MAP = {
166 [SECRET_KEYS.COMETAPI]: '#api_key_cometapi',168 [SECRET_KEYS.COMETAPI]: '#api_key_cometapi',
167 [SECRET_KEYS.AZURE_OPENAI]: '#api_key_azure_openai',169 [SECRET_KEYS.AZURE_OPENAI]: '#api_key_azure_openai',
168 [SECRET_KEYS.ZAI]: '#api_key_zai',170 [SECRET_KEYS.ZAI]: '#api_key_zai',
171 [SECRET_KEYS.SILICONFLOW]: '#api_key_siliconflow',
169};172};
170173
171const getLabel = () => moment().format('L LT');174const getLabel = () => moment().format('L LT');
public/scripts/slash-commands.js+1 -0
@@ -4844,6 +4844,7 @@ function getModelOptions(quiet) {
4844 { id: 'model_cohere_select', api: 'openai', type: chat_completion_sources.COHERE },4844 { id: 'model_cohere_select', api: 'openai', type: chat_completion_sources.COHERE },
4845 { id: 'model_perplexity_select', api: 'openai', type: chat_completion_sources.PERPLEXITY },4845 { id: 'model_perplexity_select', api: 'openai', type: chat_completion_sources.PERPLEXITY },
4846 { id: 'model_groq_select', api: 'openai', type: chat_completion_sources.GROQ },4846 { id: 'model_groq_select', api: 'openai', type: chat_completion_sources.GROQ },
4847 { id: 'model_siliconflow_select', api: 'openai', type: chat_completion_sources.SILICONFLOW },
4847 { id: 'model_electronhub_select', api: 'openai', type: chat_completion_sources.ELECTRONHUB },4848 { id: 'model_electronhub_select', api: 'openai', type: chat_completion_sources.ELECTRONHUB },
4848 { id: 'model_nanogpt_select', api: 'openai', type: chat_completion_sources.NANOGPT },4849 { id: 'model_nanogpt_select', api: 'openai', type: chat_completion_sources.NANOGPT },
4849 { id: 'model_deepseek_select', api: 'openai', type: chat_completion_sources.DEEPSEEK },4850 { id: 'model_deepseek_select', api: 'openai', type: chat_completion_sources.DEEPSEEK },
public/scripts/tool-calling.js+1 -0
@@ -662,6 +662,7 @@ export class ToolManager {
662 chat_completion_sources.ELECTRONHUB,662 chat_completion_sources.ELECTRONHUB,
663 chat_completion_sources.AZURE_OPENAI,663 chat_completion_sources.AZURE_OPENAI,
664 chat_completion_sources.ZAI,664 chat_completion_sources.ZAI,
665 chat_completion_sources.SILICONFLOW,
665 ];666 ];
666 return supportedSources.includes(oai_settings.chat_completion_source);667 return supportedSources.includes(oai_settings.chat_completion_source);
667 }668 }
src/constants.js+1 -0
@@ -207,6 +207,7 @@ export const CHAT_COMPLETION_SOURCES = {
207 COMETAPI: 'cometapi',207 COMETAPI: 'cometapi',
208 AZURE_OPENAI: 'azure_openai',208 AZURE_OPENAI: 'azure_openai',
209 ZAI: 'zai',209 ZAI: 'zai',
210 SILICONFLOW: 'siliconflow',
210};211};
211212
212/**213/**
src/endpoints/backends/chat-completions.js+13 -0
@@ -76,6 +76,7 @@ const API_MOONSHOT = 'https://api.moonshot.ai/v1';
76const API_FIREWORKS = 'https://api.fireworks.ai/inference/v1';76const API_FIREWORKS = 'https://api.fireworks.ai/inference/v1';
77const API_COMETAPI = 'https://api.cometapi.com/v1';77const API_COMETAPI = 'https://api.cometapi.com/v1';
78const API_ZAI = 'https://api.z.ai/api/paas/v4';78const API_ZAI = 'https://api.z.ai/api/paas/v4';
79const API_SILICONFLOW = 'https://api.siliconflow.com/v1';
7980
80/**81/**
81 * Gets OpenRouter transforms based on the request.82 * Gets OpenRouter transforms based on the request.
@@ -1570,6 +1571,10 @@ router.post('/status', async function (request, statusResponse) {
1570 console.error('Azure OpenAI status check connection error:', error);1571 console.error('Azure OpenAI status check connection error:', error);
1571 return statusResponse.status(500).send({ error: true, message: 'Failed to connect to the Azure endpoint.' });1572 return statusResponse.status(500).send({ error: true, message: 'Failed to connect to the Azure endpoint.' });
1572 }1573 }
1574 } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.SILICONFLOW) {
1575 apiUrl = API_SILICONFLOW;
1576 apiKey = readSecret(request.user.directories, SECRET_KEYS.SILICONFLOW);
1577 headers = {};
1573 } else {1578 } else {
1574 console.warn('This chat completion source is not supported yet.');1579 console.warn('This chat completion source is not supported yet.');
1575 return statusResponse.status(400).send({ error: true });1580 return statusResponse.status(400).send({ error: true });
@@ -1980,6 +1985,14 @@ router.post('/generate', function (request, response) {
1980 if (request.body.json_schema) {1985 if (request.body.json_schema) {
1981 setJsonObjectFormat(bodyParams, request.body.messages, request.body.json_schema);1986 setJsonObjectFormat(bodyParams, request.body.messages, request.body.json_schema);
1982 }1987 }
1988 } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.SILICONFLOW) {
1989 apiUrl = API_SILICONFLOW;
1990 apiKey = readSecret(request.user.directories, SECRET_KEYS.SILICONFLOW);
1991 headers = {};
1992 bodyParams = {};
1993 if (request.body.json_schema) {
1994 setJsonObjectFormat(bodyParams, request.body.messages, request.body.json_schema);
1995 }
1983 } else {1996 } else {
1984 console.warn('This chat completion source is not supported yet.');1997 console.warn('This chat completion source is not supported yet.');
1985 return response.status(400).send({ error: true });1998 return response.status(400).send({ error: true });
src/endpoints/secrets.js+1 -0
@@ -62,6 +62,7 @@ export const SECRET_KEYS = {
62 COMETAPI: 'api_key_cometapi',62 COMETAPI: 'api_key_cometapi',
63 AZURE_OPENAI: 'api_key_azure_openai',63 AZURE_OPENAI: 'api_key_azure_openai',
64 ZAI: 'api_key_zai',64 ZAI: 'api_key_zai',
65 SILICONFLOW: 'api_key_siliconflow',
65};66};
6667
67/**68/**