From 478215c5c184e4315e1f2f94cb825afcf96fcbc0 Mon Sep 17 00:00:00 2001 From: "Adam Perry @ OpenAI" Date: Fri, 14 Aug 2026 18:22:03 +0000 Subject: [PATCH] Preserve large gRPC code-mode tool errors (#38621) ## Why Code-mode tool failure messages larger than 64 KiB were truncated before they reached the host. ## What changed - Remove the tool error size limit from the gRPC protocol and host validation. - Forward failed tool completion messages without truncation. ## Testing - Verify that a multibyte error larger than 64 KiB is preserved exactly. GitOrigin-RevId: 264ae4ba4adea5c19b669e4f41ccfd41a0c30fb5 --- codex-rs/code-mode-host/src/grpc/mod.rs | 9 +----- .../code-mode-host/src/grpc/validation.rs | 1 - codex-rs/code-mode-protocol/src/grpc/mod.rs | 1 - .../code-mode/src/grpc_session/completion.rs | 28 ++++--------------- .../src/grpc_session/completion_tests.rs | 12 +++----- 5 files changed, 11 insertions(+), 40 deletions(-) diff --git a/codex-rs/code-mode-host/src/grpc/mod.rs b/codex-rs/code-mode-host/src/grpc/mod.rs index 10fe9df4cb..5cb991af48 100644 --- a/codex-rs/code-mode-host/src/grpc/mod.rs +++ b/codex-rs/code-mode-host/src/grpc/mod.rs @@ -83,14 +83,7 @@ impl GrpcCodeModeHost { Status::invalid_argument(format!("invalid code-mode tool output JSON: {error}")) })?, ), - Some(proto::complete_tool_call_request::Outcome::Failed(error)) => { - validation::bounded( - &error.message, - validation::MAX_TOOL_ERROR_BYTES, - "tool error message", - )?; - Err(error.message) - } + Some(proto::complete_tool_call_request::Outcome::Failed(error)) => Err(error.message), None => { return Err(Status::invalid_argument( "tool completion is missing its outcome", diff --git a/codex-rs/code-mode-host/src/grpc/validation.rs b/codex-rs/code-mode-host/src/grpc/validation.rs index 3f0559f988..6757b26aaf 100644 --- a/codex-rs/code-mode-host/src/grpc/validation.rs +++ b/codex-rs/code-mode-host/src/grpc/validation.rs @@ -3,7 +3,6 @@ use tonic::Status; use uuid::Uuid; pub(super) use codex_code_mode_protocol::grpc::MAX_IDENTIFIER_BYTES; -pub(super) use codex_code_mode_protocol::grpc::MAX_TOOL_ERROR_BYTES; pub(super) const MAX_TOOL_FILTERS: usize = 64; pub(super) fn identifier(value: &str, field: &str) -> Result<(), Status> { diff --git a/codex-rs/code-mode-protocol/src/grpc/mod.rs b/codex-rs/code-mode-protocol/src/grpc/mod.rs index 4d6ea3829e..08c88badea 100644 --- a/codex-rs/code-mode-protocol/src/grpc/mod.rs +++ b/codex-rs/code-mode-protocol/src/grpc/mod.rs @@ -5,4 +5,3 @@ pub use code_mode_proto::codex::code_mode::v1::*; tonic::include_proto!("codex.code_mode.v1"); pub const MAX_IDENTIFIER_BYTES: usize = 256; -pub const MAX_TOOL_ERROR_BYTES: usize = 64 * 1_024; diff --git a/codex-rs/code-mode/src/grpc_session/completion.rs b/codex-rs/code-mode/src/grpc_session/completion.rs index 16b743db2b..0a26154160 100644 --- a/codex-rs/code-mode/src/grpc_session/completion.rs +++ b/codex-rs/code-mode/src/grpc_session/completion.rs @@ -1,10 +1,7 @@ use codex_code_mode_protocol::grpc; -use codex_code_mode_protocol::grpc::MAX_TOOL_ERROR_BYTES; use codex_code_mode_protocol::host::MAX_FRAME_BYTES; use prost::Message; -const TRUNCATED_SUFFIX: &str = "... [truncated]"; - pub(super) fn request( session_id: &str, invocation_id: &str, @@ -27,12 +24,12 @@ fn request_with_maximum( }) } Err(error) => grpc::complete_tool_call_request::Outcome::Failed(grpc::ToolCallFailed { - message: bounded_error(format!("failed to encode code-mode tool result: {error}")), + message: format!("failed to encode code-mode tool result: {error}"), }), }, - Err(message) => grpc::complete_tool_call_request::Outcome::Failed(grpc::ToolCallFailed { - message: bounded_error(message), - }), + Err(message) => { + grpc::complete_tool_call_request::Outcome::Failed(grpc::ToolCallFailed { message }) + } }; let mut request = grpc::CompleteToolCallRequest { session_id: session_id.to_string(), @@ -43,28 +40,15 @@ fn request_with_maximum( if encoded_bytes > maximum_message_bytes { request.outcome = Some(grpc::complete_tool_call_request::Outcome::Failed( grpc::ToolCallFailed { - message: bounded_error(format!( + message: format!( "code-mode tool result of {encoded_bytes} encoded bytes exceeds the gRPC message limit of {maximum_message_bytes} bytes" - )), + ), }, )); } request } -fn bounded_error(mut message: String) -> String { - if message.len() <= MAX_TOOL_ERROR_BYTES { - return message; - } - let mut boundary = MAX_TOOL_ERROR_BYTES - TRUNCATED_SUFFIX.len(); - while !message.is_char_boundary(boundary) { - boundary -= 1; - } - message.truncate(boundary); - message.push_str(TRUNCATED_SUFFIX); - message -} - #[cfg(test)] #[path = "completion_tests.rs"] mod tests; diff --git a/codex-rs/code-mode/src/grpc_session/completion_tests.rs b/codex-rs/code-mode/src/grpc_session/completion_tests.rs index e53ba7d803..711955af41 100644 --- a/codex-rs/code-mode/src/grpc_session/completion_tests.rs +++ b/codex-rs/code-mode/src/grpc_session/completion_tests.rs @@ -2,8 +2,6 @@ use codex_code_mode_protocol::grpc; use pretty_assertions::assert_eq; use prost::Message; -use super::MAX_TOOL_ERROR_BYTES; -use super::TRUNCATED_SUFFIX; use super::request; use super::request_with_maximum; @@ -22,17 +20,15 @@ fn completion_size_includes_the_protobuf_envelope() { } #[test] -fn delegate_errors_are_truncated_at_a_utf8_boundary() { - let error = "🦀".repeat(MAX_TOOL_ERROR_BYTES); - let completion = request("session", "invocation", Err(error)); +fn delegate_errors_larger_than_64_kib_are_preserved() { + let error = "🦀".repeat(64 * 1024); + let completion = request("session", "invocation", Err(error.clone())); let Some(grpc::complete_tool_call_request::Outcome::Failed(failure)) = completion.outcome else { panic!("expected a failed tool completion"); }; - assert!(failure.message.len() <= MAX_TOOL_ERROR_BYTES); - assert!(failure.message.ends_with(TRUNCATED_SUFFIX)); - assert!(failure.message.starts_with('🦀')); + assert_eq!(failure.message, error); } #[test]