Skip to content

feat: accept view_range as alias for offset/length in read_file#517

Closed
wonderwhy-er wants to merge 1 commit into
mainfrom
fix/read-file-param-normalization
Closed

feat: accept view_range as alias for offset/length in read_file#517
wonderwhy-er wants to merge 1 commit into
mainfrom
fix/read-file-param-normalization

Conversation

@wonderwhy-er

@wonderwhy-er wonderwhy-er commented Jun 17, 2026

Copy link
Copy Markdown
Owner

Problem

LLM clients frequently call read_file with a view_range: [start, end] argument (the text-editor convention) instead of offset/length. That key wasn't in the schema, so it was silently dropped — the offset/length defaults took over and the tool returned 1000 lines from the start of the file. Looked like the read tool "ignoring the range", but it was just an unrecognized parameter.

Change

  • Accept view_range: [startLine, endLine] (1-based, inclusive) as a first-class optional arg on read_file.
  • Normalize it to offset/length in the handler: offset = start - 1, length = end - start + 1. endLine of -1 reads from startLine to end of file (capped by fileReadLineLimit).
  • offset/length continue to work exactly as before.
  • Tool description updated to document view_range alongside offset/length. No warnings added — both styles are valid.

Verification

Against a 200-line file:

  • view_range: [50, 55] → lines 50–55 (6 lines), identical to offset: 49, length: 6.
  • view_range: [198, -1] → lines 198–200 (to end).

npm run build passes.

Summary by CodeRabbit

Release Notes

  • New Features
    • Added line-range file reading capability using a view_range parameter for intuitive file access by specifying start and end line numbers (1-based, inclusive).
    • Support for reading to end-of-file using -1 as the end line value.

LLM clients frequently call read_file with a view_range: [start, end]
argument (the text-editor convention) instead of offset/length. That key
was silently dropped, so the schema defaults took over and the tool read
1000 lines from the start of the file.

Accept view_range ([startLine, endLine], 1-based inclusive) as a first-class
optional argument and normalize it to offset/length in the handler. endLine
of -1 reads to end of file. offset/length still work unchanged. Tool
description updated to document view_range alongside offset/length.
@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an optional view_range parameter ([startLine, endLine], 1-based inclusive) to the read_file tool. The schema accepts it as a 2-element number array. The handler converts it to effectiveOffset/effectiveLength (with endLine = -1 meaning read to end, capped by fileReadLineLimit), then passes these values into ReadOptions. The tool description is updated with parameter docs and examples.

Changes

view_range line-range reading for read_file

Layer / File(s) Summary
Schema and tool description
src/tools/schemas.ts, src/server.ts
ReadFileArgsSchema gains an optional view_range field (2-number array). The read_file tool description is updated to document view_range semantics and add usage examples.
Handler normalization
src/handlers/filesystem-handlers.ts
handleReadFile computes effectiveOffset (0-based) and effectiveLength from view_range, treating endLine < 0 as "to end" capped by fileReadLineLimit. These replace parsed.offset/parsed.length in the ReadOptions construction.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • wonderwhy-er/DesktopCommanderMCP#130: Modifies readFileFromDisk behavior when offset/length point past EOF — directly interacts with the normalized values this PR now computes from view_range.

Suggested reviewers

  • dmitry-ottic-ai

🐇 A range of lines, one two three,
Now view_range sets them free!
Start and end, 1-based delight,
-1 reads to end of night.
Hop along, the offsets gleam~ 🌟

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding support for view_range as an alternative parameter format in the read_file tool.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/read-file-param-normalization

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/handlers/filesystem-handlers.ts`:
- Around line 98-100: The condition checking for the special case in the
view_range calculation is too permissive. Change the condition from `end < 0` to
`end === -1` in the effectiveLength assignment, as the documented API specifies
only the value -1 to mean "to end of file". Using a strict equality check
ensures that only the documented special case is handled, and any other negative
values will not silently succeed with undocumented behavior.
- Around line 94-95: The effectiveLength assignment on line 94 uses
parsed.length as the primary value with defaultLimit as a fallback, but since
parsed.length has a schema default value of 1000, it is never undefined and the
configured defaultLimit is never applied. To fix this, modify the logic to check
whether the caller explicitly provided a length value (rather than relying on
the schema default), ensuring that when length is omitted, the configured
fileReadLineLimit setting is properly used instead of being bypassed by the
schema default.

In `@src/tools/schemas.ts`:
- Around line 53-56: The view_range field definition in the schema only
validates the shape (array of 2 numbers) but lacks contract-level validation for
the actual constraints. Replace the current
z.array(z.number()).length(2).optional() definition with a more comprehensive
validation that enforces the following rules: startLine must be >= 1, both
values must be integers, and endLine must either be -1 or be >= startLine. Use
Zod's refine method or int() helper combined with additional validation logic to
ensure these constraints are checked at schema level rather than relying on
later coercion, preventing malformed inputs from being silently accepted.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1c733bf3-0a98-482f-af3b-ce5179b7fc59

📥 Commits

Reviewing files that changed from the base of the PR and between 7a9b2ff and 46dae0c.

📒 Files selected for processing (3)
  • src/handlers/filesystem-handlers.ts
  • src/server.ts
  • src/tools/schemas.ts

Comment on lines +94 to +95
let effectiveLength = parsed.length ?? defaultLimit;
if (parsed.view_range) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Configured fileReadLineLimit is bypassed for normal reads.

Line 94 falls back to defaultLimit, but parsed.length is pre-filled by schema default (1000), so config won’t apply when callers omit length. This makes the runtime behavior diverge from the documented configurable default.

Proposed fix (preserve config default semantics)
-        let effectiveOffset = parsed.offset ?? 0;
-        let effectiveLength = parsed.length ?? defaultLimit;
+        const rawArgs = args as Record<string, unknown>;
+        const hasOffset = Object.prototype.hasOwnProperty.call(rawArgs, 'offset');
+        const hasLength = Object.prototype.hasOwnProperty.call(rawArgs, 'length');
+
+        let effectiveOffset = hasOffset ? (parsed.offset ?? 0) : 0;
+        let effectiveLength = hasLength ? (parsed.length ?? defaultLimit) : defaultLimit;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/handlers/filesystem-handlers.ts` around lines 94 - 95, The
effectiveLength assignment on line 94 uses parsed.length as the primary value
with defaultLimit as a fallback, but since parsed.length has a schema default
value of 1000, it is never undefined and the configured defaultLimit is never
applied. To fix this, modify the logic to check whether the caller explicitly
provided a length value (rather than relying on the schema default), ensuring
that when length is omitted, the configured fileReadLineLimit setting is
properly used instead of being bypassed by the schema default.

