253 lines
9.3 KiB
TOML
253 lines
9.3 KiB
TOML
[build-system]
|
|
requires = [
|
|
"setuptools>=61.0",
|
|
"wheel",
|
|
"cmake>=3.27",
|
|
# Pin nanobind to match the ABI version MLX 0.32.0 was built with
|
|
# (MLX pins nanobind v2.13.0 via FetchContent in its CMakeLists.txt).
|
|
# A mismatched nanobind isolates the `mlx` NB_DOMAIN, so custom kernel
|
|
# extensions (omlx.custom_kernels.*) reject every mlx.core.array at the
|
|
# type caster with `incompatible function arguments`.
|
|
"nanobind==2.13.0",
|
|
"mlx==0.32.0",
|
|
]
|
|
build-backend = "setuptools.build_meta"
|
|
|
|
[project]
|
|
name = "omlx"
|
|
dynamic = ["version"]
|
|
description = "LLM inference server, optimized for your Mac"
|
|
readme = "README.md"
|
|
license = {text = "Apache-2.0"}
|
|
requires-python = ">=3.11,<3.14"
|
|
authors = [
|
|
{name = "omlx contributors"}
|
|
]
|
|
keywords = ["llm", "mlx", "apple-silicon", "vllm", "inference", "transformers"]
|
|
classifiers = [
|
|
"Development Status :: 3 - Alpha",
|
|
"Intended Audience :: Developers",
|
|
"Intended Audience :: Science/Research",
|
|
"License :: OSI Approved :: Apache Software License",
|
|
"Operating System :: MacOS",
|
|
"Programming Language :: Python :: 3",
|
|
"Programming Language :: Python :: 3.10",
|
|
"Programming Language :: Python :: 3.11",
|
|
"Programming Language :: Python :: 3.12",
|
|
"Programming Language :: Python :: 3.13",
|
|
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
]
|
|
|
|
dependencies = [
|
|
# Vanilla MLX v0.32.0; optional custom kernels live under
|
|
# omlx.custom_kernels.* when built for release. The bundled kernel
|
|
# binaries are ABI-coupled to this exact mlx version — bumping the pin
|
|
# requires rebuilding them (OMLX_WITH_CUSTOM_KERNEL=1 setup.py build_ext).
|
|
"mlx==0.32.0",
|
|
# mlx-lm from commit (ab1806e, v0.31.3) - transformers 5.13+
|
|
# NewlineTokenizer registration compatibility, DeepSeek/GLM DSA indexer
|
|
# RoPE fix, trust_remote_code load gate, transformers 5.7.0
|
|
# compatibility, and prior BatchGenerator/cache fixes.
|
|
"mlx-lm @ git+https://github.com/ml-explore/mlx-lm@ab1806e8f5d6aa035973af194a1b9198ab4754dc",
|
|
# regex for mlx-lm's Gemma 4 tool parser (uses recursive patterns)
|
|
"regex",
|
|
# mlx-embeddings from latest commit (32981fa)
|
|
"mlx-embeddings @ git+https://github.com/Blaizzy/mlx-embeddings@32981fa4e8064ed664b52071789dd18271fe4206",
|
|
# mlx-vlm custom processors bypass HF AutoProcessor, so torch is not required
|
|
# Keep <5.13 until the broader dependency set gets a dedicated resolver
|
|
# smoke test with transformers 5.13+. The mlx-lm pin above includes the
|
|
# known NewlineTokenizer registration fix.
|
|
"transformers>=5.7.0,<5.13",
|
|
# transformers 5.x's tokenization_mistral_common module imports
|
|
# ReasoningEffort from mistral_common (added in 1.10). The audio extras
|
|
# transitively pull mistral-common via mlx-audio[stt], which historically
|
|
# resolved to 1.9.x and broke WhisperProcessor.from_pretrained() with a
|
|
# silent "Processor not found" on every Whisper model. Pinning the
|
|
# minimum here ensures resolution lands on a compatible version even
|
|
# without the audio extra installed.
|
|
# See pmarreck/omlx#1 for full repro and root cause.
|
|
"mistral-common>=1.10",
|
|
"tokenizers>=0.19.0",
|
|
"huggingface-hub>=0.23.0",
|
|
"numpy>=1.24.0,<2.4",
|
|
"tqdm>=4.66.0",
|
|
"pyyaml>=6.0",
|
|
"itsdangerous>=2.0",
|
|
"jinja2>=3.0",
|
|
# mlx-lm 0.31.3 imports rich from mlx_lm.cli_ui for chat/lora entrypoints.
|
|
"rich>=13.0.0",
|
|
"sentencepiece",
|
|
"tiktoken",
|
|
"protobuf",
|
|
"requests>=2.28.0",
|
|
# OpenAI-compatible external endpoint client for admin benchmarks.
|
|
# Already a transitive dep via huggingface-hub; pinned direct so
|
|
# omlx.admin.external_api can import it unconditionally at module top.
|
|
"httpx>=0.27.0,<1",
|
|
# SOCKS proxy support (used by httpx via huggingface-hub)
|
|
"socksio>=1.0.0",
|
|
"tabulate>=0.9.0",
|
|
# Resource monitoring
|
|
"psutil>=5.9.0",
|
|
# Native process title support (shows as omlx-server instead of python)
|
|
"setproctitle>=1.3.3",
|
|
# Server
|
|
"fastapi>=0.108.0",
|
|
"uvicorn>=0.23.0",
|
|
# python-multipart is needed by audio_routes.py (File/Form uploads), which
|
|
# server.py unconditionally imports regardless of the [audio] extra.
|
|
"python-multipart>=0.0.5",
|
|
# JSON Schema validation for structured output
|
|
"jsonschema>=4.0.0",
|
|
# Harmony format parser for gpt-oss models
|
|
"openai-harmony",
|
|
# Cohere Command/Cohere2 output parser for reasoning and tool calls
|
|
"cohere_melody>=0.9.0",
|
|
# mlx-vlm from commit 78b96eb. MiniMax M3 support is vendored under
|
|
# omlx.patches.mlx_vlm_minimax_m3_compat because upstream removed it.
|
|
"mlx-vlm @ git+https://github.com/Blaizzy/mlx-vlm@78b96eb5462141447b9a6b4943ef553891da56dd",
|
|
"Pillow>=9.0.0",
|
|
# dflash-mlx v0.1.10 (9ca0028) - bstnxbt repo. Apple G17 NAX verify,
|
|
# prefix snapshot metrics, CopySpec mode, and full-context draft-layer cache checks.
|
|
"dflash-mlx @ git+https://github.com/bstnxbt/dflash-mlx@9ca002898b48e14c9727dec17299f497e8467870",
|
|
"markitdown[pdf,docx,pptx]==0.1.6",
|
|
]
|
|
|
|
[project.optional-dependencies]
|
|
grammar = [
|
|
# Grammar-constrained decoding for structured output (requires torch ~2GB)
|
|
"xgrammar>=0.1.32",
|
|
]
|
|
mcp = [
|
|
"mcp>=1.5.0",
|
|
]
|
|
modelscope = [
|
|
"modelscope>=1.10.0",
|
|
]
|
|
audio = [
|
|
# mlx-audio from commit (5175326) with tts/stt/sts extras
|
|
# tts extra: misaki, num2words, spacy, phonemizer-fork, espeakng-loader, sentencepiece
|
|
# stt extra: tiktoken, mistral-common[audio]
|
|
# sts extra: tts deps + stt deps + webrtcvad
|
|
"mlx-audio[tts,stt,sts] @ git+https://github.com/Blaizzy/mlx-audio@51753266e0a4f766fd5e6fbc46652224efc23981",
|
|
]
|
|
paroquant = [
|
|
# ParoQuant runtime loader for paroquant-quantized models. Installed
|
|
# with --no-deps semantics here because the official [mlx] extra pulls
|
|
# torchvision, which the load path doesn't actually use (verified end
|
|
# to end on 0.1.14). The DMG build installs the same pin via build.py.
|
|
"paroquant==0.1.16; python_version >= '3.11'",
|
|
]
|
|
# Internal extra consumed by packaging/build.py to populate the
|
|
# venvstacks mlx-base layer's requirements list. Listed here as the
|
|
# single source of truth so the layer-template venvstacks.toml stays
|
|
# version-free. End-users don't `pip install omlx[bundle]`; this is for
|
|
# the macOS .app build pipeline.
|
|
#
|
|
# mlx-audio[tts,stt,sts]'s 12 transitive deps appear explicitly because
|
|
# venvstacks 0.7.0's internal `uv pip compile` runs with --no-config and
|
|
# doesn't propagate pyproject.toml's `tool.uv.override-dependencies`,
|
|
# so it can't resolve mlx-audio's `mlx-lm==0.31.1` pin against our
|
|
# git-pinned mlx-lm (v0.31.3). build.py installs mlx-audio + paroquant
|
|
# separately via --no-deps post-resolution.
|
|
bundle = [
|
|
"mcp>=1.5.0",
|
|
"modelscope>=1.10.0",
|
|
# mlx-audio[tts,stt,sts] transitives:
|
|
"scipy>=1.11.0",
|
|
"librosa>=0.10.0",
|
|
"miniaudio>=1.59",
|
|
"numba>=0.59.0",
|
|
"pyloudnorm>=0.1.0",
|
|
"sounddevice>=0.4.6",
|
|
"misaki>=0.9.4",
|
|
"num2words>=0.5.14",
|
|
"spacy>=3.8.4",
|
|
"phonemizer-fork>=3.3.2",
|
|
"espeakng-loader>=0.2.4",
|
|
"webrtcvad>=2.0.10",
|
|
# [audio] extra on top of pyproject's plain mistral-common>=1.10
|
|
"mistral-common[audio]>=1.10",
|
|
]
|
|
dev = [
|
|
"pytest>=7.0.0",
|
|
"pytest-asyncio>=0.21.0",
|
|
"black>=23.0.0",
|
|
"ruff>=0.1.0",
|
|
"mypy>=1.0.0",
|
|
"mcp>=1.5.0",
|
|
"venvstacks>=0.7.0",
|
|
# The torch-stub smoke test (tests/test_torch_stub.py) gates
|
|
# xgrammar / tvm-ffi version bumps. It skips when these aren't
|
|
# importable, which silently hides regressions — install no-deps
|
|
# in the dev environment so the test actually runs.
|
|
"xgrammar==0.2.3",
|
|
"apache-tvm-ffi==0.1.11",
|
|
]
|
|
# PEP 735 dependency groups — consumed by `uv sync --dev`.
|
|
# Keep in sync with [project.optional-dependencies] dev above
|
|
# (pip/legacy toolchains use that section instead).
|
|
[dependency-groups]
|
|
dev = [
|
|
"pytest>=7.0.0",
|
|
"pytest-asyncio>=0.21.0",
|
|
"black>=23.0.0",
|
|
"ruff>=0.1.0",
|
|
"mypy>=1.0.0",
|
|
"mcp>=1.5.0",
|
|
"venvstacks>=0.7.0",
|
|
"xgrammar==0.2.3",
|
|
"apache-tvm-ffi==0.1.11",
|
|
]
|
|
|
|
[project.urls]
|
|
Homepage = "https://github.com/jundot/omlx"
|
|
Documentation = "https://github.com/jundot/omlx#readme"
|
|
Repository = "https://github.com/jundot/omlx"
|
|
|
|
[project.scripts]
|
|
omlx = "omlx.cli:main"
|
|
|
|
[tool.setuptools.dynamic]
|
|
version = {attr = "omlx._version.__version__"}
|
|
|
|
[tool.setuptools.packages.find]
|
|
where = ["."]
|
|
include = ["omlx*"]
|
|
|
|
[tool.setuptools.package-data]
|
|
"omlx" = ["oq_calibration_data.json", "oqe_calibration_data.json"]
|
|
"omlx.admin" = ["templates/**/*.html", "static/**/*", "i18n/*.json"]
|
|
"omlx.eval" = ["data/*.jsonl"]
|
|
"omlx.custom_kernels.glm_moe_dsa" = ["*.metallib", "*.dylib", "*.so"]
|
|
"omlx.custom_kernels.minimax_m3" = ["*.metallib", "*.dylib", "*.so"]
|
|
"omlx.custom_kernels.qwen35_prefill" = ["*.metallib", "*.dylib", "*.so"]
|
|
|
|
[tool.uv]
|
|
# mlx and mlx-lm are git-pinned; override transitive pins
|
|
# (e.g. mlx-audio -> mlx-lm==0.31.1) so the resolver accepts them.
|
|
override-dependencies = [
|
|
"mlx==0.32.0",
|
|
"mlx-lm @ git+https://github.com/ml-explore/mlx-lm@ab1806e8f5d6aa035973af194a1b9198ab4754dc",
|
|
]
|
|
|
|
[tool.black]
|
|
line-length = 88
|
|
target-version = ["py310", "py311", "py312", "py313"]
|
|
|
|
[tool.ruff]
|
|
line-length = 88
|
|
select = ["E", "F", "W", "I", "N", "UP", "B", "SIM"]
|
|
ignore = ["E501", "B905"]
|
|
|
|
[tool.mypy]
|
|
python_version = "3.10"
|
|
warn_return_any = true
|
|
warn_unused_configs = true
|
|
ignore_missing_imports = true
|
|
|
|
[tool.pytest.ini_options]
|
|
testpaths = ["tests"]
|
|
python_files = ["test_*.py"]
|
|
asyncio_mode = "auto"
|