agent-loop / storage_manager.py
arudradey's picture
Deploy Agent Loop Docker app with full web UI
81d5a2e verified
Raw History Blame Contribute Delete
3.62 kB
import os
import shutil
from pathlib import Path
from typing import Dict, Any, List
def resolve_storage_dir() -> Path:
# Check if /data is mounted and writable (HF Spaces persistent storage bucket)
candidate = Path("/data")
if candidate.exists():
try:
test_file = candidate / ".write_test"
test_file.touch(exist_ok=True)
test_file.unlink(missing_ok=True)
return candidate
except Exception:
pass
# Local fallback
local_data = Path("./data").resolve()
local_data.mkdir(parents=True, exist_ok=True)
return local_data
STORAGE_DIR = resolve_storage_dir()
# Ensure essential directories
RUNS_DIR = STORAGE_DIR / "runs"
ARTIFACTS_DIR = STORAGE_DIR / "artifacts"
MEMORY_DIR = STORAGE_DIR / "memory"
for d in (RUNS_DIR, ARTIFACTS_DIR, MEMORY_DIR):
d.mkdir(parents=True, exist_ok=True)
def get_storage_info() -> Dict[str, Any]:
try:
total, used, free = shutil.disk_usage(STORAGE_DIR)
is_hf_bucket = str(STORAGE_DIR).startswith("/data")
file_count = sum(1 for _ in STORAGE_DIR.rglob("*") if _.is_file())
return {
"path": str(STORAGE_DIR),
"is_hf_bucket": is_hf_bucket,
"total_gb": round(total / (1024**3), 2),
"used_gb": round(used / (1024**3), 2),
"free_gb": round(free / (1024**3), 2),
"percent_used": round((used / total) * 100, 1) if total > 0 else 0,
"file_count": file_count,
}
except Exception as e:
return {
"path": str(STORAGE_DIR),
"is_hf_bucket": False,
"error": str(e),
"total_gb": 0,
"used_gb": 0,
"free_gb": 0,
"percent_used": 0,
"file_count": 0,
}
def list_storage_files(subpath: str = "") -> List[Dict[str, Any]]:
target = (STORAGE_DIR / subpath.lstrip("/")).resolve()
if not str(target).startswith(str(STORAGE_DIR)):
raise ValueError("Path traversal denied.")
if not target.exists():
return []
results = []
for item in sorted(target.iterdir(), key=lambda p: (not p.is_dir(), p.name)):
rel = item.relative_to(STORAGE_DIR).as_posix()
results.append({
"name": item.name,
"path": rel,
"is_dir": item.is_dir(),
"size_bytes": item.stat().st_size if item.is_file() else 0,
"modified_time": item.stat().st_mtime,
})
return results
def read_storage_file(rel_path: str) -> str:
target = (STORAGE_DIR / rel_path.lstrip("/")).resolve()
if not str(target).startswith(str(STORAGE_DIR)):
raise ValueError("Path traversal denied.")
if not target.is_file():
raise FileNotFoundError(f"File not found: {rel_path}")
return target.read_text(encoding="utf-8", errors="replace")
def write_storage_file(rel_path: str, content: str) -> str:
target = (STORAGE_DIR / rel_path.lstrip("/")).resolve()
if not str(target).startswith(str(STORAGE_DIR)):
raise ValueError("Path traversal denied.")
target.parent.mkdir(parents=True, exist_ok=True)
target.write_text(content, encoding="utf-8")
return str(target.relative_to(STORAGE_DIR))
def delete_storage_file(rel_path: str) -> bool:
target = (STORAGE_DIR / rel_path.lstrip("/")).resolve()
if not str(target).startswith(str(STORAGE_DIR)):
raise ValueError("Path traversal denied.")
if not target.exists():
return False
if target.is_dir():
shutil.rmtree(target)
else:
target.unlink()
return True