From 35aaa5d9fcb606fb6f27dd5747ecab3f4ba0c07e Mon Sep 17 00:00:00 2001 From: pakrym-oai Date: Fri, 1 May 2026 23:33:32 -0700 Subject: [PATCH] Bound websocket request sends with idle timeout (#20751) ## Why We saw Responses websocket sessions recover only after a long quiet period when the server had already logged the websocket as disconnected. The normal connect path is already bounded by `websocket_connect_timeout_ms`, but the first request send on an established websocket reused only the receive-side idle timeout after the write completed. If the socket write/pump stalls, the client can sit in `ws_stream.send(...)` without reaching the existing receive timeout. --- .../codex-api/src/endpoint/responses_websocket.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/codex-rs/codex-api/src/endpoint/responses_websocket.rs b/codex-rs/codex-api/src/endpoint/responses_websocket.rs index 4e97ecef9d..dd947a9dd7 100644 --- a/codex-rs/codex-api/src/endpoint/responses_websocket.rs +++ b/codex-rs/codex-api/src/endpoint/responses_websocket.rs @@ -556,10 +556,15 @@ async fn run_websocket_response_stream( trace!("websocket request: {request_text}"); let request_start = Instant::now(); - let result = ws_stream - .send(Message::Text(request_text.into())) - .await - .map_err(|err| ApiError::Stream(format!("failed to send websocket request: {err}"))); + let result = tokio::time::timeout( + idle_timeout, + ws_stream.send(Message::Text(request_text.into())), + ) + .await + .map_err(|_| ApiError::Stream("idle timeout sending websocket request".into())) + .and_then(|result| { + result.map_err(|err| ApiError::Stream(format!("failed to send websocket request: {err}"))) + }); if let Some(t) = telemetry.as_ref() { t.on_ws_request(