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
This commit is contained in:
Adam Perry @ OpenAI
2026-08-14 18:22:03 +00:00
committed by copyberry
parent 395723b238
commit 478215c5c1
5 changed files with 11 additions and 40 deletions

View File

@@ -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;

View File

@@ -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]