Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
6b9d85b
refactor(read_file): Codex-inspired indentation mode with simplified API
hannesrudolph Jan 26, 2026
75ca7b2
chore: remove orphaned maxConcurrentFileReads setting
hannesrudolph Jan 26, 2026
f462e26
fix: add max_lines to nativeArgs parsing and update test for removed …
hannesrudolph Jan 26, 2026
48d5798
fix: path display concatenation and add startLine for file navigation
hannesrudolph Jan 27, 2026
d39b0c2
docs(read_file): improve tool descriptions following Anthropic guidel…
hannesrudolph Jan 27, 2026
4fe4c92
fix: remove undefined terminalCompressProgressBar property
hannesrudolph Jan 28, 2026
7d05b59
fix(read_file): default anchor_line to offset in indentation mode
hannesrudolph Jan 28, 2026
6a260cc
feat: unify @ mention and read_file truncation format
hannesrudolph Jan 28, 2026
36c6861
feat: always show line count in read_file approval UI
hannesrudolph Jan 28, 2026
fc36c62
feat(UI): consolidate consecutive read_file asks into batch
hannesrudolph Jan 28, 2026
3c1c0fe
chore: remove unused imports from extract-text.ts
hannesrudolph Jan 28, 2026
ad9bc90
test(ReadFileTool): add unit tests for image handling, error paths, a…
hannesrudolph Jan 29, 2026
c5f79dd
feat: add backward compatibility for legacy read_file format
hannesrudolph Jan 29, 2026
a270a98
fix: show indentation mode in approval UI even when anchor_line is om…
hannesrudolph Jan 29, 2026
3e25f9c
docs(read_file): improve tool descriptions for slice vs indentation mode
hannesrudolph Jan 29, 2026
1a9bbc8
feat(read_file): add 1-indexed validation for offset/anchor_line, wra…
hannesrudolph Jan 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions apps/vscode-e2e/src/suite/tools/read-file.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ suite.skip("Roo Code read_file Tool", function () {
}
})