Comment on lines +98 to +100
effectiveLength = end < 0
? defaultLimit // endLine -1 => "to end", capped by config
: Math.max(1, Math.floor(end) - Math.floor(start) + 1);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

view_range special case is too broad (end < 0 instead of end === -1).

On Line 98, any negative end is interpreted as “to end of file,” but the documented API defines only -1 for that behavior. This creates undocumented inputs that silently succeed.

Proposed fix
-            effectiveLength = end < 0
+            effectiveLength = end === -1
                 ? defaultLimit
                 : Math.max(1, Math.floor(end) - Math.floor(start) + 1);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
effectiveLength = end < 0
? defaultLimit // endLine -1 => "to end", capped by config
: Math.max(1, Math.floor(end) - Math.floor(start) + 1);
effectiveLength = end === -1
? defaultLimit // endLine -1 => "to end", capped by config
: Math.max(1, Math.floor(end) - Math.floor(start) + 1);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/handlers/filesystem-handlers.ts` around lines 98 - 100, The condition
checking for the special case in the view_range calculation is too permissive.
Change the condition from `end < 0` to `end === -1` in the effectiveLength
assignment, as the documented API specifies only the value -1 to mean "to end of
file". Using a strict equality check ensures that only the documented special
case is handled, and any other negative values will not silently succeed with
undocumented behavior.

Comment thread src/tools/schemas.ts
Comment on lines +53 to +56
// Optional [startLine, endLine] convenience alias, 1-based and inclusive
// (matches the text-editor view_range convention). Normalized to offset/length
// in the handler. endLine of -1 means "to end of file".
view_range: z.array(z.number()).length(2).optional(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

view_range needs contract-level validation, not just shape validation.

On Line 56, the schema enforces only “2 numbers,” but the feature contract is stricter (startLine >= 1, integer lines, and endLine === -1 or endLine >= startLine). Right now malformed inputs are accepted and later coerced, which can return unexpected slices silently.

Proposed schema hardening
-  view_range: z.array(z.number()).length(2).optional(),
+  view_range: z
+    .tuple([z.number().int().min(1), z.number().int()])
+    .refine(([start, end]) => end === -1 || end >= start, {
+      message: "view_range must be [startLine, endLine] with endLine = -1 or endLine >= startLine",
+    })
+    .optional(),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Optional [startLine, endLine] convenience alias, 1-based and inclusive
// (matches the text-editor view_range convention). Normalized to offset/length
// in the handler. endLine of -1 means "to end of file".
view_range: z.array(z.number()).length(2).optional(),
// Optional [startLine, endLine] convenience alias, 1-based and inclusive
// (matches the text-editor view_range convention). Normalized to offset/length
// in the handler. endLine of -1 means "to end of file".
view_range: z
.tuple([z.number().int().min(1), z.number().int()])
.refine(([start, end]) => end === -1 || end >= start, {
message: "view_range must be [startLine, endLine] with endLine = -1 or endLine >= startLine",
})
.optional(),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tools/schemas.ts` around lines 53 - 56, The view_range field definition
in the schema only validates the shape (array of 2 numbers) but lacks
contract-level validation for the actual constraints. Replace the current
z.array(z.number()).length(2).optional() definition with a more comprehensive
validation that enforces the following rules: startLine must be >= 1, both
values must be integers, and endLine must either be -1 or be >= startLine. Use
Zod's refine method or int() helper combined with additional validation logic to
ensure these constraints are checked at schema level rather than relying on
later coercion, preventing malformed inputs from being silently accepted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant