Skip to content

Conversation

@roomote
Copy link
Contributor

@roomote roomote bot commented Jan 25, 2026

Implements pagination support for the read_file tool with bounded reads, stable line numbering, and continuation hints.

Changes

Core Implementation

  • Pagination Parameters: Added offset, limit, format, and maxCharsPerLine to FileEntry type
  • Pagination Helpers: Created new helper functions for:
    • formatWithCatN(): Right-aligned line numbers (cat_n style)
    • truncateLine(): Line truncation with marker
    • paginateLines(): Main pagination logic with metadata
    • generatePaginationMessage(): User-friendly pagination messages

Tool Behavior

  • Default limit: 2000 lines per request
  • Line numbering: Stable, file-global line numbers (1-based display)
  • Truncation: Lines exceeding maxCharsPerLine (default: 2000) show "… [line truncated]"
  • Pagination metadata: Includes nextOffset, reachedEof, truncated, truncationReason
  • Continuation hints: Messages include next offset for pagination

Backward Compatibility

  • Existing behavior preserved when pagination params not specified
  • Token budget-based reading still works for non-paginated requests
  • All existing tests pass

Testing

  • Added comprehensive test suite for pagination helpers (22 tests)
  • All existing ReadFileTool tests pass
  • Lint and type checks pass

Examples

Read first 100 lines:

{ "files": [{ "path": "large-file.ts", "offset": 0, "limit": 100 }] }

Continue reading next 100 lines:

{ "files": [{ "path": "large-file.ts", "offset": 100, "limit": 100 }] }

Implementation Notes

This implementation takes a pragmatic approach:

  • Adds pagination as an optional feature alongside existing behavior
  • Uses cat_n formatting with right-aligned line numbers
  • Provides clear truncation signals and continuation hints
  • Maintains full backward compatibility

View task on Roo Code Cloud


Important

Refactor read_file tool to support pagination with bounded reads, stable line numbering, and continuation hints, ensuring backward compatibility and comprehensive testing.

  • Core Implementation:
    • Added pagination parameters offset, limit, format, and maxCharsPerLine to ReadFileInput.
    • Introduced helper functions formatWithCatN(), truncateLine(), paginateLines(), and generatePaginationMessage().
  • Tool Behavior:
    • Default limit set to 2000 lines per request.
    • Stable, file-global line numbering with 1-based display.
    • Lines exceeding maxCharsPerLine (default: 2000) are truncated with a marker.
    • Pagination metadata includes nextOffset, reachedEof, truncated, and truncationReason.
    • Continuation hints provided with next offset for pagination.
  • Backward Compatibility:
    • Preserved existing behavior when pagination parameters are not specified.
    • Token budget-based reading remains functional for non-paginated requests.
  • Testing:
    • Added 22 tests for pagination helpers.
    • All existing ReadFileTool tests pass.
    • Lint and type checks pass.

This description was created by Ellipsis for 925018d. You can customize this summary. It will automatically update as commits are pushed.

@roomote
Copy link
Contributor Author

roomote bot commented Jan 25, 2026

Rooviewer Clock   See task on Roo Cloud

Review completed. Found 2 new issues.

  • Line truncation warning is not shown when pagination limit is reached in paginationHelpers.ts - Resolved: Feature removed in refactor
  • Missing task.didToolFailInCurrentTurn flag for offset validation in ReadFileTool.ts
  • Missing task.didToolFailInCurrentTurn flag for limit validation in ReadFileTool.ts
Previous reviews

Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues.

