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
+39 -13
View File
@@ -35,21 +35,25 @@ pub(super) fn classify_ai_public_route(
"openai:rerank",
true,
))
} else if method == http::Method::GET
&& normalized_path == "/v1/realtime"
&& is_websocket_upgrade_request(headers)
{
Some(classified(
"ai_public",
"openai",
"realtime",
"openai:realtime",
true,
))
} else if (method == http::Method::POST && normalized_path == "/v1/live")
|| (method == http::Method::GET
&& (normalized_path == "/v1/live" || normalized_path.starts_with("/v1/live/"))
&& is_websocket_upgrade_request(headers))
{
// Codex Live is an experimental companion transport for an existing
// Responses mapping. It deliberately reuses the Responses permission
// surface while its wire protocol is handled by an independent relay.
Some(classified(
"ai_public",
"openai",
"live",
"openai:responses",
true,
))
// Codex Live has an independent wire contract and permission surface;
// it must never be authorized as an OpenAI Responses request.
Some(classified("ai_public", "codex", "live", "codex:live", true))
} else if (method == http::Method::POST
|| (method == http::Method::GET
&& normalized_path == "/v1/responses"
@@ -308,11 +312,32 @@ mod tests {
}
#[test]
fn classifies_live_http_and_websocket_routes_as_responses_companions() {
fn classifies_only_websocket_upgrade_on_realtime_route() {
let mut headers = HeaderMap::new();
headers.insert(CONNECTION, HeaderValue::from_static("keep-alive, Upgrade"));
headers.insert(UPGRADE, HeaderValue::from_static("websocket"));
let route = classify_ai_public_route(&Method::GET, "/v1/realtime", &headers)
.expect("Realtime WebSocket should be an AI public route");
assert_eq!(route.route_class, "ai_public");
assert_eq!(route.route_family, "openai");
assert_eq!(route.route_kind, "realtime");
assert_eq!(route.auth_endpoint_signature, "openai:realtime");
assert!(route.execution_runtime_candidate);
assert!(
classify_ai_public_route(&Method::GET, "/v1/realtime", &HeaderMap::new()).is_none()
);
assert!(classify_ai_public_route(&Method::POST, "/v1/realtime", &headers).is_none());
}
#[test]
fn classifies_live_http_and_websocket_routes_as_codex_live() {
let post = classify_ai_public_route(&Method::POST, "/v1/live", &HeaderMap::new())
.expect("Live WebRTC call creation should be an AI public route");
assert_eq!(post.route_family, "codex");
assert_eq!(post.route_kind, "live");
assert_eq!(post.auth_endpoint_signature, "openai:responses");
assert_eq!(post.auth_endpoint_signature, "codex:live");
let mut headers = HeaderMap::new();
headers.insert(CONNECTION, HeaderValue::from_static("Upgrade"));
@@ -320,8 +345,9 @@ mod tests {
for path in ["/v1/live", "/v1/live/rtc_opaque"] {
let route = classify_ai_public_route(&Method::GET, path, &headers)
.expect("Live WebSocket should be an AI public route");
assert_eq!(route.route_family, "codex");
assert_eq!(route.route_kind, "live");
assert_eq!(route.auth_endpoint_signature, "openai:responses");
assert_eq!(route.auth_endpoint_signature, "codex:live");
}
assert!(