mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-26 11:44:28 +08:00
fix: thinking button doesn't update assistant reasoning effort (#9247)
* feat(思考模式): 添加doubao_no_auto模型支持并重构选项回退逻辑 将思考模式选项回退逻辑从组件移至配置文件中统一管理 添加doubao_no_auto模型类型及其支持的选项配置 * refactor(assistant): 将模型兼容性检查逻辑移至useAssistant钩子 将ThinkingButton组件中的模型兼容性检查逻辑重构到useAssistant钩子中,使逻辑更集中 移除不再需要的useEffect导入 * refactor(useAssistant): 移除不必要的类型断言 * refactor: 移除THINKING_OPTION_FALLBACK并使用支持选项的第一个值作为回退 不再使用预定义的选项回退映射表,改为直接使用模型支持选项列表中的第一个值作为回退选项
This commit is contained in:
parent
33ec5c5c6b
commit
aed9566409
@ -300,6 +300,7 @@ export const MODEL_SUPPORTED_REASONING_EFFORT: ReasoningEffortConfig = {
|
||||
qwen: ['low', 'medium', 'high'] as const,
|
||||
qwen_thinking: ['low', 'medium', 'high'] as const,
|
||||
doubao: ['auto', 'high'] as const,
|
||||
doubao_no_auto: ['high'] as const,
|
||||
hunyuan: ['auto'] as const,
|
||||
zhipu: ['auto'] as const,
|
||||
perplexity: ['low', 'medium', 'high'] as const
|
||||
@ -316,6 +317,7 @@ export const MODEL_SUPPORTED_OPTIONS: ThinkingOptionConfig = {
|
||||
qwen: ['off', ...MODEL_SUPPORTED_REASONING_EFFORT.qwen] as const,
|
||||
qwen_thinking: MODEL_SUPPORTED_REASONING_EFFORT.qwen_thinking,
|
||||
doubao: ['off', ...MODEL_SUPPORTED_REASONING_EFFORT.doubao] as const,
|
||||
doubao_no_auto: ['off', ...MODEL_SUPPORTED_REASONING_EFFORT.doubao_no_auto] as const,
|
||||
hunyuan: ['off', ...MODEL_SUPPORTED_REASONING_EFFORT.hunyuan] as const,
|
||||
zhipu: ['off', ...MODEL_SUPPORTED_REASONING_EFFORT.zhipu] as const,
|
||||
perplexity: MODEL_SUPPORTED_REASONING_EFFORT.perplexity
|
||||
@ -339,8 +341,13 @@ export const getThinkModelType = (model: Model): ThinkingModelType => {
|
||||
thinkingModelType = 'qwen_thinking'
|
||||
}
|
||||
thinkingModelType = 'qwen'
|
||||
} else if (isSupportedThinkingTokenDoubaoModel(model)) thinkingModelType = 'doubao'
|
||||
else if (isSupportedThinkingTokenHunyuanModel(model)) thinkingModelType = 'hunyuan'
|
||||
} else if (isSupportedThinkingTokenDoubaoModel(model)) {
|
||||
if (isDoubaoThinkingAutoModel(model)) {
|
||||
thinkingModelType = 'doubao'
|
||||
} else {
|
||||
thinkingModelType = 'doubao_no_auto'
|
||||
}
|
||||
} else if (isSupportedThinkingTokenHunyuanModel(model)) thinkingModelType = 'hunyuan'
|
||||
else if (isSupportedReasoningEffortPerplexityModel(model)) thinkingModelType = 'perplexity'
|
||||
else if (isSupportedThinkingTokenZhipuModel(model)) thinkingModelType = 'zhipu'
|
||||
return thinkingModelType
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
import { loggerService } from '@logger'
|
||||
import {
|
||||
getThinkModelType,
|
||||
isSupportedReasoningEffortModel,
|
||||
isSupportedThinkingTokenModel,
|
||||
MODEL_SUPPORTED_OPTIONS
|
||||
} from '@renderer/config/models'
|
||||
import { db } from '@renderer/databases'
|
||||
import { getDefaultTopic } from '@renderer/services/AssistantService'
|
||||
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
||||
@ -12,7 +18,7 @@ import {
|
||||
setModel,
|
||||
updateAssistant,
|
||||
updateAssistants,
|
||||
updateAssistantSettings,
|
||||
updateAssistantSettings as _updateAssistantSettings,
|
||||
updateDefaultAssistant,
|
||||
updateTopic,
|
||||
updateTopics
|
||||
@ -20,7 +26,7 @@ import {
|
||||
import { setDefaultModel, setTopicNamingModel, setTranslateModel } from '@renderer/store/llm'
|
||||
import { Assistant, AssistantSettings, Model, Topic } from '@renderer/types'
|
||||
import { uuid } from '@renderer/utils'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { useCallback, useEffect, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { TopicManager } from './useTopic'
|
||||
@ -78,6 +84,36 @@ export function useAssistant(id: string) {
|
||||
|
||||
const assistantWithModel = useMemo(() => ({ ...assistant, model }), [assistant, model])
|
||||
|
||||
const updateAssistantSettings = useCallback(
|
||||
(settings: Partial<AssistantSettings>) => {
|
||||
assistant?.id && dispatch(_updateAssistantSettings({ assistantId: assistant.id, settings }))
|
||||
},
|
||||
[assistant.id, dispatch]
|
||||
)
|
||||
|
||||
// 当model变化时,同步reasoning effort为模型支持的合法值
|
||||
useEffect(() => {
|
||||
if (isSupportedThinkingTokenModel(model) || isSupportedReasoningEffortModel(model)) {
|
||||
const currentReasoningEffort = assistant.settings?.reasoning_effort
|
||||
const supportedOptions = MODEL_SUPPORTED_OPTIONS[getThinkModelType(model)]
|
||||
if (currentReasoningEffort && !supportedOptions.includes(currentReasoningEffort)) {
|
||||
// 选项不支持时,回退到第一个支持的值
|
||||
// 注意:这里假设可用的options不会为空
|
||||
const fallbackOption = supportedOptions[0]
|
||||
|
||||
updateAssistantSettings({
|
||||
reasoning_effort: fallbackOption === 'off' ? undefined : fallbackOption,
|
||||
qwenThinkMode: fallbackOption === 'off'
|
||||
})
|
||||
}
|
||||
} else {
|
||||
updateAssistantSettings({
|
||||
reasoning_effort: undefined,
|
||||
qwenThinkMode: undefined
|
||||
})
|
||||
}
|
||||
}, [assistant.settings?.reasoning_effort, model, updateAssistantSettings])
|
||||
|
||||
return {
|
||||
assistant: assistantWithModel,
|
||||
model,
|
||||
@ -110,9 +146,7 @@ export function useAssistant(id: string) {
|
||||
[assistant, dispatch]
|
||||
),
|
||||
updateAssistant: (assistant: Assistant) => dispatch(updateAssistant(assistant)),
|
||||
updateAssistantSettings: (settings: Partial<AssistantSettings>) => {
|
||||
assistant?.id && dispatch(updateAssistantSettings({ assistantId: assistant.id, settings }))
|
||||
}
|
||||
updateAssistantSettings
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { getReasoningEffortOptionsLabel } from '@renderer/i18n/label'
|
||||
import { Assistant, Model, ThinkingOption } from '@renderer/types'
|
||||
import { Tooltip } from 'antd'
|
||||
import { FC, ReactElement, useCallback, useEffect, useImperativeHandle, useMemo } from 'react'
|
||||
import { FC, ReactElement, useCallback, useImperativeHandle, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
export interface ThinkingButtonRef {
|
||||
@ -26,16 +26,6 @@ interface Props {
|
||||
ToolbarButton: any
|
||||
}
|
||||
|
||||
// 选项转换映射表:当选项不支持时使用的替代选项
|
||||
const OPTION_FALLBACK: Record<ThinkingOption, ThinkingOption> = {
|
||||
off: 'low', // off -> low (for Gemini Pro models)
|
||||
minimal: 'low', // minimal -> low (for gpt-5 and after)
|
||||
low: 'high',
|
||||
medium: 'high', // medium -> high (for Grok models)
|
||||
high: 'high',
|
||||
auto: 'high' // auto -> high (for non-Gemini models)
|
||||
}
|
||||
|
||||
const ThinkingButton: FC<Props> = ({ ref, model, assistant, ToolbarButton }): ReactElement => {
|
||||
const { t } = useTranslation()
|
||||
const quickPanel = useQuickPanel()
|
||||
@ -59,19 +49,6 @@ const ThinkingButton: FC<Props> = ({ ref, model, assistant, ToolbarButton }): Re
|
||||
return MODEL_SUPPORTED_OPTIONS[modelType]
|
||||
}, [model, modelType])
|
||||
|
||||
// 检查当前设置是否与当前模型兼容
|
||||
useEffect(() => {
|
||||
if (currentReasoningEffort && !supportedOptions.includes(currentReasoningEffort)) {
|
||||
// 使用表中定义的替代选项
|
||||
const fallbackOption = OPTION_FALLBACK[currentReasoningEffort as ThinkingOption]
|
||||
|
||||
updateAssistantSettings({
|
||||
reasoning_effort: fallbackOption === 'off' ? undefined : fallbackOption,
|
||||
qwenThinkMode: fallbackOption === 'off'
|
||||
})
|
||||
}
|
||||
}, [currentReasoningEffort, supportedOptions, updateAssistantSettings, model.id])
|
||||
|
||||
const createThinkingIcon = useCallback((option?: ThinkingOption, isActive: boolean = false) => {
|
||||
const iconColor = isActive ? 'var(--color-primary)' : 'var(--color-icon)'
|
||||
|
||||
@ -154,13 +131,9 @@ const ThinkingButton: FC<Props> = ({ ref, model, assistant, ToolbarButton }): Re
|
||||
|
||||
// 获取当前应显示的图标
|
||||
const getThinkingIcon = useCallback(() => {
|
||||
// 如果当前选项不支持,显示回退选项的图标
|
||||
if (currentReasoningEffort && !supportedOptions.includes(currentReasoningEffort)) {
|
||||
const fallbackOption = OPTION_FALLBACK[currentReasoningEffort as ThinkingOption]
|
||||
return createThinkingIcon(fallbackOption, true)
|
||||
}
|
||||
// 不再判断选项是否支持,依赖 useAssistant 更新选项为支持选项的行为
|
||||
return createThinkingIcon(currentReasoningEffort, currentReasoningEffort !== 'off')
|
||||
}, [createThinkingIcon, currentReasoningEffort, supportedOptions])
|
||||
}, [createThinkingIcon, currentReasoningEffort])
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
openQuickPanel
|
||||
|
||||
@ -52,38 +52,29 @@ export type AssistantSettingCustomParameters = {
|
||||
type: 'string' | 'number' | 'boolean' | 'json'
|
||||
}
|
||||
|
||||
export type ReasoningEffortOption = NonNullable<OpenAI.ReasoningEffort> | 'auto'
|
||||
export type ThinkingOption = ReasoningEffortOption | 'off'
|
||||
export type ThinkingModelType =
|
||||
| 'default'
|
||||
| 'o'
|
||||
| 'gpt5'
|
||||
| 'grok'
|
||||
| 'gemini'
|
||||
| 'gemini_pro'
|
||||
| 'qwen'
|
||||
| 'qwen_thinking'
|
||||
| 'doubao'
|
||||
| 'hunyuan'
|
||||
| 'zhipu'
|
||||
| 'perplexity'
|
||||
export type ThinkingOptionConfig = Record<ThinkingModelType, ThinkingOption[]>
|
||||
export type ReasoningEffortConfig = Record<ThinkingModelType, ReasoningEffortOption[]>
|
||||
export type EffortRatio = Record<ReasoningEffortOption, number>
|
||||
|
||||
const ThinkModelTypes: ThinkingModelType[] = [
|
||||
const ThinkModelTypes = [
|
||||
'default',
|
||||
'o',
|
||||
'gpt5',
|
||||
'grok',
|
||||
'gemini',
|
||||
'gemini_pro',
|
||||
'qwen',
|
||||
'qwen_thinking',
|
||||
'doubao',
|
||||
'doubao_no_auto',
|
||||
'hunyuan',
|
||||
'zhipu',
|
||||
'perplexity'
|
||||
] as const
|
||||
|
||||
export type ReasoningEffortOption = NonNullable<OpenAI.ReasoningEffort> | 'auto'
|
||||
export type ThinkingOption = ReasoningEffortOption | 'off'
|
||||
export type ThinkingModelType = (typeof ThinkModelTypes)[number]
|
||||
export type ThinkingOptionConfig = Record<ThinkingModelType, ThinkingOption[]>
|
||||
export type ReasoningEffortConfig = Record<ThinkingModelType, ReasoningEffortOption[]>
|
||||
export type EffortRatio = Record<ReasoningEffortOption, number>
|
||||
|
||||
export function isThinkModelType(type: string): type is ThinkingModelType {
|
||||
return ThinkModelTypes.some((t) => t === type)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user