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>
Signed| @@ -435,6 +435,7 @@ export class ConnectionManagerRequestService { | |||
| 435 | max_tokens: maxTokens, | 435 | max_tokens: maxTokens, |
| 436 | model: profile.model, | 436 | model: profile.model, |
| 437 | chat_completion_source: selectedApiMap.source, | 437 | chat_completion_source: selectedApiMap.source, |
| 438 | secret_id: profile['secret-id'], | ||
| 438 | custom_url: profile['api-url'], | 439 | custom_url: profile['api-url'], |
| 439 | vertexai_region: profile['api-url'], | 440 | vertexai_region: profile['api-url'], |
| 440 | zai_endpoint: profile['api-url'], | 441 | zai_endpoint: profile['api-url'], |
| @@ -459,6 +460,7 @@ export class ConnectionManagerRequestService { | |||
| 459 | model: profile.model, | 460 | model: profile.model, |
| 460 | api_type: selectedApiMap.type, | 461 | api_type: selectedApiMap.type, |
| 461 | api_server: profile['api-url'], | 462 | api_server: profile['api-url'], |
| 463 | secret_id: profile['secret-id'], | ||
| 462 | ...overridePayload, | 464 | ...overridePayload, |
| 463 | }, { | 465 | }, { |
| 464 | instructName: includeInstruct ? profile.instruct : undefined, | 466 | instructName: includeInstruct ? profile.instruct : undefined, |
| @@ -5,10 +5,11 @@ import { getConfigValue } from './util.js'; | |||
| 5 | /** | 5 | /** |
| 6 | * Gets the headers for the Mancer API. | 6 | * Gets the headers for the Mancer API. |
| 7 | * @param {import('./users.js').UserDirectoryList} directories User directories | 7 | * @param {import('./users.js').UserDirectoryList} directories User directories |
| 8 | * @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use) | ||
| 8 | * @returns {object} Headers for the request | 9 | * @returns {object} Headers for the request |
| 9 | */ | 10 | */ |
| 10 | function getMancerHeaders(directories) { | 11 | function getMancerHeaders(directories, secretId = null) { |
| 11 | const apiKey = readSecret(directories, SECRET_KEYS.MANCER); | 12 | const apiKey = readSecret(directories, SECRET_KEYS.MANCER, secretId); |
| 12 | 13 | ||
| 13 | return apiKey ? ({ | 14 | return apiKey ? ({ |
| 14 | 'X-API-KEY': apiKey, | 15 | 'X-API-KEY': apiKey, |
| @@ -19,10 +20,11 @@ function getMancerHeaders(directories) { | |||
| 19 | /** | 20 | /** |
| 20 | * Gets the headers for the TogetherAI API. | 21 | * Gets the headers for the TogetherAI API. |
| 21 | * @param {import('./users.js').UserDirectoryList} directories User directories | 22 | * @param {import('./users.js').UserDirectoryList} directories User directories |
| 23 | * @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use) | ||
| 22 | * @returns {object} Headers for the request | 24 | * @returns {object} Headers for the request |
| 23 | */ | 25 | */ |
| 24 | function getTogetherAIHeaders(directories) { | 26 | function getTogetherAIHeaders(directories, secretId = null) { |
| 25 | const apiKey = readSecret(directories, SECRET_KEYS.TOGETHERAI); | 27 | const apiKey = readSecret(directories, SECRET_KEYS.TOGETHERAI, secretId); |
| 26 | 28 | ||
| 27 | return apiKey ? ({ | 29 | return apiKey ? ({ |
| 28 | 'Authorization': `Bearer ${apiKey}`, | 30 | 'Authorization': `Bearer ${apiKey}`, |
| @@ -32,10 +34,11 @@ function getTogetherAIHeaders(directories) { | |||
| 32 | /** | 34 | /** |
| 33 | * Gets the headers for the InfermaticAI API. | 35 | * Gets the headers for the InfermaticAI API. |
| 34 | * @param {import('./users.js').UserDirectoryList} directories User directories | 36 | * @param {import('./users.js').UserDirectoryList} directories User directories |
| 37 | * @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use) | ||
| 35 | * @returns {object} Headers for the request | 38 | * @returns {object} Headers for the request |
| 36 | */ | 39 | */ |
| 37 | function getInfermaticAIHeaders(directories) { | 40 | function getInfermaticAIHeaders(directories, secretId = null) { |
| 38 | const apiKey = readSecret(directories, SECRET_KEYS.INFERMATICAI); | 41 | const apiKey = readSecret(directories, SECRET_KEYS.INFERMATICAI, secretId); |
| 39 | 42 | ||
| 40 | return apiKey ? ({ | 43 | return apiKey ? ({ |
| 41 | 'Authorization': `Bearer ${apiKey}`, | 44 | 'Authorization': `Bearer ${apiKey}`, |
| @@ -45,10 +48,11 @@ function getInfermaticAIHeaders(directories) { | |||
| 45 | /** | 48 | /** |
| 46 | * Gets the headers for the DreamGen API. | 49 | * Gets the headers for the DreamGen API. |
| 47 | * @param {import('./users.js').UserDirectoryList} directories User directories | 50 | * @param {import('./users.js').UserDirectoryList} directories User directories |
| 51 | * @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use) | ||
| 48 | * @returns {object} Headers for the request | 52 | * @returns {object} Headers for the request |
| 49 | */ | 53 | */ |
| 50 | function getDreamGenHeaders(directories) { | 54 | function getDreamGenHeaders(directories, secretId = null) { |
| 51 | const apiKey = readSecret(directories, SECRET_KEYS.DREAMGEN); | 55 | const apiKey = readSecret(directories, SECRET_KEYS.DREAMGEN, secretId); |
| 52 | 56 | ||
| 53 | return apiKey ? ({ | 57 | return apiKey ? ({ |
| 54 | 'Authorization': `Bearer ${apiKey}`, | 58 | 'Authorization': `Bearer ${apiKey}`, |
| @@ -58,10 +62,11 @@ function getDreamGenHeaders(directories) { | |||
| 58 | /** | 62 | /** |
| 59 | * Gets the headers for the OpenRouter API. | 63 | * Gets the headers for the OpenRouter API. |
| 60 | * @param {import('./users.js').UserDirectoryList} directories User directories | 64 | * @param {import('./users.js').UserDirectoryList} directories User directories |
| 65 | * @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use) | ||
| 61 | * @returns {object} Headers for the request | 66 | * @returns {object} Headers for the request |
| 62 | */ | 67 | */ |
| 63 | function getOpenRouterHeaders(directories) { | 68 | function getOpenRouterHeaders(directories, secretId = null) { |
| 64 | const apiKey = readSecret(directories, SECRET_KEYS.OPENROUTER); | 69 | const apiKey = readSecret(directories, SECRET_KEYS.OPENROUTER, secretId); |
| 65 | const baseHeaders = { ...OPENROUTER_HEADERS }; | 70 | const baseHeaders = { ...OPENROUTER_HEADERS }; |
| 66 | 71 | ||
| 67 | return apiKey ? Object.assign(baseHeaders, { 'Authorization': `Bearer ${apiKey}` }) : baseHeaders; | 72 | return apiKey ? Object.assign(baseHeaders, { 'Authorization': `Bearer ${apiKey}` }) : baseHeaders; |
| @@ -70,10 +75,11 @@ function getOpenRouterHeaders(directories) { | |||
| 70 | /** | 75 | /** |
| 71 | * Gets the headers for the vLLM API. | 76 | * Gets the headers for the vLLM API. |
| 72 | * @param {import('./users.js').UserDirectoryList} directories User directories | 77 | * @param {import('./users.js').UserDirectoryList} directories User directories |
| 78 | * @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use) | ||
| 73 | * @returns {object} Headers for the request | 79 | * @returns {object} Headers for the request |
| 74 | */ | 80 | */ |
| 75 | function getVllmHeaders(directories) { | 81 | function getVllmHeaders(directories, secretId = null) { |
| 76 | const apiKey = readSecret(directories, SECRET_KEYS.VLLM); | 82 | const apiKey = readSecret(directories, SECRET_KEYS.VLLM, secretId); |
| 77 | 83 | ||
| 78 | return apiKey ? ({ | 84 | return apiKey ? ({ |
| 79 | 'Authorization': `Bearer ${apiKey}`, | 85 | 'Authorization': `Bearer ${apiKey}`, |
| @@ -83,10 +89,11 @@ function getVllmHeaders(directories) { | |||
| 83 | /** | 89 | /** |
| 84 | * Gets the headers for the Aphrodite API. | 90 | * Gets the headers for the Aphrodite API. |
| 85 | * @param {import('./users.js').UserDirectoryList} directories User directories | 91 | * @param {import('./users.js').UserDirectoryList} directories User directories |
| 92 | * @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use) | ||
| 86 | * @returns {object} Headers for the request | 93 | * @returns {object} Headers for the request |
| 87 | */ | 94 | */ |
| 88 | function getAphroditeHeaders(directories) { | 95 | function getAphroditeHeaders(directories, secretId = null) { |
| 89 | const apiKey = readSecret(directories, SECRET_KEYS.APHRODITE); | 96 | const apiKey = readSecret(directories, SECRET_KEYS.APHRODITE, secretId); |
| 90 | 97 | ||
| 91 | return apiKey ? ({ | 98 | return apiKey ? ({ |
| 92 | 'X-API-KEY': apiKey, | 99 | 'X-API-KEY': apiKey, |
| @@ -97,10 +104,11 @@ function getAphroditeHeaders(directories) { | |||
| 97 | /** | 104 | /** |
| 98 | * Gets the headers for the Tabby API. | 105 | * Gets the headers for the Tabby API. |
| 99 | * @param {import('./users.js').UserDirectoryList} directories User directories | 106 | * @param {import('./users.js').UserDirectoryList} directories User directories |
| 107 | * @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use) | ||
| 100 | * @returns {object} Headers for the request | 108 | * @returns {object} Headers for the request |
| 101 | */ | 109 | */ |
| 102 | function getTabbyHeaders(directories) { | 110 | function getTabbyHeaders(directories, secretId = null) { |
| 103 | const apiKey = readSecret(directories, SECRET_KEYS.TABBY); | 111 | const apiKey = readSecret(directories, SECRET_KEYS.TABBY, secretId); |
| 104 | 112 | ||
| 105 | return apiKey ? ({ | 113 | return apiKey ? ({ |
| 106 | 'x-api-key': apiKey, | 114 | 'x-api-key': apiKey, |
| @@ -111,10 +119,11 @@ function getTabbyHeaders(directories) { | |||
| 111 | /** | 119 | /** |
| 112 | * Gets the headers for the LlamaCPP API. | 120 | * Gets the headers for the LlamaCPP API. |
| 113 | * @param {import('./users.js').UserDirectoryList} directories User directories | 121 | * @param {import('./users.js').UserDirectoryList} directories User directories |
| 122 | * @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use) | ||
| 114 | * @returns {object} Headers for the request | 123 | * @returns {object} Headers for the request |
| 115 | */ | 124 | */ |
| 116 | function getLlamaCppHeaders(directories) { | 125 | function getLlamaCppHeaders(directories, secretId = null) { |
| 117 | const apiKey = readSecret(directories, SECRET_KEYS.LLAMACPP); | 126 | const apiKey = readSecret(directories, SECRET_KEYS.LLAMACPP, secretId); |
| 118 | 127 | ||
| 119 | return apiKey ? ({ | 128 | return apiKey ? ({ |
| 120 | 'Authorization': `Bearer ${apiKey}`, | 129 | 'Authorization': `Bearer ${apiKey}`, |
| @@ -123,11 +132,12 @@ function getLlamaCppHeaders(directories) { | |||
| 123 | 132 | ||
| 124 | /** | 133 | /** |
| 125 | * Gets the headers for the Ooba API. | 134 | * Gets the headers for the Ooba API. |
| 126 | * @param {import('./users.js').UserDirectoryList} directories | 135 | * @param {import('./users.js').UserDirectoryList} directories User directories |
| 136 | * @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use) | ||
| 127 | * @returns {object} Headers for the request | 137 | * @returns {object} Headers for the request |
| 128 | */ | 138 | */ |
| 129 | function getOobaHeaders(directories) { | 139 | function getOobaHeaders(directories, secretId = null) { |
| 130 | const apiKey = readSecret(directories, SECRET_KEYS.OOBA); | 140 | const apiKey = readSecret(directories, SECRET_KEYS.OOBA, secretId); |
| 131 | 141 | ||
| 132 | return apiKey ? ({ | 142 | return apiKey ? ({ |
| 133 | 'Authorization': `Bearer ${apiKey}`, | 143 | 'Authorization': `Bearer ${apiKey}`, |
| @@ -137,10 +147,11 @@ function getOobaHeaders(directories) { | |||
| 137 | /** | 147 | /** |
| 138 | * Gets the headers for the KoboldCpp API. | 148 | * Gets the headers for the KoboldCpp API. |
| 139 | * @param {import('./users.js').UserDirectoryList} directories | 149 | * @param {import('./users.js').UserDirectoryList} directories |
| 150 | * @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use) | ||
| 140 | * @returns {object} Headers for the request | 151 | * @returns {object} Headers for the request |
| 141 | */ | 152 | */ |
| 142 | function getKoboldCppHeaders(directories) { | 153 | function getKoboldCppHeaders(directories, secretId = null) { |
| 143 | const apiKey = readSecret(directories, SECRET_KEYS.KOBOLDCPP); | 154 | const apiKey = readSecret(directories, SECRET_KEYS.KOBOLDCPP, secretId); |
| 144 | 155 | ||
| 145 | return apiKey ? ({ | 156 | return apiKey ? ({ |
| 146 | 'Authorization': `Bearer ${apiKey}`, | 157 | 'Authorization': `Bearer ${apiKey}`, |
| @@ -150,10 +161,11 @@ function getKoboldCppHeaders(directories) { | |||
| 150 | /** | 161 | /** |
| 151 | * Gets the headers for the Featherless API. | 162 | * Gets the headers for the Featherless API. |
| 152 | * @param {import('./users.js').UserDirectoryList} directories | 163 | * @param {import('./users.js').UserDirectoryList} directories |
| 164 | * @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use) | ||
| 153 | * @returns {object} Headers for the request | 165 | * @returns {object} Headers for the request |
| 154 | */ | 166 | */ |
| 155 | function getFeatherlessHeaders(directories) { | 167 | function getFeatherlessHeaders(directories, secretId = null) { |
| 156 | const apiKey = readSecret(directories, SECRET_KEYS.FEATHERLESS); | 168 | const apiKey = readSecret(directories, SECRET_KEYS.FEATHERLESS, secretId); |
| 157 | const baseHeaders = { ...FEATHERLESS_HEADERS }; | 169 | const baseHeaders = { ...FEATHERLESS_HEADERS }; |
| 158 | 170 | ||
| 159 | return apiKey ? Object.assign(baseHeaders, { 'Authorization': `Bearer ${apiKey}` }) : baseHeaders; | 171 | return apiKey ? Object.assign(baseHeaders, { 'Authorization': `Bearer ${apiKey}` }) : baseHeaders; |
| @@ -162,10 +174,11 @@ function getFeatherlessHeaders(directories) { | |||
| 162 | /** | 174 | /** |
| 163 | * Gets the headers for the HuggingFace API. | 175 | * Gets the headers for the HuggingFace API. |
| 164 | * @param {import('./users.js').UserDirectoryList} directories | 176 | * @param {import('./users.js').UserDirectoryList} directories |
| 177 | * @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use) | ||
| 165 | * @returns {object} Headers for the request | 178 | * @returns {object} Headers for the request |
| 166 | */ | 179 | */ |
| 167 | function getHuggingFaceHeaders(directories) { | 180 | function getHuggingFaceHeaders(directories, secretId = null) { |
| 168 | const apiKey = readSecret(directories, SECRET_KEYS.HUGGINGFACE); | 181 | const apiKey = readSecret(directories, SECRET_KEYS.HUGGINGFACE, secretId); |
| 169 | 182 | ||
| 170 | return apiKey ? ({ | 183 | return apiKey ? ({ |
| 171 | 'Authorization': `Bearer ${apiKey}`, | 184 | 'Authorization': `Bearer ${apiKey}`, |
| @@ -175,10 +188,11 @@ function getHuggingFaceHeaders(directories) { | |||
| 175 | /** | 188 | /** |
| 176 | * Gets the headers for the Generic text completion API. | 189 | * Gets the headers for the Generic text completion API. |
| 177 | * @param {import('./users.js').UserDirectoryList} directories | 190 | * @param {import('./users.js').UserDirectoryList} directories |
| 191 | * @param {string|null} secretId Secret ID for the request (optional, used to determine which secret to use) | ||
| 178 | * @returns {object} Headers for the request | 192 | * @returns {object} Headers for the request |
| 179 | */ | 193 | */ |
| 180 | function getGenericHeaders(directories) { | 194 | function getGenericHeaders(directories, secretId = null) { |
| 181 | const apiKey = readSecret(directories, SECRET_KEYS.GENERIC); | 195 | const apiKey = readSecret(directories, SECRET_KEYS.GENERIC, secretId); |
| 182 | 196 | ||
| 183 | return apiKey ? ({ | 197 | return apiKey ? ({ |
| 184 | 'Authorization': `Bearer ${apiKey}`, | 198 | 'Authorization': `Bearer ${apiKey}`, |
| @@ -202,7 +216,7 @@ export function getOverrideHeaders(urlHost) { | |||
| 202 | * @param {string|null} server API server for new request | 216 | * @param {string|null} server API server for new request |
| 203 | */ | 217 | */ |
| 204 | export function setAdditionalHeaders(request, args, server) { | 218 | export function setAdditionalHeaders(request, args, server) { |
| 205 | setAdditionalHeadersByType(args.headers, request.body.api_type, server, request.user.directories); | 219 | setAdditionalHeadersByType(args.headers, request.body.api_type, server, request.user.directories, request.body.secret_id); |
| 206 | } | 220 | } |
| 207 | 221 | ||
| 208 | /** | 222 | /** |
| @@ -211,8 +225,9 @@ export function setAdditionalHeaders(request, args, server) { | |||
| 211 | * @param {string} type API type | 225 | * @param {string} type API type |
| 212 | * @param {string|null} server API server for new request | 226 | * @param {string|null} server API server for new request |
| 213 | * @param {import('./users.js').UserDirectoryList} directories User directories | 227 | * @param {import('./users.js').UserDirectoryList} directories User directories |
| 228 | * @param {string|null} secretId Secret ID for the request (optional, used for some API types to determine which secret to use) | ||
| 214 | */ | 229 | */ |
| 215 | export function setAdditionalHeadersByType(requestHeaders, type, server, directories) { | 230 | export function setAdditionalHeadersByType(requestHeaders, type, server, directories, secretId = null) { |
| 216 | const headerGetters = { | 231 | const headerGetters = { |
| 217 | [TEXTGEN_TYPES.MANCER]: getMancerHeaders, | 232 | [TEXTGEN_TYPES.MANCER]: getMancerHeaders, |
| 218 | [TEXTGEN_TYPES.VLLM]: getVllmHeaders, | 233 | [TEXTGEN_TYPES.VLLM]: getVllmHeaders, |
| @@ -231,7 +246,7 @@ export function setAdditionalHeadersByType(requestHeaders, type, server, directo | |||
| 231 | }; | 246 | }; |
| 232 | 247 | ||
| 233 | const getHeaders = headerGetters[type]; | 248 | const getHeaders = headerGetters[type]; |
| 234 | const headers = getHeaders ? getHeaders(directories) : {}; | 249 | const headers = getHeaders ? getHeaders(directories, secretId) : {}; |
| 235 | 250 | ||
| 236 | if (typeof server === 'string' && server.length > 0) { | 251 | if (typeof server === 'string' && server.length > 0) { |
| 237 | try { | 252 | try { |
| @@ -208,7 +208,7 @@ function setJsonObjectFormat(bodyParams, messages, jsonSchema) { | |||
| 208 | */ | 208 | */ |
| 209 | async function sendClaudeRequest(request, response) { | 209 | async function sendClaudeRequest(request, response) { |
| 210 | const apiUrl = new URL(request.body.reverse_proxy || API_CLAUDE).toString(); | 210 | const apiUrl = new URL(request.body.reverse_proxy || API_CLAUDE).toString(); |
| 211 | const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.CLAUDE); | 211 | const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.CLAUDE, request.body.secret_id); |
| 212 | const divider = '-'.repeat(process.stdout.columns); | 212 | const divider = '-'.repeat(process.stdout.columns); |
| 213 | 213 | ||
| 214 | if (!apiKey) { | 214 | if (!apiKey) { |
| @@ -425,7 +425,7 @@ async function sendMakerSuiteRequest(request, response) { | |||
| 425 | } | 425 | } |
| 426 | } else { | 426 | } else { |
| 427 | apiUrl = new URL(request.body.reverse_proxy || API_MAKERSUITE); | 427 | apiUrl = new URL(request.body.reverse_proxy || API_MAKERSUITE); |
| 428 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MAKERSUITE); | 428 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MAKERSUITE, request.body.secret_id); |
| 429 | 429 | ||
| 430 | if (!request.body.reverse_proxy && !apiKey) { | 430 | if (!request.body.reverse_proxy && !apiKey) { |
| 431 | console.warn(`${apiName} API key is missing.`); | 431 | console.warn(`${apiName} API key is missing.`); |
| @@ -641,7 +641,7 @@ async function sendMakerSuiteRequest(request, response) { | |||
| 641 | } else if (authType === 'full') { | 641 | } else if (authType === 'full') { |
| 642 | // For Full mode (service account authentication), use project-specific URL | 642 | // For Full mode (service account authentication), use project-specific URL |
| 643 | // Get project ID from Service Account JSON | 643 | // Get project ID from Service Account JSON |
| 644 | const serviceAccountJson = readSecret(request.user.directories, SECRET_KEYS.VERTEXAI_SERVICE_ACCOUNT); | 644 | const serviceAccountJson = readSecret(request.user.directories, SECRET_KEYS.VERTEXAI_SERVICE_ACCOUNT, request.body.secret_id); |
| 645 | if (!serviceAccountJson) { | 645 | if (!serviceAccountJson) { |
| 646 | console.warn('Vertex AI Service Account JSON is missing.'); | 646 | console.warn('Vertex AI Service Account JSON is missing.'); |
| 647 | return response.status(400).send({ error: true }); | 647 | return response.status(400).send({ error: true }); |
| @@ -742,7 +742,7 @@ async function sendMakerSuiteRequest(request, response) { | |||
| 742 | async function sendAI21Request(request, response) { | 742 | async function sendAI21Request(request, response) { |
| 743 | if (!request.body) return response.sendStatus(400); | 743 | if (!request.body) return response.sendStatus(400); |
| 744 | 744 | ||
| 745 | const apiKey = readSecret(request.user.directories, SECRET_KEYS.AI21); | 745 | const apiKey = readSecret(request.user.directories, SECRET_KEYS.AI21, request.body.secret_id); |
| 746 | if (!apiKey) { | 746 | if (!apiKey) { |
| 747 | console.warn('AI21 API key is missing.'); | 747 | console.warn('AI21 API key is missing.'); |
| 748 | return response.status(400).send({ error: true }); | 748 | return response.status(400).send({ error: true }); |
| @@ -822,7 +822,7 @@ async function sendAI21Request(request, response) { | |||
| 822 | */ | 822 | */ |
| 823 | async function sendMistralAIRequest(request, response) { | 823 | async function sendMistralAIRequest(request, response) { |
| 824 | const apiUrl = new URL(request.body.reverse_proxy || API_MISTRAL).toString(); | 824 | const apiUrl = new URL(request.body.reverse_proxy || API_MISTRAL).toString(); |
| 825 | const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MISTRALAI); | 825 | const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MISTRALAI, request.body.secret_id); |
| 826 | 826 | ||
| 827 | if (!apiKey) { | 827 | if (!apiKey) { |
| 828 | console.warn('MistralAI API key is missing.'); | 828 | console.warn('MistralAI API key is missing.'); |
| @@ -911,7 +911,7 @@ async function sendMistralAIRequest(request, response) { | |||
| 911 | * @param {express.Response} response Express response | 911 | * @param {express.Response} response Express response |
| 912 | */ | 912 | */ |
| 913 | async function sendCohereRequest(request, response) { | 913 | async function sendCohereRequest(request, response) { |
| 914 | const apiKey = readSecret(request.user.directories, SECRET_KEYS.COHERE); | 914 | const apiKey = readSecret(request.user.directories, SECRET_KEYS.COHERE, request.body.secret_id); |
| 915 | const controller = new AbortController(); | 915 | const controller = new AbortController(); |
| 916 | request.socket.removeAllListeners('close'); | 916 | request.socket.removeAllListeners('close'); |
| 917 | request.socket.on('close', function () { | 917 | request.socket.on('close', function () { |
| @@ -1012,7 +1012,7 @@ async function sendCohereRequest(request, response) { | |||
| 1012 | */ | 1012 | */ |
| 1013 | async function sendDeepSeekRequest(request, response) { | 1013 | async function sendDeepSeekRequest(request, response) { |
| 1014 | const apiUrl = new URL(request.body.reverse_proxy || API_DEEPSEEK).toString(); | 1014 | const apiUrl = new URL(request.body.reverse_proxy || API_DEEPSEEK).toString(); |
| 1015 | const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK); | 1015 | const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK, request.body.secret_id); |
| 1016 | 1016 | ||
| 1017 | if (!apiKey && !request.body.reverse_proxy) { | 1017 | if (!apiKey && !request.body.reverse_proxy) { |
| 1018 | console.warn('DeepSeek API key is missing.'); | 1018 | console.warn('DeepSeek API key is missing.'); |
| @@ -1122,7 +1122,7 @@ async function sendDeepSeekRequest(request, response) { | |||
| 1122 | */ | 1122 | */ |
| 1123 | async function sendXaiRequest(request, response) { | 1123 | async function sendXaiRequest(request, response) { |
| 1124 | const apiUrl = new URL(request.body.reverse_proxy || API_XAI).toString(); | 1124 | const apiUrl = new URL(request.body.reverse_proxy || API_XAI).toString(); |
| 1125 | const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.XAI); | 1125 | const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.XAI, request.body.secret_id); |
| 1126 | 1126 | ||
| 1127 | if (!apiKey && !request.body.reverse_proxy) { | 1127 | if (!apiKey && !request.body.reverse_proxy) { |
| 1128 | console.warn('xAI API key is missing.'); | 1128 | console.warn('xAI API key is missing.'); |
| @@ -1228,7 +1228,7 @@ async function sendXaiRequest(request, response) { | |||
| 1228 | */ | 1228 | */ |
| 1229 | async function sendAimlapiRequest(request, response) { | 1229 | async function sendAimlapiRequest(request, response) { |
| 1230 | const apiUrl = API_AIMLAPI; | 1230 | const apiUrl = API_AIMLAPI; |
| 1231 | const apiKey = readSecret(request.user.directories, SECRET_KEYS.AIMLAPI); | 1231 | const apiKey = readSecret(request.user.directories, SECRET_KEYS.AIMLAPI, request.body.secret_id); |
| 1232 | 1232 | ||
| 1233 | if (!apiKey) { | 1233 | if (!apiKey) { |
| 1234 | console.warn('AI/ML API key is missing.'); | 1234 | console.warn('AI/ML API key is missing.'); |
| @@ -1333,7 +1333,7 @@ async function sendAimlapiRequest(request, response) { | |||
| 1333 | */ | 1333 | */ |
| 1334 | async function sendElectronHubRequest(request, response) { | 1334 | async function sendElectronHubRequest(request, response) { |
| 1335 | const apiUrl = API_ELECTRONHUB; | 1335 | const apiUrl = API_ELECTRONHUB; |
| 1336 | const apiKey = readSecret(request.user.directories, SECRET_KEYS.ELECTRONHUB); | 1336 | const apiKey = readSecret(request.user.directories, SECRET_KEYS.ELECTRONHUB, request.body.secret_id); |
| 1337 | 1337 | ||
| 1338 | if (!apiKey) { | 1338 | if (!apiKey) { |
| 1339 | console.warn('Electron Hub key is missing.'); | 1339 | console.warn('Electron Hub key is missing.'); |
| @@ -1445,7 +1445,7 @@ async function sendElectronHubRequest(request, response) { | |||
| 1445 | */ | 1445 | */ |
| 1446 | async function sendChutesRequest(request, response) { | 1446 | async function sendChutesRequest(request, response) { |
| 1447 | const apiUrl = API_CHUTES; | 1447 | const apiUrl = API_CHUTES; |
| 1448 | const apiKey = readSecret(request.user.directories, SECRET_KEYS.CHUTES); | 1448 | const apiKey = readSecret(request.user.directories, SECRET_KEYS.CHUTES, request.body.secret_id); |
| 1449 | 1449 | ||
| 1450 | if (!apiKey) { | 1450 | if (!apiKey) { |
| 1451 | console.warn('Chutes key is missing.'); | 1451 | console.warn('Chutes key is missing.'); |
| @@ -1547,7 +1547,7 @@ async function sendChutesRequest(request, response) { | |||
| 1547 | async function sendAzureOpenAIRequest(request, response) { | 1547 | async function sendAzureOpenAIRequest(request, response) { |
| 1548 | // 1. GATHER & VALIDATE SETTINGS | 1548 | // 1. GATHER & VALIDATE SETTINGS |
| 1549 | const { azure_base_url, azure_deployment_name, azure_api_version } = request.body; | 1549 | const { azure_base_url, azure_deployment_name, azure_api_version } = request.body; |
| 1550 | const apiKey = readSecret(request.user.directories, SECRET_KEYS.AZURE_OPENAI); | 1550 | const apiKey = readSecret(request.user.directories, SECRET_KEYS.AZURE_OPENAI, request.body.secret_id); |
| 1551 | if (!azure_base_url || !azure_deployment_name || !azure_api_version || !apiKey) { | 1551 | if (!azure_base_url || !azure_deployment_name || !azure_api_version || !apiKey) { |
| 1552 | return response.status(400).send({ | 1552 | return response.status(400).send({ |
| 1553 | error: { | 1553 | error: { |
| @@ -1646,74 +1646,74 @@ router.post('/status', async function (request, statusResponse) { | |||
| 1646 | 1646 | ||
| 1647 | if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENAI) { | 1647 | if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENAI) { |
| 1648 | apiUrl = new URL(request.body.reverse_proxy || API_OPENAI).toString(); | 1648 | apiUrl = new URL(request.body.reverse_proxy || API_OPENAI).toString(); |
| 1649 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.OPENAI); | 1649 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.OPENAI, request.body.secret_id); |
| 1650 | headers = {}; | 1650 | headers = {}; |
| 1651 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENROUTER) { | 1651 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENROUTER) { |
| 1652 | apiUrl = 'https://openrouter.ai/api/v1'; | 1652 | apiUrl = 'https://openrouter.ai/api/v1'; |
| 1653 | apiKey = readSecret(request.user.directories, SECRET_KEYS.OPENROUTER); | 1653 | apiKey = readSecret(request.user.directories, SECRET_KEYS.OPENROUTER, request.body.secret_id); |
| 1654 | // OpenRouter needs to pass the Referer and X-Title: https://openrouter.ai/docs#requests | 1654 | // OpenRouter needs to pass the Referer and X-Title: https://openrouter.ai/docs#requests |
| 1655 | headers = { ...OPENROUTER_HEADERS }; | 1655 | headers = { ...OPENROUTER_HEADERS }; |
| 1656 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MISTRALAI) { | 1656 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MISTRALAI) { |
| 1657 | apiUrl = new URL(request.body.reverse_proxy || API_MISTRAL).toString(); | 1657 | apiUrl = new URL(request.body.reverse_proxy || API_MISTRAL).toString(); |
| 1658 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MISTRALAI); | 1658 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MISTRALAI, request.body.secret_id); |
| 1659 | headers = {}; | 1659 | headers = {}; |
| 1660 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.CUSTOM) { | 1660 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.CUSTOM) { |
| 1661 | apiUrl = request.body.custom_url; | 1661 | apiUrl = request.body.custom_url; |
| 1662 | apiKey = readSecret(request.user.directories, SECRET_KEYS.CUSTOM); | 1662 | apiKey = readSecret(request.user.directories, SECRET_KEYS.CUSTOM, request.body.secret_id); |
| 1663 | headers = {}; | 1663 | headers = {}; |
| 1664 | mergeObjectWithYaml(headers, request.body.custom_include_headers); | 1664 | mergeObjectWithYaml(headers, request.body.custom_include_headers); |
| 1665 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.COHERE) { | 1665 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.COHERE) { |
| 1666 | apiUrl = API_COHERE_V1; | 1666 | apiUrl = API_COHERE_V1; |
| 1667 | apiKey = readSecret(request.user.directories, SECRET_KEYS.COHERE); | 1667 | apiKey = readSecret(request.user.directories, SECRET_KEYS.COHERE, request.body.secret_id); |
| 1668 | headers = {}; | 1668 | headers = {}; |
| 1669 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.CHUTES) { | 1669 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.CHUTES) { |
| 1670 | apiUrl = API_CHUTES; | 1670 | apiUrl = API_CHUTES; |
| 1671 | apiKey = readSecret(request.user.directories, SECRET_KEYS.CHUTES); | 1671 | apiKey = readSecret(request.user.directories, SECRET_KEYS.CHUTES, request.body.secret_id); |
| 1672 | headers = {}; | 1672 | headers = {}; |
| 1673 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.ELECTRONHUB) { | 1673 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.ELECTRONHUB) { |
| 1674 | apiUrl = API_ELECTRONHUB; | 1674 | apiUrl = API_ELECTRONHUB; |
| 1675 | apiKey = readSecret(request.user.directories, SECRET_KEYS.ELECTRONHUB); | 1675 | apiKey = readSecret(request.user.directories, SECRET_KEYS.ELECTRONHUB, request.body.secret_id); |
| 1676 | headers = {}; | 1676 | headers = {}; |
| 1677 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.NANOGPT) { | 1677 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.NANOGPT) { |
| 1678 | apiUrl = API_NANOGPT; | 1678 | apiUrl = API_NANOGPT; |
| 1679 | apiKey = readSecret(request.user.directories, SECRET_KEYS.NANOGPT); | 1679 | apiKey = readSecret(request.user.directories, SECRET_KEYS.NANOGPT, request.body.secret_id); |
| 1680 | headers = {}; | 1680 | headers = {}; |
| 1681 | queryParams = { detailed: true }; | 1681 | queryParams = { detailed: true }; |
| 1682 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.DEEPSEEK) { | 1682 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.DEEPSEEK) { |
| 1683 | apiUrl = new URL(request.body.reverse_proxy || API_DEEPSEEK.replace('/beta', '')).toString(); | 1683 | apiUrl = new URL(request.body.reverse_proxy || API_DEEPSEEK.replace('/beta', '')).toString(); |
| 1684 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK); | 1684 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK, request.body.secret_id); |
| 1685 | headers = {}; | 1685 | headers = {}; |
| 1686 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.XAI) { | 1686 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.XAI) { |
| 1687 | apiUrl = new URL(request.body.reverse_proxy || API_XAI).toString(); | 1687 | apiUrl = new URL(request.body.reverse_proxy || API_XAI).toString(); |
| 1688 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.XAI); | 1688 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.XAI, request.body.secret_id); |
| 1689 | headers = {}; | 1689 | headers = {}; |
| 1690 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.AIMLAPI) { | 1690 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.AIMLAPI) { |
| 1691 | apiUrl = API_AIMLAPI; | 1691 | apiUrl = API_AIMLAPI; |
| 1692 | apiKey = readSecret(request.user.directories, SECRET_KEYS.AIMLAPI); | 1692 | apiKey = readSecret(request.user.directories, SECRET_KEYS.AIMLAPI, request.body.secret_id); |
| 1693 | headers = { ...AIMLAPI_HEADERS }; | 1693 | headers = { ...AIMLAPI_HEADERS }; |
| 1694 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.POLLINATIONS) { | 1694 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.POLLINATIONS) { |
| 1695 | apiUrl = 'https://gen.pollinations.ai/text'; | 1695 | apiUrl = 'https://gen.pollinations.ai/text'; |
| 1696 | apiKey = readSecret(request.user.directories, SECRET_KEYS.POLLINATIONS); | 1696 | apiKey = readSecret(request.user.directories, SECRET_KEYS.POLLINATIONS, request.body.secret_id); |
| 1697 | headers = {}; | 1697 | headers = {}; |
| 1698 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.GROQ) { | 1698 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.GROQ) { |
| 1699 | apiUrl = API_GROQ; | 1699 | apiUrl = API_GROQ; |
| 1700 | apiKey = readSecret(request.user.directories, SECRET_KEYS.GROQ); | 1700 | apiKey = readSecret(request.user.directories, SECRET_KEYS.GROQ, request.body.secret_id); |
| 1701 | headers = {}; | 1701 | headers = {}; |
| 1702 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.COMETAPI) { | 1702 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.COMETAPI) { |
| 1703 | apiUrl = API_COMETAPI; | 1703 | apiUrl = API_COMETAPI; |
| 1704 | apiKey = readSecret(request.user.directories, SECRET_KEYS.COMETAPI); | 1704 | apiKey = readSecret(request.user.directories, SECRET_KEYS.COMETAPI, request.body.secret_id); |
| 1705 | headers = {}; | 1705 | headers = {}; |
| 1706 | throw new Error('This provider is temporarily disabled.'); | 1706 | throw new Error('This provider is temporarily disabled.'); |
| 1707 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MOONSHOT) { | 1707 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MOONSHOT) { |
| 1708 | apiUrl = new URL(request.body.reverse_proxy || API_MOONSHOT).toString(); | 1708 | apiUrl = new URL(request.body.reverse_proxy || API_MOONSHOT).toString(); |
| 1709 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MOONSHOT); | 1709 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MOONSHOT, request.body.secret_id); |
| 1710 | headers = {}; | 1710 | headers = {}; |
| 1711 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.FIREWORKS) { | 1711 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.FIREWORKS) { |
| 1712 | apiUrl = API_FIREWORKS; | 1712 | apiUrl = API_FIREWORKS; |
| 1713 | apiKey = readSecret(request.user.directories, SECRET_KEYS.FIREWORKS); | 1713 | apiKey = readSecret(request.user.directories, SECRET_KEYS.FIREWORKS, request.body.secret_id); |
| 1714 | headers = {}; | 1714 | headers = {}; |
| 1715 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MAKERSUITE) { | 1715 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MAKERSUITE) { |
| 1716 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MAKERSUITE); | 1716 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MAKERSUITE, request.body.secret_id); |
| 1717 | apiUrl = trimTrailingSlash(request.body.reverse_proxy || API_MAKERSUITE); | 1717 | apiUrl = trimTrailingSlash(request.body.reverse_proxy || API_MAKERSUITE); |
| 1718 | const apiVersion = getConfigValue('gemini.apiVersion', 'v1beta'); | 1718 | const apiVersion = getConfigValue('gemini.apiVersion', 'v1beta'); |
| 1719 | const modelsUrl = !apiKey && request.body.reverse_proxy | 1719 | const modelsUrl = !apiKey && request.body.reverse_proxy |
| @@ -1750,7 +1750,7 @@ router.post('/status', async function (request, statusResponse) { | |||
| 1750 | } | 1750 | } |
| 1751 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.AZURE_OPENAI) { | 1751 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.AZURE_OPENAI) { |
| 1752 | const { azure_base_url, azure_deployment_name, azure_api_version } = request.body; | 1752 | const { azure_base_url, azure_deployment_name, azure_api_version } = request.body; |
| 1753 | const apiKey = readSecret(request.user.directories, SECRET_KEYS.AZURE_OPENAI); | 1753 | const apiKey = readSecret(request.user.directories, SECRET_KEYS.AZURE_OPENAI, request.body.secret_id); |
| 1754 | 1754 | ||
| 1755 | // 1) Validate configuration from the frontend | 1755 | // 1) Validate configuration from the frontend |
| 1756 | if (!apiKey || !azure_base_url || !azure_deployment_name || !azure_api_version) { | 1756 | if (!apiKey || !azure_base_url || !azure_deployment_name || !azure_api_version) { |
| @@ -1830,7 +1830,7 @@ router.post('/status', async function (request, statusResponse) { | |||
| 1830 | const defaultApiUrl = request.body.siliconflow_endpoint === SILICONFLOW_ENDPOINT.CN | 1830 | const defaultApiUrl = request.body.siliconflow_endpoint === SILICONFLOW_ENDPOINT.CN |
| 1831 | ? API_SILICONFLOW_CN : API_SILICONFLOW; | 1831 | ? API_SILICONFLOW_CN : API_SILICONFLOW; |
| 1832 | apiUrl = defaultApiUrl; | 1832 | apiUrl = defaultApiUrl; |
| 1833 | apiKey = readSecret(request.user.directories, SECRET_KEYS.SILICONFLOW); | 1833 | apiKey = readSecret(request.user.directories, SECRET_KEYS.SILICONFLOW, request.body.secret_id); |
| 1834 | headers = {}; | 1834 | headers = {}; |
| 1835 | queryParams = { type: 'text', sub_type: 'chat' }; | 1835 | queryParams = { type: 'text', sub_type: 'chat' }; |
| 1836 | } else { | 1836 | } else { |
| @@ -2053,7 +2053,7 @@ router.post('/generate', async function (request, response) { | |||
| 2053 | 2053 | ||
| 2054 | if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENAI) { | 2054 | if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENAI) { |
| 2055 | apiUrl = new URL(request.body.reverse_proxy || API_OPENAI).toString(); | 2055 | apiUrl = new URL(request.body.reverse_proxy || API_OPENAI).toString(); |
| 2056 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.OPENAI); | 2056 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.OPENAI, request.body.secret_id); |
| 2057 | headers = {}; | 2057 | headers = {}; |
| 2058 | bodyParams = { | 2058 | bodyParams = { |
| 2059 | logprobs: request.body.logprobs, | 2059 | logprobs: request.body.logprobs, |
| @@ -2073,7 +2073,7 @@ router.post('/generate', async function (request, response) { | |||
| 2073 | embedOpenRouterMedia(request.body.messages, { audio: true, video: false }); | 2073 | embedOpenRouterMedia(request.body.messages, { audio: true, video: false }); |
| 2074 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENROUTER) { | 2074 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENROUTER) { |
| 2075 | apiUrl = 'https://openrouter.ai/api/v1'; | 2075 | apiUrl = 'https://openrouter.ai/api/v1'; |
| 2076 | apiKey = readSecret(request.user.directories, SECRET_KEYS.OPENROUTER); | 2076 | apiKey = readSecret(request.user.directories, SECRET_KEYS.OPENROUTER, request.body.secret_id); |
| 2077 | // OpenRouter needs to pass the Referer and X-Title: https://openrouter.ai/docs#requests | 2077 | // OpenRouter needs to pass the Referer and X-Title: https://openrouter.ai/docs#requests |
| 2078 | headers = { ...OPENROUTER_HEADERS }; | 2078 | headers = { ...OPENROUTER_HEADERS }; |
| 2079 | const includeReasoning = Boolean(request.body.include_reasoning); | 2079 | const includeReasoning = Boolean(request.body.include_reasoning); |
| @@ -2161,7 +2161,7 @@ router.post('/generate', async function (request, response) { | |||
| 2161 | } | 2161 | } |
| 2162 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.CUSTOM) { | 2162 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.CUSTOM) { |
| 2163 | apiUrl = request.body.custom_url; | 2163 | apiUrl = request.body.custom_url; |
| 2164 | apiKey = readSecret(request.user.directories, SECRET_KEYS.CUSTOM); | 2164 | apiKey = readSecret(request.user.directories, SECRET_KEYS.CUSTOM, request.body.secret_id); |
| 2165 | headers = {}; | 2165 | headers = {}; |
| 2166 | bodyParams = { | 2166 | bodyParams = { |
| 2167 | logprobs: request.body.logprobs, | 2167 | logprobs: request.body.logprobs, |
| @@ -2179,7 +2179,7 @@ router.post('/generate', async function (request, response) { | |||
| 2179 | embedOpenRouterMedia(request.body.messages, { audio: true, video: false }); | 2179 | embedOpenRouterMedia(request.body.messages, { audio: true, video: false }); |
| 2180 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.PERPLEXITY) { | 2180 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.PERPLEXITY) { |
| 2181 | apiUrl = API_PERPLEXITY; | 2181 | apiUrl = API_PERPLEXITY; |
| 2182 | apiKey = readSecret(request.user.directories, SECRET_KEYS.PERPLEXITY); | 2182 | apiKey = readSecret(request.user.directories, SECRET_KEYS.PERPLEXITY, request.body.secret_id); |
| 2183 | headers = {}; | 2183 | headers = {}; |
| 2184 | bodyParams = { | 2184 | bodyParams = { |
| 2185 | reasoning_effort: request.body.reasoning_effort, | 2185 | reasoning_effort: request.body.reasoning_effort, |
| @@ -2195,7 +2195,7 @@ router.post('/generate', async function (request, response) { | |||
| 2195 | } | 2195 | } |
| 2196 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.GROQ) { | 2196 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.GROQ) { |
| 2197 | apiUrl = API_GROQ; | 2197 | apiUrl = API_GROQ; |
| 2198 | apiKey = readSecret(request.user.directories, SECRET_KEYS.GROQ); | 2198 | apiKey = readSecret(request.user.directories, SECRET_KEYS.GROQ, request.body.secret_id); |
| 2199 | headers = {}; | 2199 | headers = {}; |
| 2200 | bodyParams = {}; | 2200 | bodyParams = {}; |
| 2201 | if (request.body.json_schema) { | 2201 | if (request.body.json_schema) { |
| @@ -2211,7 +2211,7 @@ router.post('/generate', async function (request, response) { | |||
| 2211 | } | 2211 | } |
| 2212 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.FIREWORKS) { | 2212 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.FIREWORKS) { |
| 2213 | apiUrl = API_FIREWORKS; | 2213 | apiUrl = API_FIREWORKS; |
| 2214 | apiKey = readSecret(request.user.directories, SECRET_KEYS.FIREWORKS); | 2214 | apiKey = readSecret(request.user.directories, SECRET_KEYS.FIREWORKS, request.body.secret_id); |
| 2215 | headers = {}; | 2215 | headers = {}; |
| 2216 | bodyParams = {}; | 2216 | bodyParams = {}; |
| 2217 | if (request.body.json_schema) { | 2217 | if (request.body.json_schema) { |
| @@ -2227,7 +2227,7 @@ router.post('/generate', async function (request, response) { | |||
| 2227 | } | 2227 | } |
| 2228 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.NANOGPT) { | 2228 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.NANOGPT) { |
| 2229 | apiUrl = API_NANOGPT; | 2229 | apiUrl = API_NANOGPT; |
| 2230 | apiKey = readSecret(request.user.directories, SECRET_KEYS.NANOGPT); | 2230 | apiKey = readSecret(request.user.directories, SECRET_KEYS.NANOGPT, request.body.secret_id); |
| 2231 | headers = {}; | 2231 | headers = {}; |
| 2232 | bodyParams = {}; | 2232 | bodyParams = {}; |
| 2233 | if (request.body.enable_web_search && !/:online$/.test(request.body.model)) { | 2233 | if (request.body.enable_web_search && !/:online$/.test(request.body.model)) { |
| @@ -2256,7 +2256,7 @@ router.post('/generate', async function (request, response) { | |||
| 2256 | } | 2256 | } |
| 2257 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.POLLINATIONS) { | 2257 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.POLLINATIONS) { |
| 2258 | apiUrl = API_POLLINATIONS; | 2258 | apiUrl = API_POLLINATIONS; |
| 2259 | apiKey = readSecret(request.user.directories, SECRET_KEYS.POLLINATIONS); | 2259 | apiKey = readSecret(request.user.directories, SECRET_KEYS.POLLINATIONS, request.body.secret_id); |
| 2260 | headers = {}; | 2260 | headers = {}; |
| 2261 | bodyParams = { | 2261 | bodyParams = { |
| 2262 | reasoning_effort: request.body.reasoning_effort, | 2262 | reasoning_effort: request.body.reasoning_effort, |
| @@ -2272,7 +2272,7 @@ router.post('/generate', async function (request, response) { | |||
| 2272 | } | 2272 | } |
| 2273 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MOONSHOT) { | 2273 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MOONSHOT) { |
| 2274 | apiUrl = new URL(request.body.reverse_proxy || API_MOONSHOT).toString(); | 2274 | apiUrl = new URL(request.body.reverse_proxy || API_MOONSHOT).toString(); |
| 2275 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MOONSHOT); | 2275 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MOONSHOT, request.body.secret_id); |
| 2276 | headers = {}; | 2276 | headers = {}; |
| 2277 | bodyParams = { | 2277 | bodyParams = { |
| 2278 | thinking: { | 2278 | thinking: { |
| @@ -2284,7 +2284,7 @@ router.post('/generate', async function (request, response) { | |||
| 2284 | : addAssistantPrefix(request.body.messages, [], 'partial'); | 2284 | : addAssistantPrefix(request.body.messages, [], 'partial'); |
| 2285 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.COMETAPI) { | 2285 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.COMETAPI) { |
| 2286 | apiUrl = API_COMETAPI; | 2286 | apiUrl = API_COMETAPI; |
| 2287 | apiKey = readSecret(request.user.directories, SECRET_KEYS.COMETAPI); | 2287 | apiKey = readSecret(request.user.directories, SECRET_KEYS.COMETAPI, request.body.secret_id); |
| 2288 | headers = {}; | 2288 | headers = {}; |
| 2289 | bodyParams = { | 2289 | bodyParams = { |
| 2290 | reasoning_effort: request.body.reasoning_effort, | 2290 | reasoning_effort: request.body.reasoning_effort, |
| @@ -2293,7 +2293,7 @@ router.post('/generate', async function (request, response) { | |||
| 2293 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.ZAI) { | 2293 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.ZAI) { |
| 2294 | const defaultApiUrl = request.body.zai_endpoint === ZAI_ENDPOINT.CODING ? API_ZAI_CODING : API_ZAI_COMMON; | 2294 | const defaultApiUrl = request.body.zai_endpoint === ZAI_ENDPOINT.CODING ? API_ZAI_CODING : API_ZAI_COMMON; |
| 2295 | apiUrl = new URL(request.body.reverse_proxy || defaultApiUrl).toString(); | 2295 | apiUrl = new URL(request.body.reverse_proxy || defaultApiUrl).toString(); |
| 2296 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.ZAI); | 2296 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.ZAI, request.body.secret_id); |
| 2297 | headers = { | 2297 | headers = { |
| 2298 | 'Accept-Language': 'en-US,en', | 2298 | 'Accept-Language': 'en-US,en', |
| 2299 | }; | 2299 | }; |
| @@ -2309,7 +2309,7 @@ router.post('/generate', async function (request, response) { | |||
| 2309 | const defaultApiUrl = request.body.siliconflow_endpoint === SILICONFLOW_ENDPOINT.CN | 2309 | const defaultApiUrl = request.body.siliconflow_endpoint === SILICONFLOW_ENDPOINT.CN |
| 2310 | ? API_SILICONFLOW_CN : API_SILICONFLOW; | 2310 | ? API_SILICONFLOW_CN : API_SILICONFLOW; |
| 2311 | apiUrl = defaultApiUrl; | 2311 | apiUrl = defaultApiUrl; |
| 2312 | apiKey = readSecret(request.user.directories, SECRET_KEYS.SILICONFLOW); | 2312 | apiKey = readSecret(request.user.directories, SECRET_KEYS.SILICONFLOW, request.body.secret_id); |
| 2313 | headers = {}; | 2313 | headers = {}; |
| 2314 | bodyParams = {}; | 2314 | bodyParams = {}; |
| 2315 | if (request.body.json_schema) { | 2315 | if (request.body.json_schema) { |
| @@ -441,10 +441,11 @@ export function deleteSecret(directories, key) { | |||
| 441 | * Reads a secret from the secrets file | 441 | * Reads a secret from the secrets file |
| 442 | * @param {import('../users.js').UserDirectoryList} directories User directories | 442 | * @param {import('../users.js').UserDirectoryList} directories User directories |
| 443 | * @param {string} key Secret key | 443 | * @param {string} key Secret key |
| 444 | * @param {string?} id Secret ID (optional) | ||
| 444 | * @returns {string} Secret value | 445 | * @returns {string} Secret value |
| 445 | */ | 446 | */ |
| 446 | export function readSecret(directories, key) { | 447 | export function readSecret(directories, key, id = null) { |
| 447 | return new SecretManager(directories).readSecret(key, null); | 448 | return new SecretManager(directories).readSecret(key, id); |
| 448 | } | 449 | } |
| 449 | 450 | ||
| 450 | /** | 451 | /** |