mirror of
https://github.com/openai/codex.git
synced 2026-04-29 17:06:51 +00:00
Add the utility to truncate by tokens (#6746)
- This PR is to make it on path for truncating by tokens. This path will be initially used by unified exec and context manager (responsible for MCP calls mainly). - We are exposing new config `calls_output_max_tokens` - Use `tokens` as the main budget unit but truncate based on the model family by Introducing `TruncationPolicy`. - Introduce `truncate_text` as a router for truncation based on the mode. In next PRs: - remove truncate_with_line_bytes_budget - Add the ability to the model to override the token budget.
This commit is contained in:
@@ -26,9 +26,11 @@ use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::wait_for_event;
|
||||
use core_test_support::wait_for_event_match;
|
||||
use core_test_support::wait_for_event_with_timeout;
|
||||
use regex_lite::Regex;
|
||||
use serde_json::Value;
|
||||
use serde_json::json;
|
||||
use tokio::time::Duration;
|
||||
|
||||
fn extract_output_text(item: &Value) -> Option<&str> {
|
||||
item.get("output").and_then(|value| match value {
|
||||
@@ -814,7 +816,7 @@ async fn exec_command_reports_chunk_and_exit_metadata() -> Result<()> {
|
||||
|
||||
let call_id = "uexec-metadata";
|
||||
let args = serde_json::json!({
|
||||
"cmd": "printf 'abcdefghijklmnopqrstuvwxyz'",
|
||||
"cmd": "printf 'token one token two token three token four token five token six token seven'",
|
||||
"yield_time_ms": 500,
|
||||
"max_output_tokens": 6,
|
||||
});
|
||||
@@ -1295,7 +1297,7 @@ async fn unified_exec_streams_after_lagged_output() -> Result<()> {
|
||||
import sys
|
||||
import time
|
||||
|
||||
chunk = b'x' * (1 << 20)
|
||||
chunk = b'long content here to trigger truncation' * (1 << 10)
|
||||
for _ in range(4):
|
||||
sys.stdout.buffer.write(chunk)
|
||||
sys.stdout.flush()
|
||||
@@ -1365,8 +1367,13 @@ PY
|
||||
summary: ReasoningSummary::Auto,
|
||||
})
|
||||
.await?;
|
||||
|
||||
wait_for_event(&codex, |event| matches!(event, EventMsg::TaskComplete(_))).await;
|
||||
// This is a worst case scenario for the truncate logic.
|
||||
wait_for_event_with_timeout(
|
||||
&codex,
|
||||
|event| matches!(event, EventMsg::TaskComplete(_)),
|
||||
Duration::from_secs(10),
|
||||
)
|
||||
.await;
|
||||
|
||||
let requests = server.received_requests().await.expect("recorded requests");
|
||||
assert!(!requests.is_empty(), "expected at least one POST request");
|
||||
@@ -1523,14 +1530,15 @@ async fn unified_exec_formats_large_output_summary() -> Result<()> {
|
||||
} = builder.build(&server).await?;
|
||||
|
||||
let script = r#"python3 - <<'PY'
|
||||
for i in range(300):
|
||||
print(f"line-{i}")
|
||||
for i in range(10000):
|
||||
print("token token ")
|
||||
PY
|
||||
"#;
|
||||
|
||||
let call_id = "uexec-large-output";
|
||||
let args = serde_json::json!({
|
||||
"cmd": script,
|
||||
"max_output_tokens": 100,
|
||||
"yield_time_ms": 500,
|
||||
});
|
||||
|
||||
@@ -1577,15 +1585,14 @@ PY
|
||||
let outputs = collect_tool_outputs(&bodies)?;
|
||||
let large_output = outputs.get(call_id).expect("missing large output summary");
|
||||
|
||||
assert_regex_match(
|
||||
concat!(
|
||||
r"(?s)",
|
||||
r"line-0.*?",
|
||||
r"\[\.{3} omitted \d+ of \d+ lines \.{3}\].*?",
|
||||
r"line-299",
|
||||
),
|
||||
&large_output.output,
|
||||
);
|
||||
let output_text = large_output.output.replace("\r\n", "\n");
|
||||
let truncated_pattern = r#"(?s)^(token token \n){5,}.*\[\u{2026}\d+ tokens truncated\u{2026}]\n(token token \n){5,}$"#;
|
||||
assert_regex_match(truncated_pattern, &output_text);
|
||||
|
||||
let original_tokens = large_output
|
||||
.original_token_count
|
||||
.expect("missing original_token_count for large output summary");
|
||||
assert!(original_tokens > 0);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user