feat(gateway): add Codex Live transport

This commit is contained in:
ZheFox
2026-08-20 21:59:05 +08:00
parent 6916e9da76
commit 4185ad1b1e
35 changed files with 6683 additions and 85 deletions
@@ -321,15 +321,22 @@ async fn gateway_executes_openai_chat_stream_via_local_decision_gate_without_exe
.unwrap_or_default()
.to_string(),
});
let response_body = Body::from_stream(async_stream::stream! {
yield Ok::<Bytes, std::convert::Infallible>(Bytes::from_static(
b"data: {\"id\":\"chatcmpl-local-123\"}\n\n",
));
tokio::time::sleep(std::time::Duration::from_millis(250)).await;
yield Ok::<Bytes, std::convert::Infallible>(Bytes::from_static(
b"data: [DONE]\n\n",
));
});
let mut response = Response::builder()
.status(StatusCode::OK)
.body(Body::from(
"data: {\"id\":\"chatcmpl-local-123\"}\n\ndata: [DONE]\n\n",
))
.body(response_body)
.expect("response should build");
response.headers_mut().insert(
http::header::CONTENT_TYPE,
HeaderValue::from_static("text/event-stream"),
HeaderValue::from_static("application/octet-stream"),
);
response
}
@@ -368,12 +375,14 @@ async fn gateway_executes_openai_chat_stream_via_local_decision_gate_without_exe
DEVELOPMENT_ENCRYPTION_KEY,
),
);
let gateway = build_router_with_state(gateway_state);
let gateway = build_router_with_state(gateway_state)
.layer(tower_http::compression::CompressionLayer::new());
let (gateway_url, gateway_handle) = start_server(gateway).await;
let response = reqwest::Client::new()
let mut response = reqwest::Client::new()
.post(format!("{gateway_url}/v1/chat/completions"))
.header(http::header::CONTENT_TYPE, "application/json")
.header(http::header::ACCEPT_ENCODING, "gzip")
.header(
http::header::AUTHORIZATION,
"Bearer sk-client-openai-local-stream",
@@ -392,9 +401,32 @@ async fn gateway_executes_openai_chat_stream_via_local_decision_gate_without_exe
.and_then(|value| value.to_str().ok()),
Some(EXECUTION_PATH_EXECUTION_RUNTIME_STREAM)
);
assert_eq!(
response
.headers()
.get(http::header::CONTENT_TYPE)
.and_then(|value| value.to_str().ok()),
Some("text/event-stream")
);
assert!(
response
.headers()
.get(http::header::CONTENT_ENCODING)
.is_none(),
"SSE responses must not be gzip-buffered"
);
assert_eq!(
tokio::time::timeout(
std::time::Duration::from_millis(100),
super::super::next_non_keepalive_chunk(&mut response),
)
.await
.expect("first upstream SSE event should reach the client before completion"),
Bytes::from_static(b"data: {\"id\":\"chatcmpl-local-123\"}\n\n")
);
assert_eq!(
strip_sse_keepalive_comments(&response.text().await.expect("body should read")),
"data: {\"id\":\"chatcmpl-local-123\"}\n\ndata: [DONE]\n\n"
"data: [DONE]\n\n"
);
let seen_upstream_request = seen_upstream