test("Should read file with line range", async function () {
test("Should read file with slice offset/limit", async function () {
const api = globalThis.api
const messages: ClineMessage[] = []
let taskCompleted = false
Expand Down Expand Up @@ -446,7 +446,7 @@ suite.skip("Roo Code read_file Tool", function () {
alwaysAllowReadOnly: true,
alwaysAllowReadOnlyOutsideWorkspace: true,
},
text: `Use the read_file tool to read the file "${fileName}" and show me what's on lines 2, 3, and 4. The file contains lines like "Line 1", "Line 2", etc. Assume the file exists and you can read it directly.`,
text: `Use the read_file tool to read the file "${fileName}" using slice mode with offset=2 and limit=3 (1-based offset). The file contains lines like "Line 1", "Line 2", etc. After reading, show me the three lines you read.`,
})

// Wait for task completion
Expand All @@ -455,9 +455,8 @@ suite.skip("Roo Code read_file Tool", function () {
// Verify tool was executed
assert.ok(toolExecuted, "The read_file tool should have been executed")

// Verify the tool returned the correct lines (when line range is used)
// Verify the tool returned the correct lines (offset=2, limit=3 -> lines 2-4)
if (toolResult && (toolResult as string).includes(" | ")) {
// The result includes line numbers
assert.ok(
(toolResult as string).includes("2 | Line 2"),
"Tool result should include line 2 with line number",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ describe("CloudSettingsService - Response Parsing", () => {
version: 2,
defaultSettings: {
maxOpenTabsContext: 10,
maxReadFileLine: 1000,
},
allowList: {
allowAll: false,
Expand Down
2 changes: 0 additions & 2 deletions packages/types/src/cloud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ export const organizationDefaultSettingsSchema = globalSettingsSchema
.pick({
enableCheckpoints: true,
maxOpenTabsContext: true,
maxReadFileLine: true,
maxWorkspaceFiles: true,
showRooIgnoredFiles: true,
terminalCommandDelay: true,
Expand All @@ -107,7 +106,6 @@ export const organizationDefaultSettingsSchema = globalSettingsSchema
.merge(
z.object({
maxOpenTabsContext: z.number().int().nonnegative().optional(),
maxReadFileLine: z.number().int().gte(-1).optional(),
maxWorkspaceFiles: z.number().int().nonnegative().optional(),
terminalCommandDelay: z.number().int().nonnegative().optional(),
terminalShellIntegrationTimeout: z.number().int().nonnegative().optional(),
Expand Down
3 changes: 0 additions & 3 deletions packages/types/src/global-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ export const globalSettingsSchema = z.object({
allowedMaxCost: z.number().nullish(),
autoCondenseContext: z.boolean().optional(),
autoCondenseContextPercent: z.number().optional(),
maxConcurrentFileReads: z.number().optional(),

/**
* Whether to include current time in the environment details
Expand Down Expand Up @@ -172,7 +171,6 @@ export const globalSettingsSchema = z.object({
maxWorkspaceFiles: z.number().optional(),
showRooIgnoredFiles: z.boolean().optional(),
enableSubfolderRules: z.boolean().optional(),
maxReadFileLine: z.number().optional(),
maxImageFileSize: z.number().optional(),
maxTotalImageSize: z.number().optional(),

Expand Down Expand Up @@ -382,7 +380,6 @@ export const EVALS_SETTINGS: RooCodeSettings = {
maxWorkspaceFiles: 200,
maxGitStatusFiles: 20,
showRooIgnoredFiles: true,
maxReadFileLine: -1, // -1 to enable full file reading.

includeDiagnosticMessages: true,
maxDiagnosticMessages: 50,
Expand Down
2 changes: 2 additions & 0 deletions packages/types/src/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export enum TelemetryEventName {
CODE_INDEX_ERROR = "Code Index Error",
TELEMETRY_SETTINGS_CHANGED = "Telemetry Settings Changed",
MODEL_CACHE_EMPTY_RESPONSE = "Model Cache Empty Response",
READ_FILE_LEGACY_FORMAT_USED = "Read File Legacy Format Used",
}

/**
Expand Down Expand Up @@ -203,6 +204,7 @@ export const rooCodeTelemetryEventSchema = z.discriminatedUnion("type", [
TelemetryEventName.TAB_SHOWN,
TelemetryEventName.MODE_SETTINGS_CHANGED,
TelemetryEventName.CUSTOM_MODE_CREATED,
TelemetryEventName.READ_FILE_LEGACY_FORMAT_USED,
]),
properties: telemetryPropertiesSchema,
}),
Expand Down
80 changes: 80 additions & 0 deletions packages/types/src/tool-params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,96 @@
* Tool parameter type definitions for native protocol
*/

/**
* Read mode for the read_file tool.
* - "slice": Simple offset/limit reading (default)
* - "indentation": Semantic block extraction based on code structure
*/
export type ReadFileMode = "slice" | "indentation"

/**
* Indentation-mode configuration for the read_file tool.
*/
export interface IndentationParams {
/** 1-based line number to anchor indentation extraction (defaults to offset) */
anchor_line?: number
/** Maximum indentation levels to include above anchor (0 = unlimited) */
max_levels?: number
/** Include sibling blocks at the same indentation level */
include_siblings?: boolean
/** Include file header (imports, comments at top) */
include_header?: boolean
/** Hard cap on lines returned for indentation mode */
max_lines?: number
}

/**
* Parameters for the read_file tool (new format).
*
* NOTE: This is the canonical, single-file-per-call shape.
*/
export interface ReadFileParams {
/** Path to the file, relative to workspace */
path: string
/** Reading mode: "slice" (default) or "indentation" */
mode?: ReadFileMode
/** 1-based line number to start reading from (slice mode, default: 1) */
offset?: number
/** Maximum number of lines to read (default: 2000) */
limit?: number
/** Indentation-mode configuration (only used when mode === "indentation") */
indentation?: IndentationParams
}

// ─── Legacy Format Types (Backward Compatibility) ─────────────────────────────

/**
* Line range specification for legacy read_file format.
* Represents a contiguous range of lines [start, end] (1-based, inclusive).
*/
export interface LineRange {
start: number
end: number
}

/**
* File entry for legacy read_file format.
* Supports reading multiple disjoint line ranges from a single file.
*/
export interface FileEntry {
/** Path to the file, relative to workspace */
path: string
/** Optional list of line ranges to read (if omitted, reads entire file) */
lineRanges?: LineRange[]
}

/**
* Legacy parameters for the read_file tool (pre-refactor format).
* Supports reading multiple files in a single call with optional line ranges.
*
* @deprecated Use ReadFileParams instead. This format is maintained for
* backward compatibility with existing chat histories.
*/
export interface LegacyReadFileParams {
/** Array of file entries to read */
files: FileEntry[]
/** Discriminant flag for type narrowing */
_legacyFormat: true
}

/**
* Union type for read_file tool parameters.
* Supports both new single-file format and legacy multi-file format.
*/
export type ReadFileToolParams = ReadFileParams | LegacyReadFileParams

/**
* Type guard to check if params are in legacy format.
*/
export function isLegacyReadFileParams(params: ReadFileToolParams): params is LegacyReadFileParams {
return "_legacyFormat" in params && params._legacyFormat === true
}

export interface Coordinate {
x: number
y: number
Expand Down
4 changes: 1 addition & 3 deletions packages/types/src/vscode-extension-host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ export interface ExtensionMessage {
| "remoteBrowserEnabled"
| "ttsStart"
| "ttsStop"
| "maxReadFileLine"
| "fileSearchResults"
| "toggleApiConfigPin"
| "acceptInput"
Expand Down Expand Up @@ -304,7 +303,6 @@ export type ExtensionState = Pick<
| "ttsSpeed"
| "soundEnabled"
| "soundVolume"
| "maxConcurrentFileReads"
| "terminalOutputPreviewSize"
| "terminalShellIntegrationTimeout"
| "terminalShellIntegrationDisabled"
Expand Down Expand Up @@ -355,7 +353,6 @@ export type ExtensionState = Pick<
maxWorkspaceFiles: number // Maximum number of files to include in current working directory details (0-500)
showRooIgnoredFiles: boolean // Whether to show .rooignore'd files in listings
enableSubfolderRules: boolean // Whether to load rules from subdirectories
maxReadFileLine: number // Maximum number of lines to read from a file before truncating
maxImageFileSize: number // Maximum size of image files to process in MB
maxTotalImageSize: number // Maximum total size for all images in a single read operation in MB

Expand Down Expand Up @@ -818,6 +815,7 @@ export interface ClineSayTool {
isProtected?: boolean
additionalFileCount?: number // Number of additional files in the same read_file request
lineNumber?: number
startLine?: number // Starting line for read_file operations (for navigation on click)
query?: string
batchFiles?: Array<{
path: string
Expand Down
1 change: 0 additions & 1 deletion src/__tests__/command-mentions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ describe("Command Mentions", () => {
false, // showRooIgnoredFiles
true, // includeDiagnosticMessages
50, // maxDiagnosticMessages
undefined, // maxReadFileLine
)
}

Expand Down
36 changes: 15 additions & 21 deletions src/api/providers/__tests__/bedrock-native-tools.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,23 +135,18 @@ describe("AwsBedrockHandler Native Tool Calling", () => {
parameters: {
type: "object",
properties: {
files: {
type: "array",
items: {
type: "object",
properties: {
path: { type: "string" },
line_ranges: {
type: ["array", "null"],
items: { type: "integer" },
description: "Optional line ranges",
},
path: { type: "string" },
indentation: {
type: ["object", "null"],
properties: {
anchor_line: {
type: ["integer", "null"],
description: "Optional anchor line",
},
required: ["path", "line_ranges"],
},
},
},
required: ["files"],
required: ["path"],
},
},
},
Expand All @@ -167,15 +162,14 @@ describe("AwsBedrockHandler Native Tool Calling", () => {
expect(executeCommandSchema.properties.cwd.type).toBeUndefined()
expect(executeCommandSchema.properties.cwd.description).toBe("Working directory (optional)")

// Second tool: line_ranges should be transformed from type: ["array", "null"] to anyOf
// with items moved inside the array variant (required by GPT-5-mini strict schema validation)
// Second tool: nested nullable object should be transformed from type: ["object", "null"] to anyOf
const readFileSchema = bedrockTools[1].toolSpec.inputSchema.json as any
const lineRanges = readFileSchema.properties.files.items.properties.line_ranges
expect(lineRanges.anyOf).toEqual([{ type: "array", items: { type: "integer" } }, { type: "null" }])
expect(lineRanges.type).toBeUndefined()
// items should now be inside the array variant, not at root
expect(lineRanges.items).toBeUndefined()
expect(lineRanges.description).toBe("Optional line ranges")
const indentation = readFileSchema.properties.indentation
expect(indentation.anyOf).toBeDefined()
expect(indentation.type).toBeUndefined()
// Object-level schema properties are preserved at the root, not inside the anyOf object variant
expect(indentation.additionalProperties).toBe(false)
expect(indentation.properties.anchor_line.anyOf).toEqual([{ type: "integer" }, { type: "null" }])
})

it("should filter non-function tools", () => {
Expand Down
Loading
Loading