Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
7076717b
Unverified
Commit
7076717b
authored
Mar 05, 2026
by
Wesley Liddick
Committed by
GitHub
Mar 05, 2026
Browse files
Merge pull request #772 from mt21625457/aicodex2api-main
feat(openai-ws): 合并 WS v2 透传模式与前端 ws mode
parents
33988637
c0a4fcea
Changes
25
Show whitespace changes
Inline
Side-by-side
frontend/src/components/account/EditAccountModal.vue
View file @
7076717b
...
...
@@ -708,7 +708,7 @@
<
/div
>
<
/div
>
<!--
OpenAI
WS
Mode
三态
(
off
/
shared
/
dedicated
)
-->
<!--
OpenAI
WS
Mode
三态
(
off
/
ctx_pool
/
passthrough
)
-->
<
div
v
-
if
=
"
account?.platform === 'openai' && (account?.type === 'oauth' || account?.type === 'apikey')
"
class
=
"
border-t border-gray-200 pt-4 dark:border-dark-600
"
...
...
@@ -720,7 +720,7 @@
{{
t
(
'
admin.accounts.openai.wsModeDesc
'
)
}}
<
/p
>
<
p
class
=
"
mt-1 text-xs text-gray-500 dark:text-gray-400
"
>
{{
t
(
'
admin.accounts.openai.ws
ModeConcurrencyHint
'
)
}}
{{
t
(
openAIWS
ModeConcurrencyHint
Key
)
}}
<
/p
>
<
/div
>
<
div
class
=
"
w-52
"
>
...
...
@@ -1273,10 +1273,11 @@ import { applyInterceptWarmup } from '@/components/account/credentialsBuilder'
import
{
formatDateTimeLocalInput
,
parseDateTimeLocalInput
}
from
'
@/utils/format
'
import
{
createStableObjectKeyResolver
}
from
'
@/utils/stableObjectKey
'
import
{
OPENAI_WS_MODE_
DEDICATED
,
OPENAI_WS_MODE_
CTX_POOL
,
OPENAI_WS_MODE_OFF
,
OPENAI_WS_MODE_
SHARED
,
OPENAI_WS_MODE_
PASSTHROUGH
,
isOpenAIWSModeEnabled
,
resolveOpenAIWSModeConcurrencyHintKey
,
type
OpenAIWSMode
,
resolveOpenAIWSModeFromExtra
}
from
'
@/utils/openaiWsMode
'
...
...
@@ -1387,8 +1388,8 @@ const codexCLIOnlyEnabled = ref(false)
const
anthropicPassthroughEnabled
=
ref
(
false
)
const
openAIWSModeOptions
=
computed
(()
=>
[
{
value
:
OPENAI_WS_MODE_OFF
,
label
:
t
(
'
admin.accounts.openai.wsModeOff
'
)
}
,
{
value
:
OPENAI_WS_MODE_
SHARED
,
label
:
t
(
'
admin.accounts.openai.wsMode
Shared
'
)
}
,
{
value
:
OPENAI_WS_MODE_
DEDICATED
,
label
:
t
(
'
admin.accounts.openai.wsMode
Dedicated
'
)
}
{
value
:
OPENAI_WS_MODE_
CTX_POOL
,
label
:
t
(
'
admin.accounts.openai.wsMode
CtxPool
'
)
}
,
{
value
:
OPENAI_WS_MODE_
PASSTHROUGH
,
label
:
t
(
'
admin.accounts.openai.wsMode
Passthrough
'
)
}
])
const
openaiResponsesWebSocketV2Mode
=
computed
({
get
:
()
=>
{
...
...
@@ -1405,6 +1406,9 @@ const openaiResponsesWebSocketV2Mode = computed({
openaiOAuthResponsesWebSocketV2Mode
.
value
=
mode
}
}
)
const
openAIWSModeConcurrencyHintKey
=
computed
(()
=>
resolveOpenAIWSModeConcurrencyHintKey
(
openaiResponsesWebSocketV2Mode
.
value
)
)
const
isOpenAIModelRestrictionDisabled
=
computed
(()
=>
props
.
account
?.
platform
===
'
openai
'
&&
openaiPassthroughEnabled
.
value
)
...
...
@@ -2248,10 +2252,13 @@ const handleSubmit = async () => {
const
currentExtra
=
(
props
.
account
.
extra
as
Record
<
string
,
unknown
>
)
||
{
}
const
newExtra
:
Record
<
string
,
unknown
>
=
{
...
currentExtra
}
const
hadCodexCLIOnlyEnabled
=
currentExtra
.
codex_cli_only
===
true
if
(
props
.
account
.
type
===
'
oauth
'
)
{
newExtra
.
openai_oauth_responses_websockets_v2_mode
=
openaiOAuthResponsesWebSocketV2Mode
.
value
newExtra
.
openai_apikey_responses_websockets_v2_mode
=
openaiAPIKeyResponsesWebSocketV2Mode
.
value
newExtra
.
openai_oauth_responses_websockets_v2_enabled
=
isOpenAIWSModeEnabled
(
openaiOAuthResponsesWebSocketV2Mode
.
value
)
}
else
if
(
props
.
account
.
type
===
'
apikey
'
)
{
newExtra
.
openai_apikey_responses_websockets_v2_mode
=
openaiAPIKeyResponsesWebSocketV2Mode
.
value
newExtra
.
openai_apikey_responses_websockets_v2_enabled
=
isOpenAIWSModeEnabled
(
openaiAPIKeyResponsesWebSocketV2Mode
.
value
)
}
delete
newExtra
.
responses_websockets_v2_enabled
delete
newExtra
.
openai_ws_enabled
if
(
openaiPassthroughEnabled
.
value
)
{
...
...
frontend/src/i18n/locales/en.ts
View file @
7076717b
...
...
@@ -1846,10 +1846,13 @@ export default {
wsMode
:
'
WS mode
'
,
wsModeDesc
:
'
Only applies to the current OpenAI account type.
'
,
wsModeOff
:
'
Off (off)
'
,
wsModeCtxPool
:
'
Context Pool (ctx_pool)
'
,
wsModePassthrough
:
'
Passthrough (passthrough)
'
,
wsModeShared
:
'
Shared (shared)
'
,
wsModeDedicated
:
'
Dedicated (dedicated)
'
,
wsModeConcurrencyHint
:
'
When WS mode is enabled, account concurrency becomes the WS connection pool limit for this account.
'
,
wsModePassthroughHint
:
'
Passthrough mode does not use the WS connection pool.
'
,
oauthResponsesWebsocketsV2
:
'
OAuth WebSocket Mode
'
,
oauthResponsesWebsocketsV2Desc
:
'
Only applies to OpenAI OAuth. This account can use OpenAI WebSocket Mode only when enabled.
'
,
...
...
frontend/src/i18n/locales/zh.ts
View file @
7076717b
...
...
@@ -1994,9 +1994,12 @@ export default {
wsMode
:
'
WS mode
'
,
wsModeDesc
:
'
仅对当前 OpenAI 账号类型生效。
'
,
wsModeOff
:
'
关闭(off)
'
,
wsModeCtxPool
:
'
上下文池(ctx_pool)
'
,
wsModePassthrough
:
'
透传(passthrough)
'
,
wsModeShared
:
'
共享(shared)
'
,
wsModeDedicated
:
'
独享(dedicated)
'
,
wsModeConcurrencyHint
:
'
启用 WS mode 后,该账号并发数将作为该账号 WS 连接池上限。
'
,
wsModePassthroughHint
:
'
passthrough 模式不使用 WS 连接池。
'
,
oauthResponsesWebsocketsV2
:
'
OAuth WebSocket Mode
'
,
oauthResponsesWebsocketsV2Desc
:
'
仅对 OpenAI OAuth 生效。开启后该账号才允许使用 OpenAI WebSocket Mode 协议。
'
,
...
...
frontend/src/utils/__tests__/openaiWsMode.spec.ts
View file @
7076717b
import
{
describe
,
expect
,
it
}
from
'
vitest
'
import
{
OPENAI_WS_MODE_
DEDICATED
,
OPENAI_WS_MODE_
CTX_POOL
,
OPENAI_WS_MODE_OFF
,
OPENAI_WS_MODE_
SHARED
,
OPENAI_WS_MODE_
PASSTHROUGH
,
isOpenAIWSModeEnabled
,
normalizeOpenAIWSMode
,
openAIWSModeFromEnabled
,
resolveOpenAIWSModeConcurrencyHintKey
,
resolveOpenAIWSModeFromExtra
}
from
'
@/utils/openaiWsMode
'
describe
(
'
openaiWsMode utils
'
,
()
=>
{
it
(
'
normalizes mode values
'
,
()
=>
{
expect
(
normalizeOpenAIWSMode
(
'
off
'
)).
toBe
(
OPENAI_WS_MODE_OFF
)
expect
(
normalizeOpenAIWSMode
(
'
Shared
'
)).
toBe
(
OPENAI_WS_MODE_SHARED
)
expect
(
normalizeOpenAIWSMode
(
'
DEDICATED
'
)).
toBe
(
OPENAI_WS_MODE_DEDICATED
)
expect
(
normalizeOpenAIWSMode
(
'
ctx_pool
'
)).
toBe
(
OPENAI_WS_MODE_CTX_POOL
)
expect
(
normalizeOpenAIWSMode
(
'
passthrough
'
)).
toBe
(
OPENAI_WS_MODE_PASSTHROUGH
)
expect
(
normalizeOpenAIWSMode
(
'
Shared
'
)).
toBe
(
OPENAI_WS_MODE_CTX_POOL
)
expect
(
normalizeOpenAIWSMode
(
'
DEDICATED
'
)).
toBe
(
OPENAI_WS_MODE_CTX_POOL
)
expect
(
normalizeOpenAIWSMode
(
'
invalid
'
)).
toBeNull
()
})
it
(
'
maps legacy enabled flag to mode
'
,
()
=>
{
expect
(
openAIWSModeFromEnabled
(
true
)).
toBe
(
OPENAI_WS_MODE_
SHARED
)
expect
(
openAIWSModeFromEnabled
(
true
)).
toBe
(
OPENAI_WS_MODE_
CTX_POOL
)
expect
(
openAIWSModeFromEnabled
(
false
)).
toBe
(
OPENAI_WS_MODE_OFF
)
expect
(
openAIWSModeFromEnabled
(
'
true
'
)).
toBeNull
()
})
it
(
'
resolves by mode key first, then enabled, then fallback enabled keys
'
,
()
=>
{
const
extra
=
{
openai_oauth_responses_websockets_v2_mode
:
'
dedicated
'
,
openai_oauth_responses_websockets_v2_mode
:
'
passthrough
'
,
openai_oauth_responses_websockets_v2_enabled
:
false
,
responses_websockets_v2_enabled
:
false
}
...
...
@@ -34,7 +37,7 @@ describe('openaiWsMode utils', () => {
enabledKey
:
'
openai_oauth_responses_websockets_v2_enabled
'
,
fallbackEnabledKeys
:
[
'
responses_websockets_v2_enabled
'
,
'
openai_ws_enabled
'
]
})
expect
(
mode
).
toBe
(
OPENAI_WS_MODE_
DEDICATED
)
expect
(
mode
).
toBe
(
OPENAI_WS_MODE_
PASSTHROUGH
)
})
it
(
'
falls back to default when nothing is present
'
,
()
=>
{
...
...
@@ -47,9 +50,21 @@ describe('openaiWsMode utils', () => {
expect
(
mode
).
toBe
(
OPENAI_WS_MODE_OFF
)
})
it
(
'
treats off as disabled and
shared/dedicated
as enabled
'
,
()
=>
{
it
(
'
treats off as disabled and
non-off modes
as enabled
'
,
()
=>
{
expect
(
isOpenAIWSModeEnabled
(
OPENAI_WS_MODE_OFF
)).
toBe
(
false
)
expect
(
isOpenAIWSModeEnabled
(
OPENAI_WS_MODE_SHARED
)).
toBe
(
true
)
expect
(
isOpenAIWSModeEnabled
(
OPENAI_WS_MODE_DEDICATED
)).
toBe
(
true
)
expect
(
isOpenAIWSModeEnabled
(
OPENAI_WS_MODE_CTX_POOL
)).
toBe
(
true
)
expect
(
isOpenAIWSModeEnabled
(
OPENAI_WS_MODE_PASSTHROUGH
)).
toBe
(
true
)
})
it
(
'
resolves concurrency hint key by mode
'
,
()
=>
{
expect
(
resolveOpenAIWSModeConcurrencyHintKey
(
OPENAI_WS_MODE_OFF
)).
toBe
(
'
admin.accounts.openai.wsModeConcurrencyHint
'
)
expect
(
resolveOpenAIWSModeConcurrencyHintKey
(
OPENAI_WS_MODE_CTX_POOL
)).
toBe
(
'
admin.accounts.openai.wsModeConcurrencyHint
'
)
expect
(
resolveOpenAIWSModeConcurrencyHintKey
(
OPENAI_WS_MODE_PASSTHROUGH
)).
toBe
(
'
admin.accounts.openai.wsModePassthroughHint
'
)
})
})
frontend/src/utils/openaiWsMode.ts
View file @
7076717b
export
const
OPENAI_WS_MODE_OFF
=
'
off
'
export
const
OPENAI_WS_MODE_
SHARED
=
'
shared
'
export
const
OPENAI_WS_MODE_
DEDICATED
=
'
dedicated
'
export
const
OPENAI_WS_MODE_
CTX_POOL
=
'
ctx_pool
'
export
const
OPENAI_WS_MODE_
PASSTHROUGH
=
'
passthrough
'
export
type
OpenAIWSMode
=
|
typeof
OPENAI_WS_MODE_OFF
|
typeof
OPENAI_WS_MODE_
SHARED
|
typeof
OPENAI_WS_MODE_
DEDICATED
|
typeof
OPENAI_WS_MODE_
CTX_POOL
|
typeof
OPENAI_WS_MODE_
PASSTHROUGH
const
OPENAI_WS_MODES
=
new
Set
<
OpenAIWSMode
>
([
OPENAI_WS_MODE_OFF
,
OPENAI_WS_MODE_
SHARED
,
OPENAI_WS_MODE_
DEDICATED
OPENAI_WS_MODE_
CTX_POOL
,
OPENAI_WS_MODE_
PASSTHROUGH
])
export
interface
ResolveOpenAIWSModeOptions
{
...
...
@@ -23,6 +23,9 @@ export interface ResolveOpenAIWSModeOptions {
export
const
normalizeOpenAIWSMode
=
(
mode
:
unknown
):
OpenAIWSMode
|
null
=>
{
if
(
typeof
mode
!==
'
string
'
)
return
null
const
normalized
=
mode
.
trim
().
toLowerCase
()
if
(
normalized
===
'
shared
'
||
normalized
===
'
dedicated
'
)
{
return
OPENAI_WS_MODE_CTX_POOL
}
if
(
OPENAI_WS_MODES
.
has
(
normalized
as
OpenAIWSMode
))
{
return
normalized
as
OpenAIWSMode
}
...
...
@@ -31,13 +34,22 @@ export const normalizeOpenAIWSMode = (mode: unknown): OpenAIWSMode | null => {
export
const
openAIWSModeFromEnabled
=
(
enabled
:
unknown
):
OpenAIWSMode
|
null
=>
{
if
(
typeof
enabled
!==
'
boolean
'
)
return
null
return
enabled
?
OPENAI_WS_MODE_
SHARED
:
OPENAI_WS_MODE_OFF
return
enabled
?
OPENAI_WS_MODE_
CTX_POOL
:
OPENAI_WS_MODE_OFF
}
export
const
isOpenAIWSModeEnabled
=
(
mode
:
OpenAIWSMode
):
boolean
=>
{
return
mode
!==
OPENAI_WS_MODE_OFF
}
export
const
resolveOpenAIWSModeConcurrencyHintKey
=
(
mode
:
OpenAIWSMode
):
'
admin.accounts.openai.wsModeConcurrencyHint
'
|
'
admin.accounts.openai.wsModePassthroughHint
'
=>
{
if
(
mode
===
OPENAI_WS_MODE_PASSTHROUGH
)
{
return
'
admin.accounts.openai.wsModePassthroughHint
'
}
return
'
admin.accounts.openai.wsModeConcurrencyHint
'
}
export
const
resolveOpenAIWSModeFromExtra
=
(
extra
:
Record
<
string
,
unknown
>
|
null
|
undefined
,
options
:
ResolveOpenAIWSModeOptions
...
...
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment