"""Space entry point: serve a THOX model and join the mesh. A Space differs from Colab in two ways that matter here, and both are handled rather than papered over: * It already has a public origin, so no tunnel is needed — but the origin comes from ``SPACE_HOST``, which HF injects, and *not* ``SPACE_URL``, which it does not. Reading the wrong one is how this repo previously registered ``http://0.0.0.0:7860`` into the mesh and routed every request into a black hole. * Its container is stopped with SIGTERM on rebuild or sleep, so deregistration usually does get a chance to run — unlike a reclaimed Colab VM. Model weights live in a **private** Hub repo, so ``HF_TOKEN`` must be set as a Space secret. It is read from the environment and never written to disk or logs. """ from __future__ import annotations import logging import os import sys # The node package is copied to /app by the Dockerfile. sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from thoxmesh_node.agent import run # noqa: E402 from thoxmesh_node.errors import NodeError # noqa: E402 logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(name)s] %(levelname)s %(message)s") logger = logging.getLogger("thox.space") def _defaults() -> None: """Apply Space-appropriate defaults without clobbering explicit settings. Every value is overridable through the Space's Variables/Secrets UI, so the same image can host a different THOX model by changing configuration only. """ defaults = { "THOX_NODE_KIND": "hf-space", # ThoxMini-3B, not the smaller ThoxLLM-327M-v2. The 327M model was tried # first and serves fine mechanically, but its output is degenerate -- # it answers "The capital of France is" with "]]]]]]]]]]". It is a tiny # base model with no instruction tuning and no chat template, so # llama.cpp applies a default template it was never trained against. # ThoxMini-3B Q4_K_M is ~2 GB, instruction-tuned, and coherent on CPU. "THOX_MODEL_ID": "thoxmini-3b", "THOX_ALIAS": "thoxmini-3b-space", "THOX_MODEL_REPO": "Thox-ai/ThoxMini-3B", "THOX_MODEL_FILE": "thoxmini-3b-Q4_K_M.gguf", "THOX_N_CTX": "2048", "THOX_PORT": "7860", "THOX_CAPABILITIES": "chat,completion", # A Space is not reclaimed the way a Colab VM is, but it does sleep, so it # still publishes a lease. The window is wider because the failure mode is # slower and a shorter TTL would just add heartbeat noise. "THOX_HEARTBEAT_SECONDS": "45", "THOX_TTL_SECONDS": "300", "THOX_EPHEMERAL": "false", # Free CPU serves ~1.5 tok/s for this model, so a large cap just means slow # requests and a router that ranks this node worse. 256 is deliberate. "THOX_MAX_TOKENS_CAP": "256", } for key, value in defaults.items(): os.environ.setdefault(key, value) def main() -> int: _defaults() if not os.environ.get("HF_TOKEN"): # Not fatal: an operator may point the Space at a public GGUF instead. logger.warning("HF_TOKEN is not set; a private model repo will fail to download") try: run(echo=os.environ.get("THOX_ECHO", "").lower() in ("1", "true"), block=True) except NodeError as exc: logger.error("node failed to start: %s", exc) return 1 return 0 if __name__ == "__main__": raise SystemExit(main())