File Tool¶
file_tool reads and modifies individual files: read, write, edit
(find/replace), copy, move, delete. For directory-level operations (listing
a tree, recursively copying/deleting a whole folder), see the
Directory Tool instead.
from langchain_mero_tools import make_file_tool
file_tool = make_file_tool(ctx) # ctx=None for unrestricted access
Input schema¶
{
"operation": "read" | "write" | "edit" | "copy" | "move" | "delete",
"path": str | list[str], # list only valid for "edit"
"destination_path": str | None, # required for copy/move
"content": str | None, # required for write
"find": str | None, # required for edit
"replace": str | None, # required for edit
"mode": "overwrite" | "append" # only used by write, default "overwrite"
}
Operations¶
| Operation | Required permission | What it does |
|---|---|---|
read |
READ |
Returns the full text content of the file. |
write |
WRITE |
Writes content to the file. mode="overwrite" (default) replaces the file; mode="append" appends. Creates parent directories automatically. |
edit |
WRITE |
Find/replace: replaces every occurrence of find with replace in the file. Accepts a list of paths to apply the same find/replace across multiple files in one call. |
copy |
WRITE (checked on both source and destination_path) |
Copies the file, preserving metadata (shutil.copy2). |
move |
WRITE (checked on both source and destination_path) |
Moves/renames the file. |
delete |
DELETE |
Deletes the file. |
Examples¶
Read a file¶
Write a new file (creates parent directories automatically)¶
file_tool.invoke({
"operation": "write",
"path": "output/report.md",
"content": "# Report\n\nGenerated automatically.",
})
# "Wrote 39 chars to 'output/report.md' (mode=overwrite)."
Append to a log file¶
file_tool.invoke({
"operation": "write",
"path": "run.log",
"content": "job finished at 12:00\n",
"mode": "append",
})
Find/replace in one file¶
file_tool.invoke({
"operation": "edit",
"path": "src/config.py",
"find": "DEBUG = True",
"replace": "DEBUG = False",
})
# "Replaced 1 occurrence(s) in 'src/config.py'."
Find/replace across multiple files in one call¶
This is the one operation that accepts a list of paths — useful for a rename or a config change that spans several files:
file_tool.invoke({
"operation": "edit",
"path": ["src/a.py", "src/b.py", "src/c.py"],
"find": "old_function_name",
"replace": "new_function_name",
})
The result is a per-file breakdown:
[src/a.py] Replaced 2 occurrence(s) in 'src/a.py'.
[src/b.py] No occurrences of the given 'find' string in 'src/b.py'.
[src/c.py] Replaced 1 occurrence(s) in 'src/c.py'.
If any individual file is denied by the security context (e.g. it's not
covered by any PathEntry), only that file's line shows "Denied: ..." —
the others still proceed. This lets an agent see exactly which files
succeeded.
Copy and move¶
file_tool.invoke({
"operation": "copy",
"path": "draft.txt",
"destination_path": "archive/draft.txt",
})
file_tool.invoke({
"operation": "move",
"path": "draft.txt",
"destination_path": "final/draft.txt",
})
Both the source and destination_path are checked against the
SecurityContext independently — a scoped agent can't use copy/move to
smuggle a file outside its sandbox, and can't overwrite something outside
its scope either.
Delete¶
Requires Permission.DELETE specifically — a context with only READ |
WRITE will be denied, even though it can otherwise touch the file freely.
Error responses¶
file_tool never raises for expected failures — it always returns a
string:
file_tool.invoke({"operation": "read", "path": "does-not-exist.txt"})
# "Error: 'does-not-exist.txt' is not a file or does not exist."
file_tool.invoke({"operation": "write", "path": "/etc/passwd", "content": "x"})
# "Denied: Path '/etc/passwd' is an absolute path that isn't covered by any
# configured PathEntry, and its leading segment doesn't match a mounted slug (...)."
See Error Handling for the full pattern.
Notes and edge cases¶
writeandeditboth requirecontent/find+replacerespectively — omitting them returns a plain"Error: ..."string rather than raising.writereads files witherrors="replace"on read, so non-UTF-8 bytes don't crash the tool (they're shown as replacement characters instead).copy/movecreate the destination's parent directories automatically, same aswrite.- Multiple paths are only accepted for
edit— passing a list for any other operation returns"Error: multiple paths are only supported for the 'edit' operation."
See also¶
- Directory Tool — for recursive directory operations instead of single files.
- Security & Sandboxing — how the
PathEntrymount table is resolved and enforced. - Building Custom Tools — this tool's
source (
tools/file_tool.py) is a good template to copy from.