From 0e38bfbf0583ff8f09c282e5c9bd82fa2f6c8a64 Mon Sep 17 00:00:00 2001
From: Cohee <18619528+Cohee1207@users.noreply.github.com>
Date: Thu, 31 Jul 2025 00:01:04 +0300
Subject: [PATCH] Feat/moonshot api (#4330)
* moonshot
* Partial mode + JSON schema
* Add logo image
* Limit max temp to 1
* Add to captioning extension
---
public/img/moonshot.svg | 1 +
public/index.html | 44 +++++++++--
public/scripts/RossAscends-mods.js | 1 +
public/scripts/extensions/caption/index.js | 1 +
.../scripts/extensions/caption/settings.html | 4 +
public/scripts/extensions/shared.js | 4 +
public/scripts/openai.js | 74 ++++++++++++++++++-
public/scripts/reasoning.js | 1 +
public/scripts/secrets.js | 3 +
public/scripts/slash-commands.js | 1 +
public/scripts/tool-calling.js | 1 +
src/constants.js | 1 +
src/endpoints/backends/chat-completions.js | 42 ++++++++---
src/endpoints/openai.js | 8 ++
src/endpoints/secrets.js | 1 +
src/prompt-converters.js | 5 +-
16 files changed, 170 insertions(+), 22 deletions(-)
create mode 100644 public/img/moonshot.svg
diff --git a/public/img/moonshot.svg b/public/img/moonshot.svg
new file mode 100644
index 000000000..f48c68a80
--- /dev/null
+++ b/public/img/moonshot.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/index.html b/public/index.html
index 1c166b677..4a59a8f6b 100644
--- a/public/index.html
+++ b/public/index.html
@@ -652,7 +652,7 @@
-
+
Multiple swipes per generation
@@ -691,7 +691,7 @@
-
+
Temperature
@@ -704,7 +704,7 @@
-
+
Frequency Penalty
@@ -717,7 +717,7 @@
-
+
Presence Penalty
@@ -743,7 +743,7 @@
-
+
Top P
@@ -1984,7 +1984,7 @@
-
-
-
+
diff --git a/public/scripts/RossAscends-mods.js b/public/scripts/RossAscends-mods.js
index 6359be518..c289a3a06 100644
--- a/public/scripts/RossAscends-mods.js
+++ b/public/scripts/RossAscends-mods.js
@@ -410,6 +410,7 @@ function RA_autoconnect(PrevApi) {
|| (secret_state[SECRET_KEYS.DEEPSEEK] && oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK)
|| (secret_state[SECRET_KEYS.XAI] && oai_settings.chat_completion_source == chat_completion_sources.XAI)
|| (secret_state[SECRET_KEYS.AIMLAPI] && oai_settings.chat_completion_source == chat_completion_sources.AIMLAPI)
+ || (secret_state[SECRET_KEYS.MOONSHOT] && oai_settings.chat_completion_source == chat_completion_sources.MOONSHOT)
|| (oai_settings.chat_completion_source === chat_completion_sources.POLLINATIONS)
|| (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM)
) {
diff --git a/public/scripts/extensions/caption/index.js b/public/scripts/extensions/caption/index.js
index 3bb012928..888aa7c8c 100644
--- a/public/scripts/extensions/caption/index.js
+++ b/public/scripts/extensions/caption/index.js
@@ -438,6 +438,7 @@ jQuery(async function () {
'groq': SECRET_KEYS.GROQ,
'cohere': SECRET_KEYS.COHERE,
'aimlapi': SECRET_KEYS.AIMLAPI,
+ 'moonshot': SECRET_KEYS.MOONSHOT,
};
if (chatCompletionApis[api] && secret_state[chatCompletionApis[api]]) {
diff --git a/public/scripts/extensions/caption/settings.html b/public/scripts/extensions/caption/settings.html
index d81bf39dc..4b13906fb 100644
--- a/public/scripts/extensions/caption/settings.html
+++ b/public/scripts/extensions/caption/settings.html
@@ -27,6 +27,7 @@
+
@@ -51,6 +52,9 @@
+
+
+
diff --git a/public/scripts/extensions/shared.js b/public/scripts/extensions/shared.js
index aa25ccd11..17e5bc811 100644
--- a/public/scripts/extensions/shared.js
+++ b/public/scripts/extensions/shared.js
@@ -238,6 +238,10 @@ function throwIfInvalidModel(useReverseProxy) {
if (multimodalApi === 'aimlapi' && !secret_state[SECRET_KEYS.AIMLAPI]) {
throw new Error('AI/ML API key is not set.');
}
+
+ if (multimodalApi === 'moonshot' && !secret_state[SECRET_KEYS.MOONSHOT]) {
+ throw new Error('Moonshot AI API key is not set.');
+ }
}
/**
diff --git a/public/scripts/openai.js b/public/scripts/openai.js
index 1401d2f7b..1096449d0 100644
--- a/public/scripts/openai.js
+++ b/public/scripts/openai.js
@@ -183,6 +183,7 @@ export const chat_completion_sources = {
AIMLAPI: 'aimlapi',
XAI: 'xai',
POLLINATIONS: 'pollinations',
+ MOONSHOT: 'moonshot',
};
const character_names_behavior = {
@@ -272,6 +273,7 @@ export const settingsToUpdate = {
aimlapi_model: ['#model_aimlapi_select', 'aimlapi_model', false, true],
xai_model: ['#model_xai_select', 'xai_model', false, true],
pollinations_model: ['#model_pollinations_select', 'pollinations_model', false, true],
+ moonshot_model: ['#model_moonshot_select', 'moonshot_model', false, true],
custom_model: ['#custom_model_id', 'custom_model', false, true],
custom_url: ['#custom_api_url_text', 'custom_url', false, true],
custom_include_body: ['#custom_include_body', 'custom_include_body', false, true],
@@ -367,6 +369,7 @@ const default_settings = {
aimlapi_model: 'gpt-4o-mini-2024-07-18',
xai_model: 'grok-3-beta',
pollinations_model: 'openai',
+ moonshot_model: 'kimi-latest',
custom_model: '',
custom_url: '',
custom_include_body: '',
@@ -453,6 +456,7 @@ const oai_settings = {
aimlapi_model: 'gpt-4-turbo',
xai_model: 'grok-3-beta',
pollinations_model: 'openai',
+ moonshot_model: 'kimi-latest',
custom_model: '',
custom_url: '',
custom_include_body: '',
@@ -1613,6 +1617,8 @@ export function getChatCompletionModel(source = null) {
return oai_settings.xai_model;
case chat_completion_sources.POLLINATIONS:
return oai_settings.pollinations_model;
+ case chat_completion_sources.MOONSHOT:
+ return oai_settings.moonshot_model;
default:
console.error(`Unknown chat completion source: ${activeSource}`);
return '';
@@ -2038,13 +2044,14 @@ async function sendOpenAIRequest(type, messages, signal, { jsonSchema = null } =
const isAimlapi = oai_settings.chat_completion_source == chat_completion_sources.AIMLAPI;
const isXAI = oai_settings.chat_completion_source == chat_completion_sources.XAI;
const isPollinations = oai_settings.chat_completion_source == chat_completion_sources.POLLINATIONS;
+ const isMoonshot = oai_settings.chat_completion_source == chat_completion_sources.MOONSHOT;
const isTextCompletion = isOAI && textCompletionModels.includes(oai_settings.openai_model);
const isQuiet = type === 'quiet';
const isImpersonate = type === 'impersonate';
const isContinue = type === 'continue';
const stream = oai_settings.stream_openai && !isQuiet && !(isOAI && ['o1-2024-12-17', 'o1'].includes(oai_settings.openai_model));
const useLogprobs = !!power_user.request_token_probabilities;
- const canMultiSwipe = oai_settings.n > 1 && !isContinue && !isImpersonate && !isQuiet && (isOAI || isCustom || isXAI || isAimlapi);
+ const canMultiSwipe = oai_settings.n > 1 && !isContinue && !isImpersonate && !isQuiet && (isOAI || isCustom || isXAI || isAimlapi || isMoonshot);
const logitBiasSources = [chat_completion_sources.OPENAI, chat_completion_sources.OPENROUTER, chat_completion_sources.CUSTOM];
if (oai_settings.bias_preset_selected
@@ -2384,7 +2391,7 @@ export function getStreamingReply(data, state, { chatCompletionSource = null, ov
state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning)?.[0]?.delta?.reasoning || '');
}
return data.choices?.[0]?.delta?.content ?? data.choices?.[0]?.message?.content ?? data.choices?.[0]?.text ?? '';
- } else if ([chat_completion_sources.CUSTOM, chat_completion_sources.POLLINATIONS, chat_completion_sources.AIMLAPI].includes(chat_completion_source)) {
+ } else if ([chat_completion_sources.CUSTOM, chat_completion_sources.POLLINATIONS, chat_completion_sources.AIMLAPI, chat_completion_sources.MOONSHOT].includes(chat_completion_source)) {
if (show_thoughts) {
state.reasoning +=
data.choices?.filter(x => x?.delta?.reasoning_content)?.[0]?.delta?.reasoning_content ??
@@ -3345,6 +3352,7 @@ function loadOpenAISettings(data, settings) {
oai_settings.aimlapi_model = settings.aimlapi_model ?? default_settings.aimlapi_model;
oai_settings.xai_model = settings.xai_model ?? default_settings.xai_model;
oai_settings.pollinations_model = settings.pollinations_model ?? default_settings.pollinations_model;
+ oai_settings.moonshot_model = settings.moonshot_model ?? default_settings.moonshot_model;
oai_settings.custom_model = settings.custom_model ?? default_settings.custom_model;
oai_settings.custom_url = settings.custom_url ?? default_settings.custom_url;
oai_settings.custom_include_body = settings.custom_include_body ?? default_settings.custom_include_body;
@@ -3442,6 +3450,8 @@ function loadOpenAISettings(data, settings) {
$(`#model_xai_select option[value="${oai_settings.xai_model}"`).prop('selected', true);
$('#model_pollinations_select').val(oai_settings.pollinations_model);
$(`#model_pollinations_select option[value="${oai_settings.pollinations_model}"`).prop('selected', true);
+ $('#model_moonshot_select').val(oai_settings.moonshot_model);
+ $(`#model_moonshot_select option[value="${oai_settings.moonshot_model}"`).prop('selected', true);
$('#custom_model_id').val(oai_settings.custom_model);
$('#custom_api_url_text').val(oai_settings.custom_url);
$('#openai_max_context').val(oai_settings.openai_max_context);
@@ -3714,6 +3724,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
xai_model: settings.xai_model,
pollinations_model: settings.pollinations_model,
aimlapi_model: settings.aimlapi_model,
+ moonshot_model: settings.moonshot_model,
custom_model: settings.custom_model,
custom_url: settings.custom_url,
custom_include_body: settings.custom_include_body,
@@ -4424,6 +4435,28 @@ function getGroqMaxContext(model, isUnlocked) {
return Object.entries(contextMap).find(([key]) => model.includes(key))?.[1] || max_128k;
}
+function getMoonshotMaxContext(model, isUnlocked) {
+ if (isUnlocked) {
+ return unlocked_max;
+ }
+
+ const contextMap = {
+ 'moonshot-v1-8k': max_8k,
+ 'moonshot-v1-32k': max_32k,
+ 'moonshot-v1-128k': max_128k,
+ 'moonshot-v1-auto': max_128k,
+ 'moonshot-v1-8k-vision-preview': max_8k,
+ 'moonshot-v1-32k-vision-preview': max_32k,
+ 'moonshot-v1-128k-vision-preview': max_128k,
+ 'kimi-k2-0711-preview': max_32k,
+ 'kimi-latest': max_32k,
+ 'kimi-thinking-preview': max_32k,
+ };
+
+ // Return context size if model found, otherwise default to 32k
+ return Object.entries(contextMap).find(([key]) => model.includes(key))?.[1] || max_32k;
+}
+
async function onModelChange() {
biasCache = undefined;
let value = String($(this).val() || '');
@@ -4559,6 +4592,11 @@ async function onModelChange() {
oai_settings.xai_model = value;
}
+ if (value && $(this).is('#model_moonshot_select')) {
+ console.log('Moonshot model changed to', value);
+ oai_settings.moonshot_model = value;
+ }
+
if ([chat_completion_sources.MAKERSUITE, chat_completion_sources.VERTEXAI].includes(oai_settings.chat_completion_source)) {
if (oai_settings.max_context_unlocked) {
$('#openai_max_context').attr('max', max_2mil);
@@ -4822,6 +4860,15 @@ async function onModelChange() {
$('#freq_pen_openai').attr('max', 2).attr('min', -2).val(oai_settings.freq_pen_openai).trigger('input');
}
+ if (oai_settings.chat_completion_source === chat_completion_sources.MOONSHOT) {
+ const maxContext = getMoonshotMaxContext(oai_settings.moonshot_model, oai_settings.max_context_unlocked);
+ $('#openai_max_context').attr('max', maxContext);
+ oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context);
+ $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input');
+ oai_settings.temp_openai = Math.min(claude_max_temp, oai_settings.temp_openai);
+ $('#temp_openai').attr('max', claude_max_temp).val(oai_settings.temp_openai).trigger('input');
+ }
+
$('#openai_max_context_counter').attr('max', Number($('#openai_max_context').attr('max')));
saveSettingsDebounced();
@@ -5053,6 +5100,19 @@ async function onConnectButtonClick(e) {
}
}
+ if (oai_settings.chat_completion_source == chat_completion_sources.MOONSHOT) {
+ const api_key_moonshot = String($('#api_key_moonshot').val()).trim();
+
+ if (api_key_moonshot.length) {
+ await writeSecret(SECRET_KEYS.MOONSHOT, api_key_moonshot);
+ }
+
+ if (!secret_state[SECRET_KEYS.MOONSHOT]) {
+ console.log('No secret key saved for Moonshot');
+ return;
+ }
+ }
+
startStatusLoading();
saveSettingsDebounced();
await getStatusOpen();
@@ -5114,6 +5174,9 @@ function toggleChatCompletionForms() {
else if (oai_settings.chat_completion_source == chat_completion_sources.POLLINATIONS) {
$('#model_pollinations_select').trigger('change');
}
+ else if (oai_settings.chat_completion_source == chat_completion_sources.MOONSHOT) {
+ $('#model_moonshot_select').trigger('change');
+ }
$('[data-source]').each(function () {
const validSources = $(this).data('source').split(',');
$(this).toggle(validSources.includes(oai_settings.chat_completion_source));
@@ -5221,6 +5284,10 @@ export function isImageInliningSupported() {
'grok-4',
'grok-2-vision',
'grok-vision',
+ // Moonshot
+ 'moonshot-v1-8k-vision-preview',
+ 'moonshot-v1-32k-vision-preview',
+ 'moonshot-v1-128k-vision-preview',
];
switch (oai_settings.chat_completion_source) {
@@ -5249,6 +5316,8 @@ export function isImageInliningSupported() {
return visionSupportedModels.some(model => oai_settings.aimlapi_model.includes(model));
case chat_completion_sources.POLLINATIONS:
return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.pollinations_model)?.vision);
+ case chat_completion_sources.MOONSHOT:
+ return visionSupportedModels.some(model => oai_settings.moonshot_model.includes(model));
default:
return false;
}
@@ -6037,6 +6106,7 @@ export function initOpenAI() {
$('#model_custom_select').on('change', onModelChange);
$('#model_xai_select').on('change', onModelChange);
$('#model_pollinations_select').on('change', onModelChange);
+ $('#model_moonshot_select').on('change', onModelChange);
$('#settings_preset_openai').on('change', onSettingsPresetChange);
$('#new_oai_preset').on('click', onNewPresetClick);
$('#delete_oai_preset').on('click', onDeletePresetClick);
diff --git a/public/scripts/reasoning.js b/public/scripts/reasoning.js
index 4ad35a559..8b2cf6926 100644
--- a/public/scripts/reasoning.js
+++ b/public/scripts/reasoning.js
@@ -120,6 +120,7 @@ export function extractReasoningFromData(data, {
return data?.content?.find(part => part.type === 'thinking')?.thinking ?? '';
case chat_completion_sources.AIMLAPI:
case chat_completion_sources.POLLINATIONS:
+ case chat_completion_sources.MOONSHOT:
case chat_completion_sources.CUSTOM: {
return data?.choices?.[0]?.message?.reasoning_content
?? data?.choices?.[0]?.message?.reasoning
diff --git a/public/scripts/secrets.js b/public/scripts/secrets.js
index 46db54c29..469c30792 100644
--- a/public/scripts/secrets.js
+++ b/public/scripts/secrets.js
@@ -63,6 +63,7 @@ export const SECRET_KEYS = {
VERTEXAI_SERVICE_ACCOUNT: 'vertexai_service_account_json',
MINIMAX: 'api_key_minimax',
MINIMAX_GROUP_ID: 'minimax_group_id',
+ MOONSHOT: 'api_key_moonshot',
};
const FRIENDLY_NAMES = {
@@ -114,6 +115,7 @@ const FRIENDLY_NAMES = {
[SECRET_KEYS.DEEPLX_URL]: 'DeepLX Endpoint (e.g. http://127.0.0.1:1188/translate)',
[SECRET_KEYS.MINIMAX]: 'MiniMax TTS',
[SECRET_KEYS.MINIMAX_GROUP_ID]: 'MiniMax Group ID',
+ [SECRET_KEYS.MOONSHOT]: 'Moonshot AI',
};
const INPUT_MAP = {
@@ -148,6 +150,7 @@ const INPUT_MAP = {
[SECRET_KEYS.AIMLAPI]: '#api_key_aimlapi',
[SECRET_KEYS.XAI]: '#api_key_xai',
[SECRET_KEYS.VERTEXAI_SERVICE_ACCOUNT]: '#vertexai_service_account_json',
+ [SECRET_KEYS.MOONSHOT]: '#api_key_moonshot',
};
const getLabel = () => moment().format('L LT');
diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js
index 662573f9d..5e533ed25 100644
--- a/public/scripts/slash-commands.js
+++ b/public/scripts/slash-commands.js
@@ -4805,6 +4805,7 @@ function getModelOptions(quiet) {
{ id: 'model_aimlapi_select', api: 'openai', type: chat_completion_sources.AIMLAPI },
{ id: 'model_xai_select', api: 'openai', type: chat_completion_sources.XAI },
{ id: 'model_pollinations_select', api: 'openai', type: chat_completion_sources.POLLINATIONS },
+ { id: 'model_moonshot_select', api: 'openai', type: chat_completion_sources.MOONSHOT },
{ id: 'model_novel_select', api: 'novel', type: null },
{ id: 'horde_model', api: 'koboldhorde', type: null },
];
diff --git a/public/scripts/tool-calling.js b/public/scripts/tool-calling.js
index 0fda8fe5d..e131767f3 100644
--- a/public/scripts/tool-calling.js
+++ b/public/scripts/tool-calling.js
@@ -620,6 +620,7 @@ export class ToolManager {
chat_completion_sources.AI21,
chat_completion_sources.XAI,
chat_completion_sources.POLLINATIONS,
+ chat_completion_sources.MOONSHOT,
];
return supportedSources.includes(oai_settings.chat_completion_source);
}
diff --git a/src/constants.js b/src/constants.js
index 008efcafd..aab29c581 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -178,6 +178,7 @@ export const CHAT_COMPLETION_SOURCES = {
AIMLAPI: 'aimlapi',
XAI: 'xai',
POLLINATIONS: 'pollinations',
+ MOONSHOT: 'moonshot',
};
/**
diff --git a/src/endpoints/backends/chat-completions.js b/src/endpoints/backends/chat-completions.js
index 348bc374c..006d4d26c 100644
--- a/src/endpoints/backends/chat-completions.js
+++ b/src/endpoints/backends/chat-completions.js
@@ -65,6 +65,7 @@ const API_DEEPSEEK = 'https://api.deepseek.com/beta';
const API_XAI = 'https://api.x.ai/v1';
const API_AIMLAPI = 'https://api.aimlapi.com/v1';
const API_POLLINATIONS = 'https://text.pollinations.ai/openai';
+const API_MOONSHOT = 'https://api.moonshot.ai/v1';
/**
* Gets OpenRouter transforms based on the request.
@@ -97,6 +98,23 @@ function getOpenRouterPlugins(request) {
return plugins;
}
+/**
+ * Hacky way to use JSON schema only if json_object format is supported.
+ * @param {object} bodyParams Additional body parameters
+ * @param {object[]} messages Array of messages
+ * @param {object} jsonSchema JSON schema object
+ */
+function setJsonObjectFormat(bodyParams, messages, jsonSchema) {
+ bodyParams['response_format'] = {
+ type: 'json_object',
+ };
+ const message = {
+ role: 'user',
+ content: `JSON schema for the response:\n${JSON.stringify(jsonSchema.value, null, 4)}`,
+ };
+ messages.push(message);
+}
+
/**
* Sends a request to Claude API.
* @param {express.Request} request Express request
@@ -890,7 +908,7 @@ async function sendDeepSeekRequest(request, response) {
const postProcessType = String(request.body.model).endsWith('-reasoner')
? PROMPT_PROCESSING_TYPE.STRICT_TOOLS
: PROMPT_PROCESSING_TYPE.SEMI_TOOLS;
- const processedMessages = addAssistantPrefix(postProcessPrompt(request.body.messages, postProcessType, getPromptNames(request)), bodyParams.tools);
+ const processedMessages = addAssistantPrefix(postProcessPrompt(request.body.messages, postProcessType, getPromptNames(request)), bodyParams.tools, 'prefix');
const requestBody = {
'messages': processedMessages,
@@ -1220,6 +1238,10 @@ router.post('/status', async function (request, statusResponse) {
apiUrl = API_GROQ;
apiKey = readSecret(request.user.directories, SECRET_KEYS.GROQ);
headers = {};
+ } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MOONSHOT) {
+ apiUrl = API_MOONSHOT;
+ apiKey = readSecret(request.user.directories, SECRET_KEYS.MOONSHOT);
+ headers = {};
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MAKERSUITE) {
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MAKERSUITE);
apiUrl = trimTrailingSlash(request.body.reverse_proxy || API_MAKERSUITE);
@@ -1598,17 +1620,17 @@ router.post('/generate', function (request, response) {
referrer: 'sillytavern',
seed: request.body.seed ?? Math.floor(Math.random() * 99999999),
};
- // Hack to support JSON schema
if (request.body.json_schema) {
- bodyParams['response_format'] = {
- type: 'json_object',
- };
- const message = {
- role: 'user',
- content: `JSON schema for the response:\n${JSON.stringify(request.body.json_schema.value, null, 4)}`,
- };
- request.body.messages.push(message);
+ setJsonObjectFormat(bodyParams, request.body.messages, request.body.json_schema);
}
+ } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MOONSHOT) {
+ apiUrl = API_MOONSHOT;
+ apiKey = readSecret(request.user.directories, SECRET_KEYS.MOONSHOT);
+ headers = {};
+ bodyParams = {};
+ request.body.json_schema
+ ? setJsonObjectFormat(bodyParams, request.body.messages, request.body.json_schema)
+ : addAssistantPrefix(request.body.messages, [], 'partial');
} else {
console.warn('This chat completion source is not supported yet.');
return response.status(400).send({ error: true });
diff --git a/src/endpoints/openai.js b/src/endpoints/openai.js
index 1407767ef..c438cfbd4 100644
--- a/src/endpoints/openai.js
+++ b/src/endpoints/openai.js
@@ -73,6 +73,10 @@ router.post('/caption-image', async (request, response) => {
key = readSecret(request.user.directories, SECRET_KEYS.COHERE);
}
+ if (request.body.api === 'moonshot') {
+ key = readSecret(request.user.directories, SECRET_KEYS.MOONSHOT);
+ }
+
const noKeyTypes = ['custom', 'ooba', 'koboldcpp', 'vllm', 'llamacpp', 'pollinations'];
if (!key && !request.body.reverse_proxy && !noKeyTypes.includes(request.body.api)) {
console.warn('No key found for API', request.body.api);
@@ -153,6 +157,10 @@ router.post('/caption-image', async (request, response) => {
apiUrl = 'https://text.pollinations.ai/openai/chat/completions';
}
+ if (request.body.api === 'moonshot') {
+ apiUrl = 'https://api.moonshot.ai/v1/chat/completions';
+ }
+
if (['koboldcpp', 'vllm', 'llamacpp', 'ooba'].includes(request.body.api)) {
apiUrl = `${trimV1(request.body.server_url)}/v1/chat/completions`;
}
diff --git a/src/endpoints/secrets.js b/src/endpoints/secrets.js
index e423fce16..7b3f75043 100644
--- a/src/endpoints/secrets.js
+++ b/src/endpoints/secrets.js
@@ -56,6 +56,7 @@ export const SECRET_KEYS = {
VERTEXAI_SERVICE_ACCOUNT: 'vertexai_service_account_json',
MINIMAX: 'api_key_minimax',
MINIMAX_GROUP_ID: 'minimax_group_id',
+ MOONSHOT: 'api_key_moonshot',
};
/**
diff --git a/src/prompt-converters.js b/src/prompt-converters.js
index 74748e220..14d921953 100644
--- a/src/prompt-converters.js
+++ b/src/prompt-converters.js
@@ -53,15 +53,16 @@ export function getPromptNames(request) {
* Adds an assistant prefix to the last message.
* @param {any[]} prompt Prompt messages array
* @param {any[]} tools Array of tool definitions
+ * @param {string} property The property to set the prefix on
* @returns {any[]} Transformed messages array
*/
-export function addAssistantPrefix(prompt, tools) {
+export function addAssistantPrefix(prompt, tools, property) {
if (!prompt.length) {
return prompt;
}
const hasAnyTools = (Array.isArray(tools) && tools.length > 0) || prompt.some(x => x.role === 'tool');
if (!hasAnyTools && prompt[prompt.length - 1].role === 'assistant') {
- prompt[prompt.length - 1].prefix = true;
+ prompt[prompt.length - 1][property] = true;
}
return prompt;
}