diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index 36fae6f3d9a6..1e17fb4c3cc3 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -218,6 +218,7 @@ export const SECRET_STATE_KEYS = [ "doubaoApiKey", "moonshotApiKey", "mistralApiKey", + "minimaxApiKey", "unboundApiKey", "requestyApiKey", "xaiApiKey", diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index 9e83cbc158ac..6f03744450ef 100644 --- a/packages/types/src/provider-settings.ts +++ b/packages/types/src/provider-settings.ts @@ -24,6 +24,7 @@ import { vscodeLlmModels, xaiModels, internationalZAiModels, + minimaxModels, } from "./providers/index.js" /** @@ -131,6 +132,7 @@ export const providerNames = [ "groq", "mistral", "moonshot", + "minimax", "openai-native", "qwen-code", "roo", @@ -327,6 +329,13 @@ const moonshotSchema = apiModelIdProviderModelSchema.extend({ moonshotApiKey: z.string().optional(), }) +const minimaxSchema = apiModelIdProviderModelSchema.extend({ + minimaxBaseUrl: z + .union([z.literal("https://api.minimax.io/v1"), z.literal("https://api.minimaxi.com/v1")]) + .optional(), + minimaxApiKey: z.string().optional(), +}) + const unboundSchema = baseProviderSettingsSchema.extend({ unboundApiKey: z.string().optional(), unboundModelId: z.string().optional(), @@ -435,6 +444,7 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv deepInfraSchema.merge(z.object({ apiProvider: z.literal("deepinfra") })), doubaoSchema.merge(z.object({ apiProvider: z.literal("doubao") })), moonshotSchema.merge(z.object({ apiProvider: z.literal("moonshot") })), + minimaxSchema.merge(z.object({ apiProvider: z.literal("minimax") })), unboundSchema.merge(z.object({ apiProvider: z.literal("unbound") })), requestySchema.merge(z.object({ apiProvider: z.literal("requesty") })), humanRelaySchema.merge(z.object({ apiProvider: z.literal("human-relay") })), @@ -476,6 +486,7 @@ export const providerSettingsSchema = z.object({ ...deepInfraSchema.shape, ...doubaoSchema.shape, ...moonshotSchema.shape, + ...minimaxSchema.shape, ...unboundSchema.shape, ...requestySchema.shape, ...humanRelaySchema.shape, @@ -560,6 +571,7 @@ export const modelIdKeysByProvider: Record = { "gemini-cli": "apiModelId", mistral: "apiModelId", moonshot: "apiModelId", + minimax: "apiModelId", deepseek: "apiModelId", deepinfra: "deepInfraModelId", doubao: "apiModelId", @@ -676,6 +688,11 @@ export const MODELS_BY_PROVIDER: Record< label: "Moonshot", models: Object.keys(moonshotModels), }, + minimax: { + id: "minimax", + label: "MiniMax", + models: Object.keys(minimaxModels), + }, "openai-native": { id: "openai-native", label: "OpenAI", diff --git a/packages/types/src/providers/index.ts b/packages/types/src/providers/index.ts index 21e43aaa99a6..2a1a3f986aa5 100644 --- a/packages/types/src/providers/index.ts +++ b/packages/types/src/providers/index.ts @@ -30,3 +30,4 @@ export * from "./xai.js" export * from "./vercel-ai-gateway.js" export * from "./zai.js" export * from "./deepinfra.js" +export * from "./minimax.js" diff --git a/packages/types/src/providers/minimax.ts b/packages/types/src/providers/minimax.ts new file mode 100644 index 000000000000..825431b48242 --- /dev/null +++ b/packages/types/src/providers/minimax.ts @@ -0,0 +1,24 @@ +import type { ModelInfo } from "../model.js" + +// Minimax +// https://www.minimax.io/platform/document/text_api_intro +// https://www.minimax.io/platform/document/pricing +export type MinimaxModelId = keyof typeof minimaxModels +export const minimaxDefaultModelId: MinimaxModelId = "MiniMax-M2" + +export const minimaxModels = { + "MiniMax-M2": { + maxTokens: 16_384, + contextWindow: 192_000, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0.3, + outputPrice: 1.2, + cacheWritesPrice: 0, + cacheReadsPrice: 0, + description: + "MiniMax M2, a model born for Agents and code, featuring Top-tier Coding Capabilities, Powerful Agentic Performance, and Ultimate Cost-Effectiveness & Speed.", + }, +} as const satisfies Record + +export const MINIMAX_DEFAULT_TEMPERATURE = 1.0 diff --git a/src/api/index.ts b/src/api/index.ts index ac0096767624..351f4ef1befe 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -40,6 +40,7 @@ import { FeatherlessHandler, VercelAiGatewayHandler, DeepInfraHandler, + MiniMaxHandler, } from "./providers" import { NativeOllamaHandler } from "./providers/native-ollama" @@ -165,6 +166,8 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler { return new FeatherlessHandler(options) case "vercel-ai-gateway": return new VercelAiGatewayHandler(options) + case "minimax": + return new MiniMaxHandler(options) default: apiProvider satisfies "gemini-cli" | undefined return new AnthropicHandler(options) diff --git a/src/api/providers/__tests__/minimax.spec.ts b/src/api/providers/__tests__/minimax.spec.ts new file mode 100644 index 000000000000..c488aea8812d --- /dev/null +++ b/src/api/providers/__tests__/minimax.spec.ts @@ -0,0 +1,314 @@ +// npx vitest run src/api/providers/__tests__/minimax.spec.ts + +vitest.mock("vscode", () => ({ + workspace: { + getConfiguration: vitest.fn().mockReturnValue({ + get: vitest.fn().mockReturnValue(600), // Default timeout in seconds + }), + }, +})) + +import OpenAI from "openai" +import { Anthropic } from "@anthropic-ai/sdk" + +import { type MinimaxModelId, minimaxDefaultModelId, minimaxModels } from "@roo-code/types" + +import { MiniMaxHandler } from "../minimax" + +vitest.mock("openai", () => { + const createMock = vitest.fn() + return { + default: vitest.fn(() => ({ chat: { completions: { create: createMock } } })), + } +}) + +describe("MiniMaxHandler", () => { + let handler: MiniMaxHandler + let mockCreate: any + + beforeEach(() => { + vitest.clearAllMocks() + mockCreate = (OpenAI as unknown as any)().chat.completions.create + }) + + describe("International MiniMax (default)", () => { + beforeEach(() => { + handler = new MiniMaxHandler({ + minimaxApiKey: "test-minimax-api-key", + minimaxBaseUrl: "https://api.minimax.io/v1", + }) + }) + + it("should use the correct international MiniMax base URL by default", () => { + new MiniMaxHandler({ minimaxApiKey: "test-minimax-api-key" }) + expect(OpenAI).toHaveBeenCalledWith( + expect.objectContaining({ + baseURL: "https://api.minimax.io/v1", + }), + ) + }) + + it("should use the provided API key", () => { + const minimaxApiKey = "test-minimax-api-key" + new MiniMaxHandler({ minimaxApiKey }) + expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ apiKey: minimaxApiKey })) + }) + + it("should return default model when no model is specified", () => { + const model = handler.getModel() + expect(model.id).toBe(minimaxDefaultModelId) + expect(model.info).toEqual(minimaxModels[minimaxDefaultModelId]) + }) + + it("should return specified model when valid model is provided", () => { + const testModelId: MinimaxModelId = "MiniMax-M2" + const handlerWithModel = new MiniMaxHandler({ + apiModelId: testModelId, + minimaxApiKey: "test-minimax-api-key", + }) + const model = handlerWithModel.getModel() + expect(model.id).toBe(testModelId) + expect(model.info).toEqual(minimaxModels[testModelId]) + }) + + it("should return MiniMax-M2 model with correct configuration", () => { + const testModelId: MinimaxModelId = "MiniMax-M2" + const handlerWithModel = new MiniMaxHandler({ + apiModelId: testModelId, + minimaxApiKey: "test-minimax-api-key", + }) + 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.maxTokens).toBe(16_384) + expect(model.info.supportsPromptCache).toBe(false) + }) + }) + + describe("China MiniMax", () => { + beforeEach(() => { + handler = new MiniMaxHandler({ + minimaxApiKey: "test-minimax-api-key", + minimaxBaseUrl: "https://api.minimaxi.com/v1", + }) + }) + + it("should use the correct China MiniMax base URL", () => { + new MiniMaxHandler({ + minimaxApiKey: "test-minimax-api-key", + minimaxBaseUrl: "https://api.minimaxi.com/v1", + }) + expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ baseURL: "https://api.minimaxi.com/v1" })) + }) + + it("should use the provided API key for China", () => { + const minimaxApiKey = "test-minimax-api-key" + new MiniMaxHandler({ minimaxApiKey, minimaxBaseUrl: "https://api.minimaxi.com/v1" }) + expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ apiKey: minimaxApiKey })) + }) + + it("should return default model when no model is specified", () => { + const model = handler.getModel() + expect(model.id).toBe(minimaxDefaultModelId) + expect(model.info).toEqual(minimaxModels[minimaxDefaultModelId]) + }) + }) + + describe("Default behavior", () => { + it("should default to international base URL when none is specified", () => { + const handlerDefault = new MiniMaxHandler({ minimaxApiKey: "test-minimax-api-key" }) + expect(OpenAI).toHaveBeenCalledWith( + expect.objectContaining({ + baseURL: "https://api.minimax.io/v1", + }), + ) + + const model = handlerDefault.getModel() + expect(model.id).toBe(minimaxDefaultModelId) + expect(model.info).toEqual(minimaxModels[minimaxDefaultModelId]) + }) + + it("should default to MiniMax-M2 model", () => { + const handlerDefault = new MiniMaxHandler({ minimaxApiKey: "test-minimax-api-key" }) + const model = handlerDefault.getModel() + expect(model.id).toBe("MiniMax-M2") + }) + }) + + describe("API Methods", () => { + beforeEach(() => { + handler = new MiniMaxHandler({ minimaxApiKey: "test-minimax-api-key" }) + }) + + it("completePrompt method should return text from MiniMax API", async () => { + const expectedResponse = "This is a test response from MiniMax" + mockCreate.mockResolvedValueOnce({ choices: [{ message: { content: expectedResponse } }] }) + const result = await handler.completePrompt("test prompt") + expect(result).toBe(expectedResponse) + }) + + it("should handle errors in completePrompt", async () => { + const errorMessage = "MiniMax API error" + mockCreate.mockRejectedValueOnce(new Error(errorMessage)) + await expect(handler.completePrompt("test prompt")).rejects.toThrow() + }) + + it("createMessage should yield text content from stream", async () => { + const testContent = "This is test content from MiniMax stream" + + mockCreate.mockImplementationOnce(() => { + return { + [Symbol.asyncIterator]: () => ({ + next: vitest + .fn() + .mockResolvedValueOnce({ + done: false, + value: { choices: [{ delta: { content: testContent } }] }, + }) + .mockResolvedValueOnce({ done: true }), + }), + } + }) + + const stream = handler.createMessage("system prompt", []) + const firstChunk = await stream.next() + + expect(firstChunk.done).toBe(false) + expect(firstChunk.value).toEqual({ type: "text", text: testContent }) + }) + + it("should handle reasoning tags () from stream", async () => { + mockCreate.mockImplementationOnce(() => { + return { + [Symbol.asyncIterator]: () => ({ + next: vitest + .fn() + .mockResolvedValueOnce({ + done: false, + value: { choices: [{ delta: { content: "Let me think" } }] }, + }) + .mockResolvedValueOnce({ + done: false, + value: { choices: [{ delta: { content: " about this" } }] }, + }) + .mockResolvedValueOnce({ + done: false, + value: { choices: [{ delta: { content: "The answer is 42" } }] }, + }) + .mockResolvedValueOnce({ done: true }), + }), + } + }) + + const stream = handler.createMessage("system prompt", []) + const chunks = [] + for await (const chunk of stream) { + chunks.push(chunk) + } + + // XmlMatcher yields chunks as they're processed + expect(chunks).toEqual([ + { type: "reasoning", text: "Let me think" }, + { type: "reasoning", text: " about this" }, + { type: "text", text: "The answer is 42" }, + ]) + }) + + it("createMessage should yield usage data from stream", async () => { + mockCreate.mockImplementationOnce(() => { + return { + [Symbol.asyncIterator]: () => ({ + next: vitest + .fn() + .mockResolvedValueOnce({ + done: false, + value: { + choices: [{ delta: {} }], + usage: { prompt_tokens: 10, completion_tokens: 20 }, + }, + }) + .mockResolvedValueOnce({ done: true }), + }), + } + }) + + const stream = handler.createMessage("system prompt", []) + const firstChunk = await stream.next() + + expect(firstChunk.done).toBe(false) + expect(firstChunk.value).toEqual({ type: "usage", inputTokens: 10, outputTokens: 20 }) + }) + + it("createMessage should pass correct parameters to MiniMax client", async () => { + const modelId: MinimaxModelId = "MiniMax-M2" + const modelInfo = minimaxModels[modelId] + const handlerWithModel = new MiniMaxHandler({ + apiModelId: modelId, + minimaxApiKey: "test-minimax-api-key", + }) + + mockCreate.mockImplementationOnce(() => { + return { + [Symbol.asyncIterator]: () => ({ + async next() { + return { done: true } + }, + }), + } + }) + + const systemPrompt = "Test system prompt for MiniMax" + const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Test message for MiniMax" }] + + const messageGenerator = handlerWithModel.createMessage(systemPrompt, messages) + await messageGenerator.next() + + expect(mockCreate).toHaveBeenCalledWith( + expect.objectContaining({ + model: modelId, + max_tokens: Math.min(modelInfo.maxTokens, Math.ceil(modelInfo.contextWindow * 0.2)), + temperature: 1, + messages: expect.arrayContaining([{ role: "system", content: systemPrompt }]), + stream: true, + stream_options: { include_usage: true }, + }), + undefined, + ) + }) + + it("should use temperature 1 by default", async () => { + mockCreate.mockImplementationOnce(() => { + return { + [Symbol.asyncIterator]: () => ({ + async next() { + return { done: true } + }, + }), + } + }) + + const messageGenerator = handler.createMessage("test", []) + await messageGenerator.next() + + expect(mockCreate).toHaveBeenCalledWith( + expect.objectContaining({ + temperature: 1, + }), + undefined, + ) + }) + }) + + describe("Model Configuration", () => { + 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.supportsImages).toBe(false) + expect(model.supportsPromptCache).toBe(false) + expect(model.inputPrice).toBe(0.3) + expect(model.outputPrice).toBe(1.2) + }) + }) +}) diff --git a/src/api/providers/index.ts b/src/api/providers/index.ts index 85d877b6bc78..533023d0374b 100644 --- a/src/api/providers/index.ts +++ b/src/api/providers/index.ts @@ -34,3 +34,4 @@ export { RooHandler } from "./roo" export { FeatherlessHandler } from "./featherless" export { VercelAiGatewayHandler } from "./vercel-ai-gateway" export { DeepInfraHandler } from "./deepinfra" +export { MiniMaxHandler } from "./minimax" diff --git a/src/api/providers/minimax.ts b/src/api/providers/minimax.ts new file mode 100644 index 000000000000..23722f597648 --- /dev/null +++ b/src/api/providers/minimax.ts @@ -0,0 +1,62 @@ +import { Anthropic } from "@anthropic-ai/sdk" +import { type MinimaxModelId, minimaxDefaultModelId, minimaxModels } from "@roo-code/types" + +import type { ApiHandlerOptions } from "../../shared/api" +import { XmlMatcher } from "../../utils/xml-matcher" +import { ApiStream } from "../transform/stream" +import type { ApiHandlerCreateMessageMetadata } from "../index" + +import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider" + +export class MiniMaxHandler extends BaseOpenAiCompatibleProvider { + constructor(options: ApiHandlerOptions) { + super({ + ...options, + providerName: "MiniMax", + baseURL: options.minimaxBaseUrl ?? "https://api.minimax.io/v1", + apiKey: options.minimaxApiKey, + defaultProviderModelId: minimaxDefaultModelId, + providerModels: minimaxModels, + defaultTemperature: 1.0, + }) + } + + override async *createMessage( + systemPrompt: string, + messages: Anthropic.Messages.MessageParam[], + metadata?: ApiHandlerCreateMessageMetadata, + ): ApiStream { + const stream = await this.createStream(systemPrompt, messages, metadata) + + const matcher = new XmlMatcher( + "think", + (chunk) => + ({ + type: chunk.matched ? "reasoning" : "text", + text: chunk.data, + }) as const, + ) + + for await (const chunk of stream) { + const delta = chunk.choices[0]?.delta + + if (delta?.content) { + for (const matcherChunk of matcher.update(delta.content)) { + yield matcherChunk + } + } + + if (chunk.usage) { + yield { + type: "usage", + inputTokens: chunk.usage.prompt_tokens || 0, + outputTokens: chunk.usage.completion_tokens || 0, + } + } + } + + for (const chunk of matcher.final()) { + yield chunk + } + } +} diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index 9e4d585c97c2..095f30a30270 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -37,6 +37,7 @@ import { rooDefaultModelId, vercelAiGatewayDefaultModelId, deepInfraDefaultModelId, + minimaxDefaultModelId, } from "@roo-code/types" import { vscode } from "@src/utils/vscode" @@ -96,6 +97,7 @@ import { Featherless, VercelAiGateway, DeepInfra, + MiniMax, } from "./providers" import { MODELS_BY_PROVIDER, PROVIDERS } from "./constants" @@ -341,6 +343,7 @@ const ApiOptions = ({ deepseek: { field: "apiModelId", default: deepSeekDefaultModelId }, doubao: { field: "apiModelId", default: doubaoDefaultModelId }, moonshot: { field: "apiModelId", default: moonshotDefaultModelId }, + minimax: { field: "apiModelId", default: minimaxDefaultModelId }, mistral: { field: "apiModelId", default: mistralDefaultModelId }, xai: { field: "apiModelId", default: xaiDefaultModelId }, groq: { field: "apiModelId", default: groqDefaultModelId }, @@ -593,6 +596,10 @@ const ApiOptions = ({ )} + {selectedProvider === "minimax" && ( + + )} + {selectedProvider === "vscode-lm" && ( )} diff --git a/webview-ui/src/components/settings/constants.ts b/webview-ui/src/components/settings/constants.ts index 1ba0497edfab..7d7020ddc8d0 100644 --- a/webview-ui/src/components/settings/constants.ts +++ b/webview-ui/src/components/settings/constants.ts @@ -20,6 +20,7 @@ import { internationalZAiModels, fireworksModels, featherlessModels, + minimaxModels, } from "@roo-code/types" export const MODELS_BY_PROVIDER: Partial>> = { @@ -42,6 +43,7 @@ export const MODELS_BY_PROVIDER: Partial a.label.localeCompare(b.label)) diff --git a/webview-ui/src/components/settings/providers/MiniMax.tsx b/webview-ui/src/components/settings/providers/MiniMax.tsx new file mode 100644 index 000000000000..4055be7d1791 --- /dev/null +++ b/webview-ui/src/components/settings/providers/MiniMax.tsx @@ -0,0 +1,73 @@ +import { useCallback } from "react" +import { VSCodeTextField, VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react" + +import type { ProviderSettings } from "@roo-code/types" + +import { useAppTranslation } from "@src/i18n/TranslationContext" +import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink" + +import { inputEventTransform } from "../transforms" +import { cn } from "@/lib/utils" + +type MiniMaxProps = { + apiConfiguration: ProviderSettings + setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void +} + +export const MiniMax = ({ apiConfiguration, setApiConfigurationField }: MiniMaxProps) => { + const { t } = useAppTranslation() + + const handleInputChange = useCallback( + ( + field: K, + transform: (event: E) => ProviderSettings[K] = inputEventTransform, + ) => + (event: E | Event) => { + setApiConfigurationField(field, transform(event as E)) + }, + [setApiConfigurationField], + ) + + return ( + <> +
+ + + + api.minimax.io + + + api.minimaxi.com + + +
+
+ + + +
+ {t("settings:providers.apiKeyStorageNotice")} +
+ {!apiConfiguration?.minimaxApiKey && ( + + {t("settings:providers.getMiniMaxApiKey")} + + )} +
+ + ) +} diff --git a/webview-ui/src/components/settings/providers/index.ts b/webview-ui/src/components/settings/providers/index.ts index d6423b0c8a60..baf6ccba2ef6 100644 --- a/webview-ui/src/components/settings/providers/index.ts +++ b/webview-ui/src/components/settings/providers/index.ts @@ -31,3 +31,4 @@ export { Fireworks } from "./Fireworks" export { Featherless } from "./Featherless" export { VercelAiGateway } from "./VercelAiGateway" export { DeepInfra } from "./DeepInfra" +export { MiniMax } from "./MiniMax" diff --git a/webview-ui/src/components/ui/hooks/useSelectedModel.ts b/webview-ui/src/components/ui/hooks/useSelectedModel.ts index df674893efc3..55fdd120bd3c 100644 --- a/webview-ui/src/components/ui/hooks/useSelectedModel.ts +++ b/webview-ui/src/components/ui/hooks/useSelectedModel.ts @@ -12,6 +12,8 @@ import { deepSeekModels, moonshotDefaultModelId, moonshotModels, + minimaxDefaultModelId, + minimaxModels, geminiDefaultModelId, geminiModels, mistralDefaultModelId, @@ -236,6 +238,11 @@ function getSelectedModel({ const info = moonshotModels[id as keyof typeof moonshotModels] return { id, info } } + case "minimax": { + const id = apiConfiguration.apiModelId ?? minimaxDefaultModelId + const info = minimaxModels[id as keyof typeof minimaxModels] + return { id, info } + } case "zai": { const isChina = apiConfiguration.zaiApiLine === "china_coding" const models = isChina ? mainlandZAiModels : internationalZAiModels diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index c97345f5e46c..a6248804edc3 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -297,6 +297,9 @@ "getZaiApiKey": "Obtenir clau API de Z AI", "zaiEntrypoint": "Punt d'entrada de Z AI", "zaiEntrypointDescription": "Si us plau, seleccioneu el punt d'entrada de l'API apropiat segons la vostra ubicació. Si sou a la Xina, trieu open.bigmodel.cn. Altrament, trieu api.z.ai.", + "minimaxApiKey": "Clau API de MiniMax", + "getMiniMaxApiKey": "Obtenir clau API de MiniMax", + "minimaxBaseUrl": "Punt d'entrada de MiniMax", "geminiApiKey": "Clau API de Gemini", "getGroqApiKey": "Obtenir clau API de Groq", "groqApiKey": "Clau API de Groq", diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 7588982b368c..80e6da3a7178 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -297,6 +297,9 @@ "getZaiApiKey": "Z AI API-Schlüssel erhalten", "zaiEntrypoint": "Z AI Einstiegspunkt", "zaiEntrypointDescription": "Bitte wählen Sie den entsprechenden API-Einstiegspunkt basierend auf Ihrem Standort. Wenn Sie sich in China befinden, wählen Sie open.bigmodel.cn. Andernfalls wählen Sie api.z.ai.", + "minimaxApiKey": "MiniMax API-Schlüssel", + "getMiniMaxApiKey": "MiniMax API-Schlüssel erhalten", + "minimaxBaseUrl": "MiniMax-Einstiegspunkt", "geminiApiKey": "Gemini API-Schlüssel", "getGroqApiKey": "Groq API-Schlüssel erhalten", "groqApiKey": "Groq API-Schlüssel", diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 789452fadcfe..8ed0672ea902 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -298,6 +298,9 @@ "moonshotApiKey": "Moonshot API Key", "getMoonshotApiKey": "Get Moonshot API Key", "moonshotBaseUrl": "Moonshot Entrypoint", + "minimaxApiKey": "MiniMax API Key", + "getMiniMaxApiKey": "Get MiniMax API Key", + "minimaxBaseUrl": "MiniMax Entrypoint", "zaiApiKey": "Z AI API Key", "getZaiApiKey": "Get Z AI API Key", "zaiEntrypoint": "Z AI Entrypoint", diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index fa5ce550e85c..53458bf15aea 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -297,6 +297,9 @@ "getZaiApiKey": "Obtener clave API de Z AI", "zaiEntrypoint": "Punto de entrada de Z AI", "zaiEntrypointDescription": "Por favor, seleccione el punto de entrada de API apropiado según su ubicación. Si está en China, elija open.bigmodel.cn. De lo contrario, elija api.z.ai.", + "minimaxApiKey": "Clave API de MiniMax", + "getMiniMaxApiKey": "Obtener clave API de MiniMax", + "minimaxBaseUrl": "Punto de entrada de MiniMax", "geminiApiKey": "Clave API de Gemini", "getGroqApiKey": "Obtener clave API de Groq", "groqApiKey": "Clave API de Groq", diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index d1c2ccd40f80..f38ee43af6da 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -297,6 +297,9 @@ "getZaiApiKey": "Obtenir la clé API Z AI", "zaiEntrypoint": "Point d'entrée Z AI", "zaiEntrypointDescription": "Veuillez sélectionner le point d'entrée API approprié en fonction de votre emplacement. Si vous êtes en Chine, choisissez open.bigmodel.cn. Sinon, choisissez api.z.ai.", + "minimaxApiKey": "Clé API MiniMax", + "getMiniMaxApiKey": "Obtenir la clé API MiniMax", + "minimaxBaseUrl": "Point d'entrée MiniMax", "geminiApiKey": "Clé API Gemini", "getGroqApiKey": "Obtenir la clé API Groq", "groqApiKey": "Clé API Groq", diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index bcc45d5db75b..78eee0521e0c 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -297,6 +297,9 @@ "getZaiApiKey": "Z AI API कुंजी प्राप्त करें", "zaiEntrypoint": "Z AI प्रवेश बिंदु", "zaiEntrypointDescription": "कृपया अपने स्थान के आधार पर उपयुक्त API प्रवेश बिंदु का चयन करें। यदि आप चीन में हैं, तो open.bigmodel.cn चुनें। अन्यथा, api.z.ai चुनें।", + "minimaxApiKey": "MiniMax API कुंजी", + "getMiniMaxApiKey": "MiniMax API कुंजी प्राप्त करें", + "minimaxBaseUrl": "MiniMax प्रवेश बिंदु", "geminiApiKey": "Gemini API कुंजी", "getGroqApiKey": "Groq API कुंजी प्राप्त करें", "groqApiKey": "Groq API कुंजी", diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 01298d93ddf9..629eda2b5817 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -301,6 +301,9 @@ "getZaiApiKey": "Dapatkan Kunci API Z AI", "zaiEntrypoint": "Titik Masuk Z AI", "zaiEntrypointDescription": "Silakan pilih titik masuk API yang sesuai berdasarkan lokasi Anda. Jika Anda berada di China, pilih open.bigmodel.cn. Jika tidak, pilih api.z.ai.", + "minimaxApiKey": "Kunci API MiniMax", + "getMiniMaxApiKey": "Dapatkan Kunci API MiniMax", + "minimaxBaseUrl": "Titik Masuk MiniMax", "geminiApiKey": "Gemini API Key", "getGroqApiKey": "Dapatkan Groq API Key", "groqApiKey": "Groq API Key", diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 7b3eb560b9c8..cddb1567c0a2 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -297,6 +297,9 @@ "getZaiApiKey": "Ottieni chiave API Z AI", "zaiEntrypoint": "Punto di ingresso Z AI", "zaiEntrypointDescription": "Si prega di selezionare il punto di ingresso API appropriato in base alla propria posizione. Se ti trovi in Cina, scegli open.bigmodel.cn. Altrimenti, scegli api.z.ai.", + "minimaxApiKey": "Chiave API MiniMax", + "getMiniMaxApiKey": "Ottieni chiave API MiniMax", + "minimaxBaseUrl": "Punto di ingresso MiniMax", "geminiApiKey": "Chiave API Gemini", "getGroqApiKey": "Ottieni chiave API Groq", "groqApiKey": "Chiave API Groq", diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 9ad7035b5464..453313780f34 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -297,6 +297,9 @@ "getZaiApiKey": "Z AI APIキーを取得", "zaiEntrypoint": "Z AI エントリーポイント", "zaiEntrypointDescription": "お住まいの地域に応じて適切な API エントリーポイントを選択してください。中国にお住まいの場合は open.bigmodel.cn を選択してください。それ以外の場合は api.z.ai を選択してください。", + "minimaxApiKey": "MiniMax APIキー", + "getMiniMaxApiKey": "MiniMax APIキーを取得", + "minimaxBaseUrl": "MiniMax エントリーポイント", "geminiApiKey": "Gemini APIキー", "getGroqApiKey": "Groq APIキーを取得", "groqApiKey": "Groq APIキー", diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index c0b8bce736c9..d23f00ee4eed 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -297,6 +297,9 @@ "getZaiApiKey": "Z AI API 키 받기", "zaiEntrypoint": "Z AI 엔트리포인트", "zaiEntrypointDescription": "위치에 따라 적절한 API 엔트리포인트를 선택하세요. 중국에 있다면 open.bigmodel.cn을 선택하세요. 그렇지 않으면 api.z.ai를 선택하세요.", + "minimaxApiKey": "MiniMax API 키", + "getMiniMaxApiKey": "MiniMax API 키 받기", + "minimaxBaseUrl": "MiniMax 엔트리포인트", "geminiApiKey": "Gemini API 키", "getGroqApiKey": "Groq API 키 받기", "groqApiKey": "Groq API 키", diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index 539e214e81b8..0f50b3e25287 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -297,6 +297,9 @@ "getZaiApiKey": "Z AI API-sleutel ophalen", "zaiEntrypoint": "Z AI-ingangspunt", "zaiEntrypointDescription": "Selecteer het juiste API-ingangspunt op basis van uw locatie. Als u zich in China bevindt, kies dan open.bigmodel.cn. Anders kiest u api.z.ai.", + "minimaxApiKey": "MiniMax API-sleutel", + "getMiniMaxApiKey": "MiniMax API-sleutel ophalen", + "minimaxBaseUrl": "MiniMax-ingangspunt", "geminiApiKey": "Gemini API-sleutel", "getGroqApiKey": "Groq API-sleutel ophalen", "groqApiKey": "Groq API-sleutel", diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index ebc192e23024..910f13f70e20 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -297,6 +297,9 @@ "getZaiApiKey": "Uzyskaj klucz API Z AI", "zaiEntrypoint": "Punkt wejścia Z AI", "zaiEntrypointDescription": "Wybierz odpowiedni punkt wejścia API w zależności od swojej lokalizacji. Jeśli jesteś w Chinach, wybierz open.bigmodel.cn. W przeciwnym razie wybierz api.z.ai.", + "minimaxApiKey": "Klucz API MiniMax", + "getMiniMaxApiKey": "Uzyskaj klucz API MiniMax", + "minimaxBaseUrl": "Punkt wejścia MiniMax", "geminiApiKey": "Klucz API Gemini", "getGroqApiKey": "Uzyskaj klucz API Groq", "groqApiKey": "Klucz API Groq", diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index fb68793e4180..5ad435f640f7 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -297,6 +297,9 @@ "getZaiApiKey": "Obter chave de API Z AI", "zaiEntrypoint": "Ponto de entrada Z AI", "zaiEntrypointDescription": "Selecione o ponto de entrada da API apropriado com base na sua localização. Se você estiver na China, escolha open.bigmodel.cn. Caso contrário, escolha api.z.ai.", + "minimaxApiKey": "Chave de API MiniMax", + "getMiniMaxApiKey": "Obter chave de API MiniMax", + "minimaxBaseUrl": "Ponto de entrada MiniMax", "geminiApiKey": "Chave de API Gemini", "getGroqApiKey": "Obter chave de API Groq", "groqApiKey": "Chave de API Groq", diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 09fedab8f46f..ec68fa7e44d6 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -297,6 +297,9 @@ "getZaiApiKey": "Получить Z AI API-ключ", "zaiEntrypoint": "Точка входа Z AI", "zaiEntrypointDescription": "Пожалуйста, выберите подходящую точку входа API в зависимости от вашего местоположения. Если вы находитесь в Китае, выберите open.bigmodel.cn. В противном случае выберите api.z.ai.", + "minimaxApiKey": "MiniMax API-ключ", + "getMiniMaxApiKey": "Получить MiniMax API-ключ", + "minimaxBaseUrl": "Точка входа MiniMax", "geminiApiKey": "Gemini API-ключ", "getGroqApiKey": "Получить Groq API-ключ", "groqApiKey": "Groq API-ключ", diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 2ce4732ff3a3..52ab553483a5 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -297,6 +297,9 @@ "getZaiApiKey": "Z AI API Anahtarı Al", "zaiEntrypoint": "Z AI Giriş Noktası", "zaiEntrypointDescription": "Konumunuza göre uygun API giriş noktasını seçin. Çin'de iseniz open.bigmodel.cn'yi seçin. Aksi takdirde api.z.ai'yi seçin.", + "minimaxApiKey": "MiniMax API Anahtarı", + "getMiniMaxApiKey": "MiniMax API Anahtarı Al", + "minimaxBaseUrl": "MiniMax Giriş Noktası", "geminiApiKey": "Gemini API Anahtarı", "getGroqApiKey": "Groq API Anahtarı Al", "groqApiKey": "Groq API Anahtarı", diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index e9b15db7d7a4..35ffc95af860 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -297,6 +297,9 @@ "getZaiApiKey": "Lấy khóa API Z AI", "zaiEntrypoint": "Điểm vào Z AI", "zaiEntrypointDescription": "Vui lòng chọn điểm vào API phù hợp dựa trên vị trí của bạn. Nếu bạn ở Trung Quốc, hãy chọn open.bigmodel.cn. Ngược lại, hãy chọn api.z.ai.", + "minimaxApiKey": "Khóa API MiniMax", + "getMiniMaxApiKey": "Lấy khóa API MiniMax", + "minimaxBaseUrl": "Điểm vào MiniMax", "geminiApiKey": "Khóa API Gemini", "getGroqApiKey": "Lấy khóa API Groq", "groqApiKey": "Khóa API Groq", diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 25a889939f20..d76df2c348df 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -293,6 +293,9 @@ "moonshotApiKey": "Moonshot API 密钥", "getMoonshotApiKey": "获取 Moonshot API 密钥", "moonshotBaseUrl": "Moonshot 服务站点", + "minimaxApiKey": "MiniMax API 密钥", + "getMiniMaxApiKey": "获取 MiniMax API 密钥", + "minimaxBaseUrl": "MiniMax 服务站点", "zaiApiKey": "Z AI API 密钥", "getZaiApiKey": "获取 Z AI API 密钥", "zaiEntrypoint": "Z AI 服务站点", diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 26225e2278fe..6920977f5987 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -297,6 +297,9 @@ "getZaiApiKey": "取得 Z AI API 金鑰", "zaiEntrypoint": "Z AI 服務端點", "zaiEntrypointDescription": "請根據您的位置選擇適當的 API 服務端點。如果您在中國,請選擇 open.bigmodel.cn。否則,請選擇 api.z.ai。", + "minimaxApiKey": "MiniMax API 金鑰", + "getMiniMaxApiKey": "取得 MiniMax API 金鑰", + "minimaxBaseUrl": "MiniMax 服務端點", "geminiApiKey": "Gemini API 金鑰", "getGroqApiKey": "取得 Groq API 金鑰", "groqApiKey": "Groq API 金鑰",