mirror of
https://gitee.com/wanwujie/sub2api
synced 2026-04-17 13:24:45 +08:00
feat(openai-ws): 合并 WS v2 透传模式与前端 ws mode
新增 OpenAI WebSocket v2 passthrough relay 数据面与服务适配层, 支持按账号 ws mode 在 ctx_pool 与 passthrough 间路由。 同步调整前端 OpenAI ws mode 选项为 off/ctx_pool/passthrough, 并补充 i18n 文案与对应单测。 新增 Caddyfile.dmit 与 docker-compose-aicodex.yml 部署配置, 用于宿主机场景下的反向代理与服务编排。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,31 +1,34 @@
|
||||
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'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user