From 2f00c75509d7c9840386be161e4cca107a764ced Mon Sep 17 00:00:00 2001 From: octo-patch <266937838+octo-patch@users.noreply.github.com> Date: Sat, 1 Aug 2026 15:36:03 +0800 Subject: [PATCH] Add MiniMax provider support --- .../src/entrypoints/sdk/coreSchemas.ts | 2 +- restored-src/src/utils/model/configs.ts | 15 ++++++++++ restored-src/src/utils/model/deprecation.ts | 3 ++ restored-src/src/utils/model/model.ts | 27 +++++++++++++---- restored-src/src/utils/model/modelOptions.ts | 24 +++++++++++++++ restored-src/src/utils/model/providers.ts | 30 +++++++++++++++++-- restored-src/src/utils/status.tsx | 11 ++++++- 7 files changed, 103 insertions(+), 9 deletions(-) diff --git a/restored-src/src/entrypoints/sdk/coreSchemas.ts b/restored-src/src/entrypoints/sdk/coreSchemas.ts index 4d5b9d0a0..4ef8ea5a0 100644 --- a/restored-src/src/entrypoints/sdk/coreSchemas.ts +++ b/restored-src/src/entrypoints/sdk/coreSchemas.ts @@ -1087,7 +1087,7 @@ export const AccountInfoSchema = lazySchema(() => tokenSource: z.string().optional(), apiKeySource: z.string().optional(), apiProvider: z - .enum(['firstParty', 'bedrock', 'vertex', 'foundry']) + .enum(['firstParty', 'bedrock', 'vertex', 'foundry', 'minimax']) .optional() .describe( 'Active API backend. Anthropic OAuth login only applies when "firstParty"; for 3P providers the other fields are absent and auth is external (AWS creds, gcloud ADC, etc.).', diff --git a/restored-src/src/utils/model/configs.ts b/restored-src/src/utils/model/configs.ts index 89f243d87..07afaa98c 100644 --- a/restored-src/src/utils/model/configs.ts +++ b/restored-src/src/utils/model/configs.ts @@ -3,6 +3,10 @@ import type { APIProvider } from './providers.js' export type ModelConfig = Record +export const MINIMAX_MODEL_IDS = ['MiniMax-M3', 'MiniMax-M2.7'] as const +export const MINIMAX_DEFAULT_MODEL = MINIMAX_MODEL_IDS[0] +export const MINIMAX_FAST_MODEL = MINIMAX_MODEL_IDS[1] + // @[MODEL LAUNCH]: Add a new CLAUDE_*_CONFIG constant here. Double check the correct model strings // here since the pattern may change. @@ -11,6 +15,7 @@ export const CLAUDE_3_7_SONNET_CONFIG = { bedrock: 'us.anthropic.claude-3-7-sonnet-20250219-v1:0', vertex: 'claude-3-7-sonnet@20250219', foundry: 'claude-3-7-sonnet', + minimax: MINIMAX_DEFAULT_MODEL, } as const satisfies ModelConfig export const CLAUDE_3_5_V2_SONNET_CONFIG = { @@ -18,6 +23,7 @@ export const CLAUDE_3_5_V2_SONNET_CONFIG = { bedrock: 'anthropic.claude-3-5-sonnet-20241022-v2:0', vertex: 'claude-3-5-sonnet-v2@20241022', foundry: 'claude-3-5-sonnet', + minimax: MINIMAX_DEFAULT_MODEL, } as const satisfies ModelConfig export const CLAUDE_3_5_HAIKU_CONFIG = { @@ -25,6 +31,7 @@ export const CLAUDE_3_5_HAIKU_CONFIG = { bedrock: 'us.anthropic.claude-3-5-haiku-20241022-v1:0', vertex: 'claude-3-5-haiku@20241022', foundry: 'claude-3-5-haiku', + minimax: MINIMAX_FAST_MODEL, } as const satisfies ModelConfig export const CLAUDE_HAIKU_4_5_CONFIG = { @@ -32,6 +39,7 @@ export const CLAUDE_HAIKU_4_5_CONFIG = { bedrock: 'us.anthropic.claude-haiku-4-5-20251001-v1:0', vertex: 'claude-haiku-4-5@20251001', foundry: 'claude-haiku-4-5', + minimax: MINIMAX_FAST_MODEL, } as const satisfies ModelConfig export const CLAUDE_SONNET_4_CONFIG = { @@ -39,6 +47,7 @@ export const CLAUDE_SONNET_4_CONFIG = { bedrock: 'us.anthropic.claude-sonnet-4-20250514-v1:0', vertex: 'claude-sonnet-4@20250514', foundry: 'claude-sonnet-4', + minimax: MINIMAX_DEFAULT_MODEL, } as const satisfies ModelConfig export const CLAUDE_SONNET_4_5_CONFIG = { @@ -46,6 +55,7 @@ export const CLAUDE_SONNET_4_5_CONFIG = { bedrock: 'us.anthropic.claude-sonnet-4-5-20250929-v1:0', vertex: 'claude-sonnet-4-5@20250929', foundry: 'claude-sonnet-4-5', + minimax: MINIMAX_DEFAULT_MODEL, } as const satisfies ModelConfig export const CLAUDE_OPUS_4_CONFIG = { @@ -53,6 +63,7 @@ export const CLAUDE_OPUS_4_CONFIG = { bedrock: 'us.anthropic.claude-opus-4-20250514-v1:0', vertex: 'claude-opus-4@20250514', foundry: 'claude-opus-4', + minimax: MINIMAX_DEFAULT_MODEL, } as const satisfies ModelConfig export const CLAUDE_OPUS_4_1_CONFIG = { @@ -60,6 +71,7 @@ export const CLAUDE_OPUS_4_1_CONFIG = { bedrock: 'us.anthropic.claude-opus-4-1-20250805-v1:0', vertex: 'claude-opus-4-1@20250805', foundry: 'claude-opus-4-1', + minimax: MINIMAX_DEFAULT_MODEL, } as const satisfies ModelConfig export const CLAUDE_OPUS_4_5_CONFIG = { @@ -67,6 +79,7 @@ export const CLAUDE_OPUS_4_5_CONFIG = { bedrock: 'us.anthropic.claude-opus-4-5-20251101-v1:0', vertex: 'claude-opus-4-5@20251101', foundry: 'claude-opus-4-5', + minimax: MINIMAX_DEFAULT_MODEL, } as const satisfies ModelConfig export const CLAUDE_OPUS_4_6_CONFIG = { @@ -74,6 +87,7 @@ export const CLAUDE_OPUS_4_6_CONFIG = { bedrock: 'us.anthropic.claude-opus-4-6-v1', vertex: 'claude-opus-4-6', foundry: 'claude-opus-4-6', + minimax: MINIMAX_DEFAULT_MODEL, } as const satisfies ModelConfig export const CLAUDE_SONNET_4_6_CONFIG = { @@ -81,6 +95,7 @@ export const CLAUDE_SONNET_4_6_CONFIG = { bedrock: 'us.anthropic.claude-sonnet-4-6', vertex: 'claude-sonnet-4-6', foundry: 'claude-sonnet-4-6', + minimax: MINIMAX_DEFAULT_MODEL, } as const satisfies ModelConfig // @[MODEL LAUNCH]: Register the new config here. diff --git a/restored-src/src/utils/model/deprecation.ts b/restored-src/src/utils/model/deprecation.ts index a8b0ee231..3b0601064 100644 --- a/restored-src/src/utils/model/deprecation.ts +++ b/restored-src/src/utils/model/deprecation.ts @@ -38,6 +38,7 @@ const DEPRECATED_MODELS: Record = { bedrock: 'January 15, 2026', vertex: 'January 5, 2026', foundry: 'January 5, 2026', + minimax: null, }, }, 'claude-3-7-sonnet': { @@ -47,6 +48,7 @@ const DEPRECATED_MODELS: Record = { bedrock: 'April 28, 2026', vertex: 'May 11, 2026', foundry: 'February 19, 2026', + minimax: null, }, }, 'claude-3-5-haiku': { @@ -56,6 +58,7 @@ const DEPRECATED_MODELS: Record = { bedrock: null, vertex: null, foundry: null, + minimax: null, }, }, } diff --git a/restored-src/src/utils/model/model.ts b/restored-src/src/utils/model/model.ts index 85e369fa8..bdce4af30 100644 --- a/restored-src/src/utils/model/model.ts +++ b/restored-src/src/utils/model/model.ts @@ -20,6 +20,7 @@ import { } from '../context.js' import { isEnvTruthy } from '../envUtils.js' import { getModelStrings, resolveOverriddenModel } from './modelStrings.js' +import { MINIMAX_MODEL_IDS } from './configs.js' import { formatModelPricing, getOpus46CostTier } from '../modelCost.js' import { getSettings_DEPRECATED } from '../settings/settings.js' import type { PermissionMode } from '../permissions/PermissionMode.js' @@ -33,6 +34,13 @@ export type ModelShortName = string export type ModelName = string export type ModelSetting = ModelName | ModelAlias | null +function getMiniMaxModelDisplayName(model: ModelName): string | null { + const normalizedModel = model.toLowerCase() + return ( + MINIMAX_MODEL_IDS.find(id => id.toLowerCase() === normalizedModel) ?? null + ) +} + export function getSmallFastModel(): ModelName { return process.env.ANTHROPIC_SMALL_FAST_MODEL || getDefaultHaikuModel() } @@ -347,6 +355,10 @@ export function renderModelSetting(setting: ModelName | ModelAlias): string { * if the model is not recognized as a public model. */ export function getPublicModelDisplayName(model: ModelName): string | null { + const miniMaxModel = getMiniMaxModelDisplayName(model) + if (miniMaxModel) { + return miniMaxModel + } switch (model) { case getModelStrings().opus46: return 'Opus 4.6' @@ -416,13 +428,14 @@ export function renderModelName(model: ModelName): string { /** * Returns a safe author name for public display (e.g., in git commit trailers). - * Returns "Claude {ModelName}" for publicly known models, or "Claude ({model})" - * for unknown/internal models so the exact model name is preserved. - * - * @param model The full model name - * @returns "Claude {ModelName}" for public models, or "Claude ({model})" for non-public models + * Known external model IDs are returned unchanged. Other public models use the + * CLI author prefix, while unknown models preserve their exact identifier. */ export function getPublicModelName(model: ModelName): string { + const miniMaxModel = getMiniMaxModelDisplayName(model) + if (miniMaxModel) { + return miniMaxModel + } const publicName = getPublicModelDisplayName(model) if (publicName) { return `Claude ${publicName}` @@ -568,6 +581,10 @@ export function modelDisplayString(model: ModelSetting): string { // @[MODEL LAUNCH]: Add a marketing name mapping for the new model below. export function getMarketingNameForModel(modelId: string): string | undefined { + const miniMaxModel = getMiniMaxModelDisplayName(modelId) + if (miniMaxModel) { + return miniMaxModel + } if (getAPIProvider() === 'foundry') { // deployment ID is user-defined in Foundry, so it may have no relation to the actual model return undefined diff --git a/restored-src/src/utils/model/modelOptions.ts b/restored-src/src/utils/model/modelOptions.ts index f8ef2966a..554b8b63b 100644 --- a/restored-src/src/utils/model/modelOptions.ts +++ b/restored-src/src/utils/model/modelOptions.ts @@ -6,6 +6,7 @@ import { isTeamPremiumSubscriber, } from '../auth.js' import { getModelStrings } from './modelStrings.js' +import { MINIMAX_MODEL_IDS } from './configs.js' import { COST_TIER_3_15, COST_HAIKU_35, @@ -55,6 +56,18 @@ export function getDefaultOptionForUser(fastMode = false): ModelOption { } } + if (getAPIProvider() === 'minimax') { + const currentModel = renderDefaultModelSetting( + getDefaultMainLoopModelSetting(), + ) + return { + value: null, + label: 'Default (recommended)', + description: `Use the default model (currently ${currentModel})`, + descriptionForModel: `Default model (currently ${currentModel})`, + } + } + // Subscribers if (isClaudeAISubscriber()) { return { @@ -287,6 +300,17 @@ function getModelOptionsBase(fastMode = false): ModelOption[] { ] } + if (getAPIProvider() === 'minimax') { + return [ + getDefaultOptionForUser(fastMode), + ...MINIMAX_MODEL_IDS.map(model => ({ + value: model, + label: model, + description: model, + })), + ] + } + if (isClaudeAISubscriber()) { if (isMaxSubscriber() || isTeamPremiumSubscriber()) { // Max and Team Premium users: Opus is default, show Sonnet as alternative diff --git a/restored-src/src/utils/model/providers.ts b/restored-src/src/utils/model/providers.ts index aba9b7d7f..87b837d3c 100644 --- a/restored-src/src/utils/model/providers.ts +++ b/restored-src/src/utils/model/providers.ts @@ -1,7 +1,31 @@ import type { AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from '../../services/analytics/index.js' import { isEnvTruthy } from '../envUtils.js' -export type APIProvider = 'firstParty' | 'bedrock' | 'vertex' | 'foundry' +export type APIProvider = + | 'firstParty' + | 'bedrock' + | 'vertex' + | 'foundry' + | 'minimax' + +const MINIMAX_ANTHROPIC_BASE_URLS = new Set([ + 'https://api.minimax.io/anthropic', + 'https://api.minimaxi.com/anthropic', +]) + +export function isMiniMaxAnthropicBaseUrl(): boolean { + const baseUrl = process.env.ANTHROPIC_BASE_URL + if (!baseUrl) { + return false + } + try { + const url = new URL(baseUrl) + const normalizedPath = url.pathname.replace(/\/+$/, '') + return MINIMAX_ANTHROPIC_BASE_URLS.has(`${url.origin}${normalizedPath}`) + } catch { + return false + } +} export function getAPIProvider(): APIProvider { return isEnvTruthy(process.env.CLAUDE_CODE_USE_BEDROCK) @@ -10,7 +34,9 @@ export function getAPIProvider(): APIProvider { ? 'vertex' : isEnvTruthy(process.env.CLAUDE_CODE_USE_FOUNDRY) ? 'foundry' - : 'firstParty' + : isMiniMaxAnthropicBaseUrl() + ? 'minimax' + : 'firstParty' } export function getAPIProviderForStatsig(): AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS { diff --git a/restored-src/src/utils/status.tsx b/restored-src/src/utils/status.tsx index 2cc221b53..4c83efc01 100644 --- a/restored-src/src/utils/status.tsx +++ b/restored-src/src/utils/status.tsx @@ -244,7 +244,8 @@ export function buildAPIProviderProperties(): Property[] { const providerLabel = { bedrock: 'AWS Bedrock', vertex: 'Google Vertex AI', - foundry: 'Microsoft Foundry' + foundry: 'Microsoft Foundry', + minimax: 'MiniMax' }[apiProvider]; properties.push({ label: 'API provider', @@ -259,6 +260,14 @@ export function buildAPIProviderProperties(): Property[] { value: anthropicBaseUrl }); } + } else if (apiProvider === 'minimax') { + const miniMaxBaseUrl = process.env.ANTHROPIC_BASE_URL; + if (miniMaxBaseUrl) { + properties.push({ + label: 'MiniMax base URL', + value: miniMaxBaseUrl + }); + } } else if (apiProvider === 'bedrock') { const bedrockBaseUrl = process.env.BEDROCK_BASE_URL; if (bedrockBaseUrl) {