This commit is contained in:
roomote-v0[bot] 2026-04-08 16:00:43 +00:00 • committed by GitHub
commit f04128e882
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 71 additions and 12 deletions

View file

@ -697,4 +697,44 @@ describe("getLiteLLMModels", () => {
description: "model-with-only-max-output-tokens via LiteLLM proxy", description: "model-with-only-max-output-tokens via LiteLLM proxy",
}) })
}) })
it("sends request without Authorization header when apiKey is undefined", async () => {
const mockResponse = {
data: {
data: [],
},
}
mockedAxios.get.mockResolvedValue(mockResponse)
await getLiteLLMModels(undefined, "http://localhost:4000")
expect(mockedAxios.get).toHaveBeenCalledWith("http://localhost:4000/v1/model/info", {
headers: {
"Content-Type": "application/json",
...DEFAULT_HEADERS,
},
timeout: 5000,
})
})
it("sends request without Authorization header when apiKey is empty string", async () => {
const mockResponse = {
data: {
data: [],
},
}
mockedAxios.get.mockResolvedValue(mockResponse)
await getLiteLLMModels("", "http://localhost:4000")
expect(mockedAxios.get).toHaveBeenCalledWith("http://localhost:4000/v1/model/info", {
headers: {
"Content-Type": "application/json",
...DEFAULT_HEADERS,
},
timeout: 5000,
})
})
}) })

View file

