From fca440a62ca96c4235ef696f09ebee0cf92c7703 Mon Sep 17 00:00:00 2001 From: CleverThis Date: Mon, 13 Apr 2026 06:45:26 +0000 Subject: [PATCH] fix(error-handling): _handle_file_edit() now respects encoding parameter - Fixed _handle_file_edit() to use encoding=inputs.get("encoding", "utf-8") for both read_text() and write_text() calls, ensuring encoding is explicit and not dependent on the platform default. - Added encoding field to the FILE_EDIT_SPEC schema to surface encoding choices to callers. ISSUES CLOSED: #7559 --- features/steps/tool_builtins_steps.py | 42 ++++++++++++++++++++ features/tool_builtins.feature | 14 +++++++ src/cleveragents/tool/builtins/file_tools.py | 10 ++++- 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/features/steps/tool_builtins_steps.py b/features/steps/tool_builtins_steps.py index 012f748bd..045ecfa06 100644 --- a/features/steps/tool_builtins_steps.py +++ b/features/steps/tool_builtins_steps.py @@ -62,6 +62,15 @@ def step_given_file_with_content(context: Any, name: str, content: str) -> None: path.write_text(content) +@given('an encoded file "{name}" with encoding "{encoding}" and content "{content}"') +def step_given_file_with_content_encoding( + context: Any, name: str, encoding: str, content: str +) -> None: + path = Path(context.sandbox_dir) / name + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content, encoding=encoding) + + @given('a file "{name}" with lines "{csv_lines}"') def step_given_file_with_lines(context: Any, name: str, csv_lines: str) -> None: lines = csv_lines.split(",") @@ -149,6 +158,39 @@ def step_when_file_edit(context: Any, old: str, new: str) -> None: ) +@when( + 'I edit file "edit-enc.txt" replacing "{old}" with "{new}" specifying encoding "{encoding}"' +) +def step_when_file_edit_with_encoding( + context: Any, old: str, new: str, encoding: str +) -> None: + _run_tool( + context, + "builtin/file-edit", + { + "path": "edit-enc.txt", + "old_text": old, + "new_text": new, + "encoding": encoding, + }, + ) + + +def step_when_file_edit_with_encoding( + context: Any, old: str, new: str, encoding: str +) -> None: + _run_tool( + context, + "builtin/file-edit", + { + "path": "edit-enc.txt", + "old_text": old, + "new_text": new, + "encoding": encoding, + }, + ) + + @when('I execute the "builtin/file-edit" tool replacing all "{old}" with "{new}"') def step_when_file_edit_all(context: Any, old: str, new: str) -> None: _run_tool( diff --git a/features/tool_builtins.feature b/features/tool_builtins.feature index 944faaffb..a43782b67 100644 --- a/features/tool_builtins.feature +++ b/features/tool_builtins.feature @@ -69,6 +69,20 @@ Feature: Built-in File Tools Then the tool result should not be successful And the tool result error should mention "not found" + Scenario: Edit file uses explicit encoding parameter + Given a temporary sandbox directory + And an encoded file "edit-enc.txt" with encoding "utf-8" and content "hello world" + When I edit file "edit-enc.txt" replacing "hello" with "goodbye" specifying encoding "utf-8" + Then the tool result should be successful + And the output "replacements" should equal 1 + + Scenario: Edit file defaults to utf-8 encoding when not specified + Given a temporary sandbox directory + And a file "edit.txt" with content "default encoding test" + When I execute the "builtin/file-edit" tool replacing "default" with "explicit" + Then the tool result should be successful + And the output "replacements" should equal 1 + # ---- File Delete ---- Scenario: Delete an existing file diff --git a/src/cleveragents/tool/builtins/file_tools.py b/src/cleveragents/tool/builtins/file_tools.py index 468e7bd90..5968ecaf3 100644 --- a/src/cleveragents/tool/builtins/file_tools.py +++ b/src/cleveragents/tool/builtins/file_tools.py @@ -144,8 +144,9 @@ def _handle_file_edit(inputs: dict[str, Any]) -> dict[str, Any]: old_text: str = inputs["old_text"] new_text: str = inputs["new_text"] replace_all: bool = inputs.get("replace_all", False) + encoding: str = inputs.get("encoding", "utf-8") - content = path.read_text() + content = path.read_text(encoding=encoding) count = content.count(old_text) if count == 0: @@ -157,7 +158,7 @@ def _handle_file_edit(inputs: dict[str, Any]) -> dict[str, Any]: content = content.replace(old_text, new_text, 1) count = 1 - path.write_text(content) + path.write_text(content, encoding=encoding) return { "path": str(path), @@ -330,6 +331,11 @@ FILE_EDIT_SPEC = ToolSpec( "default": False, "description": "Replace all occurrences", }, + "encoding": { + "type": "string", + "default": "utf-8", + "description": "File encoding", + }, }, "required": ["path", "old_text", "new_text"], },