From 59898c16c697193c1ac8d8b051c7967f19e5e03a Mon Sep 17 00:00:00 2001 From: erio Date: Tue, 24 Feb 2026 16:48:16 +0800 Subject: [PATCH] fix: fix intercept_warmup_requests config not being saved Extract applyInterceptWarmup utility to unify all credential building call sites: - Fix upstream account creation missing intercept_warmup_requests write - Fix apikey edit mode missing else-branch to clear the setting - Add backend unit test for IsInterceptWarmupEnabled - Add frontend unit test for credentialsBuilder --- .../service/account_intercept_warmup_test.go | 66 +++++++++++++++++++ .../components/account/CreateAccountModal.vue | 22 +++---- .../components/account/EditAccountModal.vue | 14 ++-- .../__tests__/credentialsBuilder.spec.ts | 46 +++++++++++++ .../components/account/credentialsBuilder.ts | 11 ++++ 5 files changed, 138 insertions(+), 21 deletions(-) create mode 100644 backend/internal/service/account_intercept_warmup_test.go create mode 100644 frontend/src/components/account/__tests__/credentialsBuilder.spec.ts create mode 100644 frontend/src/components/account/credentialsBuilder.ts diff --git a/backend/internal/service/account_intercept_warmup_test.go b/backend/internal/service/account_intercept_warmup_test.go new file mode 100644 index 00000000..f117fd8d --- /dev/null +++ b/backend/internal/service/account_intercept_warmup_test.go @@ -0,0 +1,66 @@ +//go:build unit + +package service + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestAccount_IsInterceptWarmupEnabled(t *testing.T) { + tests := []struct { + name string + credentials map[string]any + expected bool + }{ + { + name: "nil credentials", + credentials: nil, + expected: false, + }, + { + name: "empty map", + credentials: map[string]any{}, + expected: false, + }, + { + name: "field not present", + credentials: map[string]any{"access_token": "tok"}, + expected: false, + }, + { + name: "field is true", + credentials: map[string]any{"intercept_warmup_requests": true}, + expected: true, + }, + { + name: "field is false", + credentials: map[string]any{"intercept_warmup_requests": false}, + expected: false, + }, + { + name: "field is string true", + credentials: map[string]any{"intercept_warmup_requests": "true"}, + expected: false, + }, + { + name: "field is int 1", + credentials: map[string]any{"intercept_warmup_requests": 1}, + expected: false, + }, + { + name: "field is nil", + credentials: map[string]any{"intercept_warmup_requests": nil}, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &Account{Credentials: tt.credentials} + result := a.IsInterceptWarmupEnabled() + require.Equal(t, tt.expected, result) + }) + } +} diff --git a/frontend/src/components/account/CreateAccountModal.vue b/frontend/src/components/account/CreateAccountModal.vue index 30da0767..64253447 100644 --- a/frontend/src/components/account/CreateAccountModal.vue +++ b/frontend/src/components/account/CreateAccountModal.vue @@ -2196,6 +2196,7 @@ import Icon from '@/components/icons/Icon.vue' import ProxySelector from '@/components/common/ProxySelector.vue' import GroupSelector from '@/components/common/GroupSelector.vue' import ModelWhitelistSelector from '@/components/account/ModelWhitelistSelector.vue' +import { applyInterceptWarmup } from '@/components/account/credentialsBuilder' import { formatDateTimeLocalInput, parseDateTimeLocalInput } from '@/utils/format' import { createStableObjectKeyResolver } from '@/utils/stableObjectKey' import OAuthAuthorizationFlow from './OAuthAuthorizationFlow.vue' @@ -3010,6 +3011,8 @@ const handleSubmit = async () => { credentials.model_mapping = antigravityModelMapping } + applyInterceptWarmup(credentials, interceptWarmupRequests.value, 'create') + submitting.value = true try { const extra = mixedScheduling.value ? { mixed_scheduling: true } : undefined @@ -3059,10 +3062,7 @@ const handleSubmit = async () => { credentials.custom_error_codes = [...selectedErrorCodes.value] } - // Add intercept warmup requests setting - if (interceptWarmupRequests.value) { - credentials.intercept_warmup_requests = true - } + applyInterceptWarmup(credentials, interceptWarmupRequests.value, 'create') if (!applyTempUnschedConfig(credentials)) { return } @@ -3606,6 +3606,7 @@ const handleAntigravityExchange = async (authCode: string) => { if (!tokenInfo) return const credentials = antigravityOAuth.buildCredentials(tokenInfo) + applyInterceptWarmup(credentials, interceptWarmupRequests.value, 'create') // Antigravity 只使用映射模式 const antigravityModelMapping = buildModelMappingObject( 'mapping', @@ -3677,10 +3678,8 @@ const handleAnthropicExchange = async (authCode: string) => { extra.cache_ttl_override_target = cacheTTLOverrideTarget.value } - const credentials = { - ...tokenInfo, - ...(interceptWarmupRequests.value ? { intercept_warmup_requests: true } : {}) - } + const credentials: Record = { ...tokenInfo } + applyInterceptWarmup(credentials, interceptWarmupRequests.value, 'create') await createAccountAndFinish(form.platform, addMethod.value as AccountType, credentials, extra) } catch (error: any) { oauth.error.value = error.response?.data?.detail || t('admin.accounts.oauth.authFailed') @@ -3779,11 +3778,8 @@ const handleCookieAuth = async (sessionKey: string) => { const accountName = keys.length > 1 ? `${form.name} #${i + 1}` : form.name - // Merge interceptWarmupRequests into credentials - const credentials: Record = { - ...tokenInfo, - ...(interceptWarmupRequests.value ? { intercept_warmup_requests: true } : {}) - } + const credentials: Record = { ...tokenInfo } + applyInterceptWarmup(credentials, interceptWarmupRequests.value, 'create') if (tempUnschedEnabled.value) { credentials.temp_unschedulable_enabled = true credentials.temp_unschedulable_rules = tempUnschedPayload diff --git a/frontend/src/components/account/EditAccountModal.vue b/frontend/src/components/account/EditAccountModal.vue index c6643717..3d75df7d 100644 --- a/frontend/src/components/account/EditAccountModal.vue +++ b/frontend/src/components/account/EditAccountModal.vue @@ -1162,6 +1162,7 @@ import Icon from '@/components/icons/Icon.vue' import ProxySelector from '@/components/common/ProxySelector.vue' import GroupSelector from '@/components/common/GroupSelector.vue' import ModelWhitelistSelector from '@/components/account/ModelWhitelistSelector.vue' +import { applyInterceptWarmup } from '@/components/account/credentialsBuilder' import { formatDateTimeLocalInput, parseDateTimeLocalInput } from '@/utils/format' import { createStableObjectKeyResolver } from '@/utils/stableObjectKey' import { @@ -1789,9 +1790,7 @@ const handleSubmit = async () => { } // Add intercept warmup requests setting - if (interceptWarmupRequests.value) { - newCredentials.intercept_warmup_requests = true - } + applyInterceptWarmup(newCredentials, interceptWarmupRequests.value, 'edit') if (!applyTempUnschedConfig(newCredentials)) { submitting.value = false return @@ -1808,6 +1807,9 @@ const handleSubmit = async () => { newCredentials.api_key = editApiKey.value.trim() } + // Add intercept warmup requests setting + applyInterceptWarmup(newCredentials, interceptWarmupRequests.value, 'edit') + if (!applyTempUnschedConfig(newCredentials)) { submitting.value = false return @@ -1819,11 +1821,7 @@ const handleSubmit = async () => { const currentCredentials = (props.account.credentials as Record) || {} const newCredentials: Record = { ...currentCredentials } - if (interceptWarmupRequests.value) { - newCredentials.intercept_warmup_requests = true - } else { - delete newCredentials.intercept_warmup_requests - } + applyInterceptWarmup(newCredentials, interceptWarmupRequests.value, 'edit') if (!applyTempUnschedConfig(newCredentials)) { submitting.value = false return diff --git a/frontend/src/components/account/__tests__/credentialsBuilder.spec.ts b/frontend/src/components/account/__tests__/credentialsBuilder.spec.ts new file mode 100644 index 00000000..be2a8d52 --- /dev/null +++ b/frontend/src/components/account/__tests__/credentialsBuilder.spec.ts @@ -0,0 +1,46 @@ +import { describe, it, expect } from 'vitest' +import { applyInterceptWarmup } from '../credentialsBuilder' + +describe('applyInterceptWarmup', () => { + it('create + enabled=true: should set intercept_warmup_requests to true', () => { + const creds: Record = { access_token: 'tok' } + applyInterceptWarmup(creds, true, 'create') + expect(creds.intercept_warmup_requests).toBe(true) + }) + + it('create + enabled=false: should not add the field', () => { + const creds: Record = { access_token: 'tok' } + applyInterceptWarmup(creds, false, 'create') + expect('intercept_warmup_requests' in creds).toBe(false) + }) + + it('edit + enabled=true: should set intercept_warmup_requests to true', () => { + const creds: Record = { api_key: 'sk' } + applyInterceptWarmup(creds, true, 'edit') + expect(creds.intercept_warmup_requests).toBe(true) + }) + + it('edit + enabled=false + field exists: should delete the field', () => { + const creds: Record = { api_key: 'sk', intercept_warmup_requests: true } + applyInterceptWarmup(creds, false, 'edit') + expect('intercept_warmup_requests' in creds).toBe(false) + }) + + it('edit + enabled=false + field absent: should not throw', () => { + const creds: Record = { api_key: 'sk' } + applyInterceptWarmup(creds, false, 'edit') + expect('intercept_warmup_requests' in creds).toBe(false) + }) + + it('should not affect other fields', () => { + const creds: Record = { + api_key: 'sk', + base_url: 'url', + intercept_warmup_requests: true + } + applyInterceptWarmup(creds, false, 'edit') + expect(creds.api_key).toBe('sk') + expect(creds.base_url).toBe('url') + expect('intercept_warmup_requests' in creds).toBe(false) + }) +}) diff --git a/frontend/src/components/account/credentialsBuilder.ts b/frontend/src/components/account/credentialsBuilder.ts new file mode 100644 index 00000000..b8008e8b --- /dev/null +++ b/frontend/src/components/account/credentialsBuilder.ts @@ -0,0 +1,11 @@ +export function applyInterceptWarmup( + credentials: Record, + enabled: boolean, + mode: 'create' | 'edit' +): void { + if (enabled) { + credentials.intercept_warmup_requests = true + } else if (mode === 'edit') { + delete credentials.intercept_warmup_requests + } +}