Move shell to use truncate_text (#6842)

Move shell to use the configurable `truncate_text`

---------

Co-authored-by: pakrym-oai <pakrym@openai.com>
This commit is contained in:
Ahmed Ibrahim
2025-11-19 01:56:08 -08:00
committed by GitHub
parent 75f38f16dd
commit efebc62fb7
16 changed files with 583 additions and 498 deletions

View File

@@ -242,12 +242,16 @@ impl ToolEmitter {
self.emit(ctx, ToolEventStage::Begin).await;
}
fn format_exec_output_for_model(&self, output: &ExecToolCallOutput) -> String {
fn format_exec_output_for_model(
&self,
output: &ExecToolCallOutput,
ctx: ToolEventCtx<'_>,
) -> String {
match self {
Self::Shell { freeform: true, .. } => {
super::format_exec_output_for_model_freeform(output)
super::format_exec_output_for_model_freeform(output, ctx.turn.truncation_policy)
}
_ => super::format_exec_output_for_model_structured(output),
_ => super::format_exec_output_for_model_structured(output, ctx.turn.truncation_policy),
}
}
@@ -258,7 +262,7 @@ impl ToolEmitter {
) -> Result<String, FunctionCallError> {
let (event, result) = match out {
Ok(output) => {
let content = self.format_exec_output_for_model(&output);
let content = self.format_exec_output_for_model(&output, ctx);
let exit_code = output.exit_code;
let event = ToolEventStage::Success(output);
let result = if exit_code == 0 {
@@ -270,7 +274,7 @@ impl ToolEmitter {
}
Err(ToolError::Codex(CodexErr::Sandbox(SandboxErr::Timeout { output })))
| Err(ToolError::Codex(CodexErr::Sandbox(SandboxErr::Denied { output }))) => {
let response = self.format_exec_output_for_model(&output);
let response = self.format_exec_output_for_model(&output, ctx);
let event = ToolEventStage::Failure(ToolEventFailure::Output(*output));
let result = Err(FunctionCallError::RespondToModel(response));
(event, result)
@@ -359,7 +363,7 @@ async fn emit_exec_stage(
aggregated_output: output.aggregated_output.text.clone(),
exit_code: output.exit_code,
duration: output.duration,
formatted_output: format_exec_output_str(&output),
formatted_output: format_exec_output_str(&output, ctx.turn.truncation_policy),
};
emit_exec_end(ctx, exec_input, exec_result).await;
}

View File

@@ -9,9 +9,10 @@ pub mod runtimes;
pub mod sandboxing;
pub mod spec;
use crate::context_manager::truncate_with_line_bytes_budget;
use crate::exec::ExecToolCallOutput;
use crate::truncate::truncate_formatted_exec_output;
use crate::truncate::TruncationPolicy;
use crate::truncate::formatted_truncate_text;
use crate::truncate::truncate_text;
pub use router::ToolRouter;
use serde::Serialize;
@@ -21,12 +22,12 @@ pub(crate) const TELEMETRY_PREVIEW_MAX_LINES: usize = 64; // lines
pub(crate) const TELEMETRY_PREVIEW_TRUNCATION_NOTICE: &str =
"[... telemetry preview truncated ...]";
// TODO(aibrahim): migrate shell tool to use truncate text and respect config value
const SHELL_OUTPUT_MAX_BYTES: usize = 10_000;
/// Format the combined exec output for sending back to the model.
/// Includes exit code and duration metadata; truncates large bodies safely.
pub fn format_exec_output_for_model_structured(exec_output: &ExecToolCallOutput) -> String {
pub fn format_exec_output_for_model_structured(
exec_output: &ExecToolCallOutput,
truncation_policy: TruncationPolicy,
) -> String {
let ExecToolCallOutput {
exit_code,
duration,
@@ -48,7 +49,7 @@ pub fn format_exec_output_for_model_structured(exec_output: &ExecToolCallOutput)
// round to 1 decimal place
let duration_seconds = ((duration.as_secs_f32()) * 10.0).round() / 10.0;
let formatted_output = format_exec_output_str(exec_output);
let formatted_output = format_exec_output_str(exec_output, truncation_policy);
let payload = ExecOutput {
output: &formatted_output,
@@ -62,18 +63,16 @@ pub fn format_exec_output_for_model_structured(exec_output: &ExecToolCallOutput)
serde_json::to_string(&payload).expect("serialize ExecOutput")
}
pub fn format_exec_output_for_model_freeform(exec_output: &ExecToolCallOutput) -> String {
pub fn format_exec_output_for_model_freeform(
exec_output: &ExecToolCallOutput,
truncation_policy: TruncationPolicy,
) -> String {
// round to 1 decimal place
let duration_seconds = ((exec_output.duration.as_secs_f32()) * 10.0).round() / 10.0;
let total_lines = exec_output.aggregated_output.text.lines().count();
let formatted_output = truncate_formatted_exec_output(
&exec_output.aggregated_output.text,
total_lines,
SHELL_OUTPUT_MAX_BYTES,
256, // TODO: to be removed
);
let formatted_output = truncate_text(&exec_output.aggregated_output.text, truncation_policy);
let mut sections = Vec::new();
@@ -89,7 +88,10 @@ pub fn format_exec_output_for_model_freeform(exec_output: &ExecToolCallOutput) -
sections.join("\n")
}
pub fn format_exec_output_str(exec_output: &ExecToolCallOutput) -> String {
pub fn format_exec_output_str(
exec_output: &ExecToolCallOutput,
truncation_policy: TruncationPolicy,
) -> String {
let ExecToolCallOutput {
aggregated_output, ..
} = exec_output;
@@ -106,5 +108,5 @@ pub fn format_exec_output_str(exec_output: &ExecToolCallOutput) -> String {
};
// Truncate for model consumption before serialization.
truncate_with_line_bytes_budget(&body, SHELL_OUTPUT_MAX_BYTES)
formatted_truncate_text(&body, truncation_policy)
}