Feature/add ling series support (#10863)

* feat(Miniapp): add Ling app and according migration support.

* feat(models): add Ling model support and related reasoning checks

Signed-off-by: cafe3310 <4354898+cafe3310@users.noreply.github.com>

* fix: resolved lint findings; simplifying model reasoning check.

---------

Signed-off-by: cafe3310 <4354898+cafe3310@users.noreply.github.com>
This commit is contained in:
Sipan 2025-10-22 18:25:11 +08:00 committed by GitHub
parent 7f83f0700b
commit f088069fb3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 102 additions and 2 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,6 +1,6 @@
import { describe, expect, it, vi } from 'vitest'
import { isDoubaoSeedAfter251015, isDoubaoThinkingAutoModel } from '../models/reasoning'
import { isDoubaoSeedAfter251015, isDoubaoThinkingAutoModel, isLingReasoningModel } from '../models/reasoning'
// FIXME: Idk why it's imported. Maybe circular dependency somewhere
vi.mock('@renderer/services/AssistantService.ts', () => ({
@ -164,3 +164,60 @@ describe('Doubao Models', () => {
})
})
})
describe('Ling Models', () => {
describe('isLingReasoningModel', () => {
it('should return false for ling variants', () => {
expect(
isLingReasoningModel({
id: 'ling-1t',
name: '',
provider: '',
group: ''
})
).toBe(false)
expect(
isLingReasoningModel({
id: 'ling-flash-2.0',
name: '',
provider: '',
group: ''
})
).toBe(false)
expect(
isLingReasoningModel({
id: 'ling-mini-2.0',
name: '',
provider: '',
group: ''
})
).toBe(false)
})
it('should return true for ring variants', () => {
expect(
isLingReasoningModel({
id: 'ring-1t',
name: '',
provider: '',
group: ''
})
).toBe(true)
expect(
isLingReasoningModel({
id: 'ring-flash-2.0',
name: '',
provider: '',
group: ''
})
).toBe(true)
expect(
isLingReasoningModel({
id: 'ring-mini-2.0',
name: '',
provider: '',
group: ''
})
).toBe(true)
})
})
})

View File

@ -25,6 +25,7 @@ import GrokXAppLogo from '@renderer/assets/images/apps/grok-x.png?url'
import KimiAppLogo from '@renderer/assets/images/apps/kimi.webp?url'
import LambdaChatLogo from '@renderer/assets/images/apps/lambdachat.webp?url'
import LeChatLogo from '@renderer/assets/images/apps/lechat.png?url'
import LingAppLogo from '@renderer/assets/images/apps/ling.png?url'
import LongCatAppLogo from '@renderer/assets/images/apps/longcat.svg?url'
import MetasoAppLogo from '@renderer/assets/images/apps/metaso.webp?url'
import MonicaLogo from '@renderer/assets/images/apps/monica.webp?url'
@ -460,6 +461,16 @@ const ORIGIN_DEFAULT_MIN_APPS: MinAppType[] = [
logo: LongCatAppLogo,
url: 'https://longcat.chat/',
bodered: true
},
{
id: 'ling',
name: i18n.t('minapps.ant-ling'),
url: 'https://ling.tbox.cn/chat',
logo: LingAppLogo,
bodered: true,
style: {
padding: 6
}
}
]

View File

@ -84,6 +84,7 @@ import JinaModelLogo from '@renderer/assets/images/models/jina.png'
import JinaModelLogoDark from '@renderer/assets/images/models/jina_dark.png'
import KeLingModelLogo from '@renderer/assets/images/models/keling.png'
import KeLingModelLogoDark from '@renderer/assets/images/models/keling_dark.png'
import LingModelLogo from '@renderer/assets/images/models/ling.png'
import LlamaModelLogo from '@renderer/assets/images/models/llama.png'
import LlamaModelLogoDark from '@renderer/assets/images/models/llama_dark.png'
import LLavaModelLogo from '@renderer/assets/images/models/llava.png'
@ -289,6 +290,8 @@ export function getModelLogoById(modelId: string): string | undefined {
zhipu: isLight ? ZhipuModelLogo : ZhipuModelLogoDark,
longcat: LongCatAppLogo,
bytedance: BytedanceModelLogo,
ling: LingModelLogo,
ring: LingModelLogo,
'(V_1|V_1_TURBO|V_2|V_2A|V_2_TURBO|DESCRIBE|UPSCALE)': IdeogramModelLogo
} as const satisfies Record<string, string>

