Files
docker-agent-sandbox/docker_agent_sandbox/tools/edit_file.py
Matte23 4bb5a645e0
Some checks failed
CI / test (push) Failing after 20s
CI / publish (push) Has been skipped
feat: Use docker api to pull files from container
2026-04-02 15:40:08 +02:00

75 lines
2.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""edit_file.py tool for str_replace editing of files inside the sandbox."""
from __future__ import annotations
from typing import TYPE_CHECKING
from langchain_core.tools import BaseTool, tool
from loguru import logger
if TYPE_CHECKING:
from docker_agent_sandbox.sandbox import DockerSandbox
def make_edit_file_tool(sandbox: "DockerSandbox") -> BaseTool:
"""Return an edit_file tool bound to *sandbox*."""
@tool
def edit_file(path: str, old_str: str, new_str: str) -> str:
"""
Replace the first exact occurrence of *old_str* with *new_str* in *path*.
This is the standard ``str_replace`` editing primitive: read the file,
find the unique snippet you want to change, and supply the replacement.
Rules:
- *old_str* must match **exactly** (including whitespace and indentation).
- *old_str* must appear **at least once**; the tool returns an error if it
is not found.
- If *old_str* appears more than once the tool refuses and asks you to
provide more surrounding context to make it unique.
- To insert text without removing anything, set *old_str* to a line that
will remain and include it verbatim in *new_str* (i.e. keep the anchor
line and add your new lines around it).
- To delete a block, set *new_str* to an empty string ``""``.
Returns a confirmation with the number of lines affected, or an error.
"""
_MAX_EDIT_BYTES = 1_000_000 # 1 MB
logger.debug("Editing file inside sandbox: {!r}", path)
try:
data = sandbox.read_file(path)
except (FileNotFoundError, IsADirectoryError, RuntimeError) as exc:
return f"[ERROR reading {path!r} for edit] {exc}"
if len(data) > _MAX_EDIT_BYTES:
return (
f"[ERROR] {path!r} is {len(data)} bytes; edit_file only supports files "
f"up to {_MAX_EDIT_BYTES} bytes."
)
content = data.decode("utf-8", errors="replace")
count = content.count(old_str)
if count == 0:
return (
f"[ERROR] old_str not found in {path!r}. "
"Check that whitespace and indentation match exactly."
)
if count > 1:
return (
f"[ERROR] old_str appears {count} times in {path!r}. "
"Provide more surrounding context to make it unique."
)
new_content = content.replace(old_str, new_str, 1)
old_lines = old_str.count("\n") + 1
new_lines = new_str.count("\n") + 1 if new_str else 0
try:
sandbox.write_file(path, new_content)
except Exception as exc:
return f"[ERROR writing {path!r} after edit] {exc}"
return f"[OK] Replaced {old_lines} line(s) with {new_lines} line(s) in {path}"
return edit_file