diff --git a/src/composables/useLlmProviderDirectory.ts b/src/composables/useLlmProviderDirectory.ts index 935f48b4..3236d29e 100644 --- a/src/composables/useLlmProviderDirectory.ts +++ b/src/composables/useLlmProviderDirectory.ts @@ -83,6 +83,7 @@ interface UseLlmProviderDirectoryOptions { apiKey: Ref baseUrl: Ref baseUrlPreset?: Ref + userAgent?: Ref model: Ref maxContextTokens?: Ref authConnected?: Ref @@ -253,6 +254,7 @@ export function useLlmProviderDirectory(options: UseLlmProviderDirectoryOptions) api_key: normalizeValue(options.apiKey.value) || undefined, base_url: normalizeValue(options.baseUrl.value) || undefined, base_url_preset: normalizeValue(options.baseUrlPreset?.value) || undefined, + user_agent: normalizeValue(options.userAgent?.value) || undefined, force_refresh: forceRefresh, }, }) diff --git a/src/composables/useSetupWizard.ts b/src/composables/useSetupWizard.ts index 2b4cdeff..c035b956 100644 --- a/src/composables/useSetupWizard.ts +++ b/src/composables/useSetupWizard.ts @@ -62,6 +62,7 @@ export interface WizardData { apiKey: string baseUrl: string baseUrlPreset: string + userAgent: string maxContextTokens: number audioInputProvider: string audioInputApiKey: string @@ -248,6 +249,7 @@ const wizardData = ref({ apiKey: '', baseUrl: 'https://api.deepseek.com', baseUrlPreset: '', + userAgent: '', maxContextTokens: 64, audioInputProvider: 'openai', audioInputApiKey: '', @@ -1445,6 +1447,7 @@ export function useSetupWizard() { LLM_API_KEY: wizardData.value.agent.apiKey, LLM_BASE_URL: wizardData.value.agent.baseUrl || null, LLM_BASE_URL_PRESET: wizardData.value.agent.baseUrlPreset || null, + LLM_USER_AGENT: wizardData.value.agent.userAgent || null, LLM_MAX_CONTEXT_TOKENS: wizardData.value.agent.maxContextTokens, AUDIO_INPUT_PROVIDER: wizardData.value.agent.audioInputProvider || 'openai', AUDIO_INPUT_API_KEY: wizardData.value.agent.audioInputApiKey || null, @@ -1558,6 +1561,7 @@ export function useSetupWizard() { wizardData.value.agent.apiKey = result.data.LLM_API_KEY || '' wizardData.value.agent.baseUrl = result.data.LLM_BASE_URL || '' wizardData.value.agent.baseUrlPreset = result.data.LLM_BASE_URL_PRESET || '' + wizardData.value.agent.userAgent = result.data.LLM_USER_AGENT || '' wizardData.value.agent.maxContextTokens = result.data.LLM_MAX_CONTEXT_TOKENS || 64 wizardData.value.agent.audioInputProvider = result.data.AUDIO_INPUT_PROVIDER || 'openai' wizardData.value.agent.audioInputApiKey = result.data.AUDIO_INPUT_API_KEY || '' diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts index a5bd8e08..5d335660 100644 --- a/src/locales/en-US.ts +++ b/src/locales/en-US.ts @@ -1456,6 +1456,8 @@ export default { llmApiKeyPlaceholder: 'Please enter API key', llmBaseUrl: 'LLM Base URL', llmBaseUrlHint: 'Base URL for LLM API, used for custom API endpoints', + llmUserAgent: 'User-Agent', + llmUserAgentHint: 'User-Agent sent to OpenAI-compatible APIs. Leave empty to use the SDK default.', llmProviderAuth: 'Provider Authorization', llmProviderAuthHint: 'Providers that support account authorization can complete sign-in here and reuse the saved auth state.', diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index c2f5d8ba..a86d7e1a 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -1448,6 +1448,8 @@ export default { llmApiKeyPlaceholder: '请输入API密钥', llmBaseUrl: 'LLM基础URL', llmBaseUrlHint: 'LLM API的基础URL地址,用于自定义API端点', + llmUserAgent: 'User-Agent', + llmUserAgentHint: 'OpenAI 兼容接口请求使用的 User-Agent,留空则使用 SDK 默认值', llmProviderAuth: '提供商授权', llmProviderAuthHint: '支持账号登录授权的提供商,可以直接在这里完成登录并复用授权状态。', llmProviderConnectedAs: '当前已连接:{label}', diff --git a/src/locales/zh-TW.ts b/src/locales/zh-TW.ts index 9faaf767..d78925f0 100644 --- a/src/locales/zh-TW.ts +++ b/src/locales/zh-TW.ts @@ -1449,6 +1449,8 @@ export default { llmApiKeyPlaceholder: '請輸入API密鑰', llmBaseUrl: 'LLM基礎URL', llmBaseUrlHint: 'LLM API的基礎URL地址,用於自定義API端點', + llmUserAgent: 'User-Agent', + llmUserAgentHint: 'OpenAI 兼容接口請求使用的 User-Agent,留空則使用 SDK 預設值', llmProviderAuth: '提供商授權', llmProviderAuthHint: '支援帳號登入授權的提供商,可以直接在這裡完成登入並重用授權狀態。', llmProviderConnectedAs: '目前已連接:{label}', diff --git a/src/views/setting/AccountSettingSystem.vue b/src/views/setting/AccountSettingSystem.vue index 30bdeb6e..5c92064e 100644 --- a/src/views/setting/AccountSettingSystem.vue +++ b/src/views/setting/AccountSettingSystem.vue @@ -58,6 +58,7 @@ const SystemSettings = ref({ LLM_API_KEY: null, LLM_BASE_URL: 'https://api.deepseek.com', LLM_BASE_URL_PRESET: null, + LLM_USER_AGENT: null, AUDIO_INPUT_PROVIDER: 'openai', AUDIO_INPUT_API_KEY: null, AUDIO_INPUT_BASE_URL: null, @@ -214,6 +215,7 @@ type LlmSettingsSnapshot = { LLM_API_KEY: string LLM_BASE_URL: string LLM_BASE_URL_PRESET: string + LLM_USER_AGENT: string } let llmTestRequestId = 0 @@ -247,6 +249,13 @@ const llmBaseUrlPresetRef = computed({ }, }) +const llmUserAgentRef = computed({ + get: () => String(SystemSettings.value.Basic.LLM_USER_AGENT ?? ''), + set: value => { + SystemSettings.value.Basic.LLM_USER_AGENT = value || '' + }, +}) + const llmModelRef = computed({ get: () => String(SystemSettings.value.Basic.LLM_MODEL ?? ''), set: value => { @@ -292,6 +301,7 @@ const { apiKey: llmApiKeyRef, baseUrl: llmBaseUrlRef, baseUrlPreset: llmBaseUrlPresetRef, + userAgent: llmUserAgentRef, model: llmModelRef, maxContextTokens: llmMaxContextRef, }) @@ -353,6 +363,7 @@ function buildLlmSnapshot(): LlmSettingsSnapshot { LLM_API_KEY: String(SystemSettings.value.Basic.LLM_API_KEY ?? ''), LLM_BASE_URL: String(SystemSettings.value.Basic.LLM_BASE_URL ?? ''), LLM_BASE_URL_PRESET: String(SystemSettings.value.Basic.LLM_BASE_URL_PRESET ?? ''), + LLM_USER_AGENT: String(SystemSettings.value.Basic.LLM_USER_AGENT ?? ''), } } @@ -369,6 +380,7 @@ function buildLlmTestPayload(snapshot: LlmSettingsSnapshot) { api_key: snapshot.LLM_API_KEY.trim(), base_url: snapshot.LLM_BASE_URL.trim(), base_url_preset: snapshot.LLM_BASE_URL_PRESET.trim(), + user_agent: snapshot.LLM_USER_AGENT.trim(), } } @@ -1205,6 +1217,15 @@ watch(currentLlmSnapshotKey, (snapshotKey, previousSnapshotKey) => { prepend-inner-icon="mdi-key-variant" /> + + +
diff --git a/src/views/setup/AgentSettingsStep.vue b/src/views/setup/AgentSettingsStep.vue index c5d7fe0a..8d705b52 100644 --- a/src/views/setup/AgentSettingsStep.vue +++ b/src/views/setup/AgentSettingsStep.vue @@ -40,6 +40,13 @@ const baseUrlPresetRef = computed({ }, }) +const userAgentRef = computed({ + get: () => wizardData.value.agent.userAgent, + set: value => { + wizardData.value.agent.userAgent = value || '' + }, +}) + const modelRef = computed({ get: () => wizardData.value.agent.model, set: value => { @@ -92,6 +99,7 @@ const { apiKey: apiKeyRef, baseUrl: baseUrlRef, baseUrlPreset: baseUrlPresetRef, + userAgent: userAgentRef, model: modelRef, maxContextTokens: maxContextTokensRef, authConnected: authConnectedRef, @@ -349,6 +357,16 @@ onMounted(async () => { /> + + + +