from __future__ import annotations import os from dataclasses import dataclass @dataclass(frozen=True) class Settings: """Runtime configuration for the orchestrator Space.""" bucket_name: str = os.getenv("SPACE_FACTORY_BUCKET_NAME", "space-factory-runs") bucket_mount: str = os.getenv("SPACE_FACTORY_BUCKET_MOUNT", "/output") job_flavor: str = os.getenv("SPACE_FACTORY_JOB_FLAVOR", "cpu-basic") job_timeout: str = os.getenv("SPACE_FACTORY_JOB_TIMEOUT", "30m") job_image: str = os.getenv("SPACE_FACTORY_JOB_IMAGE", "python:3.12") def normalize_bucket_name(value: str | None) -> str: """Return a safe bucket name, defaulting to the product bucket name.""" bucket = (value or settings.bucket_name).strip().strip("/") if not bucket: bucket = settings.bucket_name if "/" in bucket: raise ValueError("Bucket name must be a name like 'space-factory-runs', not owner/name.") return bucket def user_bucket_source(*, username: str, bucket_name: str | None = None) -> str: """Return the per-user bucket source expected by HF Jobs volumes.""" clean_user = (username or "").strip() if not clean_user: raise ValueError("Missing username for per-user bucket source.") return f"{clean_user}/{normalize_bucket_name(bucket_name)}" def bucket_uri_from_source(bucket_source: str) -> str: return f"hf://buckets/{bucket_source}" settings = Settings()