feat(secrets): update readSecret function to accept optional secret ID (#5356)

* feat(secrets): update readSecret function to accept optional secret ID

* add secret_id to ConnectionManagerRequestService payload

* fix: pass secret_id for Text Completion types

---------

Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
This commit is contained in:
lunar sheep
2026-03-31 03:30:45 +08:00
committed by GitHub
parent 6bd766f857
commit ff1ca1412a
4 changed files with 95 additions and 77 deletions
+2
View File
@@ -435,6 +435,7 @@ export class ConnectionManagerRequestService {
max_tokens: maxTokens,
model: profile.model,
chat_completion_source: selectedApiMap.source,
secret_id: profile['secret-id'],
custom_url: profile['api-url'],
vertexai_region: profile['api-url'],
zai_endpoint: profile['api-url'],
@@ -459,6 +460,7 @@ export class ConnectionManagerRequestService {
model: profile.model,
api_type: selectedApiMap.type,
api_server: profile['api-url'],
secret_id: profile['secret-id'],
...overridePayload,
}, {
instructName: includeInstruct ? profile.instruct : undefined,
+47 -32
View File
@@ -5,10 +5,11 @@ import { getConfigValue } from './util.js';
/**
* Gets the headers for the Mancer API.
* @param {import('./users.js').UserDirectoryList} directories User directories
* @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use)
* @returns {object} Headers for the request
*/
function getMancerHeaders(directories) {
const apiKey = readSecret(directories, SECRET_KEYS.MANCER);
function getMancerHeaders(directories, secretId = null) {
const apiKey = readSecret(directories, SECRET_KEYS.MANCER, secretId);
return apiKey ? ({
'X-API-KEY': apiKey,
@@ -19,10 +20,11 @@ function getMancerHeaders(directories) {
/**
* Gets the headers for the TogetherAI API.
* @param {import('./users.js').UserDirectoryList} directories User directories
* @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use)
* @returns {object} Headers for the request
*/
function getTogetherAIHeaders(directories) {
const apiKey = readSecret(directories, SECRET_KEYS.TOGETHERAI);
function getTogetherAIHeaders(directories, secretId = null) {
const apiKey = readSecret(directories, SECRET_KEYS.TOGETHERAI, secretId);
return apiKey ? ({
'Authorization': `Bearer ${apiKey}`,
@@ -32,10 +34,11 @@ function getTogetherAIHeaders(directories) {
/**
* Gets the headers for the InfermaticAI API.
* @param {import('./users.js').UserDirectoryList} directories User directories
* @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use)
* @returns {object} Headers for the request
*/
function getInfermaticAIHeaders(directories) {
const apiKey = readSecret(directories, SECRET_KEYS.INFERMATICAI);
function getInfermaticAIHeaders(directories, secretId = null) {
const apiKey = readSecret(directories, SECRET_KEYS.INFERMATICAI, secretId);
return apiKey ? ({
'Authorization': `Bearer ${apiKey}`,
@@ -45,10 +48,11 @@ function getInfermaticAIHeaders(directories) {
/**
* Gets the headers for the DreamGen API.
* @param {import('./users.js').UserDirectoryList} directories User directories
* @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use)
* @returns {object} Headers for the request
*/
function getDreamGenHeaders(directories) {
const apiKey = readSecret(directories, SECRET_KEYS.DREAMGEN);
function getDreamGenHeaders(directories, secretId = null) {
const apiKey = readSecret(directories, SECRET_KEYS.DREAMGEN, secretId);
return apiKey ? ({
'Authorization': `Bearer ${apiKey}`,
@@ -58,10 +62,11 @@ function getDreamGenHeaders(directories) {
/**
* Gets the headers for the OpenRouter API.
* @param {import('./users.js').UserDirectoryList} directories User directories
* @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use)
* @returns {object} Headers for the request
*/
function getOpenRouterHeaders(directories) {
const apiKey = readSecret(directories, SECRET_KEYS.OPENROUTER);
function getOpenRouterHeaders(directories, secretId = null) {
const apiKey = readSecret(directories, SECRET_KEYS.OPENROUTER, secretId);
const baseHeaders = { ...OPENROUTER_HEADERS };
return apiKey ? Object.assign(baseHeaders, { 'Authorization': `Bearer ${apiKey}` }) : baseHeaders;
@@ -70,10 +75,11 @@ function getOpenRouterHeaders(directories) {
/**
* Gets the headers for the vLLM API.
* @param {import('./users.js').UserDirectoryList} directories User directories
* @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use)
* @returns {object} Headers for the request
*/
function getVllmHeaders(directories) {
const apiKey = readSecret(directories, SECRET_KEYS.VLLM);
function getVllmHeaders(directories, secretId = null) {
const apiKey = readSecret(directories, SECRET_KEYS.VLLM, secretId);
return apiKey ? ({
'Authorization': `Bearer ${apiKey}`,
@@ -83,10 +89,11 @@ function getVllmHeaders(directories) {
/**
* Gets the headers for the Aphrodite API.
* @param {import('./users.js').UserDirectoryList} directories User directories
* @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use)
* @returns {object} Headers for the request
*/
function getAphroditeHeaders(directories) {
const apiKey = readSecret(directories, SECRET_KEYS.APHRODITE);
function getAphroditeHeaders(directories, secretId = null) {
const apiKey = readSecret(directories, SECRET_KEYS.APHRODITE, secretId);
return apiKey ? ({
'X-API-KEY': apiKey,
@@ -97,10 +104,11 @@ function getAphroditeHeaders(directories) {
/**
* Gets the headers for the Tabby API.
* @param {import('./users.js').UserDirectoryList} directories User directories
* @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use)
* @returns {object} Headers for the request
*/
function getTabbyHeaders(directories) {
const apiKey = readSecret(directories, SECRET_KEYS.TABBY);
function getTabbyHeaders(directories, secretId = null) {
const apiKey = readSecret(directories, SECRET_KEYS.TABBY, secretId);
return apiKey ? ({
'x-api-key': apiKey,
@@ -111,10 +119,11 @@ function getTabbyHeaders(directories) {
/**
* Gets the headers for the LlamaCPP API.
* @param {import('./users.js').UserDirectoryList} directories User directories
* @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use)
* @returns {object} Headers for the request
*/
function getLlamaCppHeaders(directories) {
const apiKey = readSecret(directories, SECRET_KEYS.LLAMACPP);
function getLlamaCppHeaders(directories, secretId = null) {
const apiKey = readSecret(directories, SECRET_KEYS.LLAMACPP, secretId);
return apiKey ? ({
'Authorization': `Bearer ${apiKey}`,
@@ -123,11 +132,12 @@ function getLlamaCppHeaders(directories) {
/**
* Gets the headers for the Ooba API.
* @param {import('./users.js').UserDirectoryList} directories
* @param {import('./users.js').UserDirectoryList} directories User directories
* @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use)
* @returns {object} Headers for the request
*/
function getOobaHeaders(directories) {
const apiKey = readSecret(directories, SECRET_KEYS.OOBA);
function getOobaHeaders(directories, secretId = null) {
const apiKey = readSecret(directories, SECRET_KEYS.OOBA, secretId);
return apiKey ? ({
'Authorization': `Bearer ${apiKey}`,
@@ -137,10 +147,11 @@ function getOobaHeaders(directories) {
/**
* Gets the headers for the KoboldCpp API.
* @param {import('./users.js').UserDirectoryList} directories
* @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use)
* @returns {object} Headers for the request
*/
function getKoboldCppHeaders(directories) {
const apiKey = readSecret(directories, SECRET_KEYS.KOBOLDCPP);
function getKoboldCppHeaders(directories, secretId = null) {
const apiKey = readSecret(directories, SECRET_KEYS.KOBOLDCPP, secretId);
return apiKey ? ({
'Authorization': `Bearer ${apiKey}`,
@@ -150,10 +161,11 @@ function getKoboldCppHeaders(directories) {
/**
* Gets the headers for the Featherless API.
* @param {import('./users.js').UserDirectoryList} directories
* @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use)
* @returns {object} Headers for the request
*/
function getFeatherlessHeaders(directories) {
const apiKey = readSecret(directories, SECRET_KEYS.FEATHERLESS);
function getFeatherlessHeaders(directories, secretId = null) {
const apiKey = readSecret(directories, SECRET_KEYS.FEATHERLESS, secretId);
const baseHeaders = { ...FEATHERLESS_HEADERS };
return apiKey ? Object.assign(baseHeaders, { 'Authorization': `Bearer ${apiKey}` }) : baseHeaders;
@@ -162,10 +174,11 @@ function getFeatherlessHeaders(directories) {
/**
* Gets the headers for the HuggingFace API.
* @param {import('./users.js').UserDirectoryList} directories
* @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use)
* @returns {object} Headers for the request
*/
function getHuggingFaceHeaders(directories) {
const apiKey = readSecret(directories, SECRET_KEYS.HUGGINGFACE);
function getHuggingFaceHeaders(directories, secretId = null) {
const apiKey = readSecret(directories, SECRET_KEYS.HUGGINGFACE, secretId);
return apiKey ? ({
'Authorization': `Bearer ${apiKey}`,
@@ -175,10 +188,11 @@ function getHuggingFaceHeaders(directories) {
/**
* Gets the headers for the Generic text completion API.
* @param {import('./users.js').UserDirectoryList} directories
* @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use)
* @returns {object} Headers for the request
*/
function getGenericHeaders(directories) {
const apiKey = readSecret(directories, SECRET_KEYS.GENERIC);
function getGenericHeaders(directories, secretId = null) {
const apiKey = readSecret(directories, SECRET_KEYS.GENERIC, secretId);
return apiKey ? ({
'Authorization': `Bearer ${apiKey}`,
@@ -202,7 +216,7 @@ export function getOverrideHeaders(urlHost) {
* @param {string|null} server API server for new request
*/
export function setAdditionalHeaders(request, args, server) {
setAdditionalHeadersByType(args.headers, request.body.api_type, server, request.user.directories);
setAdditionalHeadersByType(args.headers, request.body.api_type, server, request.user.directories, request.body.secret_id);
}
/**
@@ -211,8 +225,9 @@ export function setAdditionalHeaders(request, args, server) {
* @param {string} type API type
* @param {string|null} server API server for new request
* @param {import('./users.js').UserDirectoryList} directories User directories
* @param {string|null} secretId Secret ID for the request (optional, used for some API types to determine which secret to use)
*/
export function setAdditionalHeadersByType(requestHeaders, type, server, directories) {
export function setAdditionalHeadersByType(requestHeaders, type, server, directories, secretId = null) {
const headerGetters = {
[TEXTGEN_TYPES.MANCER]: getMancerHeaders,
[TEXTGEN_TYPES.VLLM]: getVllmHeaders,
@@ -231,7 +246,7 @@ export function setAdditionalHeadersByType(requestHeaders, type, server, directo
};
const getHeaders = headerGetters[type];
const headers = getHeaders ? getHeaders(directories) : {};
const headers = getHeaders ? getHeaders(directories, secretId) : {};
if (typeof server === 'string' && server.length > 0) {
try {
+43 -43
View File
@@ -208,7 +208,7 @@ function setJsonObjectFormat(bodyParams, messages, jsonSchema) {
*/
async function sendClaudeRequest(request, response) {
const apiUrl = new URL(request.body.reverse_proxy || API_CLAUDE).toString();
const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.CLAUDE);
const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.CLAUDE, request.body.secret_id);
const divider = '-'.repeat(process.stdout.columns);
if (!apiKey) {
@@ -425,7 +425,7 @@ async function sendMakerSuiteRequest(request, response) {
}
} else {
apiUrl = new URL(request.body.reverse_proxy || API_MAKERSUITE);
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MAKERSUITE);
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MAKERSUITE, request.body.secret_id);
if (!request.body.reverse_proxy && !apiKey) {
console.warn(`${apiName} API key is missing.`);
@@ -641,7 +641,7 @@ async function sendMakerSuiteRequest(request, response) {
} else if (authType === 'full') {
// For Full mode (service account authentication), use project-specific URL
// Get project ID from Service Account JSON
const serviceAccountJson = readSecret(request.user.directories, SECRET_KEYS.VERTEXAI_SERVICE_ACCOUNT);
const serviceAccountJson = readSecret(request.user.directories, SECRET_KEYS.VERTEXAI_SERVICE_ACCOUNT, request.body.secret_id);
if (!serviceAccountJson) {
console.warn('Vertex AI Service Account JSON is missing.');
return response.status(400).send({ error: true });
@@ -742,7 +742,7 @@ async function sendMakerSuiteRequest(request, response) {
async function sendAI21Request(request, response) {
if (!request.body) return response.sendStatus(400);
const apiKey = readSecret(request.user.directories, SECRET_KEYS.AI21);
const apiKey = readSecret(request.user.directories, SECRET_KEYS.AI21, request.body.secret_id);
if (!apiKey) {
console.warn('AI21 API key is missing.');
return response.status(400).send({ error: true });
@@ -822,7 +822,7 @@ async function sendAI21Request(request, response) {
*/
async function sendMistralAIRequest(request, response) {
const apiUrl = new URL(request.body.reverse_proxy || API_MISTRAL).toString();
const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MISTRALAI);
const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MISTRALAI, request.body.secret_id);
if (!apiKey) {
console.warn('MistralAI API key is missing.');
@@ -911,7 +911,7 @@ async function sendMistralAIRequest(request, response) {
* @param {express.Response} response Express response
*/
async function sendCohereRequest(request, response) {
const apiKey = readSecret(request.user.directories, SECRET_KEYS.COHERE);
const apiKey = readSecret(request.user.directories, SECRET_KEYS.COHERE, request.body.secret_id);
const controller = new AbortController();
request.socket.removeAllListeners('close');
request.socket.on('close', function () {
@@ -1012,7 +1012,7 @@ async function sendCohereRequest(request, response) {
*/
async function sendDeepSeekRequest(request, response) {
const apiUrl = new URL(request.body.reverse_proxy || API_DEEPSEEK).toString();
const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK);
const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK, request.body.secret_id);
if (!apiKey && !request.body.reverse_proxy) {
console.warn('DeepSeek API key is missing.');
@@ -1122,7 +1122,7 @@ async function sendDeepSeekRequest(request, response) {
*/
async function sendXaiRequest(request, response) {
const apiUrl = new URL(request.body.reverse_proxy || API_XAI).toString();
const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.XAI);
const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.XAI, request.body.secret_id);
if (!apiKey && !request.body.reverse_proxy) {
console.warn('xAI API key is missing.');
@@ -1228,7 +1228,7 @@ async function sendXaiRequest(request, response) {
*/
async function sendAimlapiRequest(request, response) {
const apiUrl = API_AIMLAPI;
const apiKey = readSecret(request.user.directories, SECRET_KEYS.AIMLAPI);
const apiKey = readSecret(request.user.directories, SECRET_KEYS.AIMLAPI, request.body.secret_id);
if (!apiKey) {
console.warn('AI/ML API key is missing.');
@@ -1333,7 +1333,7 @@ async function sendAimlapiRequest(request, response) {
*/
async function sendElectronHubRequest(request, response) {
const apiUrl = API_ELECTRONHUB;
const apiKey = readSecret(request.user.directories, SECRET_KEYS.ELECTRONHUB);
const apiKey = readSecret(request.user.directories, SECRET_KEYS.ELECTRONHUB, request.body.secret_id);
if (!apiKey) {
console.warn('Electron Hub key is missing.');
@@ -1445,7 +1445,7 @@ async function sendElectronHubRequest(request, response) {
*/
async function sendChutesRequest(request, response) {
const apiUrl = API_CHUTES;
const apiKey = readSecret(request.user.directories, SECRET_KEYS.CHUTES);
const apiKey = readSecret(request.user.directories, SECRET_KEYS.CHUTES, request.body.secret_id);
if (!apiKey) {
console.warn('Chutes key is missing.');
@@ -1547,7 +1547,7 @@ async function sendChutesRequest(request, response) {
async function sendAzureOpenAIRequest(request, response) {
// 1. GATHER & VALIDATE SETTINGS
const { azure_base_url, azure_deployment_name, azure_api_version } = request.body;
const apiKey = readSecret(request.user.directories, SECRET_KEYS.AZURE_OPENAI);
const apiKey = readSecret(request.user.directories, SECRET_KEYS.AZURE_OPENAI, request.body.secret_id);
if (!azure_base_url || !azure_deployment_name || !azure_api_version || !apiKey) {
return response.status(400).send({
error: {
@@ -1646,74 +1646,74 @@ router.post('/status', async function (request, statusResponse) {
if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENAI) {
apiUrl = new URL(request.body.reverse_proxy || API_OPENAI).toString();
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.OPENAI);
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.OPENAI, request.body.secret_id);
headers = {};
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENROUTER) {
apiUrl = 'https://openrouter.ai/api/v1';
apiKey = readSecret(request.user.directories, SECRET_KEYS.OPENROUTER);
apiKey = readSecret(request.user.directories, SECRET_KEYS.OPENROUTER, request.body.secret_id);
// OpenRouter needs to pass the Referer and X-Title: https://openrouter.ai/docs#requests
headers = { ...OPENROUTER_HEADERS };
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MISTRALAI) {
apiUrl = new URL(request.body.reverse_proxy || API_MISTRAL).toString();
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MISTRALAI);
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MISTRALAI, request.body.secret_id);
headers = {};
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.CUSTOM) {
apiUrl = request.body.custom_url;
apiKey = readSecret(request.user.directories, SECRET_KEYS.CUSTOM);
apiKey = readSecret(request.user.directories, SECRET_KEYS.CUSTOM, request.body.secret_id);
headers = {};
mergeObjectWithYaml(headers, request.body.custom_include_headers);
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.COHERE) {
apiUrl = API_COHERE_V1;
apiKey = readSecret(request.user.directories, SECRET_KEYS.COHERE);
apiKey = readSecret(request.user.directories, SECRET_KEYS.COHERE, request.body.secret_id);
headers = {};
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.CHUTES) {
apiUrl = API_CHUTES;
apiKey = readSecret(request.user.directories, SECRET_KEYS.CHUTES);
apiKey = readSecret(request.user.directories, SECRET_KEYS.CHUTES, request.body.secret_id);
headers = {};
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.ELECTRONHUB) {
apiUrl = API_ELECTRONHUB;
apiKey = readSecret(request.user.directories, SECRET_KEYS.ELECTRONHUB);
apiKey = readSecret(request.user.directories, SECRET_KEYS.ELECTRONHUB, request.body.secret_id);
headers = {};
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.NANOGPT) {
apiUrl = API_NANOGPT;
apiKey = readSecret(request.user.directories, SECRET_KEYS.NANOGPT);
apiKey = readSecret(request.user.directories, SECRET_KEYS.NANOGPT, request.body.secret_id);
headers = {};
queryParams = { detailed: true };
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.DEEPSEEK) {
apiUrl = new URL(request.body.reverse_proxy || API_DEEPSEEK.replace('/beta', '')).toString();
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK);
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK, request.body.secret_id);
headers = {};
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.XAI) {
apiUrl = new URL(request.body.reverse_proxy || API_XAI).toString();
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.XAI);
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.XAI, request.body.secret_id);
headers = {};
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.AIMLAPI) {
apiUrl = API_AIMLAPI;
apiKey = readSecret(request.user.directories, SECRET_KEYS.AIMLAPI);
apiKey = readSecret(request.user.directories, SECRET_KEYS.AIMLAPI, request.body.secret_id);
headers = { ...AIMLAPI_HEADERS };
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.POLLINATIONS) {
apiUrl = 'https://gen.pollinations.ai/text';
apiKey = readSecret(request.user.directories, SECRET_KEYS.POLLINATIONS);
apiKey = readSecret(request.user.directories, SECRET_KEYS.POLLINATIONS, request.body.secret_id);
headers = {};
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.GROQ) {
apiUrl = API_GROQ;
apiKey = readSecret(request.user.directories, SECRET_KEYS.GROQ);
apiKey = readSecret(request.user.directories, SECRET_KEYS.GROQ, request.body.secret_id);
headers = {};
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.COMETAPI) {
apiUrl = API_COMETAPI;
apiKey = readSecret(request.user.directories, SECRET_KEYS.COMETAPI);
apiKey = readSecret(request.user.directories, SECRET_KEYS.COMETAPI, request.body.secret_id);
headers = {};
throw new Error('This provider is temporarily disabled.');
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MOONSHOT) {
apiUrl = new URL(request.body.reverse_proxy || API_MOONSHOT).toString();
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MOONSHOT);
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MOONSHOT, request.body.secret_id);
headers = {};
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.FIREWORKS) {
apiUrl = API_FIREWORKS;
apiKey = readSecret(request.user.directories, SECRET_KEYS.FIREWORKS);
apiKey = readSecret(request.user.directories, SECRET_KEYS.FIREWORKS, request.body.secret_id);
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);
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MAKERSUITE, request.body.secret_id);
apiUrl = trimTrailingSlash(request.body.reverse_proxy || API_MAKERSUITE);
const apiVersion = getConfigValue('gemini.apiVersion', 'v1beta');
const modelsUrl = !apiKey && request.body.reverse_proxy
@@ -1750,7 +1750,7 @@ router.post('/status', async function (request, statusResponse) {
}
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.AZURE_OPENAI) {
const { azure_base_url, azure_deployment_name, azure_api_version } = request.body;
const apiKey = readSecret(request.user.directories, SECRET_KEYS.AZURE_OPENAI);
const apiKey = readSecret(request.user.directories, SECRET_KEYS.AZURE_OPENAI, request.body.secret_id);
// 1) Validate configuration from the frontend
if (!apiKey || !azure_base_url || !azure_deployment_name || !azure_api_version) {
@@ -1830,7 +1830,7 @@ router.post('/status', async function (request, statusResponse) {
const defaultApiUrl = request.body.siliconflow_endpoint === SILICONFLOW_ENDPOINT.CN
? API_SILICONFLOW_CN : API_SILICONFLOW;
apiUrl = defaultApiUrl;
apiKey = readSecret(request.user.directories, SECRET_KEYS.SILICONFLOW);
apiKey = readSecret(request.user.directories, SECRET_KEYS.SILICONFLOW, request.body.secret_id);
headers = {};
queryParams = { type: 'text', sub_type: 'chat' };
} else {
@@ -2053,7 +2053,7 @@ router.post('/generate', async function (request, response) {
if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENAI) {
apiUrl = new URL(request.body.reverse_proxy || API_OPENAI).toString();
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.OPENAI);
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.OPENAI, request.body.secret_id);
headers = {};
bodyParams = {
logprobs: request.body.logprobs,
@@ -2073,7 +2073,7 @@ router.post('/generate', async function (request, response) {
embedOpenRouterMedia(request.body.messages, { audio: true, video: false });
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENROUTER) {
apiUrl = 'https://openrouter.ai/api/v1';
apiKey = readSecret(request.user.directories, SECRET_KEYS.OPENROUTER);
apiKey = readSecret(request.user.directories, SECRET_KEYS.OPENROUTER, request.body.secret_id);
// OpenRouter needs to pass the Referer and X-Title: https://openrouter.ai/docs#requests
headers = { ...OPENROUTER_HEADERS };
const includeReasoning = Boolean(request.body.include_reasoning);
@@ -2161,7 +2161,7 @@ router.post('/generate', async function (request, response) {
}
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.CUSTOM) {
apiUrl = request.body.custom_url;
apiKey = readSecret(request.user.directories, SECRET_KEYS.CUSTOM);
apiKey = readSecret(request.user.directories, SECRET_KEYS.CUSTOM, request.body.secret_id);
headers = {};
bodyParams = {
logprobs: request.body.logprobs,
@@ -2179,7 +2179,7 @@ router.post('/generate', async function (request, response) {
embedOpenRouterMedia(request.body.messages, { audio: true, video: false });
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.PERPLEXITY) {
apiUrl = API_PERPLEXITY;
apiKey = readSecret(request.user.directories, SECRET_KEYS.PERPLEXITY);
apiKey = readSecret(request.user.directories, SECRET_KEYS.PERPLEXITY, request.body.secret_id);
headers = {};
bodyParams = {
reasoning_effort: request.body.reasoning_effort,
@@ -2195,7 +2195,7 @@ router.post('/generate', async function (request, response) {
}
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.GROQ) {
apiUrl = API_GROQ;
apiKey = readSecret(request.user.directories, SECRET_KEYS.GROQ);
apiKey = readSecret(request.user.directories, SECRET_KEYS.GROQ, request.body.secret_id);
headers = {};
bodyParams = {};
if (request.body.json_schema) {
@@ -2211,7 +2211,7 @@ router.post('/generate', async function (request, response) {
}
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.FIREWORKS) {
apiUrl = API_FIREWORKS;
apiKey = readSecret(request.user.directories, SECRET_KEYS.FIREWORKS);
apiKey = readSecret(request.user.directories, SECRET_KEYS.FIREWORKS, request.body.secret_id);
headers = {};
bodyParams = {};
if (request.body.json_schema) {
@@ -2227,7 +2227,7 @@ router.post('/generate', async function (request, response) {
}
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.NANOGPT) {
apiUrl = API_NANOGPT;
apiKey = readSecret(request.user.directories, SECRET_KEYS.NANOGPT);
apiKey = readSecret(request.user.directories, SECRET_KEYS.NANOGPT, request.body.secret_id);
headers = {};
bodyParams = {};
if (request.body.enable_web_search && !/:online$/.test(request.body.model)) {
@@ -2256,7 +2256,7 @@ router.post('/generate', async function (request, response) {
}
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.POLLINATIONS) {
apiUrl = API_POLLINATIONS;
apiKey = readSecret(request.user.directories, SECRET_KEYS.POLLINATIONS);
apiKey = readSecret(request.user.directories, SECRET_KEYS.POLLINATIONS, request.body.secret_id);
headers = {};
bodyParams = {
reasoning_effort: request.body.reasoning_effort,
@@ -2272,7 +2272,7 @@ router.post('/generate', async function (request, response) {
}
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MOONSHOT) {
apiUrl = new URL(request.body.reverse_proxy || API_MOONSHOT).toString();
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MOONSHOT);
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MOONSHOT, request.body.secret_id);
headers = {};
bodyParams = {
thinking: {
@@ -2284,7 +2284,7 @@ router.post('/generate', async function (request, response) {
: addAssistantPrefix(request.body.messages, [], 'partial');
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.COMETAPI) {
apiUrl = API_COMETAPI;
apiKey = readSecret(request.user.directories, SECRET_KEYS.COMETAPI);
apiKey = readSecret(request.user.directories, SECRET_KEYS.COMETAPI, request.body.secret_id);
headers = {};
bodyParams = {
reasoning_effort: request.body.reasoning_effort,
@@ -2293,7 +2293,7 @@ router.post('/generate', async function (request, response) {
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.ZAI) {
const defaultApiUrl = request.body.zai_endpoint === ZAI_ENDPOINT.CODING ? API_ZAI_CODING : API_ZAI_COMMON;
apiUrl = new URL(request.body.reverse_proxy || defaultApiUrl).toString();
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.ZAI);
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.ZAI, request.body.secret_id);
headers = {
'Accept-Language': 'en-US,en',
};
@@ -2309,7 +2309,7 @@ router.post('/generate', async function (request, response) {
const defaultApiUrl = request.body.siliconflow_endpoint === SILICONFLOW_ENDPOINT.CN
? API_SILICONFLOW_CN : API_SILICONFLOW;
apiUrl = defaultApiUrl;
apiKey = readSecret(request.user.directories, SECRET_KEYS.SILICONFLOW);
apiKey = readSecret(request.user.directories, SECRET_KEYS.SILICONFLOW, request.body.secret_id);
headers = {};
bodyParams = {};
if (request.body.json_schema) {
+3 -2
View File
@@ -441,10 +441,11 @@ export function deleteSecret(directories, key) {
* Reads a secret from the secrets file
* @param {import('../users.js').UserDirectoryList} directories User directories
* @param {string} key Secret key
* @param {string?} id Secret ID (optional)
* @returns {string} Secret value
*/
export function readSecret(directories, key) {
return new SecretManager(directories).readSecret(key, null);
export function readSecret(directories, key, id = null) {
return new SecretManager(directories).readSecret(key, id);
}
/**