Skip to content

FilesystemToolkit

autogen.beta.tools.toolkits.filesystem.FilesystemToolkit #

FilesystemToolkit(base_path='.', *, read_only=False, middleware=())

Bases: Toolkit

Toolkit that exposes local filesystem operations as function tools.

All paths are resolved relative to base_path. A path-traversal guard rejects any resolved path that escapes the base directory.

Individual tools are available as attributes and can be passed to an agent separately::

fs = FilesystemToolkit(base_path="/tmp/workspace")

# use the full toolkit
agent = Agent("agent", config=config, tools=[fs])

# or pick individual tools
agent = Agent(
    "agent",
    config=config,
    tools=[
        fs.read_file(),
        fs.find_files(),
    ],
)
Source code in autogen/beta/tools/toolkits/filesystem.py
def __init__(
    self,
    base_path: str | os.PathLike[str] = ".",
    *,
    read_only: bool = False,
    middleware: Iterable[ToolMiddleware] = (),
) -> None:
    self.base_dir = Path(base_path).resolve()

    tools = [
        self.read_file(),
        self.find_files(),
    ]

    if not read_only:
        tools.extend([
            self.write_file(),
            self.update_file(),
            self.delete_file(),
        ])

    super().__init__(
        *tools,
        name="filesystem_toolkit",
        middleware=middleware,
    )

base_dir instance-attribute #

base_dir = resolve()

name instance-attribute #

name = name or __name__

tools property #

tools

read_file #

read_file(base_path=None, *, name='read_file', description='Read the contents of a file. Returns text by default. Set raw=true to read binary content as base64.', middleware=())
Source code in autogen/beta/tools/toolkits/filesystem.py
def read_file(
    self,
    base_path: str | os.PathLike[str] | None = None,
    *,
    name: str = "read_file",
    description: str = "Read the contents of a file. Returns text by default. Set raw=true to read binary content as base64.",
    middleware: Iterable[ToolMiddleware] = (),
) -> FunctionTool:
    base_dir = _resolve_dir(base_path, self.base_dir)

    @tool(name=name, description=description, middleware=middleware)
    def _read_file(
        path: Annotated[
            str,
            Field(description="Relative path to the file to read."),
        ],
        raw: bool = Field(
            default=False,
            description="If true, read the file as binary and return base64-encoded content.",
        ),
    ) -> str:
        target = _resolve_path(base_dir, path)
        if raw:
            return base64.b64encode(target.read_bytes()).decode("ascii")
        # Pin the encoding so the toolkit produces the same bytes on Linux,
        # macOS, and Windows. Without it `Path.read_text()` inherits
        # `locale.getpreferredencoding()`, which is `cp1252` on most
        # Windows installs and raises `UnicodeDecodeError` on any file
        # written with non-cp1252 content (most modern source files,
        # config files, JSON with non-ASCII strings, etc.).
        return target.read_text(encoding="utf-8")

    return _read_file

find_files #

find_files(base_path=None, *, name='find_files', description="Search for files matching a glob pattern. Use recursive patterns like '**/*.py' to search subdirectories.", middleware=())
Source code in autogen/beta/tools/toolkits/filesystem.py
def find_files(
    self,
    base_path: str | os.PathLike[str] | None = None,
    *,
    name: str = "find_files",
    description: str = "Search for files matching a glob pattern. Use recursive patterns like '**/*.py' to search subdirectories.",
    middleware: Iterable[ToolMiddleware] = (),
) -> FunctionTool:
    base_dir = _resolve_dir(base_path, self.base_dir)

    @tool(name=name, description=description, middleware=middleware)
    def _find_files(
        pattern: Annotated[
            str,
            Field(description="Glob pattern to match files, e.g. '*.py' or '**/*.txt'."),
        ],
        path: str = Field(
            default=".",
            description="Relative path to the directory to search from. Defaults to the base directory.",
        ),
    ) -> list[str]:
        target = _resolve_path(base_dir, path)
        return sorted(str(p.relative_to(base_dir)) for p in _glob(target, pattern))

    return _find_files

write_file #

write_file(base_path=None, *, name='write_file', description='Create or overwrite a file with the given content. Parent directories are created automatically.', middleware=())
Source code in autogen/beta/tools/toolkits/filesystem.py
def write_file(
    self,
    base_path: str | os.PathLike[str] | None = None,
    *,
    name: str = "write_file",
    description: str = "Create or overwrite a file with the given content. Parent directories are created automatically.",
    middleware: Iterable[ToolMiddleware] = (),
) -> FunctionTool:
    base_dir = _resolve_dir(base_path, self.base_dir)

    @tool(name=name, description=description, middleware=middleware)
    def _write_file(
        path: Annotated[
            str,
            Field(description="Relative path to the file to create or overwrite."),
        ],
        content: Annotated[
            str,
            Field(description="The full content to write to the file."),
        ],
    ) -> str:
        target = _resolve_path(base_dir, path)
        target.parent.mkdir(parents=True, exist_ok=True)
        # Encode the payload as UTF-8 so the toolkit round-trips any
        # text the model writes (smart quotes, emoji, non-Latin scripts,
        # code with non-ASCII docstrings). The platform-default
        # encoding is `cp1252` on most Windows machines and silently
        # raises `UnicodeEncodeError` mid-write.
        target.write_text(content, encoding="utf-8")
        return f"Successfully wrote {len(content)} characters to {path}"

    return _write_file

