Rebase onto upstream (a4d95fd)
#12
@@ -367,10 +367,55 @@ class MemoryTool20250818(BaseAnthropicTool):
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def _str_replace(
|
async def _str_replace(
|
||||||
self, path: str | None, old_str: str | None, new_str: str | None
|
self,
|
||||||
|
path: str | None,
|
||||||
|
old_str: str | None,
|
||||||
|
new_str: str | None,
|
||||||
) -> CLIResult:
|
) -> CLIResult:
|
||||||
"""Placeholder for str_replace command."""
|
"""Replace unique occurrence of old_str with new_str."""
|
||||||
return CLIResult(exit_code=1, output="", error="Not implemented yet")
|
if path is None or old_str is None or new_str is None:
|
||||||
|
return CLIResult(
|
||||||
|
exit_code=1,
|
||||||
|
output="",
|
||||||
|
error="Error: old_str and new_str are required for str_replace command"
|
||||||
|
)
|
||||||
|
|
||||||
|
path_str = path
|
||||||
|
validated_path = self._validate_memory_path(path)
|
||||||
|
|
||||||
|
if not validated_path.exists() or validated_path.is_dir():
|
||||||
|
return CLIResult(
|
||||||
|
exit_code=1,
|
||||||
|
output="",
|
||||||
|
error=f"Error: The path {path_str} does not exist. Please provide a valid path."
|
||||||
|
)
|
||||||
|
|
||||||
|
content = validated_path.read_text()
|
||||||
|
count = content.count(old_str)
|
||||||
|
|
||||||
|
if count == 0:
|
||||||
|
return CLIResult(
|
||||||
|
exit_code=1,
|
||||||
|
output="",
|
||||||
|
error=f"No replacement was performed, old_str `{old_str}` did not appear verbatim in {path_str}."
|
||||||
|
)
|
||||||
|
elif count > 1:
|
||||||
|
lines = content.splitlines()
|
||||||
|
line_nums = [i + 1 for i, line in enumerate(lines) if old_str in line]
|
||||||
|
return CLIResult(
|
||||||
|
exit_code=1,
|
||||||
|
output="",
|
||||||
|
error=f"No replacement was performed. Multiple occurrences of old_str `{old_str}` in lines: {line_nums}. Please ensure it is unique"
|
||||||
|
)
|
||||||
|
|
||||||
|
new_content = content.replace(old_str, new_str, 1)
|
||||||
|
validated_path.write_text(new_content)
|
||||||
|
|
||||||
|
return CLIResult(
|
||||||
|
exit_code=0,
|
||||||
|
output="The memory file has been edited.",
|
||||||
|
error=""
|
||||||
|
)
|
||||||
|
|
||||||
async def _insert(
|
async def _insert(
|
||||||
self, path: str | None, insert_line: int | None, insert_text: str | None
|
self, path: str | None, insert_line: int | None, insert_text: str | None
|
||||||
|
|||||||
@@ -179,3 +179,61 @@ async def test_create_file_missing_text(memory_tool):
|
|||||||
assert result.exit_code == 1
|
assert result.exit_code == 1
|
||||||
assert result.output == ""
|
assert result.output == ""
|
||||||
assert "Error: file_text is required for create command" in result.error
|
assert "Error: file_text is required for create command" in result.error
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_str_replace_success(memory_tool, temp_workspace):
|
||||||
|
"""Test replacing unique string in a file."""
|
||||||
|
test_file = temp_workspace / "memories" / "config.txt"
|
||||||
|
test_file.write_text("color: blue\nsize: large\n")
|
||||||
|
|
||||||
|
result = await memory_tool(
|
||||||
|
command="str_replace",
|
||||||
|
path="/memories/config.txt",
|
||||||
|
old_str="blue",
|
||||||
|
new_str="green"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result.exit_code == 0
|
||||||
|
assert result.error == ""
|
||||||
|
assert "The memory file has been edited." in result.output
|
||||||
|
|
||||||
|
# Verify file was modified
|
||||||
|
assert test_file.read_text() == "color: green\nsize: large\n"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_str_replace_not_found(memory_tool, temp_workspace):
|
||||||
|
"""Test replacing string that doesn't exist."""
|
||||||
|
test_file = temp_workspace / "memories" / "config.txt"
|
||||||
|
test_file.write_text("color: blue\n")
|
||||||
|
|
||||||
|
result = await memory_tool(
|
||||||
|
command="str_replace",
|
||||||
|
path="/memories/config.txt",
|
||||||
|
old_str="red",
|
||||||
|
new_str="green"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result.exit_code == 1
|
||||||
|
assert result.output == ""
|
||||||
|
assert "No replacement was performed, old_str `red` did not appear verbatim" in result.error
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_str_replace_duplicate(memory_tool, temp_workspace):
|
||||||
|
"""Test replacing string that appears multiple times."""
|
||||||
|
test_file = temp_workspace / "memories" / "config.txt"
|
||||||
|
test_file.write_text("color: blue\nbackground: blue\n")
|
||||||
|
|
||||||
|
result = await memory_tool(
|
||||||
|
command="str_replace",
|
||||||
|
path="/memories/config.txt",
|
||||||
|
old_str="blue",
|
||||||
|
new_str="green"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result.exit_code == 1
|
||||||
|
assert result.output == ""
|
||||||
|
assert "Multiple occurrences of old_str `blue`" in result.error
|
||||||
|
assert "Please ensure it is unique" in result.error
|
||||||
|
|||||||
Reference in New Issue
Block a user