mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] Send Responses Lite transport header (#26542)
## Summary - send `X-OpenAI-Internal-Codex-Responses-Lite: true` on HTTP Responses requests and WebSocket upgrade requests when model metadata enables Responses Lite - use client metadata when sending it over the websocket This PR is stacked on #26490. ## Why The Responses Lite marker is request-scoped for HTTP but connection-scoped for Responses-over-WebSocket because it is carried on the upgrade request. Reusing a cached socket opened for the opposite mode would therefore send the wrong transport contract. ## Validation - `just test -p codex-core responses_lite` - `just test -p codex-core responses_websocket_reconnects_when_responses_lite_mode_changes` - `just fix -p codex-core` - `just fmt`
This commit is contained in:
committed by
GitHub
Unverified
parent
df7818c7d1
commit
954e2878bb
@@ -143,7 +143,11 @@ pub const X_RESPONSESAPI_INCLUDE_TIMING_METRICS_HEADER: &str =
|
||||
"x-responsesapi-include-timing-metrics";
|
||||
const X_CODEX_WS_STREAM_REQUEST_START_MS_CLIENT_METADATA_KEY: &str =
|
||||
"x-codex-ws-stream-request-start-ms";
|
||||
const WS_REQUEST_HEADER_RESPONSES_LITE_CLIENT_METADATA_KEY: &str =
|
||||
"ws_request_header_x_openai_internal_codex_responses_lite";
|
||||
const RESPONSES_WEBSOCKETS_V2_BETA_HEADER_VALUE: &str = "responses_websockets=2026-02-06";
|
||||
const X_OPENAI_INTERNAL_CODEX_RESPONSES_LITE_HEADER: &str =
|
||||
"x-openai-internal-codex-responses-lite";
|
||||
const RESPONSES_ENDPOINT: &str = "/responses";
|
||||
const RESPONSES_COMPACT_ENDPOINT: &str = "/responses/compact";
|
||||
// `/responses/compact` is unary, so the timeout covers the full response rather than one idle
|
||||
@@ -526,6 +530,7 @@ impl ModelClient {
|
||||
if let Some(header_value) = self.generate_attestation_header_for().await {
|
||||
extra_headers.insert(X_OAI_ATTESTATION_HEADER, header_value);
|
||||
}
|
||||
add_responses_lite_header(&mut extra_headers, model_info.use_responses_lite);
|
||||
let compact_request_timeout = client_setup
|
||||
.api_provider
|
||||
.stream_idle_timeout
|
||||
@@ -655,6 +660,7 @@ impl ModelClient {
|
||||
fn build_ws_client_metadata(
|
||||
&self,
|
||||
turn_metadata_header: Option<&str>,
|
||||
use_responses_lite: bool,
|
||||
) -> HashMap<String, String> {
|
||||
let mut client_metadata = HashMap::new();
|
||||
client_metadata.insert(
|
||||
@@ -682,6 +688,12 @@ impl ModelClient {
|
||||
turn_metadata.to_string(),
|
||||
);
|
||||
}
|
||||
if use_responses_lite {
|
||||
client_metadata.insert(
|
||||
WS_REQUEST_HEADER_RESPONSES_LITE_CLIENT_METADATA_KEY.to_string(),
|
||||
"true".to_string(),
|
||||
);
|
||||
}
|
||||
client_metadata
|
||||
}
|
||||
|
||||
@@ -982,6 +994,7 @@ impl ModelClientSession {
|
||||
&self,
|
||||
turn_metadata_header: Option<&str>,
|
||||
compression: Compression,
|
||||
use_responses_lite: bool,
|
||||
) -> ApiResponsesOptions {
|
||||
let turn_metadata_header = parse_turn_metadata_header(turn_metadata_header);
|
||||
let session_id = self.client.state.session_id.to_string();
|
||||
@@ -1000,6 +1013,7 @@ impl ModelClientSession {
|
||||
if let Some(header_value) = self.client.generate_attestation_header_for().await {
|
||||
headers.insert(X_OAI_ATTESTATION_HEADER, header_value);
|
||||
}
|
||||
add_responses_lite_header(&mut headers, use_responses_lite);
|
||||
headers
|
||||
},
|
||||
compression,
|
||||
@@ -1267,7 +1281,11 @@ impl ModelClientSession {
|
||||
);
|
||||
let compression = self.responses_request_compression(client_setup.auth.as_ref());
|
||||
let mut options = self
|
||||
.build_responses_options(turn_metadata_header, compression)
|
||||
.build_responses_options(
|
||||
turn_metadata_header,
|
||||
compression,
|
||||
model_info.use_responses_lite,
|
||||
)
|
||||
.await;
|
||||
|
||||
let request = self.client.build_responses_request(
|
||||
@@ -1377,7 +1395,11 @@ impl ModelClientSession {
|
||||
let compression = self.responses_request_compression(client_setup.auth.as_ref());
|
||||
|
||||
let options = self
|
||||
.build_responses_options(turn_metadata_header, compression)
|
||||
.build_responses_options(
|
||||
turn_metadata_header,
|
||||
compression,
|
||||
model_info.use_responses_lite,
|
||||
)
|
||||
.await;
|
||||
let request = self.client.build_responses_request(
|
||||
&client_setup.api_provider,
|
||||
@@ -1389,7 +1411,10 @@ impl ModelClientSession {
|
||||
)?;
|
||||
let mut ws_payload = ResponseCreateWsRequest {
|
||||
client_metadata: response_create_client_metadata(
|
||||
Some(self.client.build_ws_client_metadata(turn_metadata_header)),
|
||||
Some(self.client.build_ws_client_metadata(
|
||||
turn_metadata_header,
|
||||
model_info.use_responses_lite,
|
||||
)),
|
||||
request_trace.as_ref(),
|
||||
),
|
||||
..ResponseCreateWsRequest::from(&request)
|
||||
@@ -1707,6 +1732,15 @@ fn build_responses_headers(
|
||||
headers
|
||||
}
|
||||
|
||||
fn add_responses_lite_header(headers: &mut ApiHeaderMap, use_responses_lite: bool) {
|
||||
if use_responses_lite {
|
||||
headers.insert(
|
||||
X_OPENAI_INTERNAL_CODEX_RESPONSES_LITE_HEADER,
|
||||
HeaderValue::from_static("true"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn subagent_header_value(session_source: &SessionSource) -> Option<String> {
|
||||
match session_source {
|
||||
SessionSource::SubAgent(subagent_source) => match subagent_source {
|
||||
|
||||
@@ -293,7 +293,10 @@ fn build_ws_client_metadata_includes_window_lineage_and_turn_metadata() {
|
||||
|
||||
client.advance_window_generation();
|
||||
|
||||
let client_metadata = client.build_ws_client_metadata(Some(r#"{"turn_id":"turn-123"}"#));
|
||||
let client_metadata = client.build_ws_client_metadata(
|
||||
Some(r#"{"turn_id":"turn-123"}"#),
|
||||
/*use_responses_lite*/ false,
|
||||
);
|
||||
let thread_id = client.state.thread_id;
|
||||
assert_eq!(
|
||||
client_metadata,
|
||||
|
||||
Reference in New Issue
Block a user