From 891aa7f93f735baeaa4a88ed986cb4d598ee6027 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 19:48:01 +0000 Subject: [PATCH 1/3] Add offset/size support to read_file tool for partial file reads Co-Authored-By: Claude Opus 4.6 Claude-Session: https://claude.ai/code/session_017kEbY4DcgDd5sKMSauxyWf --- app/tools/read_file.py | 21 ++++++++++++++++----- tests/test_read_file.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/app/tools/read_file.py b/app/tools/read_file.py index a575963..991a9ce 100755 --- a/app/tools/read_file.py +++ b/app/tools/read_file.py @@ -8,13 +8,21 @@ def spec(): "type": "function", "function": { "name": "read_file", - "description": "Read and return the contents of a file", + "description": "Read and return the contents of a file. Supports optional offset and size parameters for partial reads.", "parameters": { "type": "object", "properties": { "file_path": { "type": "string", "description": "The path to the file to read" + }, + "offset": { + "type": "integer", + "description": "Byte offset to start reading from (default: 0)" + }, + "size": { + "type": "integer", + "description": "Maximum number of bytes to read (default: read to end of file)" } }, "required": ["file_path"] @@ -23,12 +31,15 @@ def spec(): } @staticmethod - def call(file_path: str) -> str: - log.info(f"read_file, file_path: {file_path}") + def call(file_path: str, offset: int = 0, size: int | None = None) -> str: + log.info(f"read_file, file_path: {file_path}, offset: {offset}, size: {size}") try: - with open(file_path, encoding="utf-8") as f: - return f.read() + with open(file_path, "rb") as f: + if offset: + f.seek(offset) + data = f.read(size) if size is not None else f.read() + return data.decode("utf-8") except FileNotFoundError: return f"Error: file {file_path} does not exist" except Exception as e: diff --git a/tests/test_read_file.py b/tests/test_read_file.py index f93e6c2..7411104 100644 --- a/tests/test_read_file.py +++ b/tests/test_read_file.py @@ -25,3 +25,33 @@ def test_read_file_multiline(tmp_path): f = tmp_path / "multi.txt" f.write_text(content, encoding="utf-8") assert read_file(str(f)) == content + + +def test_read_file_with_offset(tmp_path): + f = tmp_path / "offset.txt" + f.write_text("hello world", encoding="utf-8") + assert read_file(str(f), offset=6) == "world" + + +def test_read_file_with_size(tmp_path): + f = tmp_path / "size.txt" + f.write_text("hello world", encoding="utf-8") + assert read_file(str(f), size=5) == "hello" + + +def test_read_file_with_offset_and_size(tmp_path): + f = tmp_path / "both.txt" + f.write_text("hello world", encoding="utf-8") + assert read_file(str(f), offset=3, size=4) == "lo w" + + +def test_read_file_offset_beyond_end(tmp_path): + f = tmp_path / "short.txt" + f.write_text("hi", encoding="utf-8") + assert read_file(str(f), offset=100) == "" + + +def test_read_file_size_larger_than_remaining(tmp_path): + f = tmp_path / "small.txt" + f.write_text("hello", encoding="utf-8") + assert read_file(str(f), offset=3, size=100) == "lo" From d1004e65e5b1e78b1b763c914eda7ebb273f4cfe Mon Sep 17 00:00:00 2001 From: Rikul Patel Date: Sun, 5 Jul 2026 23:03:31 -0500 Subject: [PATCH 2/3] Apply suggestions from code review Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- app/tools/read_file.py | 7 ++++++- tests/test_read_file.py | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/tools/read_file.py b/app/tools/read_file.py index 991a9ce..1e301f7 100755 --- a/app/tools/read_file.py +++ b/app/tools/read_file.py @@ -34,12 +34,17 @@ def spec(): def call(file_path: str, offset: int = 0, size: int | None = None) -> str: log.info(f"read_file, file_path: {file_path}, offset: {offset}, size: {size}") + if offset < 0: + return "Error: offset must be non-negative" + if size is not None and size < 0: + return "Error: size must be non-negative" + try: with open(file_path, "rb") as f: if offset: f.seek(offset) data = f.read(size) if size is not None else f.read() - return data.decode("utf-8") + return data.decode("utf-8", errors="replace") except FileNotFoundError: return f"Error: file {file_path} does not exist" except Exception as e: diff --git a/tests/test_read_file.py b/tests/test_read_file.py index 7411104..4251876 100644 --- a/tests/test_read_file.py +++ b/tests/test_read_file.py @@ -55,3 +55,16 @@ def test_read_file_size_larger_than_remaining(tmp_path): f = tmp_path / "small.txt" f.write_text("hello", encoding="utf-8") assert read_file(str(f), offset=3, size=100) == "lo" + + +def test_read_file_negative_offset_or_size(tmp_path): + f = tmp_path / "test.txt" + f.write_text("hello", encoding="utf-8") + assert "Error" in read_file(str(f), offset=-1) + assert "Error" in read_file(str(f), size=-1) + + +def test_read_file_utf8_split(tmp_path): + f = tmp_path / "utf8.txt" + f.write_bytes(b"abc\xf0\x9f\x9a\x80def") + assert read_file(str(f), offset=3, size=2) == "\ufffd\ufffd" From db92436cd12a3b70ec516c0098235447dcb5c924 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Jul 2026 04:11:46 +0000 Subject: [PATCH 3/3] test: fix utf8 split expectation --- tests/test_read_file.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_read_file.py b/tests/test_read_file.py index 4251876..f10e19e 100644 --- a/tests/test_read_file.py +++ b/tests/test_read_file.py @@ -67,4 +67,4 @@ def test_read_file_negative_offset_or_size(tmp_path): def test_read_file_utf8_split(tmp_path): f = tmp_path / "utf8.txt" f.write_bytes(b"abc\xf0\x9f\x9a\x80def") - assert read_file(str(f), offset=3, size=2) == "\ufffd\ufffd" + assert read_file(str(f), offset=3, size=2) == "\ufffd"