From 02bdaf70b1c72737d0cf4a812683c52d585d46fc Mon Sep 17 00:00:00 2001 From: openhands Date: Tue, 19 Aug 2025 16:01:09 +0000 Subject: [PATCH 1/6] editor: clamp view_range end to file length, emit warning instead of error when beyond EOF (fixes #154) - Normalize end_line by capping to num_lines and allow -1 as before - Append NOTE: warning to output when clamped - Update tests to assert on warning text Co-authored-by: openhands --- openhands_aci/editor/editor.py | 22 ++++++++++--------- .../integration/editor/test_error_handling.py | 7 ++---- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/openhands_aci/editor/editor.py b/openhands_aci/editor/editor.py index 97ffc61..0a4e61b 100644 --- a/openhands_aci/editor/editor.py +++ b/openhands_aci/editor/editor.py @@ -348,23 +348,21 @@ def view(self, path: Path, view_range: list[int] | None = None) -> CLIResult: f'Its first element `{start_line}` should be within the range of lines of the file: {[1, num_lines]}.', ) - if end_line > num_lines: - raise EditorToolParameterInvalidError( - 'view_range', - view_range, - f'Its second element `{end_line}` should be smaller than the number of lines in the file: `{num_lines}`.', - ) + # Normalize end_line and provide a warning if it exceeds file length + warning_message: str | None = None + if end_line == -1: + end_line = num_lines + elif end_line > num_lines: + warning_message = f"We only show up to {num_lines} since there's only {num_lines} lines in this file" + end_line = num_lines - if end_line != -1 and end_line < start_line: + if end_line < start_line: raise EditorToolParameterInvalidError( 'view_range', view_range, f'Its second element `{end_line}` should be greater than or equal to the first element `{start_line}`.', ) - if end_line == -1: - end_line = num_lines - file_content = self.read_file(path, start_line=start_line, end_line=end_line) # Get the detected encoding @@ -372,6 +370,10 @@ def view(self, path: Path, view_range: list[int] | None = None) -> CLIResult: '\n'.join(file_content.splitlines()), str(path), start_line ) # Remove extra newlines + # Append warning if we truncated the end_line + if warning_message: + output += f'\nNOTE: {warning_message}\n' + return CLIResult( path=str(path), output=output, diff --git a/tests/integration/editor/test_error_handling.py b/tests/integration/editor/test_error_handling.py index 215d20d..ad7952f 100644 --- a/tests/integration/editor/test_error_handling.py +++ b/tests/integration/editor/test_error_handling.py @@ -86,7 +86,7 @@ def test_view_range_validation(temp_file): 'should be a list of two integers' in result_json['formatted_output_and_error'] ) - # Test out of bounds range + # Test out of bounds range: should clamp to file end and show a warning result = file_editor( command='view', path=temp_file, @@ -94,10 +94,7 @@ def test_view_range_validation(temp_file): enable_linting=False, ) result_json = parse_result(result) - assert ( - 'should be smaller than the number of lines' - in result_json['formatted_output_and_error'] - ) + assert 'NOTE: We only show up to 3 since there\'s only 3 lines in this file' in result_json['formatted_output_and_error'] # Test invalid range order result = file_editor( From 7f0c075ed7dc108686ceb542c56b4c21d199179d Mon Sep 17 00:00:00 2001 From: openhands Date: Wed, 20 Aug 2025 17:41:13 +0000 Subject: [PATCH 2/6] Prepend warning message instead of appending it Co-authored-by: openhands --- openhands_aci/editor/editor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openhands_aci/editor/editor.py b/openhands_aci/editor/editor.py index 0a4e61b..397a900 100644 --- a/openhands_aci/editor/editor.py +++ b/openhands_aci/editor/editor.py @@ -370,9 +370,9 @@ def view(self, path: Path, view_range: list[int] | None = None) -> CLIResult: '\n'.join(file_content.splitlines()), str(path), start_line ) # Remove extra newlines - # Append warning if we truncated the end_line + # Prepend warning if we truncated the end_line if warning_message: - output += f'\nNOTE: {warning_message}\n' + output = f'NOTE: {warning_message}\n\n{output}' return CLIResult( path=str(path), From 73274a9af0a967dcc7b8c7d1fea6498830aeda1a Mon Sep 17 00:00:00 2001 From: "Ryan H. Tran" Date: Thu, 21 Aug 2025 16:39:32 +0700 Subject: [PATCH 3/6] Update openhands_aci/editor/editor.py --- openhands_aci/editor/editor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openhands_aci/editor/editor.py b/openhands_aci/editor/editor.py index 397a900..202504e 100644 --- a/openhands_aci/editor/editor.py +++ b/openhands_aci/editor/editor.py @@ -372,7 +372,7 @@ def view(self, path: Path, view_range: list[int] | None = None) -> CLIResult: # Prepend warning if we truncated the end_line if warning_message: - output = f'NOTE: {warning_message}\n\n{output}' + output = f'NOTE: {warning_message}\n{output}' return CLIResult( path=str(path), From 5cca1fe4e460d309b9d1dca8146f3b9d0dbd3042 Mon Sep 17 00:00:00 2001 From: "Ryan H. Tran" Date: Thu, 21 Aug 2025 16:40:14 +0700 Subject: [PATCH 4/6] Update openhands_aci/editor/editor.py --- openhands_aci/editor/editor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openhands_aci/editor/editor.py b/openhands_aci/editor/editor.py index 202504e..91d4334 100644 --- a/openhands_aci/editor/editor.py +++ b/openhands_aci/editor/editor.py @@ -353,7 +353,7 @@ def view(self, path: Path, view_range: list[int] | None = None) -> CLIResult: if end_line == -1: end_line = num_lines elif end_line > num_lines: - warning_message = f"We only show up to {num_lines} since there's only {num_lines} lines in this file" + warning_message = f"We only show up to {num_lines} since there're only {num_lines} lines in this file." end_line = num_lines if end_line < start_line: From 0ddda711e5f8fbd865a1ca99c1fe45b0ed8e3e6b Mon Sep 17 00:00:00 2001 From: "Ryan H. Tran" Date: Thu, 21 Aug 2025 16:41:25 +0700 Subject: [PATCH 5/6] bump to 0.3.2 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 0598d25..50e71e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "openhands-aci" -version = "0.3.1" +version = "0.3.2" description = "An Agent-Computer Interface (ACI) designed for software development agents OpenHands." authors = ["OpenHands"] license = "MIT" From d1ca9a3d60146591ef402a272bf8cb285208f1b1 Mon Sep 17 00:00:00 2001 From: "Ryan H. Tran" Date: Thu, 21 Aug 2025 16:42:34 +0700 Subject: [PATCH 6/6] Update tests/integration/editor/test_error_handling.py --- tests/integration/editor/test_error_handling.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/editor/test_error_handling.py b/tests/integration/editor/test_error_handling.py index ad7952f..9d8ac1a 100644 --- a/tests/integration/editor/test_error_handling.py +++ b/tests/integration/editor/test_error_handling.py @@ -94,7 +94,7 @@ def test_view_range_validation(temp_file): enable_linting=False, ) result_json = parse_result(result) - assert 'NOTE: We only show up to 3 since there\'s only 3 lines in this file' in result_json['formatted_output_and_error'] + assert 'NOTE: We only show up to 3 since there\'re only 3 lines in this file.' in result_json['formatted_output_and_error'] # Test invalid range order result = file_editor(