update_file #

update_file(base_path=None, *, name='update_file', description='Update a file by replacing the first occurrence of old_content with new_content.', middleware=())
Source code in autogen/beta/tools/toolkits/filesystem.py
def update_file(
    self,
    base_path: str | os.PathLike[str] | None = None,
    *,
    name: str = "update_file",
    description: str = "Update a file by replacing the first occurrence of old_content with new_content.",
    middleware: Iterable[ToolMiddleware] = (),
) -> FunctionTool:
    base_dir = _resolve_dir(base_path, self.base_dir)

    @tool(name=name, description=description, middleware=middleware)
    def _update_file(
        path: Annotated[
            str,
            Field(description="Relative path to the file to update."),
        ],
        old_content: Annotated[
            str,
            Field(description="The exact text to find and replace."),
        ],
        new_content: Annotated[
            str,
            Field(description="The text to replace old_content with."),
        ],
    ) -> str:
        target = _resolve_path(base_dir, path)
        # See _read_file / _write_file: pin UTF-8 so update_file reads
        # back the exact bytes it (or any other UTF-8 writer) produced,
        # and writes the modified payload back in the same encoding.
        # Without this, the read/write pair on Windows would silently
        # transcode the file into cp1252 every time the model edits it.
        text = target.read_text(encoding="utf-8")
        if old_content not in text:
            raise ValueError(f"old_content not found in {path}")
        target.write_text(text.replace(old_content, new_content, 1), encoding="utf-8")
        return f"Successfully updated {path}"

    return _update_file

delete_file #

delete_file(base_path=None, *, name='delete_file', description='Delete a file or directory.', middleware=())
Source code in autogen/beta/tools/toolkits/filesystem.py
def delete_file(
    self,
    base_path: str | os.PathLike[str] | None = None,
    *,
    name: str = "delete_file",
    description: str = "Delete a file or directory.",
    middleware: Iterable[ToolMiddleware] = (),
) -> FunctionTool:
    base_dir = _resolve_dir(base_path, self.base_dir)

    @tool(name=name, description=description, middleware=middleware)
    def _delete_file(
        path: Annotated[
            str,
            Field(description="Relative path to the file or directory to delete."),
        ],
    ) -> str:
        target = _resolve_path(base_dir, path)
        if target.is_dir():
            shutil.rmtree(target)
        else:
            target.unlink()
        return f"Successfully deleted {path}"

    return _delete_file

set_provider #

set_provider(provider)
Source code in autogen/beta/tools/final/toolkit.py
def set_provider(self, provider: Provider) -> None:
    for t in self.tools:
        t.set_provider(provider)

schemas async #

schemas(context)
Source code in autogen/beta/tools/final/toolkit.py
async def schemas(self, context: "Context") -> Iterable[ToolSchema]:
    schemas: list[ToolSchema] = []
    for t in self.tools:
        schemas.extend(await t.schemas(context))
    return schemas

register #

register(stack, context, *, middleware=())
Source code in autogen/beta/tools/final/toolkit.py
def register(
    self,
    stack: "ExitStack | AsyncExitStack",
    context: "Context",
    *,
    middleware: Iterable["BaseMiddleware"] = (),
) -> None:
    for t in self.tools:
        t.register(stack, context, middleware=middleware)

tool #

tool(function: Callable[..., Any], *, name: str | None = None, description: str | None = None, schema: FunctionParameters | None = None, sync_to_thread: bool = True, middleware: Iterable[ToolMiddleware] = ()) -> FunctionTool
tool(function: None = None, *, name: str | None = None, description: str | None = None, schema: FunctionParameters | None = None, sync_to_thread: bool = True, middleware: Iterable[ToolMiddleware] = ()) -> Callable[[Callable[..., Any]], FunctionTool]
tool(function=None, *, name=None, description=None, schema=None, sync_to_thread=True, middleware=())
Source code in autogen/beta/tools/final/toolkit.py
def tool(
    self,
    function: Callable[..., Any] | None = None,
    *,
    name: str | None = None,
    description: str | None = None,
    schema: FunctionParameters | None = None,
    sync_to_thread: bool = True,
    middleware: Iterable[ToolMiddleware] = (),
) -> FunctionTool | Callable[[Callable[..., Any]], FunctionTool]:
    def make_tool(f: Callable[..., Any]) -> FunctionTool:
        t = tool(
            f,
            name=name,
            description=description,
            schema=schema,
            sync_to_thread=sync_to_thread,
            middleware=middleware,
        )
        self._add_tool(t)
        return t

    if function:
        return make_tool(function)

    return make_tool