diff --git a/backend/internal/service/openai_gateway_service.go b/backend/internal/service/openai_gateway_service.go index c7d94882..45b4c69c 100644 --- a/backend/internal/service/openai_gateway_service.go +++ b/backend/internal/service/openai_gateway_service.go @@ -649,6 +649,12 @@ func (s *OpenAIGatewayService) Forward(ctx context.Context, c *gin.Context, acco bodyModified = true } } + + // Remove prompt_cache_retention (not supported by upstream OpenAI API) + if _, has := reqBody["prompt_cache_retention"]; has { + delete(reqBody, "prompt_cache_retention") + bodyModified = true + } } // Re-serialize body only if modified diff --git a/frontend/src/components/account/CreateAccountModal.vue b/frontend/src/components/account/CreateAccountModal.vue index c81de00e..05f328ac 100644 --- a/frontend/src/components/account/CreateAccountModal.vue +++ b/frontend/src/components/account/CreateAccountModal.vue @@ -2157,6 +2157,46 @@ const handleClose = () => { emit('close') } +// Helper function to create account with mixed channel warning handling +const doCreateAccount = async (payload: any, confirmMixedChannelRisk = false) => { + if (confirmMixedChannelRisk) { + payload.confirm_mixed_channel_risk = true + } + + submitting.value = true + try { + await adminAPI.accounts.create(payload) + appStore.showSuccess(t('admin.accounts.accountCreated')) + emit('created') + handleClose() + } catch (error: any) { + // Handle 409 mixed_channel_warning - show confirmation dialog + if (error.response?.status === 409 && error.response?.data?.error === 'mixed_channel_warning') { + const details = error.response.data.details || {} + const groupName = details.group_name || 'Unknown' + const currentPlatform = details.current_platform || 'Unknown' + const otherPlatform = details.other_platform || 'Unknown' + + const confirmMessage = t('admin.accounts.mixedChannelWarning', { + groupName, + currentPlatform, + otherPlatform + }) + + if (confirm(confirmMessage)) { + // Retry with confirmation flag + submitting.value = false + await doCreateAccount(payload, true) + return + } + } else { + appStore.showError(error.response?.data?.detail || t('admin.accounts.failedToCreate')) + } + } finally { + submitting.value = false + } +} + const handleSubmit = async () => { // For OAuth-based type, handle OAuth flow (goes to step 2) if (isOAuthFlow.value) { @@ -2213,21 +2253,11 @@ const handleSubmit = async () => { form.credentials = credentials - submitting.value = true - try { - await adminAPI.accounts.create({ - ...form, - group_ids: form.group_ids, - auto_pause_on_expired: autoPauseOnExpired.value - }) - appStore.showSuccess(t('admin.accounts.accountCreated')) - emit('created') - handleClose() - } catch (error: any) { - appStore.showError(error.response?.data?.detail || t('admin.accounts.failedToCreate')) - } finally { - submitting.value = false - } + await doCreateAccount({ + ...form, + group_ids: form.group_ids, + auto_pause_on_expired: autoPauseOnExpired.value + }) } const goBackToBasicInfo = () => { diff --git a/frontend/src/components/account/EditAccountModal.vue b/frontend/src/components/account/EditAccountModal.vue index d27364f1..63b54df0 100644 --- a/frontend/src/components/account/EditAccountModal.vue +++ b/frontend/src/components/account/EditAccountModal.vue @@ -8,7 +8,7 @@
@@ -1294,12 +1294,17 @@ const handleClose = () => { emit('close') } -const handleSubmit = async () => { +const handleSubmit = async (confirmMixedChannelRisk = false) => { if (!props.account) return submitting.value = true try { const updatePayload: Record = { ...form } + + // Add confirmation flag if user confirmed mixed channel risk + if (confirmMixedChannelRisk) { + updatePayload.confirm_mixed_channel_risk = true + } // 后端期望 proxy_id: 0 表示清除代理,而不是 null if (updatePayload.proxy_id === null) { updatePayload.proxy_id = 0 @@ -1415,7 +1420,28 @@ const handleSubmit = async () => { emit('updated') handleClose() } catch (error: any) { - appStore.showError(error.response?.data?.message || error.response?.data?.detail || t('admin.accounts.failedToUpdate')) + // Handle 409 mixed_channel_warning - show confirmation dialog + if (error.response?.status === 409 && error.response?.data?.error === 'mixed_channel_warning') { + const details = error.response.data.details || {} + const groupName = details.group_name || 'Unknown' + const currentPlatform = details.current_platform || 'Unknown' + const otherPlatform = details.other_platform || 'Unknown' + + const confirmMessage = t('admin.accounts.mixedChannelWarning', { + groupName, + currentPlatform, + otherPlatform + }) + + if (confirm(confirmMessage)) { + // Retry with confirmation flag + submitting.value = false + await handleSubmit(true) + return + } + } else { + appStore.showError(error.response?.data?.message || error.response?.data?.detail || t('admin.accounts.failedToUpdate')) + } } finally { submitting.value = false } diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index b25b5a0b..b36d31e4 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -1306,6 +1306,7 @@ export default { accountUpdated: 'Account updated successfully', failedToCreate: 'Failed to create account', failedToUpdate: 'Failed to update account', + mixedChannelWarning: 'Warning: Group "{groupName}" contains both {currentPlatform} and {otherPlatform} accounts. Mixing different channels may cause thinking block signature validation issues, which will fallback to non-thinking mode. Are you sure you want to continue?', pleaseEnterAccountName: 'Please enter account name', pleaseEnterApiKey: 'Please enter API Key', apiKeyIsRequired: 'API Key is required', diff --git a/frontend/src/i18n/locales/zh.ts b/frontend/src/i18n/locales/zh.ts index b7be8557..ad8380a8 100644 --- a/frontend/src/i18n/locales/zh.ts +++ b/frontend/src/i18n/locales/zh.ts @@ -1439,6 +1439,7 @@ export default { accountUpdated: '账号更新成功', failedToCreate: '创建账号失败', failedToUpdate: '更新账号失败', + mixedChannelWarning: '警告:分组 "{groupName}" 中同时包含 {currentPlatform} 和 {otherPlatform} 账号。混合使用不同渠道可能导致 thinking block 签名验证问题,会自动回退到非 thinking 模式。确定要继续吗?', pleaseEnterAccountName: '请输入账号名称', pleaseEnterApiKey: '请输入 API Key', apiKeyIsRequired: 'API Key 是必需的',