View File

@ -424,6 +424,14 @@ export const isDeepSeekHybridInferenceModel = (model: Model) => {
return /deepseek-v3(?:\.\d|-\d)(?:(\.|-)\w+)?$/.test(modelId) || modelId.includes('deepseek-chat-v3.1')
}
export const isLingReasoningModel = (model?: Model): boolean => {
if (!model) {
return false
}
const modelId = getLowerBaseModelName(model.id, '/')
return ['ring-1t', 'ring-mini', 'ring-flash'].some((id) => modelId.includes(id))
}
export const isSupportedThinkingTokenDeepSeekModel = isDeepSeekHybridInferenceModel
export const isZhipuReasoningModel = (model?: Model): boolean => {
@ -475,6 +483,7 @@ export function isReasoningModel(model?: Model): boolean {
isZhipuReasoningModel(model) ||
isStepReasoningModel(model) ||
isDeepSeekHybridInferenceModel(model) ||
isLingReasoningModel(model) ||
modelId.includes('magistral') ||
modelId.includes('minimax-m1') ||
modelId.includes('pangu-pro-moe') ||

View File

@ -25,7 +25,9 @@ export const FUNCTION_CALLING_MODELS = [
'gemini(?:-[\\w-]+)?', // 提前排除了gemini的嵌入模型
'grok-3(?:-[\\w-]+)?',
'doubao-seed-1[.-]6(?:-[\\w-]+)?',
'kimi-k2(?:-[\\w-]+)?'
'kimi-k2(?:-[\\w-]+)?',
'ling-\\w+(?:-[\\w-]+)?',
'ring-\\w+(?:-[\\w-]+)?'
]
const FUNCTION_CALLING_EXCLUDED_MODELS = [

View File

@ -1804,6 +1804,7 @@
"title": "MinApp"
},
"minapps": {
"ant-ling": "Ant Ling",
"baichuan": "Baichuan",
"baidu-ai-search": "Baidu AI Search",
"chatglm": "ChatGLM",

View File

@ -1804,6 +1804,7 @@
"title": "小程序"
},
"minapps": {
"ant-ling": "蚂蚁百灵",
"baichuan": "百小应",
"baidu-ai-search": "百度AI搜索",
"chatglm": "智谱清言",

View File

@ -1804,6 +1804,7 @@
"title": "小工具"
},
"minapps": {
"ant-ling": "Ant Ling",
"baichuan": "百小應",
"baidu-ai-search": "百度AI搜索",
"chatglm": "智譜清言",

View File

@ -1804,6 +1804,7 @@
"title": "Μικρόπρογραμμα"
},
"minapps": {
"ant-ling": "Ant Ling",
"baichuan": "Baichuan",
"baidu-ai-search": "Baidu AI Search",
"chatglm": "ChatGLM",

View File

@ -1804,6 +1804,7 @@
"title": "Mini programa"
},
"minapps": {
"ant-ling": "Ant Ling",
"baichuan": "Baichuan",
"baidu-ai-search": "Baidu AI Search",
"chatglm": "ChatGLM",

View File

@ -1804,6 +1804,7 @@
"title": "Mini-programme"
},
"minapps": {
"ant-ling": "Ant Ling",
"baichuan": "Baichuan",
"baidu-ai-search": "Baidu AI Search",
"chatglm": "ChatGLM",

View File

@ -1804,6 +1804,7 @@
"title": "ミニアプリ"
},
"minapps": {
"ant-ling": "Ant Ling",
"baichuan": "百小應",
"baidu-ai-search": "百度AI検索",
"chatglm": "ChatGLM",

View File

@ -1804,6 +1804,7 @@
"title": "Pequeno aplicativo"
},
"minapps": {
"ant-ling": "Ant Ling",
"baichuan": "Baichuan",
"baidu-ai-search": "Baidu AI Search",
"chatglm": "ChatGLM",

View File

@ -1804,6 +1804,7 @@
"title": "Встроенные приложения"
},
"minapps": {
"ant-ling": "Ant Ling",
"baichuan": "Байчжан",
"baidu-ai-search": "Baidu AI Search",
"chatglm": "ChatGLM",

View File

@ -2683,6 +2683,15 @@ const migrateConfig = {
logger.error('migrate 163 error', error as Error)
return state
}
},
'164': (state: RootState) => {
try {
addMiniApp(state, 'ling')
return state
} catch (error) {
logger.error('migrate 164 error', error as Error)
return state
}
}
}