@ -11,7 +11,7 @@ import { DEFAULT_HEADERS } from "../constants"
* @returns A promise that resolves to a record of model IDs to model info * @returns A promise that resolves to a record of model IDs to model info
* @throws Will throw an error if the request fails or the response is not as expected. * @throws Will throw an error if the request fails or the response is not as expected.
*/ */
export async function getLiteLLMModels(apiKey: string, baseUrl: string): Promise<ModelRecord> { export async function getLiteLLMModels(apiKey: string | undefined, baseUrl: string): Promise<ModelRecord> {
try { try {
const headers: Record<string, string> = { const headers: Record<string, string> = {
"Content-Type": "application/json", "Content-Type": "application/json",

View file

@ -26,7 +26,7 @@ export class LiteLLMHandler extends RouterProvider implements SingleCompletionHa
options, options,
name: "litellm", name: "litellm",
baseURL: `${options.litellmBaseUrl || "http://localhost:4000"}`, baseURL: `${options.litellmBaseUrl || "http://localhost:4000"}`,
apiKey: options.litellmApiKey || "dummy-key", apiKey: options.litellmApiKey || "not-needed",
modelId: options.litellmModelId, modelId: options.litellmModelId,
defaultModelId: litellmDefaultModelId, defaultModelId: litellmDefaultModelId,
defaultModelInfo: litellmDefaultModelInfo, defaultModelInfo: litellmDefaultModelInfo,

View file

@ -1002,11 +1002,11 @@ export const webviewMessageHandler = async (
}, },
] ]
// LiteLLM is conditional on baseUrl+apiKey // LiteLLM is conditional on baseUrl (apiKey is optional)
const litellmApiKey = apiConfiguration.litellmApiKey || message?.values?.litellmApiKey const litellmApiKey = apiConfiguration.litellmApiKey || message?.values?.litellmApiKey
const litellmBaseUrl = apiConfiguration.litellmBaseUrl || message?.values?.litellmBaseUrl const litellmBaseUrl = apiConfiguration.litellmBaseUrl || message?.values?.litellmBaseUrl
if (litellmApiKey && litellmBaseUrl) { if (litellmBaseUrl) {
// If explicit credentials are provided in message.values (from Refresh Models button), // If explicit credentials are provided in message.values (from Refresh Models button),
// flush the cache first to ensure we fetch fresh data with the new credentials // flush the cache first to ensure we fetch fresh data with the new credentials
if (message?.values?.litellmApiKey || message?.values?.litellmBaseUrl) { if (message?.values?.litellmApiKey || message?.values?.litellmBaseUrl) {

View file

@ -171,7 +171,7 @@ type CommonFetchParams = {
const dynamicProviderExtras = { const dynamicProviderExtras = {
openrouter: {} as {}, // eslint-disable-line @typescript-eslint/no-empty-object-type openrouter: {} as {}, // eslint-disable-line @typescript-eslint/no-empty-object-type
"vercel-ai-gateway": {} as {}, // eslint-disable-line @typescript-eslint/no-empty-object-type "vercel-ai-gateway": {} as {}, // eslint-disable-line @typescript-eslint/no-empty-object-type
litellm: {} as { apiKey: string; baseUrl: string }, litellm: {} as { apiKey?: string; baseUrl: string },
requesty: {} as { apiKey?: string; baseUrl?: string }, requesty: {} as { apiKey?: string; baseUrl?: string },
unbound: {} as { apiKey?: string }, unbound: {} as { apiKey?: string },
ollama: {} as {}, // eslint-disable-line @typescript-eslint/no-empty-object-type ollama: {} as {}, // eslint-disable-line @typescript-eslint/no-empty-object-type

View file

@ -86,13 +86,16 @@ export const LiteLLM = ({
const key = apiConfiguration.litellmApiKey const key = apiConfiguration.litellmApiKey
const url = apiConfiguration.litellmBaseUrl const url = apiConfiguration.litellmBaseUrl
if (!key || !url) { if (!url) {
setRefreshStatus("error") setRefreshStatus("error")
setRefreshError(t("settings:providers.refreshModels.missingConfig")) setRefreshError(t("settings:providers.refreshModels.missingConfig"))
return return
} }
vscode.postMessage({ type: "requestRouterModels", values: { litellmApiKey: key, litellmBaseUrl: url } }) vscode.postMessage({
type: "requestRouterModels",
values: { ...(key ? { litellmApiKey: key } : {}), litellmBaseUrl: url },
})
}, [apiConfiguration, setRefreshStatus, setRefreshError, t]) }, [apiConfiguration, setRefreshStatus, setRefreshError, t])
return ( return (
@ -121,9 +124,7 @@ export const LiteLLM = ({
<Button <Button
variant="outline" variant="outline"
onClick={handleRefreshModels} onClick={handleRefreshModels}
disabled={ disabled={refreshStatus === "loading" || !apiConfiguration.litellmBaseUrl}
refreshStatus === "loading" || !apiConfiguration.litellmApiKey || !apiConfiguration.litellmBaseUrl
}
className="w-full"> className="w-full">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{refreshStatus === "loading" ? ( {refreshStatus === "loading" ? (

View file

@ -884,6 +884,7 @@
}, },
"validation": { "validation": {
"apiKey": "Heu de proporcionar una clau API vàlida.", "apiKey": "Heu de proporcionar una clau API vàlida.",
"baseUrl": "Heu de proporcionar una URL base vàlida.",
"awsRegion": "Heu de triar una regió per utilitzar Amazon Bedrock.", "awsRegion": "Heu de triar una regió per utilitzar Amazon Bedrock.",
"googleCloud": "Heu de proporcionar un ID de projecte i regió de Google Cloud vàlids.", "googleCloud": "Heu de proporcionar un ID de projecte i regió de Google Cloud vàlids.",
"modelId": "Heu de proporcionar un ID de model vàlid.", "modelId": "Heu de proporcionar un ID de model vàlid.",

View file

@ -884,6 +884,7 @@
}, },
"validation": { "validation": {
"apiKey": "Du musst einen gültigen API-Schlüssel angeben.", "apiKey": "Du musst einen gültigen API-Schlüssel angeben.",
"baseUrl": "Du musst eine gültige Basis-URL angeben.",
"awsRegion": "Du musst eine Region für die Verwendung mit Amazon Bedrock auswählen.", "awsRegion": "Du musst eine Region für die Verwendung mit Amazon Bedrock auswählen.",
"googleCloud": "Du musst eine gültige Google Cloud Projekt-ID und Region angeben.", "googleCloud": "Du musst eine gültige Google Cloud Projekt-ID und Region angeben.",
"modelId": "Du musst eine gültige Modell-ID angeben.", "modelId": "Du musst eine gültige Modell-ID angeben.",

View file

@ -947,6 +947,7 @@
}, },
"validation": { "validation": {
"apiKey": "You must provide a valid API key.", "apiKey": "You must provide a valid API key.",
"baseUrl": "You must provide a valid base URL.",
"awsRegion": "You must choose a region to use with Amazon Bedrock.", "awsRegion": "You must choose a region to use with Amazon Bedrock.",
"googleCloud": "You must provide a valid Google Cloud Project ID and Region.", "googleCloud": "You must provide a valid Google Cloud Project ID and Region.",
"modelId": "You must provide a valid model ID.", "modelId": "You must provide a valid model ID.",

View file

@ -884,6 +884,7 @@
}, },
"validation": { "validation": {
"apiKey": "Debe proporcionar una clave API válida.", "apiKey": "Debe proporcionar una clave API válida.",
"baseUrl": "Debe proporcionar una URL base válida.",
"awsRegion": "Debe elegir una región para usar con Amazon Bedrock.", "awsRegion": "Debe elegir una región para usar con Amazon Bedrock.",
"googleCloud": "Debe proporcionar un ID de proyecto y región de Google Cloud válidos.", "googleCloud": "Debe proporcionar un ID de proyecto y región de Google Cloud válidos.",
"modelId": "Debe proporcionar un ID de modelo válido.", "modelId": "Debe proporcionar un ID de modelo válido.",

View file

@ -884,6 +884,7 @@
}, },
"validation": { "validation": {
"apiKey": "Vous devez fournir une clé API valide.", "apiKey": "Vous devez fournir une clé API valide.",
"baseUrl": "Vous devez fournir une URL de base valide.",
"awsRegion": "Vous devez choisir une région pour utiliser Amazon Bedrock.", "awsRegion": "Vous devez choisir une région pour utiliser Amazon Bedrock.",
"googleCloud": "Vous devez fournir un ID de projet et une région Google Cloud valides.", "googleCloud": "Vous devez fournir un ID de projet et une région Google Cloud valides.",
"modelId": "Vous devez fournir un ID de modèle valide.", "modelId": "Vous devez fournir un ID de modèle valide.",

View file

@ -884,6 +884,7 @@
}, },
"validation": { "validation": {
"apiKey": "आपको एक मान्य API कुंजी प्रदान करनी होगी।", "apiKey": "आपको एक मान्य API कुंजी प्रदान करनी होगी।",
"baseUrl": "आपको एक मान्य बेस URL प्रदान करना होगा।",
"awsRegion": "Amazon Bedrock का उपयोग करने के लिए आपको एक क्षेत्र चुनना होगा।", "awsRegion": "Amazon Bedrock का उपयोग करने के लिए आपको एक क्षेत्र चुनना होगा।",
"googleCloud": "आपको एक मान्य Google Cloud प्रोजेक्ट ID और क्षेत्र प्रदान करना होगा।", "googleCloud": "आपको एक मान्य Google Cloud प्रोजेक्ट ID और क्षेत्र प्रदान करना होगा।",
"modelId": "आपको एक मान्य मॉडल ID प्रदान करनी होगी।", "modelId": "आपको एक मान्य मॉडल ID प्रदान करनी होगी।",

View file

@ -884,6 +884,7 @@
}, },
"validation": { "validation": {
"apiKey": "Kamu harus menyediakan API key yang valid.", "apiKey": "Kamu harus menyediakan API key yang valid.",
"baseUrl": "Kamu harus menyediakan base URL yang valid.",
"awsRegion": "Kamu harus memilih region untuk digunakan dengan Amazon Bedrock.", "awsRegion": "Kamu harus memilih region untuk digunakan dengan Amazon Bedrock.",
"googleCloud": "Kamu harus menyediakan Google Cloud Project ID dan Region yang valid.", "googleCloud": "Kamu harus menyediakan Google Cloud Project ID dan Region yang valid.",
"modelId": "Kamu harus menyediakan model ID yang valid.", "modelId": "Kamu harus menyediakan model ID yang valid.",

View file

@ -884,6 +884,7 @@
}, },
"validation": { "validation": {
"apiKey": "È necessario fornire una chiave API valida.", "apiKey": "È necessario fornire una chiave API valida.",
"baseUrl": "È necessario fornire un URL base valido.",
"awsRegion": "È necessario scegliere una regione per utilizzare Amazon Bedrock.", "awsRegion": "È necessario scegliere una regione per utilizzare Amazon Bedrock.",
"googleCloud": "È necessario fornire un ID progetto e una regione Google Cloud validi.", "googleCloud": "È necessario fornire un ID progetto e una regione Google Cloud validi.",
"modelId": "È necessario fornire un ID modello valido.", "modelId": "È necessario fornire un ID modello valido.",

View file

@ -884,6 +884,7 @@
}, },
"validation": { "validation": {
"apiKey": "有効なAPIキーを入力してください。", "apiKey": "有効なAPIキーを入力してください。",
"baseUrl": "有効なベースURLを入力してください。",
"awsRegion": "Amazon Bedrockを使用するにはリージョンを選択してください。", "awsRegion": "Amazon Bedrockを使用するにはリージョンを選択してください。",
"googleCloud": "有効なGoogle CloudプロジェクトIDとリージョンを入力してください。", "googleCloud": "有効なGoogle CloudプロジェクトIDとリージョンを入力してください。",
"modelId": "有効なモデルIDを入力してください。", "modelId": "有効なモデルIDを入力してください。",

View file

@ -884,6 +884,7 @@
}, },
"validation": { "validation": {
"apiKey": "유효한 API 키를 입력해야 합니다.", "apiKey": "유효한 API 키를 입력해야 합니다.",
"baseUrl": "유효한 기본 URL을 입력해야 합니다.",
"awsRegion": "Amazon Bedrock을 사용하려면 리전을 선택해야 합니다.", "awsRegion": "Amazon Bedrock을 사용하려면 리전을 선택해야 합니다.",
"googleCloud": "유효한 Google Cloud 프로젝트 ID와 리전을 입력해야 합니다.", "googleCloud": "유효한 Google Cloud 프로젝트 ID와 리전을 입력해야 합니다.",
"modelId": "유효한 모델 ID를 입력해야 합니다.", "modelId": "유효한 모델 ID를 입력해야 합니다.",

View file

@ -884,6 +884,7 @@
}, },
"validation": { "validation": {
"apiKey": "Je moet een geldige API-sleutel opgeven.", "apiKey": "Je moet een geldige API-sleutel opgeven.",
"baseUrl": "Je moet een geldige basis-URL opgeven.",
"awsRegion": "Je moet een regio kiezen om Amazon Bedrock te gebruiken.", "awsRegion": "Je moet een regio kiezen om Amazon Bedrock te gebruiken.",
"googleCloud": "Je moet een geldig Google Cloud Project-ID en regio opgeven.", "googleCloud": "Je moet een geldig Google Cloud Project-ID en regio opgeven.",
"modelId": "Je moet een geldig model-ID opgeven.", "modelId": "Je moet een geldig model-ID opgeven.",

View file

@ -884,6 +884,7 @@
}, },
"validation": { "validation": {
"apiKey": "Musisz podać prawidłowy klucz API.", "apiKey": "Musisz podać prawidłowy klucz API.",
"baseUrl": "Musisz podać prawidłowy bazowy URL.",
"awsRegion": "Musisz wybrać region, aby korzystać z Amazon Bedrock.", "awsRegion": "Musisz wybrać region, aby korzystać z Amazon Bedrock.",
"googleCloud": "Musisz podać prawidłowe ID projektu i region Google Cloud.", "googleCloud": "Musisz podać prawidłowe ID projektu i region Google Cloud.",
"modelId": "Musisz podać prawidłowe ID modelu.", "modelId": "Musisz podać prawidłowe ID modelu.",

View file

@ -884,6 +884,7 @@
}, },
"validation": { "validation": {
"apiKey": "Você deve fornecer uma chave de API válida.", "apiKey": "Você deve fornecer uma chave de API válida.",
"baseUrl": "Você deve fornecer uma URL base válida.",
"awsRegion": "Você deve escolher uma região para usar o Amazon Bedrock.", "awsRegion": "Você deve escolher uma região para usar o Amazon Bedrock.",
"googleCloud": "Você deve fornecer um ID de projeto e região do Google Cloud válidos.", "googleCloud": "Você deve fornecer um ID de projeto e região do Google Cloud válidos.",
"modelId": "Você deve fornecer um ID de modelo válido.", "modelId": "Você deve fornecer um ID de modelo válido.",

View file

@ -884,6 +884,7 @@
}, },
"validation": { "validation": {
"apiKey": "Вы должны указать действительный API-ключ.", "apiKey": "Вы должны указать действительный API-ключ.",
"baseUrl": "Вы должны указать действительный базовый URL.",
"awsRegion": "Вы должны выбрать регион для использования с Amazon Bedrock.", "awsRegion": "Вы должны выбрать регион для использования с Amazon Bedrock.",
"googleCloud": "Вы должны указать действительный Project ID и регион Google Cloud.", "googleCloud": "Вы должны указать действительный Project ID и регион Google Cloud.",
"modelId": "Вы должны указать действительный ID модели.", "modelId": "Вы должны указать действительный ID модели.",

View file

@ -884,6 +884,7 @@
}, },
"validation": { "validation": {
"apiKey": "Geçerli bir API anahtarı sağlamalısınız.", "apiKey": "Geçerli bir API anahtarı sağlamalısınız.",
"baseUrl": "Geçerli bir temel URL sağlamalısınız.",
"awsRegion": "Amazon Bedrock kullanmak için bir bölge seçmelisiniz.", "awsRegion": "Amazon Bedrock kullanmak için bir bölge seçmelisiniz.",
"googleCloud": "Geçerli bir Google Cloud proje kimliği ve bölge sağlamalısınız.", "googleCloud": "Geçerli bir Google Cloud proje kimliği ve bölge sağlamalısınız.",
"modelId": "Geçerli bir model kimliği sağlamalısınız.", "modelId": "Geçerli bir model kimliği sağlamalısınız.",

View file

@ -884,6 +884,7 @@
}, },
"validation": { "validation": {
"apiKey": "Bạn phải cung cấp khóa API hợp lệ.", "apiKey": "Bạn phải cung cấp khóa API hợp lệ.",
"baseUrl": "Bạn phải cung cấp URL cơ sở hợp lệ.",
"awsRegion": "Bạn phải chọn một vùng để sử dụng Amazon Bedrock.", "awsRegion": "Bạn phải chọn một vùng để sử dụng Amazon Bedrock.",
"googleCloud": "Bạn phải cung cấp ID dự án và vùng Google Cloud hợp lệ.", "googleCloud": "Bạn phải cung cấp ID dự án và vùng Google Cloud hợp lệ.",
"modelId": "Bạn phải cung cấp ID mô hình hợp lệ.", "modelId": "Bạn phải cung cấp ID mô hình hợp lệ.",

View file

@ -884,6 +884,7 @@
}, },
"validation": { "validation": {
"apiKey": "您必须提供有效的 API 密钥。", "apiKey": "您必须提供有效的 API 密钥。",
"baseUrl": "您必须提供有效的基础 URL。",
"awsRegion": "您必须选择一个区域来使用 Amazon Bedrock。", "awsRegion": "您必须选择一个区域来使用 Amazon Bedrock。",
"googleCloud": "您必须提供有效的 Google Cloud 项目 ID 和区域。", "googleCloud": "您必须提供有效的 Google Cloud 项目 ID 和区域。",
"modelId": "您必须提供有效的模型 ID。", "modelId": "您必须提供有效的模型 ID。",

View file

@ -894,6 +894,7 @@
}, },
"validation": { "validation": {
"apiKey": "請提供有效的 API 金鑰。", "apiKey": "請提供有效的 API 金鑰。",
"baseUrl": "請提供有效的基礎 URL。",
"awsRegion": "請選擇要用於 Amazon Bedrock 的區域。", "awsRegion": "請選擇要用於 Amazon Bedrock 的區域。",
"googleCloud": "請提供有效的 Google Cloud 專案 ID 和區域。", "googleCloud": "請提供有效的 Google Cloud 專案 ID 和區域。",
"modelId": "請提供有效的模型 ID。", "modelId": "請提供有效的模型 ID。",

View file

@ -54,8 +54,8 @@ function validateModelsAndKeysProvided(apiConfiguration: ProviderSettings): stri
} }
break break
case "litellm": case "litellm":
if (!apiConfiguration.litellmApiKey) { if (!apiConfiguration.litellmBaseUrl) {
return i18next.t("settings:validation.apiKey") return i18next.t("settings:validation.baseUrl")
} }
break break
case "anthropic": case "anthropic":