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
11 changes: 11 additions & 0 deletions src/utils/model/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,76 +11,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-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-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-M2.7',
} 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-M2.7',
} 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-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-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-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-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-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-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-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
13 changes: 13 additions & 0 deletions src/utils/model/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,10 @@ export function renderModelSetting(setting: ModelName | ModelAlias): string {
*/
export function getPublicModelDisplayName(model: ModelName): string | null {
switch (model) {
case 'MiniMax-M3':
return 'MiniMax M3'
case 'MiniMax-M2.7':
return 'MiniMax M2.7'
case getModelStrings().opus46:
return 'Opus 4.6'
case getModelStrings().opus46 + '[1m]':
Expand Down Expand Up @@ -425,6 +429,9 @@ export function renderModelName(model: ModelName): string {
export function getPublicModelName(model: ModelName): string {
const publicName = getPublicModelDisplayName(model)
if (publicName) {
if (publicName.startsWith('MiniMax ')) {
return publicName
}
return `Claude ${publicName}`
}
return `Claude (${model})`
Expand Down Expand Up @@ -579,6 +586,12 @@ export function getMarketingNameForModel(modelId: string): string | undefined {
if (canonical.includes('claude-opus-4-6')) {
return has1m ? 'Opus 4.6 (with 1M context)' : 'Opus 4.6'
}
if (canonical.includes('minimax-m3')) {
return 'MiniMax M3'
}
if (canonical.includes('minimax-m2.7')) {
return 'MiniMax M2.7'
}
if (canonical.includes('claude-opus-4-5')) {
return 'Opus 4.5'
}
Expand Down
12 changes: 10 additions & 2 deletions src/utils/model/modelStrings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import {
type CanonicalModelId,
type ModelKey,
} from './configs.js'
import { type APIProvider, getAPIProvider } from './providers.js'
import {
type APIProvider,
getAPIProvider,
isMiniMaxAnthropicBaseUrl,
} from './providers.js'

/**
* Maps each model version to its provider-specific model ID string.
Expand All @@ -24,8 +28,12 @@ const MODEL_KEYS = Object.keys(ALL_MODEL_CONFIGS) as ModelKey[]

function getBuiltinModelStrings(provider: APIProvider): ModelStrings {
const out = {} as ModelStrings
const resolvedProvider =
provider === 'firstParty' && isMiniMaxAnthropicBaseUrl()
? 'minimax'
: provider
for (const key of MODEL_KEYS) {
out[key] = ALL_MODEL_CONFIGS[key][provider]
out[key] = ALL_MODEL_CONFIGS[key][resolvedProvider]
Comment on lines +31 to +36

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Centralize effective-provider resolution.

This branch correctly maps a first-party MiniMax endpoint to the minimax model configuration. However, the conversion is local. getAPIProvider() still returns firstParty, so src/utils/model/deprecation.ts never selects the new minimax: null retirement entries, and the minimax provider label in src/utils/status.tsx is unreachable.

Extract a shared effective-provider helper and use it for model, deprecation, and provider metadata lookup. Keep the raw provider where the first-party transport and base-URL branch are required. Add tests covering both MiniMax hosts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/model/modelStrings.ts` around lines 31 - 36, Centralize the
first-party MiniMax-to-minimax mapping in a shared effective-provider helper,
then reuse it in the model configuration lookup, deprecation handling, and
provider metadata lookup so `minimax: null` retirement entries and the `minimax`
status label are reachable. Preserve the raw provider for first-party transport
and base-URL decisions, and add coverage for both MiniMax hosts.

}
return out
}
Expand Down
38 changes: 26 additions & 12 deletions src/utils/model/providers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
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 MINI_MAX_ANTHROPIC_HOSTS = new Set(['api.minimax.io', 'api.minimaxi.com'])

function getAnthropicBaseUrlHost(): string | null {
const baseUrl = process.env.ANTHROPIC_BASE_URL
if (!baseUrl) {
return null
}
try {
return new URL(baseUrl).host
} catch {
return null
}
Comment on lines +8 to +17

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject malformed configured URLs.

getAnthropicBaseUrlHost() returns null when ANTHROPIC_BASE_URL is unset and when new URL(baseUrl) fails. isFirstPartyAnthropicBaseUrl() then returns true for both cases. A value such as ANTHROPIC_BASE_URL=not-a-url is accepted instead of rejected.

Treat only an unset value as the default API. Return false for a configured value that cannot be parsed. Add tests for unset, malformed, allowed, and disallowed URLs.

Proposed fix
 export function isFirstPartyAnthropicBaseUrl(): boolean {
+  if (!process.env.ANTHROPIC_BASE_URL) {
+    return true
+  }
   const host = getAnthropicBaseUrlHost()
   if (!host) {
-    return true
+    return false
   }

Also applies to: 44-47

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/model/providers.ts` around lines 8 - 17, Update
getAnthropicBaseUrlHost and isFirstPartyAnthropicBaseUrl so an unset
ANTHROPIC_BASE_URL retains the default first-party behavior, while configured
values that URL parsing rejects return false rather than being treated as
first-party. Add tests covering unset, malformed, allowed, and disallowed URLs.

}

export function getAPIProvider(): APIProvider {
return isEnvTruthy(process.env.CLAUDE_CODE_USE_BEDROCK)
Expand All @@ -17,24 +31,24 @@ export function getAPIProviderForStatsig(): AnalyticsMetadata_I_VERIFIED_THIS_IS
return getAPIProvider() as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
}

export function isMiniMaxAnthropicBaseUrl(): boolean {
const host = getAnthropicBaseUrlHost()
return host !== null && MINI_MAX_ANTHROPIC_HOSTS.has(host)
}

/**
* Check if ANTHROPIC_BASE_URL is a first-party Anthropic API URL.
* Returns true if not set (default API) or points to api.anthropic.com
* (or api-staging.anthropic.com for ant users).
*/
export function isFirstPartyAnthropicBaseUrl(): boolean {
const baseUrl = process.env.ANTHROPIC_BASE_URL
if (!baseUrl) {
const host = getAnthropicBaseUrlHost()
if (!host) {
return true
}
try {
const host = new URL(baseUrl).host
const allowedHosts = ['api.anthropic.com']
if (process.env.USER_TYPE === 'ant') {
allowedHosts.push('api-staging.anthropic.com')
}
return allowedHosts.includes(host)
} catch {
return false
const allowedHosts = ['api.anthropic.com', ...MINI_MAX_ANTHROPIC_HOSTS]
if (process.env.USER_TYPE === 'ant') {
allowedHosts.push('api-staging.anthropic.com')
}
return allowedHosts.includes(host)
}
11 changes: 7 additions & 4 deletions src/utils/status.tsx

Large diffs are not rendered by default.