| [build-system] | |
| requires = ["setuptools>=75", "wheel"] | |
| build-backend = "setuptools.build_meta" | |
| [project] | |
| name = "distinct-server" | |
| version = "0.1.0" | |
| description = "Session-only Gradio control plane for community-run open-weight LLM agents" | |
| requires-python = ">=3.10" | |
| # WHAT A PLAIN `pip install -e .` HAS TO GIVE YOU: A WORKING WORKER. | |
| # | |
| # These were all behind the `[agent]` extra, which meant `pip install -e .` | |
| # produced a worker that paired, ran, and then died the first time somebody | |
| # asked for its dashboard — an ImportError for a package the install had | |
| # quietly decided was optional. Optional to whom? Everybody who installs this | |
| # repository outside the Space is installing it to run a worker. | |
| # | |
| # Costing the server nothing is what makes this free: HuggingFace Spaces | |
| # installs `requirements.txt` and the SDK version in README.md, and never | |
| # runs `pip install .` at all, so nothing here reaches the deployment. | |
| dependencies = [ | |
| "gradio[oauth]==6.24.0", | |
| # Ed25519, for the detached snapshot signature. A direct requirement, not | |
| # a transitive one: `distinct_protocol.handshake` imports it and refuses | |
| # to fall back to HMAC, so an install that happens to miss it fails at the | |
| # moment a worker pairs rather than at install time. | |
| "cryptography>=42", | |
| "gradio_client==2.6.0", | |
| "pyRAPL==0.2.3.1; sys_platform == 'linux'", | |
| # NVIDIA GPU energy. For inference on a graphics card this is nearly all of | |
| # the energy a run costs, so it is a base dependency rather than an extra: | |
| # a worker that silently measured only its CPU package would understate a | |
| # GPU run by roughly an order of magnitude while still calling the figure | |
| # measured. The library is a thin ctypes binding to the driver's own NVML | |
| # and installs on machines with no NVIDIA hardware, where it simply reports | |
| # that there is none. | |
| "nvidia-ml-py>=12.535", | |
| # The worker's own screen. Pinned rather than ranged because the frozen | |
| # build has to be reproducible, and because a Textual minor release can | |
| # change how a widget lays out, which is a visual regression no test in | |
| # this repository would catch. | |
| "textual==8.2.8", | |
| ] | |
| [project.optional-dependencies] | |
| # The DSPy RLM harness only. It is a large install and the worker degrades to | |
| # the structured harness without it, saying so on start, so it is the one | |
| # thing here that is genuinely optional. | |
| agent = [ | |
| "dspy[deno]==3.3.0", | |
| ] | |
| dev = [ | |
| "pytest==8.4.2", | |
| "ruff==0.12.11", | |
| ] | |
| [tool.setuptools.packages.find] | |
| include = [ | |
| "distinct_agent*", "distinct_mcp*", "distinct_protocol*", | |
| "distinct_server*", "distinct_skills*", "distinct_tools*", | |
| ] | |
| # A skill in `distinct_skills` is a directory of text, not a module: SKILL.md, | |
| # tool.json and the templates beside them. Without this they are left out of a | |
| # wheel, the digest table finds nothing on disk, and the repository degrades to | |
| # empty in exactly the build where nobody is watching a test run. | |
| [tool.setuptools.package-data] | |
| distinct_skills = ["NOTICE.md", "skills/**/*.md", "skills/**/*.json"] | |
| distinct_agent = ["deno.lock"] | |
| [tool.pytest.ini_options] | |
| testpaths = ["tests"] | |
| addopts = "-q" | |
| [tool.ruff] | |
| target-version = "py310" | |
| line-length = 110 | |
| exclude = [".venv", "Measure-PcPower.ps1", "measure_pc_energy.py"] | |
| [tool.ruff.lint] | |
| select = ["E4", "E7", "E9", "F", "I", "B"] | |