mirror of
https://github.com/openai/codex.git
synced 2026-10-20 17:38:45 +00:00
## Why Removing tool-result metadata alone can leave requests above the 15 MiB message budget when recorded tool calls and arguments occupy the remaining space. If trimming loses calls or arguments from a Code Mode cell, later waits must not report its call inventory as complete. ## What changed - Bound all optional tool-call observations against the serialized HTTP or WebSocket message size, preserving ordinary tool outputs and continuation history. - Shed generic result metadata, sources, and recorded arguments before resource-access evidence, retaining tool names and smaller metadata where possible. - Invalidate completeness across affected cell outputs and later waits when the outgoing copy loses calls or arguments. - Preserve size-limit omission markers for direct tool-result metadata when they fit, while continuing to exclude that metadata from custom providers. ## Testing Add regression coverage for HTTP and WebSocket message budgets, unchanged tool results and history, resource-evidence retention, direct-call omission markers, and Code Mode waits after argument truncation. GitOrigin-RevId: 538dc9d8c11b0830ec70327422f98a1803122e85
46 lines
1.7 KiB
Rust
46 lines
1.7 KiB
Rust
//! Bounds optional tool observations using the actual outgoing Responses message.
|
|
//! Only the wire copy changes; model-visible input and WebSocket continuation history stay intact.
|
|
|
|
use crate::tools::metadata_metrics;
|
|
use crate::utils::json::serialized_json_bytes;
|
|
use codex_protocol::models::ResponseItem;
|
|
use codex_protocol::models::bound_executed_tool_calls_for_message;
|
|
use serde::Serialize;
|
|
|
|
const MAX_RESPONSE_MESSAGE_BYTES: usize = 15 * 1024 * 1024;
|
|
|
|
pub(super) fn bounded_input<T: Serialize>(
|
|
message: &T,
|
|
input: &[ResponseItem],
|
|
) -> Option<Vec<ResponseItem>> {
|
|
if !input.iter().any(|item| {
|
|
item.executed_tool_call_metadata().is_some_and(|metadata| {
|
|
metadata.executed_tool_calls.is_some()
|
|
|| metadata.cell_id.is_some()
|
|
|| metadata.tool_calls_complete.is_some()
|
|
})
|
|
}) {
|
|
return None;
|
|
}
|
|
// Serialization errors belong to the transport's existing error path, not this soft budget.
|
|
let message_bytes = serialized_json_bytes(message).ok()?;
|
|
if message_bytes <= MAX_RESPONSE_MESSAGE_BYTES {
|
|
return None;
|
|
}
|
|
let before = metadata_metrics::metadata_bytes(input);
|
|
let mut bounded = input.to_vec();
|
|
let overage = message_bytes - MAX_RESPONSE_MESSAGE_BYTES;
|
|
bound_executed_tool_calls_for_message(&mut bounded, before.saturating_sub(overage));
|
|
let after = metadata_metrics::metadata_bytes(&bounded);
|
|
if before == after {
|
|
return None;
|
|
}
|
|
metadata_metrics::record_shedding("message", before, after, codex_otel::global().as_ref());
|
|
// Ordinary content alone can exceed the soft limit. Preserve it and existing error handling.
|
|
Some(bounded)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "client_tool_metadata_tests.rs"]
|
|
mod tests;
|