-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathpyproject.toml
More file actions
358 lines (346 loc) · 15.7 KB
/
Copy pathpyproject.toml
File metadata and controls
358 lines (346 loc) · 15.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "fastcrest-tether"
version = "0.12.0"
description = "FastCrest Tether — edge-to-cloud robotics + edge AI deploy CLI. Optimize, deploy, verify any VLA across Jetson, RTX, Apple Silicon, AMD. Standalone or wired to FastCrest Cloud."
readme = "README.md"
license = "BUSL-1.1"
requires-python = ">=3.10"
authors = [{ name = "FastCrest" }]
keywords = ["vla", "robotics", "edge", "tensorrt", "jetson", "deployment", "tether", "fastcrest"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python :: 3",
]
dependencies = [
"torch>=2.1.0",
"safetensors>=0.4.0",
"typer>=0.9.0",
"rich>=13.0.0",
"pydantic>=2.0.0",
# numpy upper bound is Jetson-only — JetPack ships bundled CUDA libs
# compiled against numpy 1.x ABI; numpy 2.x's ABI break corrupts ORT +
# JAX wheels on aarch64. On x86_64 (Modal A100, customer desktops) +
# arm64 (M-series Mac dev hosts) numpy 2.x is fine, AND the
# [monolithic] extra's lerobot==0.5.1 dep REQUIRES numpy>=2.0 — pinning
# numpy<2 globally makes lerobot uninstallable on Modal (caught by the
# 2026-05-20 lift #4 smoke fire). Split via PEP-508 platform marker.
"numpy>=1.24.0,<2.0; platform_machine == 'aarch64'",
"numpy>=1.24.0; platform_machine != 'aarch64'",
"pyyaml>=6.0",
# Always needed: hub access for `tether export <hf_id>` and tokenizer/config
# loading for the auto-detect path. Apr-14 install-path verification caught
# that omitting these breaks `tether export` even with [serve,gpu].
"huggingface_hub>=0.20.0",
# Base allows 4.40 → 5.3.x. [monolithic] extra pins ==5.3.0 exactly (5.4+ has
# a q_length regression that breaks onnx-diagnostic patches). Without the
# upper bound, pip would pull 5.4/5.5 here and conflict with [monolithic].
# Without raising the upper bound past 5.0, [monolithic] can't install
# alongside the base (the v0.2.1 customer-dogfood finding).
"transformers>=4.40,<5.4",
"onnx>=1.15.0",
"onnxscript>=0.1.0",
# TetherClient (Phase 0.5 customer-sdk) — sync + async HTTP client.
# Lightweight (~2MB); shared with [serve] which already needs FastAPI's
# starlette/anyio stack. Adding here so `from tether import TetherClient`
# works on a bare `pip install fastcrest-tether`.
"httpx>=0.24.0",
# Ed25519 license signature verification for Pro tier (`tether pro
# activate <code>` and the daily heartbeat path). Small (~5MB) + already
# transitively pulled by huggingface_hub on most installs. Required at
# base level so `tether pro` commands work on bare `pip install fastcrest-tether`.
"cryptography>=42.0",
# HTTP client for the `tether connect` integration framework (#188):
# integrations/registry.py + integrations/connector.py call requests.get()
# at module import, and the `tether connect` / `tether integrations`
# commands are core (not behind an extra). Undeclared since #188 — CI clean
# installs hit ModuleNotFoundError on tests/test_integrations.py collection
# (masked locally where requests is a transitive dep).
"requests>=2.28.0",
]
[project.optional-dependencies]
# CPU inference runtime (onnx is a core dep now). Use this for CPU-only boxes.
onnx = ["onnxruntime>=1.17.0"]
# GPU inference — installs onnxruntime-gpu AND the ORT-compatible CUDA stack
# AND TensorRT so ORT-TRT EP loads out of the box. Use this when deploying to
# a box with an NVIDIA GPU.
#
# ORT 1.20+ wants CUDA 12.x + cuDNN 9.x; these pip deps ship their own libs
# so the end-user doesn't have to install CUDA separately.
#
# v0.7 (2026-04-29): tensorrt added to default [gpu] extras after Modal A10G
# spike measured 5.55x speedup of ORT-TRT EP vs ORT-CUDA EP on SmolVLA
# monolithic. Without tensorrt installed, libnvinfer.so.10 isn't loadable
# and ORT silently falls back to CUDA EP — losing the 5.55x. See ADR
# 2026-04-29-ort-trt-ep-first-class-support.md. Adds ~2 GB to install.
#
# v0.9.2 (2026-05-07): bumped onnxruntime-gpu floor to 1.25.1 + dropped the
# <1.24 ceiling. ORT 1.25.0 (2026-04-20) shipped Blackwell sm_120 kernels
# via PR #27278 (CUDA arch family codes 100f/110f/120f) — first PyPI wheels
# with usable RTX 5090 / RTX 5060 / B200 / GB200 support. Earlier 1.23/1.24
# regressed sm_120 (cudaErrorNoKernelImageForDevice on Blackwell); 1.25.1
# is the current stable. Live caveat: open issue #27621 (silent threading
# deadlock on sm_120 with PTX JIT + GIL) means Blackwell tier needs smoke
# validation before declaring fully production-ready.
#
# Apr-14 post-mortem: omitting cuDNN/cuBLAS pulls was the cause of silent
# CPU fallback in v0.1 benchmarks. Same shape of bug at the TRT layer is
# why v0.7 ships tensorrt by default in [gpu].
gpu = [
"onnxruntime-gpu>=1.25.1",
"nvidia-cudnn-cu12>=9.5,<10.0",
"nvidia-cublas-cu12>=12.6,<13.0",
# New in v0.7: provides libnvinfer.so.10 for ORT-TRT EP
"tensorrt>=10.0,<11; sys_platform == 'linux'",
]
# Optional: skip tensorrt for users who explicitly don't want the 2 GB install
# footprint. They get ORT-CUDA EP only (~5x slower than TRT EP on transformers).
gpu-min = [
"onnxruntime-gpu>=1.25.1",
"nvidia-cudnn-cu12>=9.5,<10.0",
"nvidia-cublas-cu12>=12.6,<13.0",
]
# HTTP serve stack. Includes onnxruntime (CPU) so `pip install fastcrest-tether[serve]`
# gives you a working server out of the box. For GPU, use `[serve,gpu]` to pull in
# onnxruntime-gpu + CUDA libs.
serve = [
"onnxruntime>=1.17.0",
"fastapi>=0.100.0",
"uvicorn>=0.23.0",
"Pillow>=10.0.0",
# Embodiment-config validation (per-embodiment-configs B.1). Tiny dep.
"jsonschema>=4.0",
# Prometheus /metrics endpoint (D.1.8 prometheus-grafana). Tiny dep.
"prometheus-client>=0.19.0",
# ZMQ transport (Lift #2). `tether serve --transport zmq` uses these.
# Tiny deps (~2 MB total). Added to [serve] rather than a separate extra
# so `pip install fastcrest-tether[serve]` gives you BOTH transports.
"pyzmq>=25.0",
"msgpack>=1.0",
"opencv-python-headless>=4.8", # JPEG-on-wire serialization for ZMQ transport
]
safety = ["yourdfpy"]
# Offline EU evidence-pack generator. No runtime deps today; kept as an extra
# so pilots can install with `pip install fastcrest-tether[serve,comply]`.
comply = []
# Native parity verification — installs lerobot + its deps so
# `scripts/local_full_diff.py` can cross-check our export path against the
# reference PyTorch policy. Required for the native-path-parity regression
# gate in GOALS.yaml. Heavy (pulls torch, torchvision, accelerate, etc.) —
# that's why it's a separate extra, not a base dep.
#
# lerobot 0.5.x requires Python >=3.12. Jetson (JetPack 6) ships 3.10,
# so we gate lerobot behind a version marker — pip skips it on 3.10/3.11
# instead of hard-failing with ResolutionImpossible. Native parity
# verification should be run on a Python 3.12+ host.
native = [
"lerobot==0.5.1; python_version >= '3.12'",
"num2words",
]
# Monolithic ONNX export — cos=1.0 verified production path. Runs locally
# via `tether export --monolithic` (the DEFAULT as of v0.2.1). Requires
# transformers==5.3.0 EXACTLY (5.4+ has a q_length regression in
# masking_utils.sdpa_mask that breaks onnx-diagnostic patches). Base pin
# `transformers>=4.40,<5.4` permits this extra to pin-to-exact.
#
# lerobot 0.5.x requires Python >=3.12. On Jetson (Python 3.10) the
# monolithic export can't run locally — export on a cloud/desktop host
# (Python 3.12+) and `tether serve` the resulting ONNX on the Jetson
# with `pip install 'fastcrest-tether[serve]'` only.
monolithic = [
"lerobot==0.5.1; python_version >= '3.12'",
"transformers==5.3.0",
"onnx-diagnostic>=0.9",
"onnxscript>=0.1",
"optree",
"scipy",
"num2words",
]
# Task-success evaluation (heavy sim deps). Gated behind this extra so the
# base install stays light. Use with `tether bench --benchmark libero_10`.
eval = [
"vla-eval",
"mujoco>=3.0",
"robosuite==1.4.1",
"gymnasium",
"h5py",
]
dev = ["pytest>=8.0", "ruff>=0.4.0", "mypy>=1.10", "httpx>=0.24.0", "pytest-asyncio>=0.23"]
# MCP server — exposes Tether as a Model Context Protocol tool surface so
# agents (Claude Desktop, Cursor, custom) can call /act as a tool. Additive
# to the REST API; both transports share the same inference engine.
# Feature spec: features/01_serve/subfeatures/_dx_gaps/mcp-server/mcp-server.md
mcp = ["fastmcp>=3.0"]
# Full-screen TUI for `tether chat --tui`. Optional (the default Rich REPL
# works without textual). Adds a multi-panel layout (transcript / tool calls
# / input / status) with mouse + scroll-back + keyboard shortcuts.
tui = ["textual>=0.80,<10"]
# OTel record/replay backend integration (Phoenix-compatible). Optional —
# server runs fine without it; if installed AND OTEL_EXPORTER_OTLP_ENDPOINT
# is set, every /act call emits an OTel span with VLA-specific attributes.
# Phoenix is the recommended local backend (`pip install arize-phoenix`,
# `phoenix serve`). See features/01_serve/subfeatures/_rtc_a2c2/record-replay.md.
tracing = [
"opentelemetry-sdk>=1.30",
"opentelemetry-exporter-otlp-proto-grpc>=1.30",
]
# LeRobot interop — installs `lerobot>=0.5` so the SO-ARM100 adapter
# (`tether.embodiments.so_arm100`) can talk to the Feetech bus + import
# LeRobot calibration JSONs. Use this on the host wired to the arm:
#
# pip install 'fastcrest-tether[lerobot]'
# tether serve bundle/ --embodiment so_arm100 --port /dev/ttyUSB0
#
# lerobot 0.5.x requires Python >=3.12 (we skip on 3.10/3.11 to avoid pip's
# ResolutionImpossible; users on JetPack 6 Python 3.10 can still construct an
# adapter + run the conversion math, they just can't open a serial bus until
# they upgrade to Python 3.12 or install scservo_sdk directly via the [so100]
# extra).
lerobot = [
"lerobot>=0.5.1; python_version >= '3.12'",
]
# SO-100 hardware extra — installs the scservo_sdk Python package on the
# Raspberry Pi / host wired to the arm. Separate from [lerobot] because the
# legacy auto_soarm path (used by the bench wizard) only needs the SDK, not
# the full LeRobot stack. The two extras compose: `pip install
# 'fastcrest-tether[so100,lerobot]'` gives you both code paths.
so100 = [
"scservo-sdk>=0.0.4",
]
# Real-Time Chunking adapter (B.3). Pulls in lerobot's RTC module so
# `tether serve --rtc` can wrap inference with the canonical RTCProcessor.
# Lerobot is heavy (torch + vision + datasets); only install when serving
# RTC-enabled deployments. Skeleton + config validation work without this
# extra; only the actual processor construction needs it.
#
# lerobot 0.5.x requires Python >=3.12 (skipped on 3.10/3.11).
rtc = [
"lerobot==0.5.1; python_version >= '3.12'",
]
# Curate format-converter extras. Phase 1 ships LeRobot v3 + HDF5 with the
# core install (parquet via pyarrow which huggingface_hub already pulls; h5py
# is small). RLDS + OXE + LeRobot-v3-video need heavier deps that the base
# install skips.
#
# [curate-hdf5]: HDF5 converter. h5py is small (~5MB) but adds build-time
# C-extension cost; gated to keep the base wheel slim.
curate-hdf5 = [
"h5py>=3.0,<4",
]
# [curate-video]: LeRobot v3 video materialization. Decodes base64 image_b64
# frames + ffmpeg-encodes to H.264 mp4 per the LeRobot v3 spec. Without this
# extra the converter ships parquet + metadata only (warning emitted).
# imageio-ffmpeg ships its own ffmpeg binary so the customer doesn't need a
# system-wide install. We use imageio_ffmpeg.write_frames directly (simpler
# than ffmpeg-python's pipe builder + sufficient for the H.264 path).
curate-video = [
"imageio-ffmpeg>=0.4.9",
"Pillow>=10.0.0",
]
# [curate-rlds]: Google's RLDS / TFRecord format + Open X-Embodiment.
# tensorflow_datasets is heavy (~80MB; pulls TF + numpy version pins that
# may conflict with local envs). Gated behind the extra so customers who
# only need LeRobot v3 / HDF5 don't pay that cost.
curate-rlds = [
"tensorflow-datasets>=4.9.0",
"tensorflow>=2.13.0",
]
# Jetson / ARM64 edge stack.
# - Skips [gpu] x86_64 wheels (onnxruntime-gpu PyPI has no aarch64 builds)
# - Skips lerobot (0.5.1 requires Python 3.12; JetPack 6 ships 3.10)
# - User must pre-install Jetson Zoo onnxruntime-gpu from pypi.jetson-ai-lab.io
# and mount host CUDA via --runtime=nvidia.
jetson = [
# serve stack
"fastapi>=0.100.0",
"uvicorn>=0.23.0",
"Pillow>=10.0.0",
"jsonschema>=4.0",
"prometheus-client>=0.19.0",
# monolithic export stack minus lerobot
"transformers==5.3.0",
"onnx-diagnostic>=0.9",
"onnxscript>=0.1",
"optree",
"scipy",
"num2words",
]
# Opt-in Triton fast-kernels path (Lift #5). `tether serve --fast-kernels` falls
# back to ORT silently if these aren't installed, so the extra is genuinely
# optional.
#
# T-5 pinning revision (2026-05-23): the initial pin `triton>=3.0,<3.2` was
# defeated by two transitive constraints surfaced on first Modal fire:
# 1. torch 2.7+ requires triton>=3.2 (excluded by our upper bound)
# 2. lerobot 0.5.1 requires torch>=2.7 (excluded by FluxVLA's torch==2.6.0)
# Resolution: bring `triton` only (no torch lower bound — torch is supplied by
# the host stack: serve/gpu/jetson extras or whatever the user installs).
# `triton>=3.1` matches what torch 2.6-2.8 transitively bring in; we don't
# constrain torch here because the [serve,gpu] / [monolithic] / [jetson]
# extras already do.
#
# Re-vendor cadence in src/tether/kernels/ATTRIBUTION.txt covers when
# torch+triton drift breaks the vendored kernels.
fast-kernels = [
"triton>=3.1",
]
[project.scripts]
# Canonical CLI binary (v0.12.0+).
tether = "tether.cli:app"
# Backwards-compat: `reflex` entry point still works for 6 months (until
# v0.14.0). It forwards to tether's main entry point AND emits a
# DeprecationWarning so existing scripts/CI keep working while users
# migrate. See src/reflex/_redirect.py for the warning + forwarder.
reflex = "reflex._redirect:main"
[tool.hatch.build.targets.wheel]
# v0.12.0 renamed the package from `reflex` to `tether`. We ship BOTH
# directories so:
# - `from tether import X` (new canonical) works
# - `from reflex import X` (backwards-compat shim, emits DeprecationWarning)
# works until v0.14.0 (6-month support window)
# The src/reflex/ directory is a thin re-export shim; see its __init__.py.
packages = ["src/tether", "src/reflex"]
# Hatchling auto-includes .py + data files from packages. The artifacts
# directive ensures C++/CUDA extension sources (Lift #5 JIT kernels at
# src/tether/kernels/cuda/*/src/*.{cpp,cu}) and license/attribution files
# are also included. A prior force-include of "src/tether/kernels" caused
# duplicate ZIP entries (rejected by PyPI) — removed in v0.11.1.
artifacts = ["*.cpp", "*.cu", "*.txt", "*.json"]
[tool.ruff]
target-version = "py310"
line-length = 100
[tool.mypy]
python_version = "3.10"
mypy_path = "src"
ignore_missing_imports = true
follow_imports = "silent"
check_untyped_defs = false
warn_unused_configs = true
exclude = [
"src/tether/models/third_party/",
]
[[tool.mypy.overrides]]
module = "tether.exporters.monolithic"
disable_error_code = [
"assignment",
"attr-defined",
"method-assign",
"misc",
"no-redef",
]
[tool.pytest.ini_options]
testpaths = ["tests"]
# pytest-asyncio v1.x requires explicit mode declaration. Tests use
# @pytest.mark.asyncio decorators (strict mode); auto mode treats every
# async def as an async test which we don't want (some async helpers
# inside sync tests would be misinterpreted).
asyncio_mode = "strict"
markers = [
"asyncio: mark a coroutine test for pytest-asyncio (strict mode)",
"hardware: requires a physical robot wired in; skipped unless RUN_HARDWARE_TESTS=1",
]