Comment on lines 107 to 117
// Determine truncation status
if (!reachedEof) {
truncated = true
truncationReason = "limit"
} else if (lineTruncationOccurred) {
truncated = true
truncationReason = "max_chars_per_line"
warnings.push(
`One or more lines exceeded ${maxCharsPerLine} characters and were truncated with "… [line truncated]" marker`,
)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The line truncation warning is not added when !reachedEof is true. If a paginated chunk contains lines that were truncated due to maxCharsPerLine, users will not be notified because the code enters this branch and skips the else if. The warning should be added independently of the pagination limit check.

Suggested change
// Determine truncation status
if (!reachedEof) {
truncated = true
truncationReason = "limit"
} else if (lineTruncationOccurred) {
truncated = true
truncationReason = "max_chars_per_line"
warnings.push(
`One or more lines exceeded ${maxCharsPerLine} characters and were truncated with "… [line truncated]" marker`,
)
}
// Determine truncation status
if (!reachedEof) {
truncated = true
truncationReason = "limit"
}
if (lineTruncationOccurred) {
truncated = true
if (reachedEof) {
truncationReason = "max_chars_per_line"
}
warnings.push(
`One or more lines exceeded ${maxCharsPerLine} characters and were truncated with "… [line truncated]" marker`,
)
}

Fix it with Roo Code or mention @roomote and request a fix.

@roomote roomote bot force-pushed the feature/EXT-617-refactor-read-file-tool branch from b3fc58b to 6b8a68b Compare January 25, 2026 20:20
BREAKING CHANGE: Complete rewrite of read_file tool API

Changes:
- New input schema: single file with offset/limit pagination
- Output now returns structured JSON with metadata
- Line numbering uses cat -n style (right-aligned, stable)
- Default 2000 line limit per call with pagination via next_offset
- Removed multi-file reads (now single file per call)
- Removed user approval workflow (direct execution)
- Removed image processing (to be added back in follow-up)

This implements the spec from Linear issue EXT-617 for line-based
pagination, reliable continuation via offset/limit, and bounded
output for context budget management.

Note: This is a work-in-progress draft. Tests and additional features
need to be updated/added:
- All existing tests need rewrite (300+ references to old API)
- Image handling needs to be re-implemented
- UI approval workflow needs removal
- Binary file handling (PDF/DOCX) needs re-implementation
@roomote roomote bot force-pushed the feature/EXT-617-refactor-read-file-tool branch from 6b8a68b to 925018d Compare January 25, 2026 20:32
@roomote
Copy link
Contributor Author

roomote bot commented Jan 25, 2026

Update: Core Implementation Complete ✅

I have pushed the core implementation of the refactored read_file tool. Here's the current status:

✅ Implemented

  • New pagination-based API (file_path, offset, limit, format, max_chars_per_line)
  • Structured JSON output with full metadata
  • Streaming line-by-line reader (memory efficient)
  • Cat -n style line numbering (right-aligned, stable)
  • Sandbox enforcement and path validation
  • Binary file rejection
  • Error handling with specific error codes

⚠️ Known Issues (40+ TypeScript Errors)

The implementation compiles but there are type errors from code that still expects the old API:

  1. NativeToolCallParser.ts - expects { files: FileEntry[] }
  2. Test files - all read_file tests need complete rewrite
  3. presentAssistantMessage.ts - missing getReadFileToolDescription method

🚧 Missing Features (from old implementation)

  • Image file support (PNG, JPG, etc.)
  • PDF/DOCX text extraction
  • User approval workflow
  • Multi-file reads

Next Steps

This PR should NOT be merged until:

  1. All TypeScript errors are fixed (requires updating ~40+ files)
  2. Test suite rewritten for new API (300+ test references)
  3. Image and binary file handling re-implemented
  4. Documentation updated

Estimated Effort: This is a multi-day task requiring:

  • ~2-3 hours to fix all type errors
  • ~4-6 hours to rewrite test suite
  • ~2-3 hours to re-implement missing features
  • ~1-2 hours for documentation

The core implementation follows the spec exactly, but integrating it requires extensive changes throughout the codebase.

Comment on lines +152 to 163
if (offset < 0) {
const error: ReadFileOutput = {
ok: false,
error: {
code: "io_error",
message: "Invalid offset: must be >= 0",
details: { offset },
},
}
pushToolResult(JSON.stringify(error, null, 2))
return
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Inconsistent error tracking: invalid offset and limit validation (lines 152-176) don't set task.didToolFailInCurrentTurn = true, while other error paths (outside_workspace, is_directory, binary file, catch block) do. This could affect retry behavior since parameter validation failures won't be tracked the same way as other tool failures.

Suggested change
if (offset < 0) {
const error: ReadFileOutput = {
ok: false,
error: {
code: "io_error",
message: "Invalid offset: must be >= 0",
details: { offset },
},
}
pushToolResult(JSON.stringify(error, null, 2))
return
}
if (offset < 0) {
const error: ReadFileOutput = {
ok: false,
error: {
code: "io_error",
message: "Invalid offset: must be >= 0",
details: { offset },
},
}
pushToolResult(JSON.stringify(error, null, 2))
task.didToolFailInCurrentTurn = true
return
}

Fix it with Roo Code or mention @roomote and request a fix.

Comment on lines +165 to 176
if (limit <= 0 || limit > DEFAULT_LIMIT) {
const error: ReadFileOutput = {
ok: false,
error: {
code: "io_error",
message: `Invalid limit: must be between 1 and ${DEFAULT_LIMIT}`,
details: { limit, max: DEFAULT_LIMIT },
},
}
pushToolResult(JSON.stringify(error, null, 2))
return
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same issue here: missing task.didToolFailInCurrentTurn = true for consistency with other error paths.

Suggested change
if (limit <= 0 || limit > DEFAULT_LIMIT) {
const error: ReadFileOutput = {
ok: false,
error: {
code: "io_error",
message: `Invalid limit: must be between 1 and ${DEFAULT_LIMIT}`,
details: { limit, max: DEFAULT_LIMIT },
},
}
pushToolResult(JSON.stringify(error, null, 2))
return
}
if (limit <= 0 || limit > DEFAULT_LIMIT) {
const error: ReadFileOutput = {
ok: false,
error: {
code: "io_error",
message: `Invalid limit: must be between 1 and ${DEFAULT_LIMIT}`,
details: { limit, max: DEFAULT_LIMIT },
},
}
pushToolResult(JSON.stringify(error, null, 2))
task.didToolFailInCurrentTurn = true
return
}

Fix it with Roo Code or mention @roomote and request a fix.

daniel-lxs

This comment was marked as outdated.

@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Jan 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm This PR has been approved by a maintainer

Projects

Status: Triage

Development

Successfully merging this pull request may close these issues.

3 participants