feat(stage-ui): add DeepSeek thinking mode toggle (#2280)
Co-authored-by: 冼健聪 <mark.xian@evenrealities.com> Co-authored-by: RainbowBird <git@luoling.moe>
This commit is contained in:
co-authored by
冼健聪
RainbowBird
parent
133df1f1e6
commit
c71de3a0b1
@@ -1245,6 +1245,10 @@ pages:
|
||||
nano_banana: Nano Banana (Gemini 2.5 Flash Image)
|
||||
deepseek:
|
||||
description: deepseek.com
|
||||
fields:
|
||||
field:
|
||||
thinking-mode:
|
||||
description: Controls whether DeepSeek reasoning models use thinking in chat requests.
|
||||
title: DeepSeek
|
||||
elevenlabs:
|
||||
description: elevenlabs.io
|
||||
|
||||
@@ -1191,6 +1191,10 @@ pages:
|
||||
nano_banana: Nano Banana(Gemini 2.5 Flash Image)
|
||||
deepseek:
|
||||
description: DeepSeek.com
|
||||
fields:
|
||||
field:
|
||||
thinking-mode:
|
||||
description: 控制 DeepSeek 推理模型是否在聊天请求中启用深度思考。
|
||||
title: 深度求索 DeepSeek
|
||||
elevenlabs:
|
||||
description: Elevenlabs.io
|
||||
|
||||
@@ -14,6 +14,7 @@ import { useProviderValidation } from '@proj-airi/stage-ui/composables/use-provi
|
||||
import { getDefinedProvider } from '@proj-airi/stage-ui/libs'
|
||||
import { useConsciousnessStore } from '@proj-airi/stage-ui/stores/modules/consciousness'
|
||||
import { useProviderConfigStore } from '@proj-airi/stage-ui/stores/providers/config'
|
||||
import { FieldCombobox } from '@proj-airi/ui'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
@@ -44,6 +45,17 @@ const baseUrl = computed({
|
||||
},
|
||||
})
|
||||
|
||||
const thinkingMode = computed({
|
||||
get: () => providers.value[providerId]?.thinkingMode || 'auto',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
providers.value[providerId].thinkingMode = value
|
||||
},
|
||||
})
|
||||
|
||||
const supportsDeepSeekThinkingMode = computed(() => providerId === 'deepseek')
|
||||
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
@@ -107,6 +119,18 @@ function goToModelSelection() {
|
||||
v-model="baseUrl"
|
||||
:placeholder="providerMetadata?.defaultConfig.baseUrl as string || 'Base URL of your provider'"
|
||||
/>
|
||||
|
||||
<FieldCombobox
|
||||
v-if="supportsDeepSeekThinkingMode"
|
||||
v-model="thinkingMode"
|
||||
:label="t('settings.pages.providers.catalog.edit.config.common.fields.field.thinking-mode.label')"
|
||||
:description="t('settings.pages.providers.provider.deepseek.fields.field.thinking-mode.description')"
|
||||
:options="[
|
||||
{ label: t('settings.pages.providers.catalog.edit.config.common.fields.field.thinking-mode.options.auto'), value: 'auto' },
|
||||
{ label: t('settings.pages.providers.catalog.edit.config.common.fields.field.thinking-mode.options.disable'), value: 'disable' },
|
||||
{ label: t('settings.pages.providers.catalog.edit.config.common.fields.field.thinking-mode.options.enable'), value: 'enable' },
|
||||
]"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<ProviderValidationAlerts
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import type {
|
||||
ChatProvider,
|
||||
ChatProviderWithExtraOptions,
|
||||
} from '@xsai-ext/providers/utils'
|
||||
|
||||
import type { ProviderInstance } from '../../types'
|
||||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { providerDeepSeek } from './index'
|
||||
|
||||
type DeepSeekChatProvider = ChatProvider | ChatProviderWithExtraOptions
|
||||
|
||||
function isDeepSeekChatProvider(provider: ProviderInstance): provider is DeepSeekChatProvider {
|
||||
return 'chat' in provider && typeof provider.chat === 'function'
|
||||
}
|
||||
|
||||
function createDeepSeekChatProvider(
|
||||
thinkingMode: 'auto' | 'disable' | 'enable',
|
||||
): DeepSeekChatProvider {
|
||||
const provider = providerDeepSeek.createProvider({
|
||||
apiKey: 'sk-test',
|
||||
baseUrl: 'https://api.deepseek.com/',
|
||||
thinkingMode,
|
||||
})
|
||||
|
||||
if (!isDeepSeekChatProvider(provider))
|
||||
throw new Error('DeepSeek provider must support chat')
|
||||
|
||||
return provider
|
||||
}
|
||||
|
||||
describe('providerDeepSeek.createProvider chat options', () => {
|
||||
it('should not set thinking when thinkingMode is auto', () => {
|
||||
const provider = createDeepSeekChatProvider('auto')
|
||||
|
||||
expect(provider.chat('deepseek-chat')).not.toHaveProperty('thinking')
|
||||
})
|
||||
|
||||
it('should set thinking disabled when thinkingMode is disable', () => {
|
||||
const provider = createDeepSeekChatProvider('disable')
|
||||
|
||||
expect(provider.chat('deepseek-chat')).toMatchObject({
|
||||
thinking: { type: 'disabled' },
|
||||
})
|
||||
})
|
||||
|
||||
it('should set thinking enabled when thinkingMode is enable', () => {
|
||||
const provider = createDeepSeekChatProvider('enable')
|
||||
|
||||
expect(provider.chat('deepseek-chat')).toMatchObject({
|
||||
thinking: { type: 'enabled' },
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -5,6 +5,8 @@ import { ProviderValidationCheck } from '../../types'
|
||||
import { createOpenAICompatibleValidators } from '../../validators'
|
||||
import { defineProvider } from '../registry'
|
||||
|
||||
type DeepSeekThinkingMode = 'auto' | 'disable' | 'enable'
|
||||
|
||||
const deepSeekConfigSchema = z.object({
|
||||
apiKey: z
|
||||
.string('API Key'),
|
||||
@@ -12,10 +14,38 @@ const deepSeekConfigSchema = z.object({
|
||||
.string('Base URL')
|
||||
.optional()
|
||||
.default('https://api.deepseek.com/'),
|
||||
thinkingMode: z.enum(['auto', 'disable', 'enable'])
|
||||
.default('auto'),
|
||||
})
|
||||
|
||||
type DeepSeekConfig = z.input<typeof deepSeekConfigSchema>
|
||||
|
||||
function normalizeDeepSeekThinkingMode(value: unknown): DeepSeekThinkingMode {
|
||||
switch (value) {
|
||||
case 'auto':
|
||||
case 'disable':
|
||||
case 'enable':
|
||||
return value
|
||||
default:
|
||||
return 'auto'
|
||||
}
|
||||
}
|
||||
|
||||
function resolveDeepSeekThinking(modeRaw: unknown): { type: 'disabled' | 'enabled' } | undefined {
|
||||
const mode = normalizeDeepSeekThinkingMode(modeRaw)
|
||||
|
||||
switch (mode) {
|
||||
case 'auto':
|
||||
return undefined
|
||||
case 'disable':
|
||||
return { type: 'disabled' }
|
||||
case 'enable':
|
||||
return { type: 'enabled' }
|
||||
default:
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
export const providerDeepSeek = defineProvider<DeepSeekConfig>({
|
||||
id: 'deepseek',
|
||||
order: 4,
|
||||
@@ -39,9 +69,42 @@ export const providerDeepSeek = defineProvider<DeepSeekConfig>({
|
||||
descriptionLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.base-url.description'),
|
||||
placeholderLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.base-url.placeholder'),
|
||||
}),
|
||||
thinkingMode: deepSeekConfigSchema.shape.thinkingMode.meta({
|
||||
labelLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.thinking-mode.label'),
|
||||
descriptionLocalized: t('settings.pages.providers.provider.deepseek.fields.field.thinking-mode.description'),
|
||||
section: 'advanced',
|
||||
type: 'select',
|
||||
options: [
|
||||
{
|
||||
label: t('settings.pages.providers.catalog.edit.config.common.fields.field.thinking-mode.options.auto'),
|
||||
value: 'auto',
|
||||
},
|
||||
{
|
||||
label: t('settings.pages.providers.catalog.edit.config.common.fields.field.thinking-mode.options.disable'),
|
||||
value: 'disable',
|
||||
},
|
||||
{
|
||||
label: t('settings.pages.providers.catalog.edit.config.common.fields.field.thinking-mode.options.enable'),
|
||||
value: 'enable',
|
||||
},
|
||||
],
|
||||
}),
|
||||
}),
|
||||
createProvider(config) {
|
||||
return createDeepSeek(config.apiKey, config.baseUrl)
|
||||
const baseProvider = createDeepSeek(config.apiKey, config.baseUrl)
|
||||
|
||||
return {
|
||||
...baseProvider,
|
||||
chat(model: string) {
|
||||
const chatOptions = baseProvider.chat(model)
|
||||
const thinking = resolveDeepSeekThinking(config.thinkingMode)
|
||||
|
||||
if (thinking === undefined)
|
||||
return chatOptions
|
||||
|
||||
return { ...chatOptions, thinking }
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
validationRequiredWhen(config) {
|
||||
|
||||
Reference in New Issue
Block a user