feat: 后端修改前端智能助手设置 (#597)

This commit is contained in:
jxxghp
2026-07-30 13:32:19 +08:00
committed by GitHub
parent 01e7dcee56
commit 6104fb861e
7 changed files with 116 additions and 36 deletions
+11 -8
View File
@@ -85,6 +85,7 @@ interface UseLlmProviderDirectoryOptions {
baseUrlPreset?: Ref<string> baseUrlPreset?: Ref<string>
useProxy?: Ref<boolean> useProxy?: Ref<boolean>
userAgent?: Ref<string> userAgent?: Ref<string>
apiProtocol?: Ref<string>
model: Ref<string> model: Ref<string>
maxContextTokens?: Ref<number> maxContextTokens?: Ref<number>
authConnected?: Ref<boolean> authConnected?: Ref<boolean>
@@ -122,10 +123,12 @@ export function useLlmProviderDirectory(options: UseLlmProviderDirectoryOptions)
})), })),
) )
const providerConnected = computed(() => Boolean(selectedProvider.value?.auth_status?.connected)) const providerConnected = computed(() => Boolean(selectedProvider.value?.auth_status?.connected))
const showBaseUrlField = computed( const showBaseUrlField = computed(() =>
() => Boolean(selectedProvider.value && (selectedProvider.value.oauth_methods || []).length === 0), Boolean(selectedProvider.value && (selectedProvider.value.oauth_methods || []).length === 0),
) )
const showApiKeyField = computed(() => selectedProvider.value?.supports_api_key !== false) const showApiKeyField = computed(() => selectedProvider.value?.supports_api_key !== false)
// OpenAI 兼容接口才需要选择 API 协议(Chat Completions / Responses)。
const showApiProtocolField = computed(() => selectedProvider.value?.runtime === 'openai')
const hasUsableCredential = computed(() => { const hasUsableCredential = computed(() => {
if (providerConnected.value) return true if (providerConnected.value) return true
return Boolean(normalizeValue(options.apiKey.value)) return Boolean(normalizeValue(options.apiKey.value))
@@ -195,6 +198,9 @@ export function useLlmProviderDirectory(options: UseLlmProviderDirectoryOptions)
if (options.maxContextTokens) { if (options.maxContextTokens) {
options.maxContextTokens.value = 64 options.maxContextTokens.value = 64
} }
if (options.apiProtocol) {
options.apiProtocol.value = 'auto'
}
models.value = [] models.value = []
options.model.value = '' options.model.value = ''
syncAuthConnected() syncAuthConnected()
@@ -269,9 +275,7 @@ export function useLlmProviderDirectory(options: UseLlmProviderDirectoryOptions)
updateProviderAuthStatus(normalizeValue(options.provider.value), payload.auth_status) updateProviderAuthStatus(normalizeValue(options.provider.value), payload.auth_status)
const currentModelId = normalizeValue(options.model.value) const currentModelId = normalizeValue(options.model.value)
const matchedModel = currentModelId const matchedModel = currentModelId ? models.value.find(item => item.id === currentModelId) : null
? models.value.find(item => item.id === currentModelId)
: null
if (matchedModel) { if (matchedModel) {
applyModelMetadata(matchedModel.id) applyModelMetadata(matchedModel.id)
@@ -301,9 +305,7 @@ export function useLlmProviderDirectory(options: UseLlmProviderDirectoryOptions)
authPolling.value = true authPolling.value = true
clearPollTimer() clearPollTimer()
try { try {
const result: { [key: string]: any } = await api.post( const result: { [key: string]: any } = await api.post(`llm/provider-auth/${authSession.value.session_id}/poll`)
`llm/provider-auth/${authSession.value.session_id}/poll`,
)
if (!result.success) { if (!result.success) {
throw new Error(result.message || 'Poll LLM auth failed') throw new Error(result.message || 'Poll LLM auth failed')
} }
@@ -393,6 +395,7 @@ export function useLlmProviderDirectory(options: UseLlmProviderDirectoryOptions)
providerConnected, providerConnected,
showBaseUrlField, showBaseUrlField,
showApiKeyField, showApiKeyField,
showApiProtocolField,
hasUsableCredential, hasUsableCredential,
canRefreshModels, canRefreshModels,
setBaseUrlPreset, setBaseUrlPreset,
+13 -8
View File
@@ -56,6 +56,7 @@ export interface WizardData {
authConnected: boolean authConnected: boolean
model: string model: string
thinkingLevel: string thinkingLevel: string
apiProtocol: string
supportImageInput: boolean supportImageInput: boolean
supportAudioInput: boolean supportAudioInput: boolean
supportAudioOutput: boolean supportAudioOutput: boolean
@@ -142,7 +143,9 @@ export interface ValidationErrorState {
} }
function normalizeThinkingLevelValue(value?: unknown) { function normalizeThinkingLevelValue(value?: unknown) {
const normalized = String(value ?? '').trim().toLowerCase() const normalized = String(value ?? '')
.trim()
.toLowerCase()
if (!normalized) return '' if (!normalized) return ''
const aliasMap: Record<string, string> = { const aliasMap: Record<string, string> = {
@@ -245,6 +248,7 @@ const wizardData = ref<WizardData>({
authConnected: false, authConnected: false,
model: 'deepseek-chat', model: 'deepseek-chat',
thinkingLevel: 'off', thinkingLevel: 'off',
apiProtocol: 'auto',
supportImageInput: true, supportImageInput: true,
supportAudioInput: false, supportAudioInput: false,
supportAudioOutput: false, supportAudioOutput: false,
@@ -593,10 +597,7 @@ export function useSetupWizard() {
errors.push(t('downloader.passwordRequired')) errors.push(t('downloader.passwordRequired'))
validationErrors.value.downloader.password = true validationErrors.value.downloader.password = true
} }
} else if ( } else if (wizardData.value.downloader.type === 'transmission' || wizardData.value.downloader.type === 'rtorrent') {
wizardData.value.downloader.type === 'transmission'
|| wizardData.value.downloader.type === 'rtorrent'
) {
if (!wizardData.value.downloader.config?.username?.trim()) { if (!wizardData.value.downloader.config?.username?.trim()) {
errors.push(t('downloader.usernameRequired')) errors.push(t('downloader.usernameRequired'))
validationErrors.value.downloader.username = true validationErrors.value.downloader.username = true
@@ -799,7 +800,10 @@ export function useSetupWizard() {
validationErrors.value.agent.maxContextTokens = true validationErrors.value.agent.maxContextTokens = true
} }
if (wizardData.value.agent.recommendEnabled && (!wizardData.value.agent.recommendMaxItems || wizardData.value.agent.recommendMaxItems < 1)) { if (
wizardData.value.agent.recommendEnabled &&
(!wizardData.value.agent.recommendMaxItems || wizardData.value.agent.recommendMaxItems < 1)
) {
errors.push(t('setupWizard.agent.recommendMaxItemsRequired')) errors.push(t('setupWizard.agent.recommendMaxItemsRequired'))
validationErrors.value.agent.recommendMaxItems = true validationErrors.value.agent.recommendMaxItems = true
} }
@@ -1446,6 +1450,7 @@ export function useSetupWizard() {
LLM_PROVIDER: wizardData.value.agent.provider, LLM_PROVIDER: wizardData.value.agent.provider,
LLM_MODEL: wizardData.value.agent.model, LLM_MODEL: wizardData.value.agent.model,
LLM_THINKING_LEVEL: wizardData.value.agent.thinkingLevel, LLM_THINKING_LEVEL: wizardData.value.agent.thinkingLevel,
LLM_API_PROTOCOL: wizardData.value.agent.apiProtocol || 'auto',
LLM_SUPPORT_IMAGE_INPUT: wizardData.value.agent.supportImageInput, LLM_SUPPORT_IMAGE_INPUT: wizardData.value.agent.supportImageInput,
LLM_SUPPORT_AUDIO_INPUT: wizardData.value.agent.supportAudioInput, LLM_SUPPORT_AUDIO_INPUT: wizardData.value.agent.supportAudioInput,
LLM_SUPPORT_AUDIO_OUTPUT: wizardData.value.agent.supportAudioOutput, LLM_SUPPORT_AUDIO_OUTPUT: wizardData.value.agent.supportAudioOutput,
@@ -1469,8 +1474,7 @@ export function useSetupWizard() {
AUDIO_OUTPUT_INCLUDE_TEXT: wizardData.value.agent.audioOutputIncludeText, AUDIO_OUTPUT_INCLUDE_TEXT: wizardData.value.agent.audioOutputIncludeText,
AI_AGENT_JOB_INTERVAL: wizardData.value.agent.enabled ? wizardData.value.agent.jobInterval : 0, AI_AGENT_JOB_INTERVAL: wizardData.value.agent.enabled ? wizardData.value.agent.jobInterval : 0,
AI_AGENT_RETRY_TRANSFER: wizardData.value.agent.enabled ? wizardData.value.agent.retryTransfer : false, AI_AGENT_RETRY_TRANSFER: wizardData.value.agent.enabled ? wizardData.value.agent.retryTransfer : false,
AI_RECOMMEND_ENABLED: AI_RECOMMEND_ENABLED: wizardData.value.agent.enabled && wizardData.value.agent.recommendEnabled,
wizardData.value.agent.enabled && wizardData.value.agent.recommendEnabled,
AI_RECOMMEND_USER_PREFERENCE: wizardData.value.agent.recommendUserPreference, AI_RECOMMEND_USER_PREFERENCE: wizardData.value.agent.recommendUserPreference,
AI_RECOMMEND_MAX_ITEMS: wizardData.value.agent.recommendMaxItems, AI_RECOMMEND_MAX_ITEMS: wizardData.value.agent.recommendMaxItems,
} }
@@ -1562,6 +1566,7 @@ export function useSetupWizard() {
wizardData.value.agent.authConnected = false wizardData.value.agent.authConnected = false
wizardData.value.agent.model = result.data.LLM_MODEL || '' wizardData.value.agent.model = result.data.LLM_MODEL || ''
wizardData.value.agent.thinkingLevel = resolveThinkingLevelValue(result.data) wizardData.value.agent.thinkingLevel = resolveThinkingLevelValue(result.data)
wizardData.value.agent.apiProtocol = result.data.LLM_API_PROTOCOL || 'auto'
wizardData.value.agent.supportImageInput = result.data.LLM_SUPPORT_IMAGE_INPUT ?? true wizardData.value.agent.supportImageInput = result.data.LLM_SUPPORT_IMAGE_INPUT ?? true
wizardData.value.agent.supportAudioInput = Boolean(result.data.LLM_SUPPORT_AUDIO_INPUT) wizardData.value.agent.supportAudioInput = Boolean(result.data.LLM_SUPPORT_AUDIO_INPUT)
wizardData.value.agent.supportAudioOutput = Boolean(result.data.LLM_SUPPORT_AUDIO_OUTPUT) wizardData.value.agent.supportAudioOutput = Boolean(result.data.LLM_SUPPORT_AUDIO_OUTPUT)
+6
View File
@@ -1799,6 +1799,12 @@ export default {
'When enabled, Agent connections to the current LLM provider use the system proxy from advanced settings.', 'When enabled, Agent connections to the current LLM provider use the system proxy from advanced settings.',
llmUserAgent: 'User-Agent', llmUserAgent: 'User-Agent',
llmUserAgentHint: 'User-Agent sent to OpenAI-compatible APIs. Leave empty to use the SDK default.', llmUserAgentHint: 'User-Agent sent to OpenAI-compatible APIs. Leave empty to use the SDK default.',
llmApiProtocol: 'API Protocol',
llmApiProtocolHint:
'Request protocol for OpenAI-compatible APIs: auto-select by model capability, or force Chat Completions / Responses.',
llmApiProtocolAuto: 'Auto (auto)',
llmApiProtocolChatCompletions: 'Chat Completions',
llmApiProtocolResponses: 'Responses',
llmTemperature: 'Temperature', llmTemperature: 'Temperature',
llmTemperatureHint: llmTemperatureHint:
'Controls response randomness. Lower values are steadier and higher values are more varied. Backend default is 0.3; 0-2 is usually recommended.', 'Controls response randomness. Lower values are steadier and higher values are more varied. Backend default is 0.3; 0-2 is usually recommended.',
+5
View File
@@ -1784,6 +1784,11 @@ export default {
llmUseProxyHint: '启用后,Agent 连接当前 LLM 提供商时会应用高级设置中的系统代理', llmUseProxyHint: '启用后,Agent 连接当前 LLM 提供商时会应用高级设置中的系统代理',
llmUserAgent: 'User-Agent', llmUserAgent: 'User-Agent',
llmUserAgentHint: 'OpenAI 兼容接口请求使用的 User-Agent,留空则使用 SDK 默认值', llmUserAgentHint: 'OpenAI 兼容接口请求使用的 User-Agent,留空则使用 SDK 默认值',
llmApiProtocol: 'API 协议',
llmApiProtocolHint: 'OpenAI 兼容接口的请求协议:自动按模型能力选择,或强制使用 Chat Completions / Responses',
llmApiProtocolAuto: '自动 (auto)',
llmApiProtocolChatCompletions: 'Chat Completions',
llmApiProtocolResponses: 'Responses',
llmTemperature: '温度参数', llmTemperature: '温度参数',
llmTemperatureHint: '控制回复随机性,数值越低越稳定,越高越发散;后端默认 0.3,通常建议 0-2', llmTemperatureHint: '控制回复随机性,数值越低越稳定,越高越发散;后端默认 0.3,通常建议 0-2',
llmProviderAuth: '提供商授权', llmProviderAuth: '提供商授权',
+5
View File
@@ -1783,6 +1783,11 @@ export default {
llmUseProxyHint: '啟用後,Agent 連接目前 LLM 提供商時會套用進階設定中的系統代理', llmUseProxyHint: '啟用後,Agent 連接目前 LLM 提供商時會套用進階設定中的系統代理',
llmUserAgent: 'User-Agent', llmUserAgent: 'User-Agent',
llmUserAgentHint: 'OpenAI 兼容接口請求使用的 User-Agent,留空則使用 SDK 預設值', llmUserAgentHint: 'OpenAI 兼容接口請求使用的 User-Agent,留空則使用 SDK 預設值',
llmApiProtocol: 'API 協議',
llmApiProtocolHint: 'OpenAI 兼容接口的請求協議:自動按模型能力選擇,或強制使用 Chat Completions / Responses',
llmApiProtocolAuto: '自動 (auto)',
llmApiProtocolChatCompletions: 'Chat Completions',
llmApiProtocolResponses: 'Responses',
llmTemperature: '溫度參數', llmTemperature: '溫度參數',
llmTemperatureHint: '控制回覆隨機性,數值越低越穩定,越高越發散;後端預設 0.3,通常建議 0-2', llmTemperatureHint: '控制回覆隨機性,數值越低越穩定,越高越發散;後端預設 0.3,通常建議 0-2',
llmProviderAuth: '提供商授權', llmProviderAuth: '提供商授權',
+31 -6
View File
@@ -53,6 +53,7 @@ const SystemSettings = ref<any>({
LLM_PROVIDER: 'deepseek', LLM_PROVIDER: 'deepseek',
LLM_MODEL: 'deepseek-chat', LLM_MODEL: 'deepseek-chat',
LLM_THINKING_LEVEL: 'off', LLM_THINKING_LEVEL: 'off',
LLM_API_PROTOCOL: 'auto',
LLM_SUPPORT_IMAGE_INPUT: false, LLM_SUPPORT_IMAGE_INPUT: false,
LLM_SUPPORT_AUDIO_INPUT: false, LLM_SUPPORT_AUDIO_INPUT: false,
LLM_SUPPORT_AUDIO_OUTPUT: false, LLM_SUPPORT_AUDIO_OUTPUT: false,
@@ -221,6 +222,7 @@ type LlmSettingsSnapshot = {
LLM_PROVIDER: string LLM_PROVIDER: string
LLM_MODEL: string LLM_MODEL: string
LLM_THINKING_LEVEL: string LLM_THINKING_LEVEL: string
LLM_API_PROTOCOL: string
LLM_API_KEY: string LLM_API_KEY: string
LLM_BASE_URL: string LLM_BASE_URL: string
LLM_USE_PROXY: boolean LLM_USE_PROXY: boolean
@@ -292,6 +294,13 @@ const llmUserAgentRef = computed({
}, },
}) })
const llmApiProtocolRef = computed({
get: () => String(SystemSettings.value.Basic.LLM_API_PROTOCOL ?? 'auto'),
set: value => {
SystemSettings.value.Basic.LLM_API_PROTOCOL = value || 'auto'
},
})
const llmModelRef = computed({ const llmModelRef = computed({
get: () => String(SystemSettings.value.Basic.LLM_MODEL ?? ''), get: () => String(SystemSettings.value.Basic.LLM_MODEL ?? ''),
set: value => { set: value => {
@@ -317,6 +326,7 @@ const {
providerConnected, providerConnected,
showBaseUrlField, showBaseUrlField,
showApiKeyField, showApiKeyField,
showApiProtocolField: showLlmApiProtocolField,
canRefreshModels, canRefreshModels,
setBaseUrlPreset, setBaseUrlPreset,
authDialogVisible, authDialogVisible,
@@ -339,6 +349,7 @@ const {
baseUrlPreset: llmBaseUrlPresetRef, baseUrlPreset: llmBaseUrlPresetRef,
useProxy: llmUseProxyRef, useProxy: llmUseProxyRef,
userAgent: llmUserAgentRef, userAgent: llmUserAgentRef,
apiProtocol: llmApiProtocolRef,
model: llmModelRef, model: llmModelRef,
maxContextTokens: llmMaxContextRef, maxContextTokens: llmMaxContextRef,
}) })
@@ -397,6 +408,7 @@ function buildLlmSnapshot(): LlmSettingsSnapshot {
LLM_PROVIDER: String(SystemSettings.value.Basic.LLM_PROVIDER ?? ''), LLM_PROVIDER: String(SystemSettings.value.Basic.LLM_PROVIDER ?? ''),
LLM_MODEL: String(SystemSettings.value.Basic.LLM_MODEL ?? ''), LLM_MODEL: String(SystemSettings.value.Basic.LLM_MODEL ?? ''),
LLM_THINKING_LEVEL: String(SystemSettings.value.Basic.LLM_THINKING_LEVEL ?? 'off'), LLM_THINKING_LEVEL: String(SystemSettings.value.Basic.LLM_THINKING_LEVEL ?? 'off'),
LLM_API_PROTOCOL: String(SystemSettings.value.Basic.LLM_API_PROTOCOL ?? 'auto'),
LLM_API_KEY: String(SystemSettings.value.Basic.LLM_API_KEY ?? ''), LLM_API_KEY: String(SystemSettings.value.Basic.LLM_API_KEY ?? ''),
LLM_BASE_URL: String(SystemSettings.value.Basic.LLM_BASE_URL ?? ''), LLM_BASE_URL: String(SystemSettings.value.Basic.LLM_BASE_URL ?? ''),
LLM_USE_PROXY: Boolean(SystemSettings.value.Basic.LLM_USE_PROXY), LLM_USE_PROXY: Boolean(SystemSettings.value.Basic.LLM_USE_PROXY),
@@ -416,6 +428,7 @@ function buildLlmTestPayload(snapshot: LlmSettingsSnapshot) {
provider: snapshot.LLM_PROVIDER.trim(), provider: snapshot.LLM_PROVIDER.trim(),
model: snapshot.LLM_MODEL.trim(), model: snapshot.LLM_MODEL.trim(),
thinking_level: snapshot.LLM_THINKING_LEVEL.trim(), thinking_level: snapshot.LLM_THINKING_LEVEL.trim(),
api_protocol: snapshot.LLM_API_PROTOCOL.trim() || 'auto',
api_key: snapshot.LLM_API_KEY.trim(), api_key: snapshot.LLM_API_KEY.trim(),
base_url: snapshot.LLM_BASE_URL.trim(), base_url: snapshot.LLM_BASE_URL.trim(),
use_proxy: snapshot.LLM_USE_PROXY, use_proxy: snapshot.LLM_USE_PROXY,
@@ -513,6 +526,12 @@ const thinkingLevelItems = computed(() => [
{ title: t('setting.system.llmThinkingLevelXhigh'), value: 'xhigh' }, { title: t('setting.system.llmThinkingLevelXhigh'), value: 'xhigh' },
]) ])
const apiProtocolItems = computed(() => [
{ title: t('setting.system.llmApiProtocolAuto'), value: 'auto' },
{ title: t('setting.system.llmApiProtocolChatCompletions'), value: 'chat_completions' },
{ title: t('setting.system.llmApiProtocolResponses'), value: 'responses' },
])
const activeTab = ref('system') const activeTab = ref('system')
// //
@@ -608,9 +627,7 @@ function addSecurityDomain() {
function addImageProxyAllowedPrivateRange() { function addImageProxyAllowedPrivateRange() {
if ( if (
newImageProxyAllowedPrivateRange.value && newImageProxyAllowedPrivateRange.value &&
!SystemSettings.value.Advanced.IMAGE_PROXY_ALLOWED_PRIVATE_RANGES.includes( !SystemSettings.value.Advanced.IMAGE_PROXY_ALLOWED_PRIVATE_RANGES.includes(newImageProxyAllowedPrivateRange.value)
newImageProxyAllowedPrivateRange.value,
)
) { ) {
SystemSettings.value.Advanced.IMAGE_PROXY_ALLOWED_PRIVATE_RANGES.push(newImageProxyAllowedPrivateRange.value) SystemSettings.value.Advanced.IMAGE_PROXY_ALLOWED_PRIVATE_RANGES.push(newImageProxyAllowedPrivateRange.value)
newImageProxyAllowedPrivateRange.value = '' newImageProxyAllowedPrivateRange.value = ''
@@ -1214,6 +1231,16 @@ watch(currentLlmSnapshotKey, (snapshotKey, previousSnapshotKey) => {
@update:model-value="handleLlmProviderChanged" @update:model-value="handleLlmProviderChanged"
/> />
</VCol> </VCol>
<VCol v-if="SystemSettings.Basic.AI_AGENT_ENABLE && showLlmApiProtocolField" cols="12" md="6">
<VSelect
v-model="SystemSettings.Basic.LLM_API_PROTOCOL"
:label="t('setting.system.llmApiProtocol')"
:hint="t('setting.system.llmApiProtocolHint')"
persistent-hint
:items="apiProtocolItems"
prepend-inner-icon="mdi-swap-horizontal"
/>
</VCol>
<VCol v-if="SystemSettings.Basic.AI_AGENT_ENABLE && showBaseUrlField" cols="12" md="6"> <VCol v-if="SystemSettings.Basic.AI_AGENT_ENABLE && showBaseUrlField" cols="12" md="6">
<VCombobox <VCombobox
:model-value="SystemSettings.Basic.LLM_BASE_URL" :model-value="SystemSettings.Basic.LLM_BASE_URL"
@@ -2265,9 +2292,7 @@ watch(currentLlmSnapshotKey, (snapshotKey, previousSnapshotKey) => {
v-for="(range, index) in SystemSettings.Advanced.IMAGE_PROXY_ALLOWED_PRIVATE_RANGES" v-for="(range, index) in SystemSettings.Advanced.IMAGE_PROXY_ALLOWED_PRIVATE_RANGES"
:key="index" :key="index"
closable closable
@click:close=" @click:close="SystemSettings.Advanced.IMAGE_PROXY_ALLOWED_PRIVATE_RANGES.splice(index, 1)"
SystemSettings.Advanced.IMAGE_PROXY_ALLOWED_PRIVATE_RANGES.splice(index, 1)
"
> >
{{ range }} {{ range }}
</VChip> </VChip>
+45 -14
View File
@@ -54,6 +54,13 @@ const userAgentRef = computed({
}, },
}) })
const apiProtocolRef = computed({
get: () => wizardData.value.agent.apiProtocol,
set: value => {
wizardData.value.agent.apiProtocol = value || 'auto'
},
})
const modelRef = computed({ const modelRef = computed({
get: () => wizardData.value.agent.model, get: () => wizardData.value.agent.model,
set: value => { set: value => {
@@ -86,6 +93,7 @@ const {
providerConnected, providerConnected,
showBaseUrlField, showBaseUrlField,
showApiKeyField, showApiKeyField,
showApiProtocolField,
canRefreshModels, canRefreshModels,
setBaseUrlPreset, setBaseUrlPreset,
authDialogVisible, authDialogVisible,
@@ -108,6 +116,7 @@ const {
baseUrlPreset: baseUrlPresetRef, baseUrlPreset: baseUrlPresetRef,
useProxy: useProxyRef, useProxy: useProxyRef,
userAgent: userAgentRef, userAgent: userAgentRef,
apiProtocol: apiProtocolRef,
model: modelRef, model: modelRef,
maxContextTokens: maxContextTokensRef, maxContextTokens: maxContextTokensRef,
authConnected: authConnectedRef, authConnected: authConnectedRef,
@@ -183,6 +192,12 @@ const thinkingLevelItems = computed(() => [
{ title: t('setting.system.llmThinkingLevelXhigh'), value: 'xhigh' }, { title: t('setting.system.llmThinkingLevelXhigh'), value: 'xhigh' },
]) ])
const apiProtocolItems = computed(() => [
{ title: t('setting.system.llmApiProtocolAuto'), value: 'auto' },
{ title: t('setting.system.llmApiProtocolChatCompletions'), value: 'chat_completions' },
{ title: t('setting.system.llmApiProtocolResponses'), value: 'responses' },
])
const audioProviderItems = computed(() => [ const audioProviderItems = computed(() => [
{ title: t('setting.system.audioProviderOpenAiAudio'), value: 'openai' }, { title: t('setting.system.audioProviderOpenAiAudio'), value: 'openai' },
{ title: t('setting.system.audioProviderChatAudio'), value: 'openai_chat_audio' }, { title: t('setting.system.audioProviderChatAudio'), value: 'openai_chat_audio' },
@@ -324,16 +339,30 @@ onMounted(async () => {
/> />
</VCol> </VCol>
<VCol v-if="showApiProtocolField" cols="12" md="6">
<VSelect
v-model="wizardData.agent.apiProtocol"
:label="t('setting.system.llmApiProtocol')"
:hint="t('setting.system.llmApiProtocolHint')"
:items="apiProtocolItems"
persistent-hint
prepend-inner-icon="mdi-swap-horizontal"
color="primary"
/>
</VCol>
<VCol v-if="showBaseUrlField" cols="12" md="6"> <VCol v-if="showBaseUrlField" cols="12" md="6">
<VCombobox <VCombobox
:model-value="wizardData.agent.baseUrl" :model-value="wizardData.agent.baseUrl"
@update:model-value="(value: any) => { @update:model-value="
if (typeof value === 'object' && value !== null) { (value: any) => {
setBaseUrlPreset(value.id, value.value); if (typeof value === 'object' && value !== null) {
} else { setBaseUrlPreset(value.id, value.value)
setBaseUrlPreset('', value || ''); } else {
setBaseUrlPreset('', value || '')
}
} }
}" "
:label="t('setting.system.llmBaseUrl')" :label="t('setting.system.llmBaseUrl')"
:hint="t('setting.system.llmBaseUrlHint')" :hint="t('setting.system.llmBaseUrlHint')"
:placeholder="selectedProvider?.default_base_url || 'https://api.deepseek.com'" :placeholder="selectedProvider?.default_base_url || 'https://api.deepseek.com'"
@@ -366,9 +395,7 @@ onMounted(async () => {
:hint="selectedProvider?.api_key_hint || t('setting.system.llmApiKeyHint')" :hint="selectedProvider?.api_key_hint || t('setting.system.llmApiKeyHint')"
:placeholder="t('setting.system.llmApiKeyPlaceholder')" :placeholder="t('setting.system.llmApiKeyPlaceholder')"
:error="validationErrors.agent.apiKey" :error="validationErrors.agent.apiKey"
:error-messages=" :error-messages="validationErrors.agent.apiKey ? [t('setupWizard.agent.authOrApiKeyRequired')] : []"
validationErrors.agent.apiKey ? [t('setupWizard.agent.authOrApiKeyRequired')] : []
"
persistent-hint persistent-hint
prepend-inner-icon="mdi-key-variant" prepend-inner-icon="mdi-key-variant"
type="password" type="password"
@@ -384,7 +411,9 @@ onMounted(async () => {
{{ selectedProvider?.description || t('setting.system.llmProviderAuthHint') }} {{ selectedProvider?.description || t('setting.system.llmProviderAuthHint') }}
</div> </div>
<div v-if="providerConnected" class="text-body-2 mt-2"> <div v-if="providerConnected" class="text-body-2 mt-2">
{{ t('setting.system.llmProviderConnectedAs', { label: providerAuthLabel || selectedProvider?.name }) }} {{
t('setting.system.llmProviderConnectedAs', { label: providerAuthLabel || selectedProvider?.name })
}}
</div> </div>
</div> </div>
@@ -417,10 +446,12 @@ onMounted(async () => {
<VCol cols="12" md="6"> <VCol cols="12" md="6">
<VCombobox <VCombobox
:model-value="wizardData.agent.model" :model-value="wizardData.agent.model"
@update:model-value="(val: any) => { @update:model-value="
wizardData.agent.model = typeof val === 'object' && val !== null ? val.id : val; (val: any) => {
handleModelChanged(); wizardData.agent.model = typeof val === 'object' && val !== null ? val.id : val
}" handleModelChanged()
}
"
:label="t('setting.system.llmModel')" :label="t('setting.system.llmModel')"
:hint="t('setting.system.llmModelHint')" :hint="t('setting.system.llmModelHint')"
:items="llmModels" :items="llmModels"