Skip to content
Merged
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: 2 additions & 0 deletions src/background/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
isUsingGeminiWebModel,
isUsingClaudeWebModel,
isUsingMoonshotApiModel,
isUsingMistralApiModel,
isUsingMoonshotWebModel,
isUsingOpenRouterApiModel,
isUsingAimlApiModel,
Expand Down Expand Up @@ -396,6 +397,7 @@ function isUsingOpenAICompatibleApiSession(session) {
isUsingCustomModel(session) ||
isUsingChatgptApiModel(session) ||
isUsingMoonshotApiModel(session) ||
isUsingMistralApiModel(session) ||
isUsingChatGLMApiModel(session) ||
isUsingDeepSeekApiModel(session) ||
isUsingOllamaApiModel(session) ||
Expand Down
28 changes: 28 additions & 0 deletions src/config/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ export const moonshotApiModelKeys = [
'moonshot_v1_32k',
'moonshot_v1_128k',
]
export const mistralApiModelKeys = [
'mistralMediumLatest',
'mistralSmallLatest',
'mistralLargeLatest',
]
export const deepSeekApiModelKeys = [
'deepseek_chat',
'deepseek_reasoner',
Expand Down Expand Up @@ -229,6 +234,10 @@ export const ModelGroups = {
value: moonshotApiModelKeys,
desc: 'Kimi.Moonshot (API)',
},
mistralApiModelKeys: {
value: mistralApiModelKeys,
desc: 'Mistral AI (API)',
Comment thread
PeterDaveHello marked this conversation as resolved.
},
chatglmApiModelKeys: {
value: chatglmApiModelKeys,
desc: 'ChatGLM (API)',
Expand Down Expand Up @@ -433,6 +442,19 @@ export const Models = {
desc: 'DeepSeek (Reasoner)',
},

mistralMediumLatest: {
value: 'mistral-medium-latest',
desc: 'Mistral AI (Medium latest)',
},
mistralSmallLatest: {
value: 'mistral-small-latest',
desc: 'Mistral AI (Small latest)',
},
mistralLargeLatest: {
value: 'mistral-large-latest',
desc: 'Mistral AI (Large latest)',
},

openRouter_anthropic_claude_haiku4_5: {
value: 'anthropic/claude-haiku-4.5',
desc: 'OpenRouter (Claude Haiku 4.5)',
Expand Down Expand Up @@ -691,6 +713,7 @@ export const defaultConfig = {
anthropicApiKey: '',
chatglmApiKey: '',
moonshotApiKey: '',
mistralApiKey: '',
deepSeekApiKey: '',

customApiKey: '',
Expand Down Expand Up @@ -750,6 +773,7 @@ export const defaultConfig = {
'claudeHaiku45Api',
'googleGemini3_1Pro',
'googleGemini3_5Flash',
'mistralMediumLatest',
Comment thread
PeterDaveHello marked this conversation as resolved.
'openRouter_auto',
'openRouter_free',
],
Expand Down Expand Up @@ -895,6 +919,10 @@ export function isUsingMoonshotApiModel(configOrSession) {
return isInApiModeGroup(moonshotApiModelKeys, configOrSession)
}

export function isUsingMistralApiModel(configOrSession) {
return isInApiModeGroup(mistralApiModelKeys, configOrSession)
}

export function isUsingDeepSeekApiModel(configOrSession) {
return isInApiModeGroup(deepSeekApiModelKeys, configOrSession)
}
Expand Down
2 changes: 2 additions & 0 deletions src/config/openai-provider-mappings.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export const LEGACY_API_KEY_FIELD_BY_PROVIDER_ID = {
openai: 'apiKey',
deepseek: 'deepSeekApiKey',
moonshot: 'moonshotApiKey',
mistral: 'mistralApiKey',
openrouter: 'openRouterApiKey',
aiml: 'aimlApiKey',
chatglm: 'chatglmApiKey',
Expand All @@ -21,6 +22,7 @@ export const OPENAI_COMPATIBLE_GROUP_TO_PROVIDER_ID = {
chatgptApiModelKeys: 'openai',
gptApiModelKeys: 'openai',
moonshotApiModelKeys: 'moonshot',
mistralApiModelKeys: 'mistral',
deepSeekApiModelKeys: 'deepseek',
openRouterApiModelKeys: 'openrouter',
aimlModelKeys: 'aiml',
Expand Down
2 changes: 2 additions & 0 deletions src/popup/sections/GeneralPart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ function getProviderApiKeySetupUrl(providerId) {
return 'https://platform.openai.com/account/api-keys'
case 'moonshot':
return 'https://platform.moonshot.cn/console/api-keys'
case 'mistral':
return 'https://console.mistral.ai/api-keys'
default:
return ''
}
Expand Down
10 changes: 10 additions & 0 deletions src/services/apis/provider-registry.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ const BUILTIN_PROVIDER_TEMPLATE = [
builtin: true,
enabled: true,
},
{
id: 'mistral',
Comment thread
PeterDaveHello marked this conversation as resolved.
name: 'Mistral AI',
baseUrl: 'https://api.mistral.ai/v1',
chatCompletionsPath: '/chat/completions',
builtin: true,
enabled: true,
},
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
{
id: 'openrouter',
name: 'OpenRouter',
Expand Down Expand Up @@ -111,6 +119,8 @@ function resolveProviderIdFromLegacyModelName(modelName) {
}
if (preset.startsWith('deepseek_') || preset === 'deepSeekApiModelKeys') return 'deepseek'
if (preset.startsWith('moonshot_') || preset === 'moonshotApiModelKeys') return 'moonshot'
if (/^mistral(?:Medium|Small|Large)/.test(preset) || preset === 'mistralApiModelKeys')
return 'mistral'
if (preset.startsWith('openRouter_') || preset === 'openRouterApiModelKeys') return 'openrouter'
if (preset.startsWith('aiml_') || preset === 'aimlModelKeys' || preset === 'aimlApiModelKeys') {
return 'aiml'
Expand Down
9 changes: 9 additions & 0 deletions tests/unit/config/config-predicates.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
chatgptApiModelKeys,
gptApiModelKeys,
claudeApiModelKeys,
mistralApiModelKeys,
openRouterApiModelKeys,
aimlApiModelKeys,
isUsingAimlApiModel,
Expand All @@ -22,6 +23,7 @@ import {
isUsingGeminiWebModel,
isUsingGithubThirdPartyApiModel,
isUsingMoonshotApiModel,
isUsingMistralApiModel,
isUsingMoonshotWebModel,
isUsingMultiModeModel,
isUsingOllamaApiModel,
Expand Down Expand Up @@ -223,6 +225,13 @@ test('isUsingMoonshotApiModel detects moonshot API models', () => {
assert.equal(isUsingMoonshotApiModel({ modelName: 'moonshotWebFree' }), false)
})

test('isUsingMistralApiModel accepts exported Mistral API model keys', () => {
for (const modelName of mistralApiModelKeys) {
assert.equal(isUsingMistralApiModel({ modelName }), true)
}
assert.equal(isUsingMistralApiModel({ modelName: 'chatgptApi4oMini' }), false)
})

test('isUsingDeepSeekApiModel detects DeepSeek models', () => {
assert.equal(isUsingDeepSeekApiModel({ modelName: 'deepseek_v4_flash' }), true)
assert.equal(isUsingDeepSeekApiModel({ modelName: 'deepseek_v4_pro' }), true)
Expand Down
5 changes: 5 additions & 0 deletions tests/unit/services/apis/provider-registry.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ test('resolveEndpointTypeForSession falls back to legacy modelName when apiMode
assert.equal(resolveEndpointTypeForSession(session), 'completion')
})

test('resolveProviderIdForSession resolves legacy Mistral preset keys', () => {
assert.equal(resolveProviderIdForSession({ modelName: 'mistralMediumLatest' }), 'mistral')
assert.equal(resolveProviderIdForSession({ modelName: 'mistralApiModelKeys-custom' }), 'mistral')
})

test('resolveProviderIdForSession resolves legacy Google preset keys', () => {
assert.equal(resolveProviderIdForSession({ modelName: 'googleGemini2_5Flash' }), 'google')
assert.equal(resolveProviderIdForSession({ modelName: 'googleApiModelKeys-custom' }), 'google')
Expand Down
7 changes: 7 additions & 0 deletions tests/unit/services/apis/thin-adapters.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ const adapters = [
expectedBaseUrl: 'https://api.moonshot.cn/v1',
expectedApiKey: 'ms-key',
},
{
name: 'mistral-api',
apiMode: { groupName: 'mistralApiModelKeys', itemName: 'mistralMediumLatest' },
providerId: 'mistral',
expectedBaseUrl: 'https://api.mistral.ai/v1',
expectedApiKey: 'mistral-key',
},
{
name: 'openrouter-api',
apiMode: { groupName: 'openRouterApiModelKeys', itemName: 'openRouter_openai_o3' },
Expand Down