Skip to content

Commit e4fcc58

Browse files
committed
fix(oai): align HTTPS Codex compatibility identity
1 parent 498058e commit e4fcc58

4 files changed

Lines changed: 55 additions & 11 deletions

File tree

crates/nanocodex-oai-api/src/transport/http.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use http::header;
55
use tokio::time::timeout;
66
use tokio_tungstenite::tungstenite::Utf8Bytes;
77

8+
use super::{CODEX_COMPATIBILITY_USER_AGENT, CODEX_COMPATIBILITY_VERSION, CODEX_ORIGINATOR};
89
use crate::{EncodedRequest, ResponsesError, socket::ReceivedText};
910

1011
const EVENT_IDLE_TIMEOUT: Duration = if cfg!(test) {
@@ -55,10 +56,9 @@ impl ResponsesHttp {
5556
.header("session-id", session_id)
5657
.header("thread-id", session_id)
5758
.header("x-client-request-id", session_id)
58-
.header(
59-
header::USER_AGENT,
60-
concat!("nanocodex/", env!("CARGO_PKG_VERSION")),
61-
)
59+
.header("originator", CODEX_ORIGINATOR)
60+
.header("version", CODEX_COMPATIBILITY_VERSION)
61+
.header(header::USER_AGENT, CODEX_COMPATIBILITY_USER_AGENT)
6262
.body(request.raw().get().to_owned());
6363
if let Some(account_id) = auth.account_id() {
6464
builder = builder.header("ChatGPT-Account-ID", account_id);

crates/nanocodex-oai-api/src/transport/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ pub(crate) mod socket;
1616
pub(crate) mod telemetry;
1717
mod wire;
1818

19+
pub(crate) const CODEX_ORIGINATOR: &str = "codex_cli_rs";
20+
pub(crate) const CODEX_COMPATIBILITY_VERSION: &str = "0.1337.0";
21+
pub(crate) const CODEX_COMPATIBILITY_USER_AGENT: &str = concat!(
22+
"codex_cli_rs/0.1337.0 (nanocodex/",
23+
env!("CARGO_PKG_VERSION"),
24+
")"
25+
);
26+
1927
use std::{fmt, str::FromStr};
2028

2129
pub use crate::tower::attempt::{TransportStats, TransportStatsDelta, TransportStatsSnapshot};

crates/nanocodex-oai-api/src/transport/socket.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use tokio_tungstenite::{
1717
use crate::{EncodedRequest, OpenAiAuthSnapshot, ResponsesError, connector::connect_async};
1818
use crate::{monotonic_now_ns, transport::wire::turn_state_from_event};
1919

20+
use super::{CODEX_COMPATIBILITY_USER_AGENT, CODEX_COMPATIBILITY_VERSION, CODEX_ORIGINATOR};
2021
pub(crate) use crate::transport::wire::{decode_event, parse_raw_json};
2122

2223
const CONNECT_TIMEOUT: Duration = Duration::from_secs(30);
@@ -30,13 +31,6 @@ const SOCKET_MESSAGE_CAPACITY: usize = 32;
3031
const RESPONSES_WEBSOCKETS_BETA: &str = "responses_websockets=2026-02-06";
3132
const RESPONSES_LITE_HEADER: &str = "x-openai-internal-codex-responses-lite";
3233
const TURN_STATE_HEADER: &str = "x-codex-turn-state";
33-
const CODEX_ORIGINATOR: &str = "codex_cli_rs";
34-
const CODEX_COMPATIBILITY_VERSION: &str = "0.1337.0";
35-
const CODEX_COMPATIBILITY_USER_AGENT: &str = concat!(
36-
"codex_cli_rs/0.1337.0 (nanocodex/",
37-
env!("CARGO_PKG_VERSION"),
38-
")"
39-
);
4034

4135
type Socket = WebSocketStream<MaybeTlsStream<TcpStream>>;
4236

crates/nanocodex-oai-api/tests/it/https.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,48 @@ use tokio::{
99

1010
const TURN_STATE_HEADER: &str = "x-codex-turn-state";
1111

12+
#[tokio::test]
13+
async fn https_requests_advertise_supported_codex_compatibility_version() -> Result<()> {
14+
let listener = TcpListener::bind("127.0.0.1:0").await?;
15+
let api_base_url = format!("http://{}", listener.local_addr()?);
16+
let server = tokio::spawn(async move {
17+
let request = read_http_json(&listener).await?;
18+
assert!(
19+
request.headers.contains("\r\noriginator: codex_cli_rs\r\n"),
20+
"HTTPS requests must identify as the supported Codex client"
21+
);
22+
assert!(
23+
request.headers.contains("\r\nversion: 0.1337.0\r\n"),
24+
"HTTPS requests must advertise the supported Codex compatibility version"
25+
);
26+
let expected_user_agent = format!(
27+
"\r\nuser-agent: codex_cli_rs/0.1337.0 (nanocodex/{})\r\n",
28+
env!("CARGO_PKG_VERSION")
29+
);
30+
assert!(
31+
request.headers.contains(&expected_user_agent),
32+
"HTTPS requests must retain Nanocodex provenance in the Codex user agent"
33+
);
34+
send_http_events(
35+
request.stream,
36+
None,
37+
[completed_response("resp-version", "ok")],
38+
)
39+
.await
40+
});
41+
42+
let openai = OpenAi::builder("test-key")
43+
.transport(ResponsesTransport::Https)
44+
.api_base_url(api_base_url)
45+
.build()?;
46+
let mut session = openai.instructions("Respond with one word.").build()?;
47+
assert_eq!(session.turn().create("test").await?.output_text(), "ok");
48+
timeout(std::time::Duration::from_secs(5), server)
49+
.await
50+
.map_err(|_| eyre!("mock HTTPS compatibility server did not finish"))???;
51+
Ok(())
52+
}
53+
1254
#[tokio::test]
1355
async fn https_turn_state_is_scoped_to_one_logical_turn_and_survives_retry() -> Result<()> {
1456
let listener = TcpListener::bind("127.0.0.1:0").await?;

0 commit comments

Comments
 (0)