Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/entrypoints/sdk/coreSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.).',
Expand Down
9 changes: 9 additions & 0 deletions src/utils/context.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
import { CONTEXT_1M_BETA_HEADER } from '../constants/betas.js'
import { getGlobalConfig } from './config.js'
import { MINIMAX_MODEL_CONFIGS } from './model/configs.js'
import { isEnvTruthy } from './envUtils.js'
import { getCanonicalName } from './model/model.js'
import { getModelCapability } from './model/modelCapabilities.js'
Expand Down Expand Up @@ -71,6 +72,14 @@ export function getContextWindowForModel(
return 1_000_000
}

const normalizedModel = model.toLowerCase()
if (normalizedModel === MINIMAX_MODEL_CONFIGS.m3.toLowerCase()) {
return 1_000_000
}
if (normalizedModel === MINIMAX_MODEL_CONFIGS.m27.toLowerCase()) {
return 204_800
}

const cap = getModelCapability(model)
if (cap?.max_input_tokens && cap.max_input_tokens >= 100_000) {
if (
Expand Down
16 changes: 16 additions & 0 deletions src/utils/model/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import type { APIProvider } from './providers.js'

export type ModelConfig = Record<APIProvider, ModelName>

export const MINIMAX_MODEL_CONFIGS = {
m3: 'MiniMax-M3',
m27: 'MiniMax-M2.7',
} as const satisfies Record<string, ModelName>

// @[MODEL LAUNCH]: Add a new CLAUDE_*_CONFIG constant here. Double check the correct model strings
// here since the pattern may change.

Expand All @@ -11,76 +16,87 @@ 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_MODEL_CONFIGS.m3,
} as const satisfies ModelConfig

export const CLAUDE_3_5_V2_SONNET_CONFIG = {
firstParty: 'claude-3-5-sonnet-20241022',
bedrock: 'anthropic.claude-3-5-sonnet-20241022-v2:0',
vertex: 'claude-3-5-sonnet-v2@20241022',
foundry: 'claude-3-5-sonnet',
minimax: MINIMAX_MODEL_CONFIGS.m3,
} as const satisfies ModelConfig

export const CLAUDE_3_5_HAIKU_CONFIG = {
firstParty: 'claude-3-5-haiku-20241022',
bedrock: 'us.anthropic.claude-3-5-haiku-20241022-v1:0',
vertex: 'claude-3-5-haiku@20241022',
foundry: 'claude-3-5-haiku',
minimax: MINIMAX_MODEL_CONFIGS.m3,
} as const satisfies ModelConfig

export const CLAUDE_HAIKU_4_5_CONFIG = {
firstParty: 'claude-haiku-4-5-20251001',
bedrock: 'us.anthropic.claude-haiku-4-5-20251001-v1:0',
vertex: 'claude-haiku-4-5@20251001',
foundry: 'claude-haiku-4-5',
minimax: MINIMAX_MODEL_CONFIGS.m3,
} as const satisfies ModelConfig

export const CLAUDE_SONNET_4_CONFIG = {
firstParty: 'claude-sonnet-4-20250514',
bedrock: 'us.anthropic.claude-sonnet-4-20250514-v1:0',
vertex: 'claude-sonnet-4@20250514',
foundry: 'claude-sonnet-4',
minimax: MINIMAX_MODEL_CONFIGS.m3,
} as const satisfies ModelConfig

export const CLAUDE_SONNET_4_5_CONFIG = {
firstParty: 'claude-sonnet-4-5-20250929',
bedrock: 'us.anthropic.claude-sonnet-4-5-20250929-v1:0',
vertex: 'claude-sonnet-4-5@20250929',
foundry: 'claude-sonnet-4-5',
minimax: MINIMAX_MODEL_CONFIGS.m3,
} as const satisfies ModelConfig

export const CLAUDE_OPUS_4_CONFIG = {
firstParty: 'claude-opus-4-20250514',
bedrock: 'us.anthropic.claude-opus-4-20250514-v1:0',
vertex: 'claude-opus-4@20250514',
foundry: 'claude-opus-4',
minimax: MINIMAX_MODEL_CONFIGS.m3,
} as const satisfies ModelConfig

export const CLAUDE_OPUS_4_1_CONFIG = {
firstParty: 'claude-opus-4-1-20250805',
bedrock: 'us.anthropic.claude-opus-4-1-20250805-v1:0',
vertex: 'claude-opus-4-1@20250805',
foundry: 'claude-opus-4-1',
minimax: MINIMAX_MODEL_CONFIGS.m3,
} as const satisfies ModelConfig

export const CLAUDE_OPUS_4_5_CONFIG = {
firstParty: 'claude-opus-4-5-20251101',
bedrock: 'us.anthropic.claude-opus-4-5-20251101-v1:0',
vertex: 'claude-opus-4-5@20251101',
foundry: 'claude-opus-4-5',
minimax: MINIMAX_MODEL_CONFIGS.m3,
} as const satisfies ModelConfig

export const CLAUDE_OPUS_4_6_CONFIG = {
firstParty: 'claude-opus-4-6',
bedrock: 'us.anthropic.claude-opus-4-6-v1',
vertex: 'claude-opus-4-6',
foundry: 'claude-opus-4-6',
minimax: MINIMAX_MODEL_CONFIGS.m3,
} as const satisfies ModelConfig

export const CLAUDE_SONNET_4_6_CONFIG = {
firstParty: 'claude-sonnet-4-6',
bedrock: 'us.anthropic.claude-sonnet-4-6',
vertex: 'claude-sonnet-4-6',
foundry: 'claude-sonnet-4-6',
minimax: MINIMAX_MODEL_CONFIGS.m3,
} as const satisfies ModelConfig

// @[MODEL LAUNCH]: Register the new config here.
Expand Down
3 changes: 3 additions & 0 deletions src/utils/model/deprecation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const DEPRECATED_MODELS: Record<string, DeprecationEntry> = {
bedrock: 'January 15, 2026',
vertex: 'January 5, 2026',
foundry: 'January 5, 2026',
minimax: null,
},
},
'claude-3-7-sonnet': {
Expand All @@ -47,6 +48,7 @@ const DEPRECATED_MODELS: Record<string, DeprecationEntry> = {
bedrock: 'April 28, 2026',
vertex: 'May 11, 2026',
foundry: 'February 19, 2026',
minimax: null,
},
},
'claude-3-5-haiku': {
Expand All @@ -56,6 +58,7 @@ const DEPRECATED_MODELS: Record<string, DeprecationEntry> = {
bedrock: null,
vertex: null,
foundry: null,
minimax: null,
},
},
}
Expand Down
15 changes: 15 additions & 0 deletions src/utils/model/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
} from '../context.js'
import { isEnvTruthy } from '../envUtils.js'
import { getModelStrings, resolveOverriddenModel } from './modelStrings.js'
import { MINIMAX_MODEL_CONFIGS } from './configs.js'
import { formatModelPricing, getOpus46CostTier } from '../modelCost.js'
import { getSettings_DEPRECATED } from '../settings/settings.js'
import type { PermissionMode } from '../permissions/PermissionMode.js'
Expand Down Expand Up @@ -348,6 +349,12 @@ export function renderModelSetting(setting: ModelName | ModelAlias): string {
*/
export function getPublicModelDisplayName(model: ModelName): string | null {
switch (model) {
case MINIMAX_MODEL_CONFIGS.m3:
return 'MiniMax M3'
case MINIMAX_MODEL_CONFIGS.m3 + '[1m]':
return 'MiniMax M3 (1M context)'
case MINIMAX_MODEL_CONFIGS.m27:
return 'MiniMax M2.7'
case getModelStrings().opus46:
return 'Opus 4.6'
case getModelStrings().opus46 + '[1m]':
Expand Down Expand Up @@ -575,6 +582,14 @@ export function getMarketingNameForModel(modelId: string): string | undefined {

const has1m = modelId.toLowerCase().includes('[1m]')
const canonical = getCanonicalName(modelId)
const normalizedModel = normalizeModelStringForAPI(modelId).toLowerCase()

if (normalizedModel === MINIMAX_MODEL_CONFIGS.m3.toLowerCase()) {
return has1m ? 'MiniMax M3 (with 1M context)' : 'MiniMax M3'
}
if (normalizedModel === MINIMAX_MODEL_CONFIGS.m27.toLowerCase()) {
return 'MiniMax M2.7'
}

if (canonical.includes('claude-opus-4-6')) {
return has1m ? 'Opus 4.6 (with 1M context)' : 'Opus 4.6'
Expand Down
21 changes: 21 additions & 0 deletions src/utils/model/modelOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from '../modelCost.js'
import { getSettings_DEPRECATED } from '../settings/settings.js'
import { checkOpus1mAccess, checkSonnet1mAccess } from './check1mAccess.js'
import { MINIMAX_MODEL_CONFIGS } from './configs.js'
import { getAPIProvider } from './providers.js'
import { isModelAllowed } from './modelAllowlist.js'
import {
Expand Down Expand Up @@ -266,6 +267,22 @@ function getOpusPlanOption(): ModelOption {
}
}

function getMiniMaxModelOptions(): ModelOption[] {
return [
getDefaultOptionForUser(),
{
value: MINIMAX_MODEL_CONFIGS.m3,
label: 'MiniMax M3',
description: 'MiniMax M3 - 1M context - text, image, and video input',
},
{
value: MINIMAX_MODEL_CONFIGS.m27,
label: 'MiniMax M2.7',
description: 'MiniMax M2.7 - 204.8K context - text input',
},
]
}

// @[MODEL LAUNCH]: Update the model picker lists below to include/reorder options for the new model.
// Each user tier (ant, Max/Team Premium, Pro/Team Standard/Enterprise, PAYG 1P, PAYG 3P) has its own list.
function getModelOptionsBase(fastMode = false): ModelOption[] {
Expand All @@ -287,6 +304,10 @@ function getModelOptionsBase(fastMode = false): ModelOption[] {
]
}

if (getAPIProvider() === 'minimax') {
return getMiniMaxModelOptions()
}

if (isClaudeAISubscriber()) {
if (isMaxSubscriber() || isTeamPremiumSubscriber()) {
// Max and Team Premium users: Opus is default, show Sonnet as alternative
Expand Down
30 changes: 28 additions & 2 deletions src/utils/model/providers.ts
Original file line number Diff line number Diff line change
@@ -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 normalizedUrl = `${url.protocol}//${url.host}${url.pathname.replace(/\/+$/, '')}`
return MINIMAX_ANTHROPIC_BASE_URLS.has(normalizedUrl)
} catch {
return false
}
}

export function getAPIProvider(): APIProvider {
return isEnvTruthy(process.env.CLAUDE_CODE_USE_BEDROCK)
Expand All @@ -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 {
Expand Down
11 changes: 10 additions & 1 deletion src/utils/status.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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) {
Expand Down
18 changes: 17 additions & 1 deletion src/utils/thinking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getCanonicalName } from './model/model.js'
import { get3PModelCapabilityOverride } from './model/modelSupportOverrides.js'
import { getAPIProvider } from './model/providers.js'
import { getSettingsWithErrors } from './settings/settings.js'
import { MINIMAX_MODEL_CONFIGS } from './model/configs.js'

export type ThinkingConfig =
| { type: 'adaptive' }
Expand Down Expand Up @@ -101,6 +102,15 @@ export function modelSupportsThinking(model: string): boolean {
// launch DRI and research. This can greatly affect model quality and bashing.
const canonical = getCanonicalName(model)
const provider = getAPIProvider()
if (provider === 'minimax') {
const normalizedModel = model
.replace(/\[1m\]$/i, '')
.toLowerCase()
return (
normalizedModel === MINIMAX_MODEL_CONFIGS.m3.toLowerCase() ||
normalizedModel === MINIMAX_MODEL_CONFIGS.m27.toLowerCase()
)
}
// 1P and Foundry: all Claude 4+ models (including Haiku 4.5)
if (provider === 'foundry' || provider === 'firstParty') {
return !canonical.includes('claude-3-')
Expand All @@ -116,6 +126,13 @@ export function modelSupportsAdaptiveThinking(model: string): boolean {
return supported3P
}
const canonical = getCanonicalName(model)
const provider = getAPIProvider()
if (provider === 'minimax') {
const normalizedModel = model
.replace(/\[1m\]$/i, '')
.toLowerCase()
return normalizedModel === MINIMAX_MODEL_CONFIGS.m3.toLowerCase()
}
// Supported by a subset of Claude 4 models
if (canonical.includes('opus-4-6') || canonical.includes('sonnet-4-6')) {
return true
Expand All @@ -139,7 +156,6 @@ export function modelSupportsAdaptiveThinking(model: string): boolean {
// Default to true for unknown model strings on 1P and Foundry (because Foundry
// is a proxy). Do not default to true for other 3P as they have different formats
// for their model strings.
const provider = getAPIProvider()
return provider === 'firstParty' || provider === 'foundry'
}

Expand Down