From 33ecb0a68f5ffb575a515ed6a60c36fae55850f8 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Mon, 1 Dec 2025 14:00:18 -0500 Subject: [PATCH] Clarify how outlining works in read_file_tool description (#43929) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Screenshot 2025-12-01 at 1 27 02 PM Closes #419 Release Notes: - Revise tool call description for read file tool to explain outlining behavior --- crates/agent/src/outline.rs | 6 ++---- crates/agent/src/tools/read_file_tool.rs | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/crates/agent/src/outline.rs b/crates/agent/src/outline.rs index 40a84bc28b4402d8251e164a423a2309127c50ce..77af4849ffd19c1630331f5c755ff372cb69aeba 100644 --- a/crates/agent/src/outline.rs +++ b/crates/agent/src/outline.rs @@ -66,11 +66,9 @@ pub async fn get_buffer_content_or_outline( let outline_text = render_outline(outline_items, None, 0, usize::MAX).await?; let text = if let Some(path) = path { - format!( - "# File outline for {path} (file too large to show full content)\n\n{outline_text}", - ) + format!("# File outline for {path}\n\n{outline_text}",) } else { - format!("# File outline (file too large to show full content)\n\n{outline_text}",) + format!("# File outline\n\n{outline_text}",) }; Ok(BufferContent { text, diff --git a/crates/agent/src/tools/read_file_tool.rs b/crates/agent/src/tools/read_file_tool.rs index 77852c5fda674c55b324af8bae90d7d6a57bcff0..fd7b85d5ee4d075f5ab5f3fcdef2d1919e763dd7 100644 --- a/crates/agent/src/tools/read_file_tool.rs +++ b/crates/agent/src/tools/read_file_tool.rs @@ -17,6 +17,9 @@ use crate::{AgentTool, Thread, ToolCallEventStream, outline}; /// Reads the content of the given file in the project. /// /// - Never attempt to read a path that hasn't been previously mentioned. +/// - For large files, this tool returns a file outline with symbol names and line numbers instead of the full content. +/// This outline IS a successful response - use the line numbers to read specific sections with start_line/end_line. +/// Do NOT retry reading the same file without line numbers if you receive an outline. #[derive(Debug, Serialize, Deserialize, JsonSchema)] pub struct ReadFileToolInput { /// The relative path of the file to read. @@ -254,16 +257,15 @@ impl AgentTool for ReadFileTool { if buffer_content.is_outline { Ok(formatdoc! {" - This file was too big to read all at once. + SUCCESS: File outline retrieved. This file is too large to read all at once, so the outline below shows the file's structure with line numbers. - {} + IMPORTANT: Do NOT retry this call without line numbers - you will get the same outline. + Instead, use the line numbers below to read specific sections by calling this tool again with start_line and end_line parameters. - Using the line numbers in this outline, you can call this tool again - while specifying the start_line and end_line fields to see the - implementations of symbols in the outline. + {} - Alternatively, you can fall back to the `grep` tool (if available) - to search the file for specific content.", buffer_content.text + NEXT STEPS: To read a specific symbol's implementation, call read_file with the same path plus start_line and end_line from the outline above. + For example, to read a function shown as [L100-150], use start_line: 100 and end_line: 150.", buffer_content.text } .into()) } else { @@ -440,7 +442,7 @@ mod test { let content = result.to_str().unwrap(); assert_eq!( - content.lines().skip(4).take(6).collect::>(), + content.lines().skip(7).take(6).collect::>(), vec![ "struct Test0 [L1-4]", " a [L2]", @@ -475,7 +477,7 @@ mod test { pretty_assertions::assert_eq!( content .lines() - .skip(4) + .skip(7) .take(expected_content.len()) .collect::>(), expected_content