import os import re from pathlib import Path from dotenv import load_dotenv load_dotenv() EDGE_ROOT = Path(__file__).resolve().parents[2] PROJECT_ROOT = EDGE_ROOT.parent EDGE_HOST = str(os.getenv("EDGE_HOST", "0.0.0.0") or "0.0.0.0").strip() or "0.0.0.0" try: EDGE_PORT = int(os.getenv("EDGE_PORT", "8010")) except Exception: EDGE_PORT = 8010 EDGE_PORT = max(1, min(EDGE_PORT, 65535)) EDGE_RELOAD = str(os.getenv("EDGE_RELOAD", "true")).strip().lower() in {"1", "true", "yes", "on"} EDGE_AUTH_TOKEN = str(os.getenv("EDGE_AUTH_TOKEN", "") or "").strip() EDGE_NODE_ID = str(os.getenv("EDGE_NODE_ID", "local") or "local").strip().lower() or "local" EDGE_NODE_NAME = str(os.getenv("EDGE_NODE_NAME", "Local Node") or "Local Node").strip() or "Local Node" EDGE_BASE_IMAGE = str(os.getenv("EDGE_BASE_IMAGE", "nanobot-base:v0.1.5") or "nanobot-base:v0.1.5").strip() EDGE_LOG_LEVEL = str(os.getenv("EDGE_LOG_LEVEL", "warning") or "warning").strip().lower() or "warning" EDGE_ACCESS_LOG = str(os.getenv("EDGE_ACCESS_LOG", "false")).strip().lower() in {"1", "true", "yes", "on"} def _default_native_command() -> str: configured = str(os.getenv("EDGE_NATIVE_COMMAND", "") or "").strip() if configured: return configured native_python = PROJECT_ROOT / "engines" / "nanobot-v0.1.4-post5" / ".venv" / "bin" / "python" if native_python.is_file() and os.access(native_python, os.X_OK): return f"{native_python} -m nanobot.cli.commands gateway" return "nanobot gateway" EDGE_NATIVE_COMMAND = _default_native_command() EDGE_NATIVE_DASHBOARD_URL = str( os.getenv("EDGE_NATIVE_DASHBOARD_URL", "http://127.0.0.1:9000/chat") or "http://127.0.0.1:9000/chat" ).strip() or "http://127.0.0.1:9000/chat" EDGE_NATIVE_WORKDIR = str(os.getenv("EDGE_NATIVE_WORKDIR", "") or "").strip() EDGE_BOTS_WORKSPACE_ROOT = str( Path(os.getenv("EDGE_BOTS_WORKSPACE_ROOT", str(PROJECT_ROOT / "workspace" / "bots"))).expanduser().resolve() ) def _env_int(name: str, default: int, min_value: int, max_value: int) -> int: raw = os.getenv(name) if raw is None: return default try: value = int(str(raw).strip()) except Exception: value = default return max(min_value, min(max_value, value)) def _normalize_extension(raw: str) -> str: text = str(raw or "").strip().lower() if not text: return "" if text.startswith("*."): text = text[1:] if not text.startswith("."): text = f".{text}" if not re.fullmatch(r"\.[a-z0-9][a-z0-9._+-]{0,31}", text): return "" return text def _env_extensions(name: str) -> tuple[str, ...]: raw = os.getenv(name) if raw is None: return () rows: list[str] = [] for item in re.split(r"[,;\s]+", str(raw)): ext = _normalize_extension(item) if ext and ext not in rows: rows.append(ext) return tuple(rows) EDGE_UPLOAD_MAX_MB = _env_int("EDGE_UPLOAD_MAX_MB", 100, 1, 2048) EDGE_ALLOWED_ATTACHMENT_EXTENSIONS = _env_extensions("EDGE_ALLOWED_ATTACHMENT_EXTENSIONS")