Repository navigation
fix(filesystem): let read mode return line ranges from files over 10 MB - #538
Merged
Jeomon merged 1 commit intoNov 1, 2026
Merged
Conversation
read_file() refused every file over MAX_READ_SIZE before it looked at
offset and limit, so the advice in its own error ("Use offset/limit
parameters or the Shell tool for large files") could never work. The
ranged branch also loaded the whole file with readlines().
Ranged reads now stream the file, still count every line for the
"Lines a-b of N" header, and refuse to return more than MAX_READ_SIZE
characters. readline() is capped, so a very long line is read in
pieces. A read without offset or limit is still refused for a file over
the limit, and the message now names the PowerShell tool. A negative
limit, which used to slice from the end of the file with a header such
as "Lines 1--2 of 10", is now an error.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
FileSysteminreadmode refuses a file overMAX_READ_SIZE(10 MB) and says what to do instead:read_file()checks the size before it looks atoffsetandlimit, though, so a read that passes them gets the same error. The remedy the message offers can never work: two lines of an 11 MB log are refused just like the whole file, and an agent that follows the advice gets the same answer again and has to fall back to the PowerShell tool. The message also points to aShelltool; the tool is registered asPowerShell.For files under the limit, the ranged branch reads the whole file with
readlines()to return a few lines of it.Reproduced at a736a72 on Windows 11 with Python 3.14, with a log of 110,000 numbered lines (11,110,000 bytes) in a temp folder:
FileSystemhandler gives the same error forFileSystem(mode="read", path=p, offset=100, limit=2).tracemalloc).Fix
In
read_file():offsetandlimitis refused for a file over the limit. The message is unchanged apart from naming the PowerShell tool.readline()instead of loading it withreadlines(). It still counts every line, so theLines a-b of N:header is the same as before, and it keeps only the requested lines.MAX_READ_SIZE(10,485,760) characters, the same number that limits whole reads. Past that it answersError: The requested lines add up to more than 10,485,760 characters. Use a smaller limit or the PowerShell tool.readline()getsMAX_READ_SIZEas its size argument, so a file that is one very long line, such as minified JSON or a binary file read by mistake, is read in pieces instead of being loaded whole. A single line longer than the cap gets the error above.limitis now refused withError: limit cannot be negative.It used to slice from the end of the list of lines: on a 10-line file,limit=-2returned lines 1-8 under the headerLines 1--2 of 10, andoffset=3, limit=-1returned no lines underLines 3-1 of 10. Streaming cannot reproduce that slicing, and neither result makes sense as a number of lines, so I made a negative limit an explicit error.limit=0still reads to the end of the file, and anoffsetbelow 1 still starts at line 1.With the change:
read_file(p, offset=100, limit=2)returns the headerLines 100-101 of 110000:and those two lines, in about 35 ms here.offset=109_999without a limit returns the last two lines. A read withoutoffsetandlimitstill gets the "File too large" error, which now names the PowerShell tool. TheFileSystemhandler returns the same.readlines()was fast: on a file made of very short lines (10 MiB of empty lines) a ranged read takes about 2.3 s instead of 0.8 s, while its peak memory drops from 89 MB to 0.2 MB. Binary content read by mistake is now scanned at about 45 MB/s instead of being refused, so a multi-GB binary file takes tens of seconds. Counting the lines after the requested range in 1 MiB chunks would make those cases much faster; I can add that if you prefer.last,offset=2, limit=1returnsLines 2-2 of 2:andlastwith a peak of about 32 MB, andoffset=1, limit=1gets the "add up to more than" error.read_file()in 2,696 calls: small files with LF, CRLF, CR and mixed line endings, without a final newline, empty, with invalid UTF-8 and with UTF-8 and UTF-16 BOMs, plus 2.7 to 6.1 MB files with lines of up to 20,000 characters; offsets from negative to past the end of the file, limits from none and 0 up, and theutf-8,latin-1andcp1252encodings. Every result was identical. The Python loop is slower thanreadlines(): lines 100-101 of the 9.1 MB file take about 27 ms instead of 17 ms.This only touches
read_file(). #537 changeswrite_file()in the same file and adds tests toTestWriteFile; the two branches merge without conflicts, andTestReadFileandTestWriteFilepass on the merge.Tests
tests/test_filesystem_service.py: 9 cases inTestReadFile, with a fixture that writes the 110,000-line, 11,110,000-byte log totmp_path:limit=10, andoffset=109999without a limit come back with the right header and lines;offset=1, limit=110000andoffset=1alone get the "add up to more than" error;MAX_READ_SIZE,offset=2, limit=1returnsLines 2-2 of 2:and the second line, and reading the first line gets the error;Error: limit cannot be negative.All 9 fail on
mainand pass with this change. The otherTestReadFilecases pass on both, including the BOM case from fix(filesystem): decode BOM-marked UTF-16 and UTF-8 files in read mode #516 that reads withoffset=2, limit=1. The new cases write about 90 MB of temp files in all and take about 2 to 3 s here.tests/test_filesystem_service.py(45 passed onmain, 54 with the new tests),tests/test_tool_boolean_flags.py(3 passed),tests/test_filesystem_overlap.py(8 passed) andtests/test_filesystem_views.py(18 passed): same results onmainand on this branch. I ran these files one at a time, not the whole suite. The 14 symlink and junction tests intest_filesystem_service.pyand the 2 case-only rename tests intest_filesystem_overlap.pyfail here onmainand on this branch alike, because the drive I ran them on is exFAT, which has no reparse points and keeps the old name on a case-only rename. They need NTFS, as on the CI runner.ruff checkis clean on the changed files, andruff format --checkis clean on the test file. Forservice.py,ruff format --checkreports formatting throughout the file, mostly single quotes it would turn into double quotes, the same as onmain. The changed lines use single quotes like the rest of the file, and I did not reformat the other lines.Not tested: a full MCP client session (I called
read_file()and the registeredFileSystemhandler directly, the waytests/test_tool_boolean_flags.pydoes), files larger than 303 MB, and encodings other than UTF-8, UTF-16, latin-1 and cp1252.