@@ -2979,7 +2979,7 @@ const syncFormFromAccount = (newAccount: Account | null) => {
autoPause5hDisabled.value = extra?.auto_pause_5h_disabled === true
autoPause7dDisabled.value = extra?.auto_pause_7d_disabled === true
- // Load OpenAI passthrough toggle (OpenAI OAuth/API Key)
+ // Load OpenAI passthrough toggle (OpenAI OAuth/SetupToken/API Key)
openaiPassthroughEnabled.value = false
openAICompactMode.value = 'auto'
openAIResponsesMode.value = 'auto'
@@ -2992,7 +2992,7 @@ const syncFormFromAccount = (newAccount: Account | null) => {
codexImageGenerationBridgeMode.value = 'inherit'
anthropicPassthroughEnabled.value = false
webSearchEmulationMode.value = 'default'
- if (newAccount.platform === 'openai' && (newAccount.type === 'oauth' || newAccount.type === 'apikey')) {
+ if (newAccount.platform === 'openai' && (newAccount.type === 'oauth' || newAccount.type === 'setup-token' || newAccount.type === 'apikey')) {
openaiPassthroughEnabled.value = extra?.openai_passthrough === true || extra?.openai_oauth_passthrough === true
openAICompactMode.value = (extra?.openai_compact_mode as OpenAICompactMode) || 'auto'
if (newAccount.type === 'apikey') {
@@ -3024,7 +3024,7 @@ const syncFormFromAccount = (newAccount: Account | null) => {
fallbackEnabledKeys: ['responses_websockets_v2_enabled', 'openai_ws_enabled'],
defaultMode: OPENAI_WS_MODE_OFF
})
- if (newAccount.type === 'oauth') {
+ if (newAccount.type === 'oauth' || newAccount.type === 'setup-token') {
codexCLIOnlyEnabled.value = extra?.codex_cli_only === true
codexCLIOnlyAppServerEnabled.value =
extra?.codex_cli_only_allow_app_server === true
@@ -4101,12 +4101,12 @@ const handleSubmit = async () => {
updatePayload.extra = newExtra
}
- // For OpenAI OAuth/API Key accounts, handle passthrough mode in extra
- if (props.account.platform === 'openai' && (props.account.type === 'oauth' || props.account.type === 'apikey')) {
- const currentExtra = (props.account.extra as Record) || {}
- const newExtra: Record = { ...currentExtra }
+ // For OpenAI OAuth/SetupToken/API Key accounts, handle passthrough mode in extra
+ if (props.account.platform === 'openai' && (props.account.type === 'oauth' || props.account.type === 'setup-token' || props.account.type === 'apikey')) {
+ const currentExtra = (props.account.extra as Record) || {}
+ const newExtra: Record = { ...currentExtra }
const hadCodexCLIOnlyEnabled = currentExtra.codex_cli_only === true
- if (props.account.type === 'oauth') {
+ if (props.account.type === 'oauth' || props.account.type === 'setup-token') {
newExtra.openai_oauth_responses_websockets_v2_mode = openaiOAuthResponsesWebSocketV2Mode.value
newExtra.openai_oauth_responses_websockets_v2_enabled = isOpenAIWSModeEnabled(openaiOAuthResponsesWebSocketV2Mode.value)
} else if (props.account.type === 'apikey') {
@@ -4161,7 +4161,7 @@ const handleSubmit = async () => {
newExtra.codex_image_generation_bridge = codexImageGenerationBridgeMode.value === 'enabled'
}
- if (props.account.type === 'oauth') {
+ if (props.account.type === 'oauth' || props.account.type === 'setup-token') {
if (codexCLIOnlyEnabled.value) {
newExtra.codex_cli_only = true
} else if (hadCodexCLIOnlyEnabled) {
diff --git a/frontend/src/components/account/__tests__/EditAccountModal.spec.ts b/frontend/src/components/account/__tests__/EditAccountModal.spec.ts
index 77c333fb2d..8d28b2b003 100644
--- a/frontend/src/components/account/__tests__/EditAccountModal.spec.ts
+++ b/frontend/src/components/account/__tests__/EditAccountModal.spec.ts
@@ -192,6 +192,17 @@ function buildAntigravityAccount(projectId = 'configured-project') {
} as any
}
+function buildOpenAISetupTokenAccount() {
+ return {
+ ...buildAccount(),
+ type: 'setup-token',
+ extra: {
+ openai_oauth_responses_websockets_v2_mode: 'ctx_pool',
+ openai_oauth_responses_websockets_v2_enabled: true
+ }
+ } as any
+}
+
function mountModal(account = buildAccount()) {
return mount(EditAccountModal, {
props: {
@@ -487,6 +498,23 @@ describe('EditAccountModal', () => {
expect(updateAccountMock.mock.calls[0]?.[1]?.extra).not.toHaveProperty('codex_image_generation_bridge_enabled')
})
+ it('setup-token account can select and submit OAuth WS mode', async () => {
+ const account = buildOpenAISetupTokenAccount()
+ updateAccountMock.mockReset()
+ checkMixedChannelRiskMock.mockReset()
+ checkMixedChannelRiskMock.mockResolvedValue({ has_risk: false })
+ updateAccountMock.mockResolvedValue(account)
+
+ const wrapper = mountModal(account)
+
+ await wrapper.get('[data-testid="edit-openai-ws-mode-select"]').setValue('http_bridge')
+ await wrapper.get('form#edit-account-form').trigger('submit.prevent')
+
+ expect(updateAccountMock).toHaveBeenCalledTimes(1)
+ expect(updateAccountMock.mock.calls[0]?.[1]?.extra?.openai_oauth_responses_websockets_v2_mode).toBe('http_bridge')
+ expect(updateAccountMock.mock.calls[0]?.[1]?.extra?.openai_oauth_responses_websockets_v2_enabled).toBe(true)
+ })
+
it('allows saving apikey account when backend redacted api_key but credentials_status reports it exists', async () => {
// 新前端 + 新后端:响应已脱敏,credentials 里没有 api_key,credentials_status.has_api_key=true
const account = buildAccount()