diff --git a/src/core/prompts/tools/simple-read-file.ts b/src/core/prompts/tools/simple-read-file.ts
index 28f4f1129e..b6c7c896ad 100644
--- a/src/core/prompts/tools/simple-read-file.ts
+++ b/src/core/prompts/tools/simple-read-file.ts
@@ -2,34 +2,46 @@ import { ToolArgs } from "./types"
/**
* Generate a simplified read_file tool description for models that only support single file reads
- * Uses the simpler format: file/path.ext
+ * Supports optional line_range for reading specific portions of a file
+ * Uses the simpler format: file/path.extstart-end
*/
export function getSimpleReadFileDescription(args: ToolArgs): string {
return `## read_file
-Description: Request to read the contents of a file. The tool outputs line-numbered content (e.g. "1 | const x = 1") for easy reference when discussing code.
+Description: Request to read the contents of a file. The tool outputs line-numbered content (e.g. "1 | const x = 1") for easy reference when discussing code. Use line_range to efficiently read specific portions of large files.
Parameters:
- path: (required) File path (relative to workspace directory ${args.cwd})
+- line_range: (optional) Line range in format "start-end" (1-based, inclusive). Use this to read specific sections of a file, especially useful for continuing to read a large file that was truncated.
Usage:
path/to/file
+start-end
Examples:
-1. Reading a TypeScript file:
+1. Reading a TypeScript file (full file):
src/app.ts
-2. Reading a configuration file:
+2. Reading specific lines from a file:
+
+src/app.ts
+1-100
+
+
+3. Continuing to read after truncation (e.g., after reading lines 1-500):
+
+src/app.ts
+501-1000
+
+
+4. Reading a configuration file:
config.json
-3. Reading a markdown file:
-
-README.md
-`
+IMPORTANT: When a file is too large to display completely, the tool will show a truncation notice with the exact line number to continue from. Use the line_range parameter to read the next section of the file.`
}
diff --git a/src/core/tools/ReadFileTool.ts b/src/core/tools/ReadFileTool.ts
index 58f3cc495e..d15a3ba76a 100644
--- a/src/core/tools/ReadFileTool.ts
+++ b/src/core/tools/ReadFileTool.ts
@@ -458,7 +458,7 @@ export class ReadFileTool extends BaseTool<"read_file"> {
task.rooIgnoreController,
)
if (defResult) {
- const notice = `Showing only ${maxReadFileLine} of ${totalLines} total lines. Use line_range if you need to read more lines`
+ const notice = `Showing only definitions of ${totalLines} total lines. To read actual content, use the read_file tool again with the line_range parameter (e.g., line_ranges: [[1, 500]])`
updateFileResult(relPath, {
xmlContent: `${relPath}\n${defResult}\n${notice}\n`,
nativeContent: `File: ${relPath}\nCode Definitions:\n${defResult}\n\nNote: ${notice}`,
@@ -493,7 +493,9 @@ export class ReadFileTool extends BaseTool<"read_file"> {
nativeInfo += `\nCode Definitions:\n${truncatedDefs}\n`
}
- const notice = `Showing only ${maxReadFileLine} of ${totalLines} total lines. Use line_range if you need to read more lines`
+ const nextStart = maxReadFileLine + 1
+ const suggestedEnd = Math.min(maxReadFileLine * 2, totalLines)
+ const notice = `Showing lines 1-${maxReadFileLine} of ${totalLines} total lines. To continue reading, use the read_file tool again with the line_range parameter starting at line ${nextStart} (e.g., line_ranges: [[${nextStart}, ${suggestedEnd}]])`
xmlInfo += `${notice}\n`
nativeInfo += `\nNote: ${notice}`
@@ -548,7 +550,9 @@ export class ReadFileTool extends BaseTool<"read_file"> {
if (!result.complete) {
// File was truncated
- const notice = `File truncated: showing ${result.lineCount} lines (${result.tokenCount} tokens) due to context budget. Use line_range to read specific sections.`
+ const nextStart = result.lineCount + 1
+ const suggestedEnd = Math.min(result.lineCount * 2, totalLines)
+ const notice = `File truncated: showing lines 1-${result.lineCount} of ${totalLines} total (${result.tokenCount} tokens) due to context budget. To continue reading, use the read_file tool again with the line_range parameter starting at line ${nextStart} (e.g., line_ranges: [[${nextStart}, ${suggestedEnd}]])`
const lineRangeAttr = result.lineCount > 0 ? ` lines="1-${result.lineCount}"` : ""
xmlInfo =
result.lineCount > 0
diff --git a/src/core/tools/simpleReadFileTool.ts b/src/core/tools/simpleReadFileTool.ts
index 1b41e9e9d6..48d81ecc60 100644
--- a/src/core/tools/simpleReadFileTool.ts
+++ b/src/core/tools/simpleReadFileTool.ts
@@ -22,14 +22,27 @@ import {
processImageFile,
} from "./helpers/imageHelpers"
+/**
+ * Helper function to parse line range string (e.g., "1-100" -> {start: 1, end: 100})
+ */
+function parseLineRange(lineRangeStr: string | undefined): { start: number; end: number } | null {
+ if (!lineRangeStr) return null
+ const match = lineRangeStr.match(/^(\d+)-(\d+)$/)
+ if (!match) return null
+ const start = parseInt(match[1], 10)
+ const end = parseInt(match[2], 10)
+ if (isNaN(start) || isNaN(end) || start < 1 || end < start) return null
+ return { start, end }
+}
+
/**
* Simplified read file tool for models that only support single file reads
- * Uses the format: file/path.ext
+ * Uses the format: file/path.extstart-end
*
* This is a streamlined version of readFileTool that:
* - Only accepts a single path parameter
* - Does not support multiple files
- * - Does not support line ranges
+ * - Supports a single optional line_range parameter for reading specific portions
* - Has simpler XML parsing
*/
export async function simpleReadFileTool(
@@ -42,6 +55,10 @@ export async function simpleReadFileTool(
toolProtocol?: ToolProtocol,
) {
const filePath: string | undefined = block.params.path
+ const lineRangeStr: string | undefined = block.params.line_range
+
+ // Parse line range if provided
+ const lineRange = parseLineRange(lineRangeStr)
// Check if the current model supports images
const modelInfo = cline.api.getModel().info
@@ -91,7 +108,9 @@ export async function simpleReadFileTool(
// Create approval message
const isOutsideWorkspace = isPathOutsideWorkspace(fullPath)
let lineSnippet = ""
- if (maxReadFileLine === 0) {
+ if (lineRange) {
+ lineSnippet = t("tools:readFile.linesRange", { start: lineRange.start, end: lineRange.end })
+ } else if (maxReadFileLine === 0) {
lineSnippet = t("tools:readFile.definitionsOnly")
} else if (maxReadFileLine > 0) {
lineSnippet = t("tools:readFile.maxLines", { max: maxReadFileLine })
@@ -201,6 +220,44 @@ export async function simpleReadFileTool(
}
}
+ // Handle specific line range reading (when line_range parameter is provided)
+ if (lineRange) {
+ // Validate line range against total lines
+ if (lineRange.start > totalLines) {
+ const errorMsg = `Invalid line range: start line ${lineRange.start} exceeds total lines ${totalLines}`
+ pushToolResult(`${relPath}${errorMsg}`)
+ return
+ }
+
+ // Clamp end line to total lines
+ const effectiveEnd = Math.min(lineRange.end, totalLines)
+ const content = addLineNumbers(
+ await readLines(fullPath, effectiveEnd - 1, lineRange.start - 1),
+ lineRange.start,
+ )
+ const lineRangeAttr = ` lines="${lineRange.start}-${effectiveEnd}"`
+ let xmlInfo = `\n${content}\n`
+
+ // Add notice if there are more lines after this range
+ if (effectiveEnd < totalLines) {
+ const nextStart = effectiveEnd + 1
+ const suggestedEnd = Math.min(effectiveEnd + (effectiveEnd - lineRange.start + 1), totalLines)
+ xmlInfo += `Showing lines ${lineRange.start}-${effectiveEnd} of ${totalLines} total lines. To continue reading, use the read_file tool again with the line_range parameter starting at line ${nextStart} (e.g., ${nextStart}-${suggestedEnd})\n`
+ }
+
+ // Track file read
+ await cline.fileContextTracker.trackFileContext(relPath, "read_tool" as RecordSource)
+
+ // Return the result
+ if (text) {
+ const statusMessage = formatResponse.toolApprovedWithFeedback(text)
+ pushToolResult(`${statusMessage}\n${relPath}\n${xmlInfo}`)
+ } else {
+ pushToolResult(`${relPath}\n${xmlInfo}`)
+ }
+ return
+ }
+
// Handle definitions-only mode
if (maxReadFileLine === 0) {
try {
@@ -234,7 +291,9 @@ export async function simpleReadFileTool(
if (defResult) {
xmlInfo += `${defResult}\n`
}
- xmlInfo += `Showing only ${maxReadFileLine} of ${totalLines} total lines. File is too large for complete display\n`
+ const nextStart = maxReadFileLine + 1
+ const suggestedEnd = Math.min(maxReadFileLine * 2, totalLines)
+ xmlInfo += `Showing lines 1-${maxReadFileLine} of ${totalLines} total lines. To continue reading, use the read_file tool again with the line_range parameter starting at line ${nextStart} (e.g., ${nextStart}-${suggestedEnd})\n`
pushToolResult(`${relPath}\n${xmlInfo}`)
} catch (error) {
if (error instanceof Error && error.message.startsWith("Unsupported language:")) {
@@ -282,7 +341,8 @@ export async function simpleReadFileTool(
*/
export function getSimpleReadFileToolDescription(blockName: string, blockParams: any): string {
if (blockParams.path) {
- return `[${blockName} for '${blockParams.path}']`
+ const lineRangeInfo = blockParams.line_range ? ` (lines ${blockParams.line_range})` : ""
+ return `[${blockName} for '${blockParams.path}'${lineRangeInfo}]`
} else {
return `[${blockName} with missing path]`
}
diff --git a/src/shared/tools.ts b/src/shared/tools.ts
index f2b4ec3544..24ccc285c8 100644
--- a/src/shared/tools.ts
+++ b/src/shared/tools.ts
@@ -70,6 +70,7 @@ export const toolParamNames = [
"prompt",
"image",
"files", // Native protocol parameter for read_file
+ "line_range", // Simple read_file parameter for single line range
"operations", // search_and_replace parameter for multiple operations
"patch", // apply_patch parameter
"file_path", // search_replace and edit_file parameter