mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-14 20:12:39 +08:00
Merge pull request #7064 from xlplbo/codex/openai-ws-v2-pool-capacity
fix(openai-ws): 对齐新版 ctx_pool 连接容量计算
This commit is contained in:
@@ -1274,7 +1274,9 @@ type GatewayOpenAIWSConfig struct {
|
||||
MaxConnsPerAccount int `mapstructure:"max_conns_per_account"`
|
||||
MinIdlePerAccount int `mapstructure:"min_idle_per_account"`
|
||||
MaxIdlePerAccount int `mapstructure:"max_idle_per_account"`
|
||||
// DynamicMaxConnsByAccountConcurrencyEnabled: 是否按账号并发动态计算连接池上限
|
||||
// DynamicMaxConnsByAccountConcurrencyEnabled: 是否按账号并发动态计算连接池上限。
|
||||
// 旧版及 mode_router_v2 的 ctx_pool 共用此开关和类型系数;关闭后使用 max_conns_per_account。
|
||||
// mode_router_v2 下并发数 <= 0 的账号仍不可调度。
|
||||
DynamicMaxConnsByAccountConcurrencyEnabled bool `mapstructure:"dynamic_max_conns_by_account_concurrency_enabled"`
|
||||
// OAuthMaxConnsFactor: OAuth 账号连接池系数(effective=ceil(concurrency*factor),再受 max_conns_per_account 封顶)。
|
||||
// ctx_pool 接入下每个客户端会话在整个生命周期(含轮次之间)持有一条上游连接,此上限限制的是同时持有连接的会话数,
|
||||
|
||||
@@ -2221,14 +2221,8 @@ func (p *openAIWSConnPool) effectiveMaxConnsByAccount(account *Account) int {
|
||||
if hardCap <= 0 {
|
||||
return 0
|
||||
}
|
||||
if p.modeRouterV2Enabled() {
|
||||
if account == nil {
|
||||
return hardCap
|
||||
}
|
||||
if account.Concurrency <= 0 {
|
||||
return 0
|
||||
}
|
||||
return min(account.Concurrency, hardCap)
|
||||
if p.modeRouterV2Enabled() && account != nil && account.Concurrency <= 0 {
|
||||
return 0
|
||||
}
|
||||
if account == nil || !p.dynamicMaxConnsEnabled() {
|
||||
return hardCap
|
||||
|
||||
@@ -1338,21 +1338,95 @@ func TestOpenAIWSConnPool_EffectiveMaxConnsDisabledFallbackHardCap(t *testing.T)
|
||||
require.Equal(t, 8, pool.effectiveMaxConnsByAccount(account), "关闭动态模式后应保持旧行为")
|
||||
}
|
||||
|
||||
func TestOpenAIWSConnPool_EffectiveMaxConnsByAccount_ModeRouterV2RespectsHardCap(t *testing.T) {
|
||||
cfg := &config.Config{}
|
||||
cfg.Gateway.OpenAIWS.ModeRouterV2Enabled = true
|
||||
cfg.Gateway.OpenAIWS.MaxConnsPerAccount = 8
|
||||
cfg.Gateway.OpenAIWS.DynamicMaxConnsByAccountConcurrencyEnabled = true
|
||||
cfg.Gateway.OpenAIWS.OAuthMaxConnsFactor = 0.3
|
||||
cfg.Gateway.OpenAIWS.APIKeyMaxConnsFactor = 0.6
|
||||
func TestOpenAIWSConnPool_EffectiveMaxConnsByAccount_ModeRouterV2(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
accountType string
|
||||
concurrency int
|
||||
factor float64
|
||||
dynamic bool
|
||||
want int
|
||||
}{
|
||||
{name: "oauth expansion", accountType: AccountTypeOAuth, concurrency: 1, factor: 5, dynamic: true, want: 5},
|
||||
{name: "apikey expansion", accountType: AccountTypeAPIKey, concurrency: 1, factor: 5, dynamic: true, want: 5},
|
||||
{name: "oauth fraction", accountType: AccountTypeOAuth, concurrency: 20, factor: 0.3, dynamic: true, want: 6},
|
||||
{name: "apikey rounding", accountType: AccountTypeAPIKey, concurrency: 3, factor: 0.6, dynamic: true, want: 2},
|
||||
{name: "minimum one", accountType: AccountTypeOAuth, concurrency: 1, factor: 0.3, dynamic: true, want: 1},
|
||||
{name: "hard cap", accountType: AccountTypeOAuth, concurrency: 3, factor: 5, dynamic: true, want: 8},
|
||||
{name: "dynamic disabled", accountType: AccountTypeAPIKey, concurrency: 2, factor: 0.6, want: 8},
|
||||
{name: "zero concurrency", accountType: AccountTypeOAuth, factor: 5, dynamic: true, want: 0},
|
||||
{name: "negative concurrency", accountType: AccountTypeAPIKey, concurrency: -1, factor: 5, dynamic: true, want: 0},
|
||||
{name: "zero concurrency dynamic disabled", accountType: AccountTypeOAuth, factor: 5, want: 0},
|
||||
{name: "negative concurrency dynamic disabled", accountType: AccountTypeAPIKey, concurrency: -1, factor: 5, want: 0},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg := &config.Config{}
|
||||
cfg.Gateway.OpenAIWS.ModeRouterV2Enabled = true
|
||||
cfg.Gateway.OpenAIWS.MaxConnsPerAccount = 8
|
||||
cfg.Gateway.OpenAIWS.DynamicMaxConnsByAccountConcurrencyEnabled = tt.dynamic
|
||||
cfg.Gateway.OpenAIWS.OAuthMaxConnsFactor = 1
|
||||
cfg.Gateway.OpenAIWS.APIKeyMaxConnsFactor = 1
|
||||
if tt.accountType == AccountTypeOAuth {
|
||||
cfg.Gateway.OpenAIWS.OAuthMaxConnsFactor = tt.factor
|
||||
} else {
|
||||
cfg.Gateway.OpenAIWS.APIKeyMaxConnsFactor = tt.factor
|
||||
}
|
||||
pool := newOpenAIWSConnPool(cfg)
|
||||
t.Cleanup(pool.Close)
|
||||
account := &Account{Platform: PlatformOpenAI, Type: tt.accountType, Concurrency: tt.concurrency}
|
||||
require.Equal(t, tt.want, pool.effectiveMaxConnsByAccount(account))
|
||||
require.Equal(t, 8, pool.effectiveMaxConnsByAccount(nil))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pool := newOpenAIWSConnPool(cfg)
|
||||
func TestOpenAIWSConnPool_AcquireRetainedSessionsUsesScaledCapacity(t *testing.T) {
|
||||
for _, mode := range []struct {
|
||||
name string
|
||||
v2 bool
|
||||
}{
|
||||
{name: "legacy"},
|
||||
{name: "mode router v2", v2: true},
|
||||
} {
|
||||
t.Run(mode.name, func(t *testing.T) {
|
||||
cfg := &config.Config{}
|
||||
cfg.Gateway.OpenAIWS.ModeRouterV2Enabled = mode.v2
|
||||
cfg.Gateway.OpenAIWS.MaxConnsPerAccount = 3
|
||||
cfg.Gateway.OpenAIWS.MaxIdlePerAccount = 3
|
||||
cfg.Gateway.OpenAIWS.PoolTargetUtilization = 1
|
||||
cfg.Gateway.OpenAIWS.DynamicMaxConnsByAccountConcurrencyEnabled = true
|
||||
cfg.Gateway.OpenAIWS.OAuthMaxConnsFactor = 2
|
||||
pool := newOpenAIWSConnPool(cfg)
|
||||
pool.setClientDialerForTest(&openAIWSFakeDialer{})
|
||||
t.Cleanup(pool.Close)
|
||||
req := openAIWSAcquireRequest{
|
||||
Account: &Account{ID: 902, Platform: PlatformOpenAI, Type: AccountTypeOAuth, Concurrency: 2},
|
||||
WSURL: "wss://example.com/v1/responses",
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
leases := make([]*openAIWSConnLease, 0, 3)
|
||||
for range 3 {
|
||||
lease, err := pool.Acquire(ctx, req)
|
||||
require.NoError(t, err, "轮次之间仍持有连接的会话应可使用系数扩出的容量")
|
||||
t.Cleanup(lease.Release)
|
||||
leases = append(leases, lease)
|
||||
}
|
||||
|
||||
high := &Account{Platform: PlatformOpenAI, Type: AccountTypeOAuth, Concurrency: 20}
|
||||
require.Equal(t, 8, pool.effectiveMaxConnsByAccount(high), "v2 路径也必须受连接池硬上限约束")
|
||||
fullCtx, fullCancel := context.WithTimeout(context.Background(), 30*time.Millisecond)
|
||||
defer fullCancel()
|
||||
_, err := pool.Acquire(fullCtx, req)
|
||||
require.ErrorIs(t, err, context.DeadlineExceeded, "扩容后仍必须受全局硬上限约束")
|
||||
|
||||
nonPositive := &Account{Platform: PlatformOpenAI, Type: AccountTypeAPIKey, Concurrency: 0}
|
||||
require.Equal(t, 0, pool.effectiveMaxConnsByAccount(nonPositive), "并发数<=0 时应不可调度")
|
||||
leases[0].Release()
|
||||
reused, err := pool.Acquire(ctx, req)
|
||||
require.NoError(t, err)
|
||||
defer reused.Release()
|
||||
require.Equal(t, leases[0].ConnID(), reused.ConnID())
|
||||
require.True(t, reused.Reused())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenAIWSConnPool_AcquireRejectsWhenEffectiveMaxConnsIsZero(t *testing.T) {
|
||||
|
||||
@@ -357,6 +357,8 @@ gateway:
|
||||
max_idle_per_account: 12
|
||||
# 是否按账号并发动态计算连接池上限:
|
||||
# effective_max_conns = min(max_conns_per_account, ceil(account.concurrency * factor))
|
||||
# 旧版及 mode_router_v2 的 ctx_pool 共用此开关和下方类型系数;关闭后使用 max_conns_per_account。
|
||||
# mode_router_v2 下并发数 <= 0 的账号仍不可调度。
|
||||
dynamic_max_conns_by_account_concurrency_enabled: true
|
||||
# 按账号类型分别设置系数(OAuth / API Key)。
|
||||
# ctx_pool 接入下每个客户端会话在整个生命周期(轮次之间也不释放)持有一条上游连接,
|
||||
|
||||
@@ -873,8 +873,8 @@
|
||||
<p class="mb-3 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.accounts.openai.wsModeDesc') }}
|
||||
</p>
|
||||
<p class="mb-3 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t(openAIWSModeConcurrencyHintKey) }}
|
||||
<p v-if="openAIWSModeHintKey" class="mb-3 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t(openAIWSModeHintKey) }}
|
||||
</p>
|
||||
<Select
|
||||
v-model="openaiOAuthResponsesWebSocketV2Mode"
|
||||
@@ -1151,8 +1151,8 @@
|
||||
<p class="mb-3 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.accounts.openai.wsModeDesc') }}
|
||||
</p>
|
||||
<p class="mb-3 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t(openAIAPIKeyWSModeConcurrencyHintKey) }}
|
||||
<p v-if="openAIAPIKeyWSModeHintKey" class="mb-3 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t(openAIAPIKeyWSModeHintKey) }}
|
||||
</p>
|
||||
<Select
|
||||
v-model="openaiAPIKeyResponsesWebSocketV2Mode"
|
||||
@@ -1513,7 +1513,7 @@ import {
|
||||
OPENAI_WS_MODE_PASSTHROUGH,
|
||||
OPENAI_WS_MODE_HTTP_BRIDGE,
|
||||
isOpenAIWSModeEnabled,
|
||||
resolveOpenAIWSModeConcurrencyHintKey
|
||||
resolveOpenAIWSModeHintKey
|
||||
} from '@/utils/openaiWsMode'
|
||||
import type { OpenAIWSMode } from '@/utils/openaiWsMode'
|
||||
interface Props {
|
||||
@@ -1824,11 +1824,11 @@ const toggleOpenAIEndpointCapability = (
|
||||
capability
|
||||
])
|
||||
}
|
||||
const openAIWSModeConcurrencyHintKey = computed(() =>
|
||||
resolveOpenAIWSModeConcurrencyHintKey(openaiOAuthResponsesWebSocketV2Mode.value)
|
||||
const openAIWSModeHintKey = computed(() =>
|
||||
resolveOpenAIWSModeHintKey(openaiOAuthResponsesWebSocketV2Mode.value)
|
||||
)
|
||||
const openAIAPIKeyWSModeConcurrencyHintKey = computed(() =>
|
||||
resolveOpenAIWSModeConcurrencyHintKey(openaiAPIKeyResponsesWebSocketV2Mode.value)
|
||||
const openAIAPIKeyWSModeHintKey = computed(() =>
|
||||
resolveOpenAIWSModeHintKey(openaiAPIKeyResponsesWebSocketV2Mode.value)
|
||||
)
|
||||
|
||||
// Model mapping helpers
|
||||
|
||||
@@ -3132,8 +3132,8 @@
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.accounts.openai.wsModeDesc') }}
|
||||
</p>
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t(openAIWSModeConcurrencyHintKey) }}
|
||||
<p v-if="openAIWSModeHintKey" class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t(openAIWSModeHintKey) }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="w-52">
|
||||
@@ -3975,7 +3975,7 @@ import {
|
||||
OPENAI_WS_MODE_PASSTHROUGH,
|
||||
OPENAI_WS_MODE_HTTP_BRIDGE,
|
||||
isOpenAIWSModeEnabled,
|
||||
resolveOpenAIWSModeConcurrencyHintKey,
|
||||
resolveOpenAIWSModeHintKey,
|
||||
type OpenAIWSMode
|
||||
} from '@/utils/openaiWsMode'
|
||||
import OAuthAuthorizationFlow from './OAuthAuthorizationFlow.vue'
|
||||
@@ -4653,8 +4653,8 @@ const openaiResponsesWebSocketV2Mode = computed({
|
||||
}
|
||||
})
|
||||
|
||||
const openAIWSModeConcurrencyHintKey = computed(() =>
|
||||
resolveOpenAIWSModeConcurrencyHintKey(openaiResponsesWebSocketV2Mode.value)
|
||||
const openAIWSModeHintKey = computed(() =>
|
||||
resolveOpenAIWSModeHintKey(openaiResponsesWebSocketV2Mode.value)
|
||||
)
|
||||
|
||||
const isOpenAIModelRestrictionDisabled = computed(() =>
|
||||
|
||||
@@ -1871,8 +1871,8 @@
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.accounts.openai.wsModeDesc') }}
|
||||
</p>
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t(openAIWSModeConcurrencyHintKey) }}
|
||||
<p v-if="openAIWSModeHintKey" class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t(openAIWSModeHintKey) }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="w-52">
|
||||
@@ -3101,7 +3101,7 @@ import {
|
||||
OPENAI_WS_MODE_PASSTHROUGH,
|
||||
OPENAI_WS_MODE_HTTP_BRIDGE,
|
||||
isOpenAIWSModeEnabled,
|
||||
resolveOpenAIWSModeConcurrencyHintKey,
|
||||
resolveOpenAIWSModeHintKey,
|
||||
type OpenAIWSMode,
|
||||
resolveOpenAIWSModeFromExtra
|
||||
} from '@/utils/openaiWsMode'
|
||||
@@ -3588,8 +3588,8 @@ const openaiResponsesWebSocketV2Mode = computed({
|
||||
openaiOAuthResponsesWebSocketV2Mode.value = mode
|
||||
}
|
||||
})
|
||||
const openAIWSModeConcurrencyHintKey = computed(() =>
|
||||
resolveOpenAIWSModeConcurrencyHintKey(openaiResponsesWebSocketV2Mode.value)
|
||||
const openAIWSModeHintKey = computed(() =>
|
||||
resolveOpenAIWSModeHintKey(openaiResponsesWebSocketV2Mode.value)
|
||||
)
|
||||
const codexImageToolOptions = computed<Array<{
|
||||
value: CodexImageToolMode
|
||||
|
||||
@@ -5,9 +5,7 @@ import zh from '../locales/zh/admin/accounts'
|
||||
|
||||
describe('OpenAI WS mode locale descriptions', () => {
|
||||
it('documents the global v2 router requirement for account WS modes', () => {
|
||||
expect(zh.accounts.openai.wsModeDesc).toContain('mode_router_v2_enabled')
|
||||
expect(zh.accounts.openai.wsModeDesc).toContain('http_bridge')
|
||||
expect(en.accounts.openai.wsModeDesc).toContain('mode_router_v2_enabled')
|
||||
expect(en.accounts.openai.wsModeDesc).toContain('http_bridge')
|
||||
expect(zh.accounts.openai.wsModeDesc).toContain('mode_router_v2_enabled=true')
|
||||
expect(en.accounts.openai.wsModeDesc).toContain('mode_router_v2_enabled=true')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -605,16 +605,19 @@ export default {
|
||||
'Disabled by default. Enable to allow responses_websockets_v2 capability (still gated by global and account-type switches).',
|
||||
wsMode: 'WS mode',
|
||||
wsModeDesc:
|
||||
'Only applies to the current OpenAI account type; account WS modes, including http_bridge, take effect only when the global gateway.openai_ws.mode_router_v2_enabled=true.',
|
||||
'Applies only to the current OpenAI account type. Select Off to disable WS. Other modes use the selected connection method only when gateway.openai_ws.mode_router_v2_enabled=true; otherwise, they use the context pool.',
|
||||
wsModeOff: 'Off (off)',
|
||||
wsModeCtxPool: 'Context Pool (ctx_pool)',
|
||||
wsModePassthrough: 'Passthrough (passthrough)',
|
||||
wsModeHttpBridge: 'HTTP Bridge (http_bridge)',
|
||||
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.',
|
||||
wsModeCtxPoolHint:
|
||||
'The gateway gets and reuses upstream WS connections from a pool, with the pool limit determined by gateway configuration.',
|
||||
wsModePassthroughHint:
|
||||
'The gateway opens a separate upstream WS connection for each client session, without using a connection pool.',
|
||||
wsModeHttpBridgeHint:
|
||||
'The gateway converts client WS requests to upstream HTTP requests, then converts SSE streaming responses back into WS messages.',
|
||||
oauthResponsesWebsocketsV2: 'OAuth WebSocket Mode',
|
||||
oauthResponsesWebsocketsV2Desc:
|
||||
'Only applies to OpenAI OAuth. This account can use OpenAI WebSocket Mode only when enabled.',
|
||||
|
||||
@@ -691,15 +691,16 @@ export default {
|
||||
'默认关闭。开启后可启用 responses_websockets_v2 协议能力(受网关全局开关与账号类型开关约束)。',
|
||||
wsMode: 'WS mode',
|
||||
wsModeDesc:
|
||||
'仅对当前 OpenAI 账号类型生效;包括 http_bridge 在内的账号 WS mode 仅在全局 gateway.openai_ws.mode_router_v2_enabled=true 时生效。',
|
||||
'仅对当前 OpenAI 账号类型生效。选择“关闭”可禁用 WS;其余模式需全局 gateway.openai_ws.mode_router_v2_enabled=true 才按所选方式连接,未开启时统一使用上下文池。',
|
||||
wsModeOff: '关闭(off)',
|
||||
wsModeCtxPool: '上下文池(ctx_pool)',
|
||||
wsModePassthrough: '透传(passthrough)',
|
||||
wsModeHttpBridge: 'HTTP 桥接(http_bridge)',
|
||||
wsModeShared: '共享(shared)',
|
||||
wsModeDedicated: '独享(dedicated)',
|
||||
wsModeConcurrencyHint: '启用 WS mode 后,该账号并发数将作为该账号 WS 连接池上限。',
|
||||
wsModePassthroughHint: 'passthrough 模式不使用 WS 连接池。',
|
||||
wsModeCtxPoolHint: '网关从连接池获取并复用上游 WS 连接,连接池上限由网关配置决定。',
|
||||
wsModePassthroughHint: '网关为每个客户端会话单独建立上游 WS 连接,不使用连接池。',
|
||||
wsModeHttpBridgeHint: '网关将客户端 WS 请求转换为上游 HTTP 请求,再将 SSE 流式响应转换为 WS 消息返回。',
|
||||
oauthResponsesWebsocketsV2: 'OAuth WebSocket Mode',
|
||||
oauthResponsesWebsocketsV2Desc:
|
||||
'仅对 OpenAI OAuth 生效。开启后该账号才允许使用 OpenAI WebSocket Mode 协议。',
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
isOpenAIWSModeEnabled,
|
||||
normalizeOpenAIWSMode,
|
||||
openAIWSModeFromEnabled,
|
||||
resolveOpenAIWSModeConcurrencyHintKey,
|
||||
resolveOpenAIWSModeHintKey,
|
||||
resolveOpenAIWSModeFromExtra
|
||||
} from '@/utils/openaiWsMode'
|
||||
|
||||
@@ -59,18 +59,16 @@ describe('openaiWsMode utils', () => {
|
||||
expect(isOpenAIWSModeEnabled(OPENAI_WS_MODE_HTTP_BRIDGE)).toBe(true)
|
||||
})
|
||||
|
||||
it('resolves concurrency hint key by mode', () => {
|
||||
expect(resolveOpenAIWSModeConcurrencyHintKey(OPENAI_WS_MODE_OFF)).toBe(
|
||||
'admin.accounts.openai.wsModeConcurrencyHint'
|
||||
it('hides the off hint and resolves each active mode separately', () => {
|
||||
expect(resolveOpenAIWSModeHintKey(OPENAI_WS_MODE_OFF)).toBeNull()
|
||||
expect(resolveOpenAIWSModeHintKey(OPENAI_WS_MODE_CTX_POOL)).toBe(
|
||||
'admin.accounts.openai.wsModeCtxPoolHint'
|
||||
)
|
||||
expect(resolveOpenAIWSModeConcurrencyHintKey(OPENAI_WS_MODE_CTX_POOL)).toBe(
|
||||
'admin.accounts.openai.wsModeConcurrencyHint'
|
||||
)
|
||||
expect(resolveOpenAIWSModeConcurrencyHintKey(OPENAI_WS_MODE_PASSTHROUGH)).toBe(
|
||||
expect(resolveOpenAIWSModeHintKey(OPENAI_WS_MODE_PASSTHROUGH)).toBe(
|
||||
'admin.accounts.openai.wsModePassthroughHint'
|
||||
)
|
||||
expect(resolveOpenAIWSModeConcurrencyHintKey(OPENAI_WS_MODE_HTTP_BRIDGE)).toBe(
|
||||
'admin.accounts.openai.wsModePassthroughHint'
|
||||
expect(resolveOpenAIWSModeHintKey(OPENAI_WS_MODE_HTTP_BRIDGE)).toBe(
|
||||
'admin.accounts.openai.wsModeHttpBridgeHint'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -44,13 +44,23 @@ export const isOpenAIWSModeEnabled = (mode: OpenAIWSMode): boolean => {
|
||||
return mode !== OPENAI_WS_MODE_OFF
|
||||
}
|
||||
|
||||
export const resolveOpenAIWSModeConcurrencyHintKey = (
|
||||
export const resolveOpenAIWSModeHintKey = (
|
||||
mode: OpenAIWSMode
|
||||
): 'admin.accounts.openai.wsModeConcurrencyHint' | 'admin.accounts.openai.wsModePassthroughHint' => {
|
||||
if (mode === OPENAI_WS_MODE_PASSTHROUGH || mode === OPENAI_WS_MODE_HTTP_BRIDGE) {
|
||||
return 'admin.accounts.openai.wsModePassthroughHint'
|
||||
):
|
||||
| 'admin.accounts.openai.wsModeCtxPoolHint'
|
||||
| 'admin.accounts.openai.wsModePassthroughHint'
|
||||
| 'admin.accounts.openai.wsModeHttpBridgeHint'
|
||||
| null => {
|
||||
switch (mode) {
|
||||
case OPENAI_WS_MODE_CTX_POOL:
|
||||
return 'admin.accounts.openai.wsModeCtxPoolHint'
|
||||
case OPENAI_WS_MODE_PASSTHROUGH:
|
||||
return 'admin.accounts.openai.wsModePassthroughHint'
|
||||
case OPENAI_WS_MODE_HTTP_BRIDGE:
|
||||
return 'admin.accounts.openai.wsModeHttpBridgeHint'
|
||||
default:
|
||||
return null
|
||||
}
|
||||
return 'admin.accounts.openai.wsModeConcurrencyHint'
|
||||
}
|
||||
|
||||
export const resolveOpenAIWSModeFromExtra = (
|
||||
|
||||
Reference in New Issue
Block a user