fix litellm metadata discovery auth
This commit is contained in:
parent
90cdf17bd9
commit
8d69fe57a5
5 changed files with 46 additions and 7 deletions
|
|
@ -325,6 +325,11 @@
|
|||
<button id="btn-test-assistant-image-model" class="btn-sm btn-primary" type="button"><i class="fas fa-image"></i> Test</button>
|
||||
</div>
|
||||
<div id="assistant-image-test-result" style="font-size:12px;color:var(--g500);"></div>
|
||||
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:-6px;">
|
||||
<label style="font-size:12px;font-weight:600;color:var(--g600);min-width:130px;">Custom image model</label>
|
||||
<input id="assistant-custom-image-model" type="text" placeholder="e.g. openrouter-gpt-5-image" style="font-size:13px;padding:5px 8px;border:1px solid var(--g300);border-radius:6px;flex:1;max-width:420px;">
|
||||
<button id="btn-use-custom-assistant-image-model" class="btn-sm btn-ghost" type="button"><i class="fas fa-plus"></i> Use Custom</button>
|
||||
</div>
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;">
|
||||
<div>
|
||||
<label style="font-size:12px;font-weight:600;color:var(--g600);display:block;margin-bottom:4px;">Search result limit</label>
|
||||
|
|
|
|||
|
|
@ -703,6 +703,7 @@ function adminFlashButtonBackground(btn, color) {
|
|||
if (e.target.closest('#btn-test-assistant-chat-model')) testAssistantChatModel();
|
||||
if (e.target.closest('#btn-refresh-assistant-image-models')) loadAssistantImageModels();
|
||||
if (e.target.closest('#btn-test-assistant-image-model')) testAssistantImageModel();
|
||||
if (e.target.closest('#btn-use-custom-assistant-image-model')) useCustomAssistantImageModel();
|
||||
});
|
||||
|
||||
function loadAssistantAdmin() {
|
||||
|
|
@ -826,6 +827,22 @@ function adminFlashButtonBackground(btn, color) {
|
|||
});
|
||||
}
|
||||
|
||||
function useCustomAssistantImageModel() {
|
||||
var input = document.getElementById('assistant-custom-image-model');
|
||||
var sel = document.getElementById('assistant-image-model');
|
||||
var model = input ? input.value.trim() : '';
|
||||
if (!model) { showToast('Enter an image model ID', 'error'); return; }
|
||||
if (sel && !Array.prototype.some.call(sel.options, function(o) { return o.value === model; })) {
|
||||
var opt = document.createElement('option');
|
||||
opt.value = model;
|
||||
opt.textContent = model + ' (custom)';
|
||||
sel.appendChild(opt);
|
||||
}
|
||||
if (sel) sel.value = model;
|
||||
window._assistantImageModelValue = model;
|
||||
showToast('Custom image model selected. Save settings to keep it.', 'info');
|
||||
}
|
||||
|
||||
function saveAssistantAdmin() {
|
||||
var status = document.getElementById('assistant-admin-status');
|
||||
if (status) status.textContent = 'Saving...';
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ var PROMPTS = require('../utils/prompts');
|
|||
var logger = require('../utils/logger');
|
||||
var { gatewayUrl } = require('../utils/errors');
|
||||
var { getTTSEnvProvider, getLiteLLMTTSDiscoveryItems, getTTSProvider, getTTSVoiceLists } = require('../utils/ttsProvider');
|
||||
var { getLiteLLMHeaders } = require('../utils/litellm');
|
||||
var { getLiteLLMHeaders, getLiteLLMAdminHeaders } = require('../utils/litellm');
|
||||
var { getSTTDependencies, getLiteLLMSTTModels, getSTTModelLists, getSTTProvider } = require('../utils/sttProvider');
|
||||
var { getLiteLLMEmbeddingModels } = require('../utils/embeddings');
|
||||
|
||||
|
|
@ -448,7 +448,7 @@ router.get('/config/image-models/discover', async function(req, res) {
|
|||
var axios = require('axios');
|
||||
var discovered = [];
|
||||
if (process.env.LITELLM_API_BASE) {
|
||||
var resp = await axios.get(liteLLMBaseUrl() + '/model/info', { headers: getLiteLLMHeaders(), timeout: 15000 });
|
||||
var resp = await axios.get(liteLLMBaseUrl() + '/model/info', { headers: getLiteLLMAdminHeaders(), timeout: 15000 });
|
||||
var models = (resp.data && resp.data.data) || [];
|
||||
models.forEach(function(m) {
|
||||
if (liteLLMModelMode(m) === 'image_generation') {
|
||||
|
|
@ -535,7 +535,7 @@ router.get('/config/tts/discover', async function(req, res) {
|
|||
var currentModel = dbModel || process.env.LITELLM_TTS_MODEL || '';
|
||||
var modelInfo = [];
|
||||
try {
|
||||
var lResp = await axios.get(liteLLMBaseUrl() + '/model/info', { headers: getLiteLLMHeaders(), timeout: 10000 });
|
||||
var lResp = await axios.get(liteLLMBaseUrl() + '/model/info', { headers: getLiteLLMAdminHeaders(), timeout: 10000 });
|
||||
modelInfo = lResp.data && lResp.data.data ? lResp.data.data : [];
|
||||
} catch (e) { logger.warn('LiteLLM TTS model list failed: ' + e.message); }
|
||||
getLiteLLMTTSDiscoveryItems(modelInfo, { currentModel: currentModel, currentVoice: currentVoice }).forEach(function(item) {
|
||||
|
|
@ -616,7 +616,7 @@ router.get('/config/stt/discover', async function(req, res) {
|
|||
|
||||
if (provider === 'litellm' && process.env.LITELLM_API_BASE) {
|
||||
try {
|
||||
var sResp = await axios.get(liteLLMBaseUrl() + '/model/info', { headers: getLiteLLMHeaders(), timeout: 10000 });
|
||||
var sResp = await axios.get(liteLLMBaseUrl() + '/model/info', { headers: getLiteLLMAdminHeaders(), timeout: 10000 });
|
||||
getLiteLLMSTTModels(sResp.data && sResp.data.data).forEach(function(id) {
|
||||
discovered.push({ id: id, name: id, source: 'gateway-api' });
|
||||
});
|
||||
|
|
@ -712,7 +712,7 @@ router.get('/config/embeddings/discover', async function(req, res) {
|
|||
|
||||
if (provider === 'litellm') {
|
||||
try {
|
||||
var eResp = await axios.get(liteLLMBaseUrl() + '/model/info', { headers: getLiteLLMHeaders(), timeout: 10000 });
|
||||
var eResp = await axios.get(liteLLMBaseUrl() + '/model/info', { headers: getLiteLLMAdminHeaders(), timeout: 10000 });
|
||||
var embeddingModels = getLiteLLMEmbeddingModels(eResp.data && eResp.data.data);
|
||||
for (var i = 0; i < embeddingModels.length; i++) {
|
||||
var m = embeddingModels[i];
|
||||
|
|
|
|||
|
|
@ -6,6 +6,15 @@ function getLiteLLMHeaders(contentType) {
|
|||
return headers;
|
||||
}
|
||||
|
||||
function getLiteLLMAdminHeaders(contentType) {
|
||||
var headers = {};
|
||||
if (contentType) headers['Content-Type'] = contentType;
|
||||
var key = process.env.LITELLM_MASTER_KEY || process.env.LITELLM_API_KEY;
|
||||
if (key) headers.Authorization = 'Bearer ' + key;
|
||||
return headers;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getLiteLLMHeaders
|
||||
getLiteLLMHeaders,
|
||||
getLiteLLMAdminHeaders
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
const { test } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
const ENV_KEYS = ['TTS_PROVIDER', 'LITELLM_API_BASE', 'LITELLM_API_KEY', 'LITELLM_TTS_VOICES'];
|
||||
const ENV_KEYS = ['TTS_PROVIDER', 'LITELLM_API_BASE', 'LITELLM_API_KEY', 'LITELLM_MASTER_KEY', 'LITELLM_TTS_VOICES'];
|
||||
|
||||
function withEnv(overrides, fn) {
|
||||
const previous = {};
|
||||
|
|
@ -112,3 +112,11 @@ test('LiteLLM headers include optional content type without exposing key value',
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('LiteLLM admin headers prefer master key for metadata routes', () => {
|
||||
const { getLiteLLMHeaders, getLiteLLMAdminHeaders } = require('../src/utils/litellm');
|
||||
withEnv({ LITELLM_API_KEY: 'virtual-token', LITELLM_MASTER_KEY: 'master-token' }, () => {
|
||||
assert.equal(getLiteLLMHeaders().Authorization, 'Bearer virtual-token');
|
||||
assert.equal(getLiteLLMAdminHeaders().Authorization, 'Bearer master-token');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue