From 8579517a35ef1865fc9b428899d73d52dcb27a14 Mon Sep 17 00:00:00 2001 From: historia Date: Wed, 2 Sep 2026 01:26:09 -0400 Subject: feat: sglang backend support --- app/backends/sglomni/pythonenv.py | 96 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 app/backends/sglomni/pythonenv.py (limited to 'app/backends/sglomni/pythonenv.py') diff --git a/app/backends/sglomni/pythonenv.py b/app/backends/sglomni/pythonenv.py new file mode 100644 index 0000000..11bbaa6 --- /dev/null +++ b/app/backends/sglomni/pythonenv.py @@ -0,0 +1,96 @@ +"""The sglang-omni venv: interpreter selection and provisioning. + +sglang-omni requires Python >=3.10,<3.13 while the app itself is +version-agnostic — a host whose only ``python`` is 3.13+ must still be +able to install and run this backend. ``prepare_env`` resolves a usable +interpreter for the dedicated venv (``app/envs/sglomni``), in order: + +1. the venv already exists with an acceptable interpreter (no-op); +2. the app env's interpreter or a ``python3.10/3.11/3.12`` on PATH fits + (the venv is created from it — no download); +3. uv (pip-installed into the app env) provisions a managed standalone + CPython 3.12 into ``app/envs/pythons`` and creates the venv from it — + the zero-prerequisites path for hosts like stock Arch, where only the + latest Python exists and no root/package-manager knowledge is needed. + +An existing venv built with an incompatible interpreter (an older tool +version, a since-upgraded system Python) is transparently recreated: a +venv holds nothing user-owned, and every package in it is reinstalled by +the setup that follows anyway. +""" + +import shutil +import sys +from pathlib import Path +from typing import Optional, Tuple + +from backends import common, envs +from backends.sglomni.constants import PYTHON_SPEC, PYTHON_VERSIONS + +# The dedicated venv (its interpreter may differ from the launching one). +SGLOMNI_ENV = envs.SGLOMNI_ENV_DIR + + +def env_version() -> Optional[Tuple[int, int]]: + """The (major, minor) Python version of the venv's interpreter.""" + if not envs.env_exists(SGLOMNI_ENV): + return None + return envs.python_version(envs.env_python(SGLOMNI_ENV)) + + +def env_compatible() -> bool: + """True when the venv exists with a Python the sglang-omni stack accepts.""" + version = env_version() + return version is not None and tuple(version) in {tuple(v) for v in PYTHON_VERSIONS} + + +def prepare_env(*, emit=None, cancel=None) -> int: + """Make SGLOMNI_ENV exist with a Python in PYTHON_VERSIONS. Returns 0/1. + + The three resolution paths are described in the module docstring; every + path ends with a pip-equipped venv so the regular ``python -m pip`` + helpers (requirements installs, model-companion extras) keep working. + Prints what it does so the task view shows why a download happens (or, + usually, does not). + """ + if env_compatible(): + return 0 + if envs.env_exists(SGLOMNI_ENV): + version = env_version() + found = f"{version[0]}.{version[1]}" if version else "unknown" + print(f"[WARNING] {SGLOMNI_ENV} was built with Python {found}, " + "which the sglang-omni stack does not support (needs " + "3.10-3.12); recreating it with a compatible interpreter.") + # Nothing user-owned lives in the tool-managed venv, and every + # package is reinstalled by the steps that follow this one. + shutil.rmtree(SGLOMNI_ENV, ignore_errors=True) + if SGLOMNI_ENV.exists(): + print("[ERROR] Could not remove the incompatible venv; " + f"delete {SGLOMNI_ENV} manually and re-run setup.") + return 1 + + interpreter = envs.compatible_interpreter(PYTHON_VERSIONS) + if interpreter is not None: + if interpreter == envs.env_python(envs.ENV_DIR): + print(f"[INFO] using the app environment's interpreter " + f"({sys.version_info.major}.{sys.version_info.minor}) " + "for the sglang-omni venv.") + else: + print(f"[INFO] using {interpreter} for the sglang-omni venv.") + return envs.create_env(SGLOMNI_ENV, interpreter) + + # No compatible interpreter anywhere: provision one with uv. + print("[INFO] no Python 3.10-3.12 found on this system — provisioning " + f"a managed CPython {PYTHON_SPEC} with uv (no root required).") + rc = envs.ensure_uv(emit=emit, cancel=cancel) + if rc != 0: + print("[WARNING] pip install uv failed (exit " + f"{rc}); install uv manually and re-run setup") + return rc + rc = envs.provision_env_with_uv(SGLOMNI_ENV, PYTHON_SPEC, + emit=emit, cancel=cancel) + if rc != 0: + print(f"[WARNING] uv venv failed (exit {rc}); create the venv " + f"manually, e.g.: uv venv --seed --python {PYTHON_SPEC} " + f"{SGLOMNI_ENV}") + return rc -- cgit v1.2.3