Add CometAPI as a model provider in "Chat Completion" (#4402) * feat: Add support for CometAPI, including API key management and model selection features. * Some code fixes * Fix loading model from presets * Add logo image * Enable tool calling, reasoning effort, reasoning display, structured generation --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>

41c74fd142eda6d4ed43987dad19c01459ce711d

TensorNull <129579691+TensorNull@users.noreply.github.com>

Signed
12 files changed, +132 -10Ignore whitespace
public/img/cometapi.svg+1 -0
@@ -0,0 +1 @@
1<svg version="1.0" width="274.67" height="309.33" viewBox="0 0 206 232" xmlns="http://www.w3.org/2000/svg"><path d="M127.3.98c-7 0-14 .67-19.3 2.02a77.68 77.68 0 0 0-50 40.5C53.2 53 0 200.9 0 204.5c0 1.4.6 2.5 1.3 2.5 1.5 0 10.1-8.7 23.1-23.7 10.1-11.6 14.2-15.1 15.7-13.6 1.4 1.4-.7 7.2-10.1 29.3-9.7 22.6-11.5 27.9-10 29.4 1.8 1.8 4.6-.3 29.1-22.2 15.6-14 21.9-17.9 21.9-13.5 0 .9-2.9 7.8-6.4 15.4-7.5 16-9.4 21.5-7.9 23 2.6 2.6 3.3 2.1 71.9-52.7 27-21.5 51.4-41.5 54.2-44.3 9.8-9.8 17.2-22.8 20.8-36.6 2.6-10.4 2.5-28.6-.4-38.8-8-28.1-28.7-48.5-56.6-55.7-5.3-1.35-12.3-2.02-19.3-2.02zm-.74 14.13c5.77-.1 11.5.48 16.64 1.79a64.64 64.64 0 0 1 46.3 46.2c2.2 8.3 2.3 22.5.1 30.9-4.5 17.9-17.4 34-33.6 41.9-11 5.4-20.9 7.5-32.1 6.8-22.9-1.4-44.1-15.5-53.8-35.9-5-10.6-6.5-17.1-6.4-28.3.1-24.7 13.5-46 36.1-57.4 7.37-3.75 17.13-5.82 26.76-6zm.61 16.05c-4.6.02-9.17.44-12.17 1.24-24.2 6.8-39.6 31.4-34.6 55.3 4 19.5 18.5 34.2 37.4 38.2 36.7 7.6 67.3-28.2 54.7-64-4.9-13.8-18-25.5-33-29.5-3.1-.85-7.73-1.25-12.33-1.24zM132 42.41c3.9.05 7.81.87 11.5 2.49a29 29 0 0 1 17.3 24.9c.5 7.6-1.1 14-4.9 19.2-5.1 7.1-10.8 8.5-19.9 5.1-6.9-2.6-26.9-16.1-29.9-20.1-4.6-6.4-3.7-13.9 2.8-21.3A30.28 30.28 0 0 1 132 42.41z"/></svg>
\ No newline at end of file1 \ No newline at end of file
public/index.html+27 -8
@@ -691,7 +691,7 @@
691 </span>691 </span>
692 </div>692 </div>
693 </div>693 </div>
694 <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,nanogpt,deepseek,xai,pollinations,moonshot,fireworks">694 <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi">
695 <div class="range-block-title" data-i18n="Temperature">695 <div class="range-block-title" data-i18n="Temperature">
696 Temperature696 Temperature
697 </div>697 </div>
@@ -704,7 +704,7 @@
704 </div>704 </div>
705 </div>705 </div>
706 </div>706 </div>
707 <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek,xai,pollinations,moonshot,fireworks">707 <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi">
708 <div class="range-block-title" data-i18n="Frequency Penalty">708 <div class="range-block-title" data-i18n="Frequency Penalty">
709 Frequency Penalty709 Frequency Penalty
710 </div>710 </div>
@@ -717,7 +717,7 @@
717 </div>717 </div>
718 </div>718 </div>
719 </div>719 </div>
720 <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek,xai,pollinations,moonshot,fireworks">720 <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi">
721 <div class="range-block-title" data-i18n="Presence Penalty">721 <div class="range-block-title" data-i18n="Presence Penalty">
722 Presence Penalty722 Presence Penalty
723 </div>723 </div>
@@ -743,7 +743,7 @@
743 </div>743 </div>
744 </div>744 </div>
745 </div>745 </div>
746 <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,nanogpt,deepseek,xai,pollinations,moonshot,fireworks">746 <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi">
747 <div class="range-block-title" data-i18n="Top P">747 <div class="range-block-title" data-i18n="Top P">
748 Top P748 Top P
749 </div>749 </div>
@@ -1984,7 +1984,7 @@
1984 </b>1984 </b>
1985 </div>1985 </div>
1986 </div>1986 </div>
1987 <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,aimlapi,openrouter,groq,deepseek,makersuite,vertexai,ai21,xai,pollinations,moonshot,fireworks">1987 <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,aimlapi,openrouter,groq,deepseek,makersuite,vertexai,ai21,xai,pollinations,moonshot,fireworks,cometapi">
1988 <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand">1988 <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand">
1989 <input id="openai_function_calling" type="checkbox" />1989 <input id="openai_function_calling" type="checkbox" />
1990 <span data-i18n="Enable function calling">Enable function calling</span>1990 <span data-i18n="Enable function calling">Enable function calling</span>
@@ -1999,7 +1999,7 @@
1999 <strong data-i18n="enable_functions_desc_4">Not supported when Prompt Post-Processing with "no tools" is used!</strong>1999 <strong data-i18n="enable_functions_desc_4">Not supported when Prompt Post-Processing with "no tools" is used!</strong>
2000 </div>2000 </div>
2001 </div>2001 </div>
2002 <div class="range-block" data-source="openai,aimlapi,openrouter,mistralai,makersuite,vertexai,claude,custom,xai,pollinations,moonshot,cohere">2002 <div class="range-block" data-source="openai,aimlapi,openrouter,mistralai,makersuite,vertexai,claude,custom,xai,pollinations,moonshot,cohere,cometapi">
2003 <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand">2003 <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand">
2004 <input id="openai_image_inlining" type="checkbox" />2004 <input id="openai_image_inlining" type="checkbox" />
2005 <span data-i18n="Send inline images">Send inline images</span>2005 <span data-i18n="Send inline images">Send inline images</span>
@@ -2077,7 +2077,7 @@
2077 </span>2077 </span>
2078 </div>2078 </div>
2079 </div>2079 </div>
2080 <div class="range-block" data-source="deepseek,aimlapi,openrouter,custom,claude,xai,makersuite,vertexai,pollinations,moonshot,mistralai,fireworks">2080 <div class="range-block" data-source="deepseek,aimlapi,openrouter,custom,claude,xai,makersuite,vertexai,pollinations,moonshot,mistralai,fireworks,cometapi">
2081 <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand">2081 <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand">
2082 <input id="openai_show_thoughts" type="checkbox" />2082 <input id="openai_show_thoughts" type="checkbox" />
2083 <span data-i18n="Request model reasoning">Request model reasoning</span>2083 <span data-i18n="Request model reasoning">Request model reasoning</span>
@@ -2091,7 +2091,7 @@
2091 </span>2091 </span>
2092 </div>2092 </div>
2093 </div>2093 </div>
2094 <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,claude,xai,makersuite,vertexai,aimlapi,openrouter,pollinations,perplexity">2094 <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,claude,xai,makersuite,vertexai,aimlapi,openrouter,pollinations,perplexity,cometapi">
2095 <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.">2095 <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.">
2096 <label for="openai_reasoning_effort">2096 <label for="openai_reasoning_effort">
2097 <span data-i18n="Reasoning Effort">Reasoning Effort</span>2097 <span data-i18n="Reasoning Effort">Reasoning Effort</span>
@@ -2804,6 +2804,7 @@
2804 <option value="aimlapi">AI/ML API</option>2804 <option value="aimlapi">AI/ML API</option>
2805 <option value="claude">Claude</option>2805 <option value="claude">Claude</option>
2806 <option value="cohere">Cohere</option>2806 <option value="cohere">Cohere</option>
2807 <option value="cometapi">CometAPI</option>
2807 <option value="deepseek">DeepSeek</option>2808 <option value="deepseek">DeepSeek</option>
2808 <option value="fireworks">Fireworks AI</option>2809 <option value="fireworks">Fireworks AI</option>
2809 <option value="groq">Groq</option>2810 <option value="groq">Groq</option>
@@ -3515,6 +3516,24 @@
3515 </select>3516 </select>
3516 </div>3517 </div>
3517 </div>3518 </div>
3519 <div id="cometapi_form" data-source="cometapi">
3520 <h4><a href="https://api.cometapi.com/" target="_blank" rel="noopener noreferrer" data-i18n="CometAPI API Key">CometAPI API Key</a></h4>
3521 <div class="flex-container">
3522 <input id="api_key_cometapi" name="api_key_cometapi" class="text_pole flex1" value="" type="text" autocomplete="off">
3523 <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_cometapi"></div>
3524 </div>
3525 <div data-for="api_key_cometapi" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'.">
3526 For privacy reasons, your API key will be hidden after you click 'Connect'.
3527 </div>
3528 <div>
3529 <h4 data-i18n="CometAPI Model">CometAPI Model</h4>
3530 <div class="flex-container">
3531 <select id="model_cometapi_select" class="flex1">
3532 <option value="" data-i18n="-- Connect to the API --">-- Connect to the API --</option>
3533 </select>
3534 </div>
3535 </div>
3536 </div>
3518 <div id="perplexity_form" data-source="perplexity">3537 <div id="perplexity_form" data-source="perplexity">
3519 <h4 data-i18n="Perplexity API Key">Perplexity API Key</h4>3538 <h4 data-i18n="Perplexity API Key">Perplexity API Key</h4>
3520 <div class="flex-container">3539 <div class="flex-container">
public/scripts/RossAscends-mods.js+1 -0
@@ -408,6 +408,7 @@ function RA_autoconnect(PrevApi) {
408 || (secret_state[SECRET_KEYS.AIMLAPI] && oai_settings.chat_completion_source == chat_completion_sources.AIMLAPI)408 || (secret_state[SECRET_KEYS.AIMLAPI] && oai_settings.chat_completion_source == chat_completion_sources.AIMLAPI)
409 || (secret_state[SECRET_KEYS.MOONSHOT] && oai_settings.chat_completion_source == chat_completion_sources.MOONSHOT)409 || (secret_state[SECRET_KEYS.MOONSHOT] && oai_settings.chat_completion_source == chat_completion_sources.MOONSHOT)
410 || (secret_state[SECRET_KEYS.FIREWORKS] && oai_settings.chat_completion_source == chat_completion_sources.FIREWORKS)410 || (secret_state[SECRET_KEYS.FIREWORKS] && oai_settings.chat_completion_source == chat_completion_sources.FIREWORKS)
411 || (secret_state[SECRET_KEYS.COMETAPI] && oai_settings.chat_completion_source == chat_completion_sources.COMETAPI)
411 || (oai_settings.chat_completion_source === chat_completion_sources.POLLINATIONS)412 || (oai_settings.chat_completion_source === chat_completion_sources.POLLINATIONS)
412 || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM)413 || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM)
413 ) {414 ) {
public/scripts/constants.js+13 -0
@@ -52,3 +52,16 @@ export const inject_ids = {
52 CUSTOM_WI_DEPTH: 'customDepthWI',52 CUSTOM_WI_DEPTH: 'customDepthWI',
53 CUSTOM_WI_DEPTH_ROLE: (depth, role) => `customDepthWI_${depth}_${role}`,53 CUSTOM_WI_DEPTH_ROLE: (depth, role) => `customDepthWI_${depth}_${role}`,
54};54};
55
56export const COMETAPI_IGNORE_PATTERNS = [
57 // Image generation models
58 'dall-e', 'dalle', 'midjourney', 'mj_', 'stable-diffusion', 'sd-',
59 'flux-', 'playground-v', 'ideogram', 'recraft-', 'black-forest-labs',
60 '/recraft-v3', 'recraftv3', 'stability-ai/', 'sdxl',
61 // Audio generation models
62 'suno_', 'tts', 'whisper',
63 // Video generation models
64 'runway', 'luma_', 'luma-', 'veo', 'kling_', 'minimax_video', 'hunyuan-t1',
65 // Utility models
66 'embedding', 'search-gpts', 'files_retrieve', 'moderation',
67];
public/scripts/openai.js+70 -2
@@ -74,7 +74,7 @@ import { callGenericPopup, Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js';
74import { t } from './i18n.js';74import { t } from './i18n.js';
75import { ToolManager } from './tool-calling.js';75import { ToolManager } from './tool-calling.js';
76import { accountStorage } from './util/AccountStorage.js';76import { accountStorage } from './util/AccountStorage.js';
77import { IGNORE_SYMBOL } from './constants.js';77import { COMETAPI_IGNORE_PATTERNS, IGNORE_SYMBOL } from './constants.js';
7878
79export {79export {
80 openai_messages_count,80 openai_messages_count,
@@ -186,6 +186,7 @@ export const chat_completion_sources = {
186 POLLINATIONS: 'pollinations',186 POLLINATIONS: 'pollinations',
187 MOONSHOT: 'moonshot',187 MOONSHOT: 'moonshot',
188 FIREWORKS: 'fireworks',188 FIREWORKS: 'fireworks',
189 COMETAPI: 'cometapi',
189};190};
190191
191const character_names_behavior = {192const character_names_behavior = {
@@ -277,6 +278,7 @@ export const settingsToUpdate = {
277 pollinations_model: ['#model_pollinations_select', 'pollinations_model', false, true],278 pollinations_model: ['#model_pollinations_select', 'pollinations_model', false, true],
278 moonshot_model: ['#model_moonshot_select', 'moonshot_model', false, true],279 moonshot_model: ['#model_moonshot_select', 'moonshot_model', false, true],
279 fireworks_model: ['#model_fireworks_select', 'fireworks_model', false, true],280 fireworks_model: ['#model_fireworks_select', 'fireworks_model', false, true],
281 cometapi_model: ['#model_cometapi_select', 'cometapi_model', false, true],
280 custom_model: ['#custom_model_id', 'custom_model', false, true],282 custom_model: ['#custom_model_id', 'custom_model', false, true],
281 custom_url: ['#custom_api_url_text', 'custom_url', false, true],283 custom_url: ['#custom_api_url_text', 'custom_url', false, true],
282 custom_include_body: ['#custom_include_body', 'custom_include_body', false, true],284 custom_include_body: ['#custom_include_body', 'custom_include_body', false, true],
@@ -372,6 +374,7 @@ const default_settings = {
372 aimlapi_model: 'gpt-4o-mini-2024-07-18',374 aimlapi_model: 'gpt-4o-mini-2024-07-18',
373 xai_model: 'grok-3-beta',375 xai_model: 'grok-3-beta',
374 pollinations_model: 'openai',376 pollinations_model: 'openai',
377 cometapi_model: 'gpt-4o',
375 moonshot_model: 'kimi-latest',378 moonshot_model: 'kimi-latest',
376 fireworks_model: 'accounts/fireworks/models/kimi-k2-instruct',379 fireworks_model: 'accounts/fireworks/models/kimi-k2-instruct',
377 custom_model: '',380 custom_model: '',
@@ -460,6 +463,7 @@ const oai_settings = {
460 aimlapi_model: 'gpt-4-turbo',463 aimlapi_model: 'gpt-4-turbo',
461 xai_model: 'grok-3-beta',464 xai_model: 'grok-3-beta',
462 pollinations_model: 'openai',465 pollinations_model: 'openai',
466 cometapi_model: 'gpt-4o',
463 moonshot_model: 'kimi-latest',467 moonshot_model: 'kimi-latest',
464 fireworks_model: 'accounts/fireworks/models/kimi-k2-instruct',468 fireworks_model: 'accounts/fireworks/models/kimi-k2-instruct',
465 custom_model: '',469 custom_model: '',
@@ -1622,6 +1626,8 @@ export function getChatCompletionModel(source = null) {
1622 return oai_settings.xai_model;1626 return oai_settings.xai_model;
1623 case chat_completion_sources.POLLINATIONS:1627 case chat_completion_sources.POLLINATIONS:
1624 return oai_settings.pollinations_model;1628 return oai_settings.pollinations_model;
1629 case chat_completion_sources.COMETAPI:
1630 return oai_settings.cometapi_model;
1625 case chat_completion_sources.MOONSHOT:1631 case chat_completion_sources.MOONSHOT:
1626 return oai_settings.moonshot_model;1632 return oai_settings.moonshot_model;
1627 case chat_completion_sources.FIREWORKS:1633 case chat_completion_sources.FIREWORKS:
@@ -1899,6 +1905,29 @@ function saveModelList(data) {
18991905
1900 $('#model_fireworks_select').val(oai_settings.fireworks_model).trigger('change');1906 $('#model_fireworks_select').val(oai_settings.fireworks_model).trigger('change');
1901 }1907 }
1908
1909 if (oai_settings.chat_completion_source === chat_completion_sources.COMETAPI) {
1910 $('#model_cometapi_select').empty();
1911
1912 model_list.forEach((model) => {
1913 const modelId = model.id.toLowerCase();
1914 const isIgnoredModel = COMETAPI_IGNORE_PATTERNS.some(pattern => modelId.includes(pattern));
1915
1916 if (isIgnoredModel) {
1917 return;
1918 }
1919
1920 $('#model_cometapi_select').append(new Option(model.id, model.id));
1921 });
1922
1923 const selectedModel = model_list.find(model => model.id === oai_settings.cometapi_model);
1924 if (model_list.length > 0 && (!selectedModel || !oai_settings.cometapi_model)) {
1925 oai_settings.cometapi_model = model_list[0].id;
1926 saveSettingsDebounced();
1927 }
1928
1929 $('#model_cometapi_select').val(oai_settings.cometapi_model).trigger('change');
1930 }
1902}1931}
19031932
1904function appendOpenRouterOptions(model_list, groupModels = false, sort = false) {1933function appendOpenRouterOptions(model_list, groupModels = false, sort = false) {
@@ -2016,6 +2045,7 @@ function getReasoningEffort() {
2016 chat_completion_sources.OPENROUTER,2045 chat_completion_sources.OPENROUTER,
2017 chat_completion_sources.POLLINATIONS,2046 chat_completion_sources.POLLINATIONS,
2018 chat_completion_sources.PERPLEXITY,2047 chat_completion_sources.PERPLEXITY,
2048 chat_completion_sources.COMETAPI,
2019 ];2049 ];
20202050
2021 if (!reasoningEffortSources.includes(oai_settings.chat_completion_source)) {2051 if (!reasoningEffortSources.includes(oai_settings.chat_completion_source)) {
@@ -2439,7 +2469,7 @@ export function getStreamingReply(data, state, { chatCompletionSource = null, ov
2439 state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning)?.[0]?.delta?.reasoning || '');2469 state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning)?.[0]?.delta?.reasoning || '');
2440 }2470 }
2441 return data.choices?.[0]?.delta?.content ?? data.choices?.[0]?.message?.content ?? data.choices?.[0]?.text ?? '';2471 return data.choices?.[0]?.delta?.content ?? data.choices?.[0]?.message?.content ?? data.choices?.[0]?.text ?? '';
2442 } else if ([chat_completion_sources.CUSTOM, chat_completion_sources.POLLINATIONS, chat_completion_sources.AIMLAPI, chat_completion_sources.MOONSHOT].includes(chat_completion_source)) {2472 } else if ([chat_completion_sources.CUSTOM, chat_completion_sources.POLLINATIONS, chat_completion_sources.AIMLAPI, chat_completion_sources.MOONSHOT, chat_completion_sources.COMETAPI].includes(chat_completion_source)) {
2443 if (show_thoughts) {2473 if (show_thoughts) {
2444 state.reasoning +=2474 state.reasoning +=
2445 data.choices?.filter(x => x?.delta?.reasoning_content)?.[0]?.delta?.reasoning_content ??2475 data.choices?.filter(x => x?.delta?.reasoning_content)?.[0]?.delta?.reasoning_content ??
@@ -3406,6 +3436,7 @@ function loadOpenAISettings(data, settings) {
3406 oai_settings.aimlapi_model = settings.aimlapi_model ?? default_settings.aimlapi_model;3436 oai_settings.aimlapi_model = settings.aimlapi_model ?? default_settings.aimlapi_model;
3407 oai_settings.xai_model = settings.xai_model ?? default_settings.xai_model;3437 oai_settings.xai_model = settings.xai_model ?? default_settings.xai_model;
3408 oai_settings.pollinations_model = settings.pollinations_model ?? default_settings.pollinations_model;3438 oai_settings.pollinations_model = settings.pollinations_model ?? default_settings.pollinations_model;
3439 oai_settings.cometapi_model = settings.cometapi_model ?? default_settings.cometapi_model;
3409 oai_settings.moonshot_model = settings.moonshot_model ?? default_settings.moonshot_model;3440 oai_settings.moonshot_model = settings.moonshot_model ?? default_settings.moonshot_model;
3410 oai_settings.fireworks_model = settings.fireworks_model ?? default_settings.fireworks_model;3441 oai_settings.fireworks_model = settings.fireworks_model ?? default_settings.fireworks_model;
3411 oai_settings.custom_model = settings.custom_model ?? default_settings.custom_model;3442 oai_settings.custom_model = settings.custom_model ?? default_settings.custom_model;
@@ -3783,6 +3814,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
3783 aimlapi_model: settings.aimlapi_model,3814 aimlapi_model: settings.aimlapi_model,
3784 moonshot_model: settings.moonshot_model,3815 moonshot_model: settings.moonshot_model,
3785 fireworks_model: settings.fireworks_model,3816 fireworks_model: settings.fireworks_model,
3817 cometapi_model: settings.cometapi_model,
3786 custom_model: settings.custom_model,3818 custom_model: settings.custom_model,
3787 custom_url: settings.custom_url,3819 custom_url: settings.custom_url,
3788 custom_include_body: settings.custom_include_body,3820 custom_include_body: settings.custom_include_body,
@@ -4694,6 +4726,15 @@ async function onModelChange() {
4694 oai_settings.fireworks_model = value;4726 oai_settings.fireworks_model = value;
4695 }4727 }
46964728
4729 if ($(this).is('#model_cometapi_select')) {
4730 if (!value) {
4731 console.debug('Null CometAPI model selected. Ignoring.');
4732 return;
4733 }
4734 console.log('CometAPI model changed to', value);
4735 oai_settings.cometapi_model = value;
4736 }
4737
4697 if ([chat_completion_sources.MAKERSUITE, chat_completion_sources.VERTEXAI].includes(oai_settings.chat_completion_source)) {4738 if ([chat_completion_sources.MAKERSUITE, chat_completion_sources.VERTEXAI].includes(oai_settings.chat_completion_source)) {
4698 if (oai_settings.max_context_unlocked) {4739 if (oai_settings.max_context_unlocked) {
4699 $('#openai_max_context').attr('max', max_2mil);4740 $('#openai_max_context').attr('max', max_2mil);
@@ -4905,6 +4946,13 @@ async function onModelChange() {
4905 $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input');4946 $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input');
4906 }4947 }
49074948
4949 if (oai_settings.chat_completion_source === chat_completion_sources.COMETAPI) {
4950 $('#openai_max_context').attr('max', oai_settings.max_context_unlocked ? unlocked_max : max_128k);
4951 oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context);
4952 $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input');
4953 $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input');
4954 }
4955
4908 if (oai_settings.chat_completion_source === chat_completion_sources.XAI) {4956 if (oai_settings.chat_completion_source === chat_completion_sources.XAI) {
4909 if (oai_settings.max_context_unlocked) {4957 if (oai_settings.max_context_unlocked) {
4910 $('#openai_max_context').attr('max', unlocked_max);4958 $('#openai_max_context').attr('max', unlocked_max);
@@ -5233,6 +5281,19 @@ async function onConnectButtonClick(e) {
5233 }5281 }
5234 }5282 }
52355283
5284 if (oai_settings.chat_completion_source == chat_completion_sources.COMETAPI) {
5285 const api_key_cometapi = String($('#api_key_cometapi').val()).trim();
5286
5287 if (api_key_cometapi.length) {
5288 await writeSecret(SECRET_KEYS.COMETAPI, api_key_cometapi);
5289 }
5290
5291 if (!api_key_cometapi && !secret_state[SECRET_KEYS.COMETAPI]) {
5292 console.log('No secret key saved for CometAPI');
5293 return;
5294 }
5295 }
5296
5236 startStatusLoading();5297 startStatusLoading();
5237 saveSettingsDebounced();5298 saveSettingsDebounced();
5238 await getStatusOpen();5299 await getStatusOpen();
@@ -5300,6 +5361,10 @@ function toggleChatCompletionForms() {
5300 else if (oai_settings.chat_completion_source == chat_completion_sources.FIREWORKS) {5361 else if (oai_settings.chat_completion_source == chat_completion_sources.FIREWORKS) {
5301 $('#model_fireworks_select').trigger('change');5362 $('#model_fireworks_select').trigger('change');
5302 }5363 }
5364 else if (oai_settings.chat_completion_source == chat_completion_sources.COMETAPI) {
5365 $('#model_cometapi_select').trigger('change');
5366 }
5367
5303 $('[data-source]').each(function () {5368 $('[data-source]').each(function () {
5304 const validSources = $(this).data('source').split(',');5369 const validSources = $(this).data('source').split(',');
5305 $(this).toggle(validSources.includes(oai_settings.chat_completion_source));5370 $(this).toggle(validSources.includes(oai_settings.chat_completion_source));
@@ -5442,6 +5507,8 @@ export function isImageInliningSupported() {
5442 return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.aimlapi_model)?.features?.includes('openai/chat-completion.vision'));5507 return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.aimlapi_model)?.features?.includes('openai/chat-completion.vision'));
5443 case chat_completion_sources.POLLINATIONS:5508 case chat_completion_sources.POLLINATIONS:
5444 return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.pollinations_model)?.vision);5509 return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.pollinations_model)?.vision);
5510 case chat_completion_sources.COMETAPI:
5511 return true;
5445 case chat_completion_sources.MOONSHOT:5512 case chat_completion_sources.MOONSHOT:
5446 return visionSupportedModels.some(model => oai_settings.moonshot_model.includes(model));5513 return visionSupportedModels.some(model => oai_settings.moonshot_model.includes(model));
5447 default:5514 default:
@@ -6250,6 +6317,7 @@ export function initOpenAI() {
6250 $('#model_custom_select').on('change', onModelChange);6317 $('#model_custom_select').on('change', onModelChange);
6251 $('#model_xai_select').on('change', onModelChange);6318 $('#model_xai_select').on('change', onModelChange);
6252 $('#model_pollinations_select').on('change', onModelChange);6319 $('#model_pollinations_select').on('change', onModelChange);
6320 $('#model_cometapi_select').on('change', onModelChange);
6253 $('#model_moonshot_select').on('change', onModelChange);6321 $('#model_moonshot_select').on('change', onModelChange);
6254 $('#model_fireworks_select').on('change', onModelChange);6322 $('#model_fireworks_select').on('change', onModelChange);
6255 $('#settings_preset_openai').on('change', onSettingsPresetChange);6323 $('#settings_preset_openai').on('change', onSettingsPresetChange);
public/scripts/reasoning.js+1 -0
@@ -123,6 +123,7 @@ export function extractReasoningFromData(data, {
123 case chat_completion_sources.AIMLAPI:123 case chat_completion_sources.AIMLAPI:
124 case chat_completion_sources.POLLINATIONS:124 case chat_completion_sources.POLLINATIONS:
125 case chat_completion_sources.MOONSHOT:125 case chat_completion_sources.MOONSHOT:
126 case chat_completion_sources.COMETAPI:
126 case chat_completion_sources.CUSTOM: {127 case chat_completion_sources.CUSTOM: {
127 return data?.choices?.[0]?.message?.reasoning_content128 return data?.choices?.[0]?.message?.reasoning_content
128 ?? data?.choices?.[0]?.message?.reasoning129 ?? data?.choices?.[0]?.message?.reasoning
public/scripts/secrets.js+3 -0
@@ -65,6 +65,7 @@ export const SECRET_KEYS = {
65 MINIMAX: 'api_key_minimax',65 MINIMAX: 'api_key_minimax',
66 MINIMAX_GROUP_ID: 'minimax_group_id',66 MINIMAX_GROUP_ID: 'minimax_group_id',
67 MOONSHOT: 'api_key_moonshot',67 MOONSHOT: 'api_key_moonshot',
68 COMETAPI: 'api_key_cometapi',
68};69};
6970
70const FRIENDLY_NAMES = {71const FRIENDLY_NAMES = {
@@ -118,6 +119,7 @@ const FRIENDLY_NAMES = {
118 [SECRET_KEYS.MINIMAX]: 'MiniMax TTS',119 [SECRET_KEYS.MINIMAX]: 'MiniMax TTS',
119 [SECRET_KEYS.MINIMAX_GROUP_ID]: 'MiniMax Group ID',120 [SECRET_KEYS.MINIMAX_GROUP_ID]: 'MiniMax Group ID',
120 [SECRET_KEYS.MOONSHOT]: 'Moonshot AI',121 [SECRET_KEYS.MOONSHOT]: 'Moonshot AI',
122 [SECRET_KEYS.COMETAPI]: 'CometAPI',
121};123};
122124
123const INPUT_MAP = {125const INPUT_MAP = {
@@ -154,6 +156,7 @@ const INPUT_MAP = {
154 [SECRET_KEYS.VERTEXAI_SERVICE_ACCOUNT]: '#vertexai_service_account_json',156 [SECRET_KEYS.VERTEXAI_SERVICE_ACCOUNT]: '#vertexai_service_account_json',
155 [SECRET_KEYS.MOONSHOT]: '#api_key_moonshot',157 [SECRET_KEYS.MOONSHOT]: '#api_key_moonshot',
156 [SECRET_KEYS.FIREWORKS]: '#api_key_fireworks',158 [SECRET_KEYS.FIREWORKS]: '#api_key_fireworks',
159 [SECRET_KEYS.COMETAPI]: '#api_key_cometapi',
157};160};
158161
159const getLabel = () => moment().format('L LT');162const getLabel = () => moment().format('L LT');
public/scripts/slash-commands.js+1 -0
@@ -4857,6 +4857,7 @@ function getModelOptions(quiet) {
4857 { id: 'model_pollinations_select', api: 'openai', type: chat_completion_sources.POLLINATIONS },4857 { id: 'model_pollinations_select', api: 'openai', type: chat_completion_sources.POLLINATIONS },
4858 { id: 'model_moonshot_select', api: 'openai', type: chat_completion_sources.MOONSHOT },4858 { id: 'model_moonshot_select', api: 'openai', type: chat_completion_sources.MOONSHOT },
4859 { id: 'model_fireworks_select', api: 'openai', type: chat_completion_sources.FIREWORKS },4859 { id: 'model_fireworks_select', api: 'openai', type: chat_completion_sources.FIREWORKS },
4860 { id: 'model_cometapi_select', api: 'openai', type: chat_completion_sources.COMETAPI },
4860 { id: 'model_novel_select', api: 'novel', type: null },4861 { id: 'model_novel_select', api: 'novel', type: null },
4861 { id: 'horde_model', api: 'koboldhorde', type: null },4862 { id: 'horde_model', api: 'koboldhorde', type: null },
4862 ];4863 ];
public/scripts/tool-calling.js+1 -0
@@ -650,6 +650,7 @@ export class ToolManager {
650 chat_completion_sources.POLLINATIONS,650 chat_completion_sources.POLLINATIONS,
651 chat_completion_sources.MOONSHOT,651 chat_completion_sources.MOONSHOT,
652 chat_completion_sources.FIREWORKS,652 chat_completion_sources.FIREWORKS,
653 chat_completion_sources.COMETAPI,
653 ];654 ];
654 return supportedSources.includes(oai_settings.chat_completion_source);655 return supportedSources.includes(oai_settings.chat_completion_source);
655 }656 }
src/constants.js+1 -0
@@ -180,6 +180,7 @@ export const CHAT_COMPLETION_SOURCES = {
180 POLLINATIONS: 'pollinations',180 POLLINATIONS: 'pollinations',
181 MOONSHOT: 'moonshot',181 MOONSHOT: 'moonshot',
182 FIREWORKS: 'fireworks',182 FIREWORKS: 'fireworks',
183 COMETAPI: 'cometapi',
183};184};
184185
185/**186/**
src/endpoints/backends/chat-completions.js+12 -0
@@ -67,6 +67,7 @@ const API_AIMLAPI = 'https://api.aimlapi.com/v1';
67const API_POLLINATIONS = 'https://text.pollinations.ai/openai';67const API_POLLINATIONS = 'https://text.pollinations.ai/openai';
68const API_MOONSHOT = 'https://api.moonshot.ai/v1';68const API_MOONSHOT = 'https://api.moonshot.ai/v1';
69const API_FIREWORKS = 'https://api.fireworks.ai/inference/v1';69const API_FIREWORKS = 'https://api.fireworks.ai/inference/v1';
70const API_COMETAPI = 'https://api.cometapi.com/v1';
7071
71/**72/**
72 * Gets OpenRouter transforms based on the request.73 * Gets OpenRouter transforms based on the request.
@@ -1248,6 +1249,10 @@ router.post('/status', async function (request, statusResponse) {
1248 apiUrl = API_GROQ;1249 apiUrl = API_GROQ;
1249 apiKey = readSecret(request.user.directories, SECRET_KEYS.GROQ);1250 apiKey = readSecret(request.user.directories, SECRET_KEYS.GROQ);
1250 headers = {};1251 headers = {};
1252 } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.COMETAPI) {
1253 apiUrl = API_COMETAPI;
1254 apiKey = readSecret(request.user.directories, SECRET_KEYS.COMETAPI);
1255 headers = {};
1251 } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MOONSHOT) {1256 } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MOONSHOT) {
1252 apiUrl = API_MOONSHOT;1257 apiUrl = API_MOONSHOT;
1253 apiKey = readSecret(request.user.directories, SECRET_KEYS.MOONSHOT);1258 apiKey = readSecret(request.user.directories, SECRET_KEYS.MOONSHOT);
@@ -1661,6 +1666,13 @@ router.post('/generate', function (request, response) {
1661 request.body.json_schema1666 request.body.json_schema
1662 ? setJsonObjectFormat(bodyParams, request.body.messages, request.body.json_schema)1667 ? setJsonObjectFormat(bodyParams, request.body.messages, request.body.json_schema)
1663 : addAssistantPrefix(request.body.messages, [], 'partial');1668 : addAssistantPrefix(request.body.messages, [], 'partial');
1669 } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.COMETAPI) {
1670 apiUrl = API_COMETAPI;
1671 apiKey = readSecret(request.user.directories, SECRET_KEYS.COMETAPI);
1672 headers = {};
1673 bodyParams = {
1674 reasoning_effort: request.body.reasoning_effort,
1675 };
1664 } else {1676 } else {
1665 console.warn('This chat completion source is not supported yet.');1677 console.warn('This chat completion source is not supported yet.');
1666 return response.status(400).send({ error: true });1678 return response.status(400).send({ error: true });
src/endpoints/secrets.js+1 -0
@@ -58,6 +58,7 @@ export const SECRET_KEYS = {
58 MINIMAX: 'api_key_minimax',58 MINIMAX: 'api_key_minimax',
59 MINIMAX_GROUP_ID: 'minimax_group_id',59 MINIMAX_GROUP_ID: 'minimax_group_id',
60 MOONSHOT: 'api_key_moonshot',60 MOONSHOT: 'api_key_moonshot',
61 COMETAPI: 'api_key_cometapi',
61};62};
6263
63/**64/**