frontier-agent-demo / plugins /tools /document_node_toolchain.py
christlurker's picture
FrontierAgent react demo
9d0fd45
Raw
History Blame Contribute Delete
5.58 kB
"""Runtime discovery and prompt guidance for the baked document Node toolchain."""
from __future__ import annotations
import json
import os
import shutil
import subprocess
from dataclasses import dataclass
from pathlib import Path
from plugins.tools._sandbox import is_e2b_available
_DOCUMENT_PACKAGES = ("docx", "pptxgenjs")
_BWRAP_VISIBLE_ROOTS = (
Path("/usr"),
Path("/bin"),
Path("/lib"),
Path("/lib64"),
Path("/etc"),
)
@dataclass(frozen=True)
class DocumentNodeToolchain:
"""Versions proven available to the active model-authored command backend."""
node_version: str
docx_version: str
pptxgenjs_version: str
def _is_within(path: Path, roots: tuple[Path, ...]) -> bool:
resolved = path.resolve()
for root in roots:
try:
resolved.relative_to(root)
return True
except ValueError:
continue
return False
def _package_version(package: str, roots: tuple[Path, ...]) -> tuple[str, Path] | None:
for root in roots:
manifest = root / package / "package.json"
if not manifest.is_file():
continue
try:
data = json.loads(manifest.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError, TypeError):
continue
version = str(data.get("version") or "").strip()
if version:
return version, manifest
return None
def discover_document_node_toolchain(
*,
sandbox_mode: str,
) -> DocumentNodeToolchain | None:
"""Return the document Node stack visible to model-authored commands.
``container`` executes in the current image. ``bwrap`` (and ``auto``
without E2B) can see only paths mounted into the jail, so both the Node
binary and module roots must live under its read-only system mounts.
Explicit/auto E2B executes off-host and must never inherit a capability
merely because the serving process itself has it installed.
"""
mode = (sandbox_mode or "auto").strip().lower()
if mode not in {"container", "native", "bwrap"} and is_e2b_available():
return None
node_path = os.environ.get("NODE_PATH", "").strip()
path_env = os.environ.get("PATH", "").strip()
if not node_path or not path_env:
return None
roots = tuple(
Path(raw.strip()).expanduser()
for raw in node_path.split(os.pathsep)
if raw.strip()
)
node = shutil.which("node", path=path_env)
if not roots or not node:
return None
packages = {
package: _package_version(package, roots)
for package in _DOCUMENT_PACKAGES
}
if any(value is None for value in packages.values()):
return None
if mode not in {"container", "native"}:
visible_paths = [
Path(node),
*(value[1] for value in packages.values() if value is not None),
]
if not all(_is_within(path, _BWRAP_VISIBLE_ROOTS) for path in visible_paths):
return None
try:
result = subprocess.run(
[node, "--version"],
capture_output=True,
text=True,
timeout=2,
check=False,
env={"PATH": path_env, "NODE_PATH": node_path},
)
except (OSError, subprocess.SubprocessError):
return None
if result.returncode != 0:
return None
node_version = result.stdout.strip().removeprefix("v")
if not node_version:
return None
docx = packages["docx"]
pptxgenjs = packages["pptxgenjs"]
assert docx is not None and pptxgenjs is not None
return DocumentNodeToolchain(
node_version=node_version,
docx_version=docx[0],
pptxgenjs_version=pptxgenjs[0],
)
def render_document_node_toolchain_note(
*,
sandbox_mode: str,
tool_names: list[str] | tuple[str, ...],
audience: str = "agent",
) -> str:
"""Render a truthful prompt note for agents that can execute ``bash``."""
names = {str(name) for name in tool_names}
if "bash" not in names:
return ""
capability = discover_document_node_toolchain(sandbox_mode=sandbox_mode)
if capability is None:
return ""
if "create_file" in names:
fallback = (
"Use this fallback order: (1) `create_file`; (2) Python libraries "
"such as `python-docx` or `python-pptx` only after `create_file` "
"explicitly reports the required operation unsupported; (3) these "
"Node packages only when Python still cannot cover the operation, "
"or when the user requires accurate preservation of an existing "
"template that the Python path would not preserve."
)
else:
fallback = (
"`create_file` is not available in this tool set. Use Python "
"libraries first; use these Node packages only when Python cannot "
"cover the required operation, or when the user requires accurate "
"preservation of an existing template that Python would not "
"preserve."
)
scope = "sub-agent runtime" if audience == "coordinator" else "runtime-discovered"
return (
f"\n\nDOCUMENT TOOLCHAIN ({scope}): `bash` has Node.js "
f"{capability.node_version}, `docx@{capability.docx_version}`, and "
f"`pptxgenjs@{capability.pptxgenjs_version}`. `NODE_PATH` is already "
"configured: load them as `require('docx')` and "
"`require('pptxgenjs')`; do not hard-code `/usr/lib/node_modules`. "
f"{fallback}"
)