feat(gateway): add Codex Live and OpenAI Realtime

Implement preflighted Live/Realtime WebSocket transports, protocol-aware authentication, usage auditing, UI filtering, and legacy Codex permission migration.
This commit is contained in:
ZheFox
2026-08-21 04:27:34 +08:00
parent fe38dcd294
commit 2c89202001
105 changed files with 7553 additions and 947 deletions
@@ -113,6 +113,55 @@ function buildFastTierDetail(): RequestDetail {
}
describe('RequestDetailDrawer settlement pricing', () => {
it('labels an unmetered Codex Live WebSocket detail without rendering zero usage as billing', async () => {
apiMocks.getRequestDetail.mockResolvedValue({
...buildEmbeddingDetail(),
id: 'usage-live-ws-1',
request_id: 'req-live-ws-1',
tokens: { input: 0, output: 0, total: 0 },
input_tokens: 0,
output_tokens: 0,
total_tokens: 0,
cost: { input: 0, output: 0, total: 0 },
total_cost: 0,
is_stream: true,
is_websocket: true,
websocket_transport: 'codex_live_sideband',
usage_available: false,
} satisfies RequestDetail)
let isOpen!: Ref<boolean>
const Host = defineComponent({
setup() {
isOpen = ref(false)
return () => h(RequestDetailDrawer, {
isOpen: isOpen.value,
requestId: 'usage-live-ws-1',
})
},
})
const root = document.createElement('div')
document.body.appendChild(root)
const app = createApp(Host)
app.mount(root)
mountedApps.push({ app, root })
isOpen.value = true
await nextTick()
await vi.waitFor(() => {
const transport = document.body.querySelector<HTMLElement>('[data-usage-transport="websocket"]')
expect(transport?.textContent?.trim()).toBe('Live WS')
expect(transport?.title).toBe('Codex Live Sideband WebSocket')
expect(document.body.querySelector('[data-request-detail-usage-unavailable]')).not.toBeNull()
})
const totals = [...document.body.querySelectorAll<HTMLElement>('[data-request-detail-total-cost]')]
expect(totals.length).toBe(2)
expect(totals.every(total => total.textContent?.trim() === '不可用')).toBe(true)
})
it('shows end-to-end latency while keeping output TPS scoped to candidate timing', async () => {
apiMocks.getRequestDetail.mockResolvedValue({
...buildEmbeddingDetail(),