CoolFace
Apppublic

apodex/frontier-agent-demo

sourceHugging Faceapache-2.0updated 1mo agoView on Hugging Face
14likes
write_file.py115 linesDownload Raw Back to tools
1"""File writing tool — writes content to files in E2B sandbox or local fallback.2 3References:4- DeerFlow: sandbox/tools.py write_file_tool()5"""6 7from __future__ import annotations8 9import logging10import os11 12from frontier_agent.core.tool import tool13from plugins.tools._deliverable_policy import output_write_error14from plugins.tools._path_auth import _authorized_local_path15from plugins.tools._sandbox import (16    aget_sandbox,17    arun_sandbox_cmd,18    asandbox_write_file,19    resolve_runtime_path,20    resolve_sandbox_mode,21    sandbox_available,22)23 24logger = logging.getLogger(__name__)25 26_MAX_CONTENT_BYTES = 1_048_576  # 1MB27_LOCAL_OUTPUT_DIR = "/tmp/agent-outputs"28 29 30@tool31async def write_file(path: str, content: str, append: bool = False) -> str:32    """Write plain-text content or source code to a file.33 34    In sandbox mode, writes to the E2B sandbox filesystem.35    Without sandbox, writes to /tmp/agent-outputs/ only.36    This tool only writes bytes; it does not execute generated scripts or load37    runtime packages. Use `bash` to run a generated JavaScript file. Use38    `create_file`, not this tool, for .docx/.xlsx/.pptx deliverables.39 40    Args:41        path: Absolute file path (e.g., /tmp/output.html, /root/chart.png).42        content: The text content to write.43        append: If True, append to existing file instead of overwriting.44 45    Returns:46        Confirmation message with the file path.47    """48    if not path or not path.strip():49        return "Error: file path is required."50 51    deliverable_error = output_write_error(path)52    if deliverable_error:53        return f"Error: {deliverable_error}"54    path = resolve_runtime_path(path)55 56    if len(content) > _MAX_CONTENT_BYTES:57        return f"Error: content exceeds maximum size of {_MAX_CONTENT_BYTES // 1024}KB."58 59    local_path, _reason = _authorized_local_path(path, write_access=True)60 61    # Prefer local writes for allowed repo paths62    if local_path is not None:63        try:64            local_path.parent.mkdir(parents=True, exist_ok=True)65            mode = "a" if append else "w"66            with open(local_path, mode, encoding="utf-8") as f:67                f.write(content)68            return f"File written: {local_path} ({len(content)} bytes)"69        except Exception as e:70            return f"Error writing file: {e}"71 72    if sandbox_available():73        try:74            sandbox = await aget_sandbox()75            parent = os.path.dirname(path)76            if parent:77                await arun_sandbox_cmd(78                    sandbox, f"mkdir -p {parent}", timeout=10,79                )80 81            mode = "a" if append else "w"82            ok, err = await asandbox_write_file(83                sandbox, path, content, mode=mode,84            )85            if not ok:86                raise RuntimeError(err)87 88            return f"File written: {path} ({len(content)} bytes)"89        except Exception as e:90            # Container mode: /outputs & /workspace are REAL mounts inside the91            # isolated task container, so a write failure is a genuine error —92            # NOT a cue to silently redirect the deliverable to /tmp (which93            # would make it vanish from /outputs and emit no file_delta). Fail94            # loudly so the misconfiguration surfaces.95            if resolve_sandbox_mode() == "container":96                return (97                    f"Error writing file {path!r}: {e}. "98                    "(container mode: writes must target the mounted "99                    "/outputs or /workspace; no /tmp fallback)"100                )101            logger.warning("Sandbox write_file failed, trying local: %s", e)102 103    # Local fallback — restricted to /tmp/agent-outputs/104    if not path.startswith(_LOCAL_OUTPUT_DIR):105        path = os.path.join(_LOCAL_OUTPUT_DIR, os.path.basename(path))106 107    try:108        os.makedirs(os.path.dirname(path), exist_ok=True)109        mode = "a" if append else "w"110        with open(path, mode, encoding="utf-8") as f:111            f.write(content)112        return f"File written: {path} ({len(content)} bytes)"113    except Exception as e:114        return f"Error writing file: {e}"115