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:
Mark Xian
2026-08-14 19:53:14 +08:00
committed by GitHub
co-authored by 冼健聪 RainbowBird
parent 133df1f1e6
commit c71de3a0b1
5 changed files with 151 additions and 1 deletions
@@ -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 BananaGemini 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) {