mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-07-05 21:50:46 +08:00
hotfix(models): add MiMo V2.5 model support (#14557)
### What this PR does Before this PR: - Cherry Studio did not recognize the new MiMo V2.5 chat models as expected across model capability checks. - MiMo V2.5 models were missing or incomplete in the built-in model list. - Function calling, reasoning option detection, and vision capability detection were not aligned for the new MiMo V2.5 models. After this PR: - Adds MiMo V2.5 and MiMo V2.5 Pro to the built-in MiMo model list. - Enables reasoning/thinking support detection for MiMo V2.5 chat models. - Enables function-calling detection for MiMo V2.5 chat models. - Enables vision detection for MiMo V2.5 while keeping unsupported MiMo V2.5 speech models excluded. - Adds regression tests covering reasoning, tool calling, and vision behavior for the MiMo V2.5 family. <!-- (optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*: --> Fixes # N/A ### Why we need it and why it was done in this way The following tradeoffs were made: - This hotfix keeps the change set minimal and scoped to model capability configuration and tests only. - The implementation updates existing model detection logic instead of introducing new abstractions, which reduces risk for a `main` branch hotfix. The following alternatives were considered: - Deferring support until a larger model capability refactor on the `v2` branch. - Adding broader refactoring around MiMo model matching and capability normalization. Links to places where the discussion took place: N/A <!-- optional: slack, other GH issue, mailinglist, ... --> ### Breaking changes <!-- optional --> If this PR introduces breaking changes, please describe the changes and the impact on users. - None. ### Special notes for your reviewer <!-- optional --> - This PR is intentionally minimal because it targets `main` from a `hotfix/*` branch under code freeze. - Validation performed: - `pnpm test:renderer -- src/renderer/src/config/models/__tests__/vision.test.ts src/renderer/src/config/models/__tests__/tooluse.test.ts src/renderer/src/config/models/__tests__/reasoning.test.ts` ### Checklist This checklist is not enforcing, but it's a reminder of items that could be relevant to every PR. Approvers are expected to review this list. - [x] PR: The PR description is expressive enough and will help future contributors - [x] Code: [Write code that humans can understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans) and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle) - [x] Refactor: You have [left the code cleaner than you found it (Boy Scout Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html) - [x] Upgrade: Impact of this change on upgrade flows was considered and addressed if required - [] Documentation: A [user-guide update](https://docs.cherry-ai.com) was considered and is present (link) or not required. Check this only when the PR introduces or changes a user-facing feature or behavior. - [x] Self-review: I have reviewed my own code (e.g., via [`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`, or GitHub UI) before requesting review from others ### Release note <!-- Write your release note: 1. Enter your extended release note in the below block. If the PR requires additional action from users switching to the new release, include the string "action required". 2. If no release note is required, just write "NONE". 3. Only include user-facing changes (new features, bug fixes visible to users, UI changes, behavior changes). For CI, maintenance, internal refactoring, build tooling, or other non-user-facing work, write "NONE". --> ```release-note Fixed MiMo V2.5 model capability detection so MiMo V2.5 chat models are recognized correctly for reasoning controls, function calling, and vision support. Signed-off-by: ousugo <dkzyxh@gmail.com> Co-authored-by: SuYao <sy20010504@gmail.com>
This commit is contained in:
@@ -31,6 +31,7 @@ import {
|
||||
isSupportedThinkingTokenDoubaoModel,
|
||||
isSupportedThinkingTokenGeminiModel,
|
||||
isSupportedThinkingTokenKimiModel,
|
||||
isSupportedThinkingTokenMiMoModel,
|
||||
isSupportedThinkingTokenModel,
|
||||
isSupportedThinkingTokenQwenModel,
|
||||
isSupportedThinkingTokenZhipuModel,
|
||||
@@ -831,6 +832,13 @@ describe('getThinkModelType - Comprehensive Coverage', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('MiMo models', () => {
|
||||
it('should return mimo for V2.5 thinking models', () => {
|
||||
expect(getThinkModelType(createModel({ id: 'mimo-v2.5' }))).toBe('mimo')
|
||||
expect(getThinkModelType(createModel({ id: 'mimo-v2.5-pro' }))).toBe('mimo')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Perplexity models', () => {
|
||||
it('should return perplexity for supported Perplexity models', () => {
|
||||
expect(getThinkModelType(createModel({ id: 'sonar-pro', provider: 'perplexity' }))).toBe('default')
|
||||
@@ -2168,6 +2176,19 @@ describe('getModelSupportedReasoningEffortOptions', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('should return correct options for MiMo V2.5 models', () => {
|
||||
expect(getModelSupportedReasoningEffortOptions(createModel({ id: 'mimo-v2.5' }))).toEqual([
|
||||
'default',
|
||||
'none',
|
||||
'auto'
|
||||
])
|
||||
expect(getModelSupportedReasoningEffortOptions(createModel({ id: 'mimo-v2.5-pro' }))).toEqual([
|
||||
'default',
|
||||
'none',
|
||||
'auto'
|
||||
])
|
||||
})
|
||||
|
||||
it('should return correct options for Zhipu models', () => {
|
||||
expect(getModelSupportedReasoningEffortOptions(createModel({ id: 'glm-4.5' }))).toEqual([
|
||||
'default',
|
||||
@@ -2335,6 +2356,13 @@ describe('isInterleavedThinkingModel', () => {
|
||||
})
|
||||
|
||||
describe('MiMo models', () => {
|
||||
it('should support thinking control for V2.5 models only on chat models', () => {
|
||||
expect(isSupportedThinkingTokenMiMoModel(createModel({ id: 'mimo-v2.5' }))).toBe(true)
|
||||
expect(isSupportedThinkingTokenMiMoModel(createModel({ id: 'mimo-v2.5-pro' }))).toBe(true)
|
||||
expect(isSupportedThinkingTokenMiMoModel(createModel({ id: 'mimo-v2.5-tts' }))).toBe(false)
|
||||
expect(isSupportedThinkingTokenMiMoModel(createModel({ id: 'mimo-v2.5-tts-voiceclone' }))).toBe(false)
|
||||
})
|
||||
|
||||
it('should return true for mimo-v2-flash', () => {
|
||||
expect(isInterleavedThinkingModel(createModel({ id: 'mimo-v2-flash' }))).toBe(true)
|
||||
})
|
||||
|
||||
@@ -177,6 +177,18 @@ describe('isFunctionCallingModel', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('MiMo V2.5 Models', () => {
|
||||
it('supports function calling for V2.5 chat models', () => {
|
||||
expect(isFunctionCallingModel(createModel({ id: 'mimo-v2.5', provider: 'mimo' }))).toBe(true)
|
||||
expect(isFunctionCallingModel(createModel({ id: 'mimo-v2.5-pro', provider: 'mimo' }))).toBe(true)
|
||||
})
|
||||
|
||||
it('does not treat V2.5 speech models as function calling chat models', () => {
|
||||
expect(isFunctionCallingModel(createModel({ id: 'mimo-v2.5-tts', provider: 'mimo' }))).toBe(false)
|
||||
expect(isFunctionCallingModel(createModel({ id: 'mimo-v2.5-tts-voiceclone', provider: 'mimo' }))).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Doubao Seed 2.0 Models', () => {
|
||||
it('should identify doubao-seed-2-0-pro-260215 as function calling model', () => {
|
||||
const model: Model = {
|
||||
|
||||
@@ -349,6 +349,15 @@ describe('isVisionModel', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('MiMo Models', () => {
|
||||
it('should identify only the full-modal V2.5 chat model as vision-capable', () => {
|
||||
expect(isVisionModel(createModel({ id: 'mimo-v2.5' }))).toBe(true)
|
||||
expect(isVisionModel(createModel({ id: 'xiaomi/mimo-v2.5' }))).toBe(true)
|
||||
expect(isVisionModel(createModel({ id: 'mimo-v2.5-pro' }))).toBe(false)
|
||||
expect(isVisionModel(createModel({ id: 'mimo-v2.5-tts' }))).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Qwen Models', () => {
|
||||
it('should return true for Qwen vision models', () => {
|
||||
expect(isVisionModel(createModel({ id: 'qwen-vl-max' }))).toBe(true)
|
||||
|
||||
@@ -2029,23 +2029,29 @@ export const SYSTEM_MODELS: Record<SystemProviderId | 'defaultModel', Model[]> =
|
||||
}
|
||||
],
|
||||
mimo: [
|
||||
{
|
||||
id: 'mimo-v2.5',
|
||||
name: 'Mimo V2.5',
|
||||
provider: 'mimo',
|
||||
group: 'mimo'
|
||||
},
|
||||
{
|
||||
id: 'mimo-v2.5-pro',
|
||||
name: 'Mimo V2.5 Pro',
|
||||
provider: 'mimo',
|
||||
group: 'mimo'
|
||||
},
|
||||
{
|
||||
id: 'mimo-v2-flash',
|
||||
name: 'Mimo V2 Flash',
|
||||
provider: 'mimo',
|
||||
group: 'Mimo'
|
||||
},
|
||||
{
|
||||
id: 'mimo-v2-pro',
|
||||
name: 'Mimo V2 Pro',
|
||||
provider: 'mimo',
|
||||
group: 'Mimo'
|
||||
group: 'mimo'
|
||||
},
|
||||
{
|
||||
id: 'mimo-v2-omni',
|
||||
name: 'Mimo V2 Omni',
|
||||
provider: 'mimo',
|
||||
group: 'Mimo'
|
||||
group: 'mimo'
|
||||
}
|
||||
],
|
||||
zai: [
|
||||
|
||||
@@ -613,7 +613,7 @@ export const isSupportedThinkingTokenZhipuModel = (model: Model): boolean => {
|
||||
|
||||
export const isSupportedThinkingTokenMiMoModel = (model: Model): boolean => {
|
||||
const modelId = getLowerBaseModelName(model.id, '/')
|
||||
return ['mimo-v2-flash', 'mimo-v2-pro', 'mimo-v2-omni'].some((id) => modelId.includes(id))
|
||||
return ['mimo-v2-flash', 'mimo-v2-pro', 'mimo-v2-omni', 'mimo-v2.5', 'mimo-v2.5-pro'].includes(modelId)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,6 +36,7 @@ export const FUNCTION_CALLING_MODELS = [
|
||||
'ling-\\w+(?:-[\\w-]+)?',
|
||||
'ring-\\w+(?:-[\\w-]+)?',
|
||||
'minimax-m2(?:\\.\\d+)?(?:-[\\w-]+)?',
|
||||
'mimo-v2\\.5(?:-pro)?(?!-)',
|
||||
'mimo-v2-flash',
|
||||
'mimo-v2-pro',
|
||||
'mimo-v2-omni',
|
||||
|
||||
@@ -61,6 +61,7 @@ const visionAllowedModels = [
|
||||
'mistral-large-(2512|latest)',
|
||||
'mistral-medium-(2508|latest)',
|
||||
'mistral-small-(2506|latest)',
|
||||
'mimo-v2\\.5$',
|
||||
'mimo-v2-omni(?:-[\\w-]+)?',
|
||||
'glm-5v-turbo'
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user