[project] # Import package and CLI are `distil`; the PyPI distribution is `distil-llm` # (the bare `distil` name is already taken on PyPI). name = "distil-llm" version = "1.53.0rc1" description = "Compression with a quality contract — cache-aware, causally-pruned context compression for agentic runtimes, gated by a statistical non-inferiority test." readme = "README.md" # Python floor is 3.9 — the version macOS still ships as the system `python3`. The # package is stdlib-only and uses `from __future__ import annotations`, so it imports # and the `distil bench` gate passes on 3.9/3.10/3.11/3.12/3.13 (verified in CI). A # higher floor here is what made `pipx install distil-llm` fail with the misleading # "Could not find a version ... (from versions: none)" on stock macOS Python. requires-python = ">=3.9" license = "Apache-2.0" license-files = ["LICENSE"] authors = [{ name = "shakes", email = "chandu1221@gmail.com" }] keywords = ["llm", "context-compression", "prompt-caching", "agentic-runtime", "non-inferiority", "tokens", "cost"] classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Operating System :: OS Independent", "Typing :: Typed", ] dependencies = [] # core is stdlib-only by design: it must run anywhere, day one. [project.urls] Homepage = "https://github.com/dshakes/distil" Repository = "https://github.com/dshakes/distil" Issues = "https://github.com/dshakes/distil/issues" Changelog = "https://github.com/dshakes/distil/blob/main/CHANGELOG.md" [project.optional-dependencies] # Production hardening swaps these in; the core does not require them. # - live: billing-grade tokenizer (count_tokens) + live AgentRunner, via the Anthropic SDK dev = ["pytest>=8", "opentelemetry-api>=1.20", "opentelemetry-sdk>=1.20"] live = ["anthropic>=0.40", "openai>=1.60"] onnx = ["onnxruntime>=1.17", "transformers>=4.40"] # transformer keep-model inference train = ["torch>=2.2", "transformers>=4.40", "onnx>=1.16", "onnxscript>=0.1", "sentencepiece>=0.2"] # training + ONNX export async = ["aiohttp>=3.9"] # async high-concurrency proxy (distil.aproxy) otel = ["opentelemetry-api>=1.20"] # GenAI semantic-convention spans (distil.otel) # OIDC RS256 verification for the gateway. HS256 needs nothing (stdlib hmac); # this is only for asymmetric IdP signing keys. Without it an RS256 token is # REFUSED, never verified-by-skipping — see distil/authz.py. oidc = ["cryptography>=42.0"] # Image downscaling (distil/compress/vision_scale.py). Resampling needs a real # codec, which the stdlib does not have. Without this extra the transform is # INERT — available() is False and images pass through untouched — so distil's # zero-dependency guarantee is unchanged for anyone who does not opt in. image = ["Pillow>=10.0"] # native = the Rust hot-path core (rust/distil-core); build with `maturin develop --release` [project.scripts] distil = "distil.cli:main" # Unambiguous MCP launch target for registry/client configs: `uvx --from # distil-llm distil-mcp` — the console script is otherwise `distil` while the # distribution is `distil-llm`, and MCP server.json launch specs don't cover # the `script subcommand` form cleanly. distil-mcp = "distil.mcp_server:serve" # `uvx ` runs the executable *named after the package*, so without this the # official MCP registry's own launch spec (`uvx distil-llm ...`) fails with # "An executable named `distil-llm` is not provided by package `distil-llm`". # serve() ignores argv, so the already-published `uvx distil-llm mcp` form works # too — this repairs the live registry entry without needing it republished. distil-llm = "distil.mcp_server:serve" [build-system] # PINNED, like ruff and mypy in CI, and for the same reason: an unpinned build # backend drifts and breaks the release. hatchling 1.32 emits # `Metadata-Version: 2.5`, which the publish action's bundled twine rejects with # "not a valid metadata version" — so v1.43.0rc3 built green and published # nothing. Worse, it was invisible locally: this machine had an older hatchling # cached, so `uv build` produced an acceptable 2.4 wheel while CI produced an # unpublishable one. Local and CI must build the SAME artifact. # Lifting this pin requires the publish action to accept 2.5 first — see the # metadata assertion in tests/test_packaging_smoke.py. requires = ["hatchling<1.32"] build-backend = "hatchling.build" # Keep local cruft (alt venvs, caches, result dumps) out of the sdist — an # untracked .venv-*/ with absolute symlinks otherwise breaks `uv build`. [tool.hatch.build.targets.sdist] exclude = [".venv*", ".e7_cache", "logs", "benchmarks/results*", "docs/paper/results"] [tool.hatch.build.targets.wheel] packages = ["distil"] # Ship the trajectory corpus inside the wheel so `pip install distil && distil bench` # is self-contained. [tool.hatch.build.targets.wheel.force-include] "corpus" = "distil/_corpus" [tool.ruff] target-version = "py311" line-length = 100 [tool.ruff.lint.per-file-ignores] "tests/test_aproxy.py" = ["E402"] # imports follow pytest.importorskip("aiohttp") [tool.pytest.ini_options] # All tests live under tests/; keep collection out of the SWE-bench E7 harness's # transient logs/ and image/worktree caches (which contain files named test_*.py). testpaths = ["tests"] norecursedirs = ["logs", ".e7_cache", ".venv*", "docs", "corpus", "benchmarks"] [tool.coverage.run] branch = false # Excluded from the coverage metric because they cannot be exercised by an # offline unit test — they require a GPU/torch training run or live, credentialed # model calls (the proof-harness runners). They ARE integration-tested manually. omit = [ "distil/codec/train_transformer.py", # torch training loop (optional [transformer] extra) "distil/replay/anthropic_runner.py", # live Anthropic SDK + credentials "distil/replay/openai_runner.py", # live OpenAI SDK + credentials "distil/replay/claude_cli_runner.py", # spawns the real `claude` CLI subprocess "distil/replay/expand_runner.py", # live model round-trip ] [tool.coverage.report] # Compare fail_under at 2-decimal precision. coverage.py defaults precision to 0, # which ALSO rounds the number used for the --cov-fail-under decision (not just # the printed report): 94.90% rounds to 95 and silently passes a 95 floor. Pin it # so the gate enforces the real figure. (Issue #32.) precision = 2 exclude_also = [ "if TYPE_CHECKING:", "raise NotImplementedError", "if __name__ == .__main__.:", "@(abc\\.)?abstractmethod", # Blocking server-launch / subprocess-spawn entry points. The request- # handling LOGIC they wire up (build_handler / make_app) is unit-tested # directly; these functions themselves run a server forever or Popen the # agent, so they're exercised by integration, not unit tests. "def serve\\(", "def wrap_run\\(", "def serve_gateway\\(", # Fail-open defensive handlers, explicitly marked `# noqa: BLE001`: they exist # ONLY to guarantee "telemetry/compression must never break a request" and do # nothing but log at debug and continue. There is no behaviour to assert, and a # unit test cannot reliably force the internal exception that triggers them. "except .*# noqa: BLE001", ]