Compare commits

...

4 commits

Author SHA1 Message Date
roomote-v0[bot]
f04128e882
Merge bcbe39ac4d into eafed9705c 2026-04-08 16:00:43 +00:00
Ksandr
eafed9705c
Fix/minimax context window and models (#12069) 2026-04-08 08:44:36 -06:00
Roo Code
bcbe39ac4d fix: add missing validation.baseUrl translations to all locale files 2026-03-16 07:11:28 +00:00
Roo Code
bc55c0068a fix: make LiteLLM API key optional for self-hosted proxies
LiteLLM supports and is often used without authentication in self-hosted
or local environments. This change makes the API key field optional so
users can configure LiteLLM with just a base URL.

Changes:
- Remove API key requirement from validation (require only base URL)
- Update Refresh Models button to work without API key
- Make apiKey optional in LiteLLM type definition
- Update fetcher to accept undefined apiKey and skip Auth header
- Update webviewMessageHandler to only require baseUrl
- Add validation.baseUrl translation key
- Add tests for no-API-key scenarios

Closes #11918
2026-03-13 10:21:07 +00:00
28 changed files with 255 additions and 29 deletions

View file

@ -1,11 +1,11 @@
import type { ModelInfo } from "../model.js"
// Minimax
// https://platform.minimax.io/docs/guides/pricing
// https://platform.minimax.io/docs/api-reference/text-openai-api
// https://platform.minimax.io/docs/api-reference/text-anthropic-api
// https://platform.minimax.io/docs/guides/models-intro
// https://platform.minimax.io/docs/guides/pricing-paygo
// https://platform.minimax.io/docs/guides/pricing-tokenplan
export type MinimaxModelId = keyof typeof minimaxModels
export const minimaxDefaultModelId: MinimaxModelId = "MiniMax-M2.5"
export const minimaxDefaultModelId: MinimaxModelId = "MiniMax-M2.7"
export const minimaxModels = {
"MiniMax-M2.5": {
@ -21,11 +21,56 @@ export const minimaxModels = {
cacheWritesPrice: 0.375,
cacheReadsPrice: 0.03,
description:
"MiniMax M2.5, the latest MiniMax model with enhanced coding and agentic capabilities, building on the strengths of the M2 series.",
"MiniMax M2.5, the latest MiniMax model with enhanced coding and agentic capabilities, building on the strengths of the M2 series. See pricing at https://platform.minimax.io/docs/guides/pricing-paygo. Note: When using TokenPlan, usage is billed per request, not per token.",
},
"MiniMax-M2.5-highspeed": {
maxTokens: 16_384,
contextWindow: 204_800,
supportsImages: false,
supportsPromptCache: true,
includedTools: ["search_and_replace"],
excludedTools: ["apply_diff"],
preserveReasoning: true,
inputPrice: 0.6,
outputPrice: 2.4,
cacheWritesPrice: 0.375,
cacheReadsPrice: 0.03,
description:
"MiniMax M2.5 highspeed: same performance as M2.5 but with faster response (approximately 100 tps vs 60 tps). See pricing at https://platform.minimax.io/docs/guides/pricing-paygo. Requires TokenPlan High-Speed subscription for use with TokenPlan keys. Note: When using TokenPlan, usage is billed per request, not per token.",
},
"MiniMax-M2.7": {
maxTokens: 16_384,
contextWindow: 204_800,
supportsImages: false,
supportsPromptCache: true,
includedTools: ["search_and_replace"],
excludedTools: ["apply_diff"],
preserveReasoning: true,
inputPrice: 0.3,
outputPrice: 1.2,
cacheWritesPrice: 0.375,
cacheReadsPrice: 0.06,
description:
"MiniMax M2.7, the latest MiniMax model with recursive self-improvement capabilities. See pricing at https://platform.minimax.io/docs/guides/pricing-paygo. Note: When using TokenPlan, usage is billed per request, not per token.",
},
"MiniMax-M2.7-highspeed": {
maxTokens: 16_384,
contextWindow: 204_800,
supportsImages: false,
supportsPromptCache: true,
includedTools: ["search_and_replace"],
excludedTools: ["apply_diff"],
preserveReasoning: true,
inputPrice: 0.6,
outputPrice: 2.4,
cacheWritesPrice: 0.375,
cacheReadsPrice: 0.06,
description:
"MiniMax M2.7 highspeed: same performance as M2.7 but with faster response (approximately 100 tps vs 60 tps). See pricing at https://platform.minimax.io/docs/guides/pricing-paygo. Requires TokenPlan High-Speed subscription for use with TokenPlan keys. Note: When using TokenPlan, usage is billed per request, not per token.",
},
"MiniMax-M2": {
maxTokens: 16_384,
contextWindow: 192_000,
contextWindow: 204_800,
supportsImages: false,
supportsPromptCache: true,
includedTools: ["search_and_replace"],
@ -36,11 +81,11 @@ export const minimaxModels = {
cacheWritesPrice: 0.375,
cacheReadsPrice: 0.03,
description:
"MiniMax M2, a model born for Agents and code, featuring Top-tier Coding Capabilities, Powerful Agentic Performance, and Ultimate Cost-Effectiveness & Speed.",
"MiniMax M2, a model born for Agents and code, featuring Top-tier Coding Capabilities, Powerful Agentic Performance, and Ultimate Cost-Effectiveness & Speed. See pricing at https://platform.minimax.io/docs/guides/pricing-paygo. Note: When using TokenPlan, usage is billed per request, not per token.",
},
"MiniMax-M2-Stable": {
maxTokens: 16_384,
contextWindow: 192_000,
contextWindow: 204_800,
supportsImages: false,
supportsPromptCache: true,
includedTools: ["search_and_replace"],
@ -51,11 +96,11 @@ export const minimaxModels = {
cacheWritesPrice: 0.375,
cacheReadsPrice: 0.03,
description:
"MiniMax M2 Stable (High Concurrency, Commercial Use), a model born for Agents and code, featuring Top-tier Coding Capabilities, Powerful Agentic Performance, and Ultimate Cost-Effectiveness & Speed.",
"MiniMax M2 Stable (High Concurrency, Commercial Use), a model born for Agents and code, featuring Top-tier Coding Capabilities, Powerful Agentic Performance, and Ultimate Cost-Effectiveness & Speed. See pricing at https://platform.minimax.io/docs/guides/pricing-paygo. Note: When using TokenPlan, usage is billed per request, not per token.",
},
"MiniMax-M2.1": {
maxTokens: 16_384,
contextWindow: 192_000,
contextWindow: 204_800,
supportsImages: false,
supportsPromptCache: true,
includedTools: ["search_and_replace"],
@ -66,7 +111,22 @@ export const minimaxModels = {
cacheWritesPrice: 0.375,
cacheReadsPrice: 0.03,
description:
"MiniMax M2.1 builds on M2 with improved overall performance for agentic coding tasks and significantly faster response times.",
"MiniMax M2.1 builds on M2 with improved overall performance for agentic coding tasks and significantly faster response times. See pricing at https://platform.minimax.io/docs/guides/pricing-paygo. Note: When using TokenPlan, usage is billed per request, not per token.",
},
"MiniMax-M2.1-highspeed": {
maxTokens: 16_384,
contextWindow: 204_800,
supportsImages: false,
supportsPromptCache: true,
includedTools: ["search_and_replace"],
excludedTools: ["apply_diff"],
preserveReasoning: true,
inputPrice: 0.6,
outputPrice: 2.4,
cacheWritesPrice: 0.375,
cacheReadsPrice: 0.03,
description:
"MiniMax M2.1 highspeed: same performance as M2.1 but with faster response (approximately 100 tps vs 60 tps). See pricing at https://platform.minimax.io/docs/guides/pricing-paygo. Requires TokenPlan High-Speed subscription for use with TokenPlan keys. Note: When using TokenPlan, usage is billed per request, not per token.",
},
} as const satisfies Record<string, ModelInfo>

View file

@ -112,7 +112,7 @@ describe("MiniMaxHandler", () => {
const model = handlerWithModel.getModel()
expect(model.id).toBe(testModelId)
expect(model.info).toEqual(minimaxModels[testModelId])
expect(model.info.contextWindow).toBe(192_000)
expect(model.info.contextWindow).toBe(204_800)
expect(model.info.maxTokens).toBe(16_384)
expect(model.info.supportsPromptCache).toBe(true)
expect(model.info.cacheWritesPrice).toBe(0.375)
@ -128,7 +128,7 @@ describe("MiniMaxHandler", () => {
const model = handlerWithModel.getModel()
expect(model.id).toBe(testModelId)
expect(model.info).toEqual(minimaxModels[testModelId])
expect(model.info.contextWindow).toBe(192_000)
expect(model.info.contextWindow).toBe(204_800)
expect(model.info.maxTokens).toBe(16_384)
expect(model.info.supportsPromptCache).toBe(true)
expect(model.info.cacheWritesPrice).toBe(0.375)
@ -191,10 +191,10 @@ describe("MiniMaxHandler", () => {
expect(model.info).toEqual(minimaxModels[minimaxDefaultModelId])
})
it("should default to MiniMax-M2.5 model", () => {
it("should default to MiniMax-M2.7 model", () => {
const handlerDefault = new MiniMaxHandler({ minimaxApiKey: "test-minimax-api-key" })
const model = handlerDefault.getModel()
expect(model.id).toBe("MiniMax-M2.5")
expect(model.id).toBe("MiniMax-M2.7")
})
})
@ -399,7 +399,7 @@ describe("MiniMaxHandler", () => {
it("should correctly configure MiniMax-M2 model properties", () => {
const model = minimaxModels["MiniMax-M2"]
expect(model.maxTokens).toBe(16_384)
expect(model.contextWindow).toBe(192_000)
expect(model.contextWindow).toBe(204_800)
expect(model.supportsImages).toBe(false)
expect(model.supportsPromptCache).toBe(true)
expect(model.inputPrice).toBe(0.3)
@ -411,7 +411,7 @@ describe("MiniMaxHandler", () => {
it("should correctly configure MiniMax-M2-Stable model properties", () => {
const model = minimaxModels["MiniMax-M2-Stable"]
expect(model.maxTokens).toBe(16_384)
expect(model.contextWindow).toBe(192_000)
expect(model.contextWindow).toBe(204_800)
expect(model.supportsImages).toBe(false)
expect(model.supportsPromptCache).toBe(true)
expect(model.inputPrice).toBe(0.3)
@ -419,5 +419,63 @@ describe("MiniMaxHandler", () => {
expect(model.cacheWritesPrice).toBe(0.375)
expect(model.cacheReadsPrice).toBe(0.03)
})
it("should correctly configure MiniMax-M2.7 model properties", () => {
const model = minimaxModels["MiniMax-M2.7"]
expect(model.maxTokens).toBe(16_384)
expect(model.contextWindow).toBe(204_800)
expect(model.supportsImages).toBe(false)
expect(model.supportsPromptCache).toBe(true)
expect(model.inputPrice).toBe(0.3)
expect(model.outputPrice).toBe(1.2)
expect(model.cacheWritesPrice).toBe(0.375)
expect(model.cacheReadsPrice).toBe(0.06)
})
it("should correctly configure MiniMax-M2.7-highspeed model properties", () => {
const model = minimaxModels["MiniMax-M2.7-highspeed"]
expect(model.maxTokens).toBe(16_384)
expect(model.contextWindow).toBe(204_800)
expect(model.supportsImages).toBe(false)
expect(model.supportsPromptCache).toBe(true)
expect(model.inputPrice).toBe(0.6)
expect(model.outputPrice).toBe(2.4)
expect(model.cacheWritesPrice).toBe(0.375)
expect(model.cacheReadsPrice).toBe(0.06)
})
it("should correctly configure MiniMax-M2.5-highspeed model properties", () => {
const model = minimaxModels["MiniMax-M2.5-highspeed"]
expect(model.maxTokens).toBe(16_384)
expect(model.contextWindow).toBe(204_800)
expect(model.supportsImages).toBe(false)
expect(model.supportsPromptCache).toBe(true)
expect(model.inputPrice).toBe(0.6)
expect(model.outputPrice).toBe(2.4)
expect(model.cacheWritesPrice).toBe(0.375)
expect(model.cacheReadsPrice).toBe(0.03)
})
it("should correctly configure MiniMax-M2.1-highspeed model properties", () => {
const model = minimaxModels["MiniMax-M2.1-highspeed"]
expect(model.maxTokens).toBe(16_384)
expect(model.contextWindow).toBe(204_800)
expect(model.supportsImages).toBe(false)
expect(model.supportsPromptCache).toBe(true)
expect(model.inputPrice).toBe(0.6)
expect(model.outputPrice).toBe(2.4)
expect(model.cacheWritesPrice).toBe(0.375)
expect(model.cacheReadsPrice).toBe(0.03)
})
it("should correctly configure MiniMax-M2.1 model properties with updated context window", () => {
const model = minimaxModels["MiniMax-M2.1"]
expect(model.contextWindow).toBe(204_800)
})
it("should correctly configure MiniMax-M2 model properties with updated context window", () => {
const model = minimaxModels["MiniMax-M2"]
expect(model.contextWindow).toBe(204_800)
})
})
})

View file

@ -697,4 +697,44 @@ describe("getLiteLLMModels", () => {
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
* @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 {
const headers: Record<string, string> = {
"Content-Type": "application/json",

View file

@ -26,7 +26,7 @@ export class LiteLLMHandler extends RouterProvider implements SingleCompletionHa
options,
name: "litellm",
baseURL: `${options.litellmBaseUrl || "http://localhost:4000"}`,
apiKey: options.litellmApiKey || "dummy-key",
apiKey: options.litellmApiKey || "not-needed",
modelId: options.litellmModelId,
defaultModelId: litellmDefaultModelId,
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 litellmBaseUrl = apiConfiguration.litellmBaseUrl || message?.values?.litellmBaseUrl
if (litellmApiKey && litellmBaseUrl) {
if (litellmBaseUrl) {
// 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
if (message?.values?.litellmApiKey || message?.values?.litellmBaseUrl) {

View file

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

View file

@ -11,6 +11,8 @@ import {
BEDROCK_1M_CONTEXT_MODEL_IDS,
litellmDefaultModelInfo,
openAiModelInfoSaneDefaults,
minimaxDefaultModelId,
minimaxModels,
} from "@roo-code/types"
import { useSelectedModel } from "../useSelectedModel"
@ -725,4 +727,51 @@ describe("useSelectedModel", () => {
expect(result.current.info).toEqual(customModelInfo)
})
})
describe("minimax provider", () => {
beforeEach(() => {
mockUseRouterModels.mockReturnValue({
data: {
openrouter: {},
requesty: {},
litellm: {},
},
isLoading: false,
isError: false,
} as any)
mockUseOpenRouterModelProviders.mockReturnValue({
data: {},
isLoading: false,
isError: false,
} as any)
})
it("should return default minimax model when no custom model is specified", () => {
const apiConfiguration: ProviderSettings = {
apiProvider: "minimax",
}
const wrapper = createWrapper()
const { result } = renderHook(() => useSelectedModel(apiConfiguration), { wrapper })
expect(result.current.provider).toBe("minimax")
expect(result.current.id).toBe(minimaxDefaultModelId)
expect(result.current.info).toEqual(minimaxModels[minimaxDefaultModelId])
})
it("should use custom model ID and info when model exists in minimaxModels", () => {
const apiConfiguration: ProviderSettings = {
apiProvider: "minimax",
apiModelId: "MiniMax-M2.7",
}
const wrapper = createWrapper()
const { result } = renderHook(() => useSelectedModel(apiConfiguration), { wrapper })
expect(result.current.provider).toBe("minimax")
expect(result.current.id).toBe("MiniMax-M2.7")
expect(result.current.info).toEqual(minimaxModels["MiniMax-M2.7"])
})
})
})

View file

@ -884,6 +884,7 @@
},
"validation": {
"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.",
"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.",

View file

@ -884,6 +884,7 @@
},
"validation": {
"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.",
"googleCloud": "Du musst eine gültige Google Cloud Projekt-ID und Region angeben.",
"modelId": "Du musst eine gültige Modell-ID angeben.",

View file

@ -947,6 +947,7 @@
},
"validation": {
"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.",
"googleCloud": "You must provide a valid Google Cloud Project ID and Region.",
"modelId": "You must provide a valid model ID.",

View file

@ -884,6 +884,7 @@
},
"validation": {
"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.",
"googleCloud": "Debe proporcionar un ID de proyecto y región de Google Cloud válidos.",
"modelId": "Debe proporcionar un ID de modelo válido.",

View file

@ -884,6 +884,7 @@
},
"validation": {
"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.",
"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.",

View file

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

View file

@ -884,6 +884,7 @@
},
"validation": {
"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.",
"googleCloud": "Kamu harus menyediakan Google Cloud Project ID dan Region yang valid.",
"modelId": "Kamu harus menyediakan model ID yang valid.",

View file

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

View file

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

View file

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

View file

@ -884,6 +884,7 @@
},
"validation": {
"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.",
"googleCloud": "Je moet een geldig Google Cloud Project-ID en regio opgeven.",
"modelId": "Je moet een geldig model-ID opgeven.",

View file

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

View file

@ -884,6 +884,7 @@
},
"validation": {
"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.",
"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.",

View file

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

View file

@ -884,6 +884,7 @@
},
"validation": {
"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.",
"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.",

View file

@ -884,6 +884,7 @@
},
"validation": {
"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.",
"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ệ.",

View file

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

View file

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

View file

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