Added many tools
This commit is contained in:
188
tools/venv.py
188
tools/venv.py
@@ -0,0 +1,188 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from core.tools.base import BaseTool, ToolContext
|
||||
from core.tools.registry import registry
|
||||
from core.safety import safety
|
||||
from core.events import bus
|
||||
|
||||
|
||||
class VenvTool(BaseTool):
|
||||
name = "venv"
|
||||
description = "Python virtual environment management (create, install, run, list packages)"
|
||||
|
||||
# =========================================================
|
||||
# EXECUTE ROUTER (ONLY ENTRYPOINT WITH ctx)
|
||||
# =========================================================
|
||||
|
||||
def execute(self, payload: dict[str, Any], ctx: ToolContext):
|
||||
action = str(payload.get("action", "")).strip()
|
||||
|
||||
bus.log(
|
||||
"VENV",
|
||||
"venv_execute",
|
||||
"INFO",
|
||||
{"action": action}
|
||||
)
|
||||
|
||||
match action:
|
||||
case "create":
|
||||
return self.create_venv(payload)
|
||||
|
||||
case "install":
|
||||
return self.install_package(payload)
|
||||
|
||||
case "run":
|
||||
return self.run_python(payload)
|
||||
|
||||
case "list":
|
||||
return self.list_packages(payload)
|
||||
|
||||
case _:
|
||||
raise ValueError(f"Unknown venv action: {action}")
|
||||
|
||||
# =========================================================
|
||||
# PATH HELPERS
|
||||
# =========================================================
|
||||
|
||||
def _venv_path(self, path: str) -> Path:
|
||||
return safety.validate_path(path)
|
||||
|
||||
def _python_bin(self, venv: Path) -> Path:
|
||||
"""Cross-platform python binary resolution."""
|
||||
if (venv / "bin").exists():
|
||||
return venv / "bin" / "python"
|
||||
return venv / "Scripts" / "python.exe"
|
||||
|
||||
def _pip_bin(self, venv: Path) -> Path:
|
||||
"""Cross-platform pip binary resolution."""
|
||||
if (venv / "bin").exists():
|
||||
return venv / "bin" / "pip"
|
||||
return venv / "Scripts" / "pip.exe"
|
||||
|
||||
# =========================================================
|
||||
# CREATE VENV
|
||||
# =========================================================
|
||||
|
||||
def create_venv(self, payload: dict[str, Any]):
|
||||
path = payload.get("path")
|
||||
|
||||
if not isinstance(path, str):
|
||||
raise ValueError("path must be string")
|
||||
|
||||
venv_path = self._venv_path(path)
|
||||
|
||||
if venv_path.exists():
|
||||
return {
|
||||
"status": "exists",
|
||||
"path": str(venv_path)
|
||||
}
|
||||
|
||||
subprocess.run(
|
||||
[sys.executable, "-m", "venv", str(venv_path)],
|
||||
check=True
|
||||
)
|
||||
|
||||
return {
|
||||
"status": "created",
|
||||
"path": str(venv_path)
|
||||
}
|
||||
|
||||
# =========================================================
|
||||
# INSTALL PACKAGE
|
||||
# =========================================================
|
||||
|
||||
def install_package(self, payload: dict[str, Any]):
|
||||
path = payload.get("path")
|
||||
package = payload.get("package")
|
||||
|
||||
if not isinstance(path, str):
|
||||
raise ValueError("path must be string")
|
||||
|
||||
if not isinstance(package, str):
|
||||
raise ValueError("package must be string")
|
||||
|
||||
venv_path = self._venv_path(path)
|
||||
pip = self._pip_bin(venv_path)
|
||||
|
||||
if not pip.exists():
|
||||
raise ValueError("pip not found in virtual environment")
|
||||
|
||||
result = subprocess.run(
|
||||
[str(pip), "install", package],
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
return {
|
||||
"status": "ok" if result.returncode == 0 else "error",
|
||||
"stdout": result.stdout,
|
||||
"stderr": result.stderr
|
||||
}
|
||||
|
||||
# =========================================================
|
||||
# RUN PYTHON CODE
|
||||
# =========================================================
|
||||
|
||||
def run_python(self, payload: dict[str, Any]):
|
||||
path = payload.get("path")
|
||||
code = payload.get("code")
|
||||
|
||||
if not isinstance(path, str):
|
||||
raise ValueError("path must be string")
|
||||
|
||||
if not isinstance(code, str):
|
||||
raise ValueError("code must be string")
|
||||
|
||||
venv_path = self._venv_path(path)
|
||||
python_bin = self._python_bin(venv_path)
|
||||
|
||||
if not python_bin.exists():
|
||||
raise ValueError("python executable not found in venv")
|
||||
|
||||
result = subprocess.run(
|
||||
[str(python_bin), "-c", code],
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
return {
|
||||
"status": "ok" if result.returncode == 0 else "error",
|
||||
"stdout": result.stdout,
|
||||
"stderr": result.stderr
|
||||
}
|
||||
|
||||
# =========================================================
|
||||
# LIST PACKAGES
|
||||
# =========================================================
|
||||
|
||||
def list_packages(self, payload: dict[str, Any]):
|
||||
path = payload.get("path")
|
||||
|
||||
if not isinstance(path, str):
|
||||
raise ValueError("path must be string")
|
||||
|
||||
venv_path = self._venv_path(path)
|
||||
pip = self._pip_bin(venv_path)
|
||||
|
||||
result = subprocess.run(
|
||||
[str(pip), "list"],
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
return {
|
||||
"status": "ok",
|
||||
"output": result.stdout
|
||||
}
|
||||
|
||||
|
||||
# =========================================================
|
||||
# REGISTER TOOL
|
||||
# =========================================================
|
||||
|
||||
registry.register(VenvTool())
|
||||
Reference in New Issue
Block a user
