From 89bc71395f96d36c7265704ce9a9f10a3dac75c0 Mon Sep 17 00:00:00 2001 From: chaofengw Date: Mon, 7 Sep 2026 10:15:01 +0000 Subject: [PATCH 1/5] fix(build): restore reproducible bundle identity Record exact checkpoint, source, and build-request provenance in every new bundle, expose it through inspect, and reject stale benchmark cache entries. Pin remote checkpoint revisions and direct dependency declarations so source builds no longer resolve mutable inputs. Signed-off-by: chaofengw --- Dockerfile | 26 +-- README.md | 1 + apps/benchmark/trtmc_benchmark/builder.py | 77 +++++++-- .../trtmc_benchmark/tests/test_benchmark.py | 152 +++++++++++++++++- apps/cli/cli.cpp | 18 ++- apps/cli/tests/test_cli.cpp | 36 +++++ .../tensorrt_model_connect/__init__.py | 7 +- core/builder/tensorrt_model_connect/build.py | 79 +++++++++ .../tensorrt_model_connect/build_cli.py | 39 ++++- .../tensorrt_model_connect/bundle_writer.py | 42 +++++ core/builder/tests/test_build.py | 72 +++++++++ core/builder/tests/test_build_cli.py | 93 +++++++++++ .../tests/manifests/albert-base-tp4.json | 1 + .../albert/tests/manifests/albert-base.json | 1 + families/bark/requirements.txt | 4 +- .../bark/tests/manifests/bark-large-tp4.json | 1 + families/bark/tests/manifests/bark-large.json | 1 + .../tests/manifests/bark-small-fp32-l0.json | 1 + .../bark/tests/manifests/bark-small-tp4.json | 1 + families/bark/tests/manifests/bark-small.json | 1 + .../bart/tests/manifests/bart-base-tp4.json | 1 + families/bart/tests/manifests/bart-base.json | 1 + .../tests/manifests/all-minilm-l6-v2.json | 1 + .../manifests/bert-base-uncased-tp4.json | 1 + .../tests/manifests/bert-base-uncased.json | 1 + .../tests/manifests/bge-small-en-v1.5.json | 1 + ...paraphrase-multilingual-minilm-l12-v2.json | 1 + .../bloom/tests/manifests/bloom-560m-tp4.json | 1 + .../bloom/tests/manifests/bloom-560m.json | 1 + .../tests/manifests/canary-1b-v2-tp4.json | 1 + .../canary/tests/manifests/canary-1b-v2.json | 1 + .../chronos-bolt-tiny-official-tp4.json | 1 + .../manifests/chronos-bolt-tiny-official.json | 1 + .../tests/manifests/codegen-350m-tp4.json | 1 + .../codegen/tests/manifests/codegen-350m.json | 1 + .../tests/manifests/convbert-base-tp2.json | 1 + .../tests/manifests/convbert-base.json | 1 + families/cosmos3/requirements.txt | 2 +- .../tests/manifests/deberta-base-tp4.json | 1 + .../deberta/tests/manifests/deberta-base.json | 1 + families/deepseek_ocr/requirements.txt | 4 +- .../tests/manifests/deepseek-ocr-l0-tp2.json | 1 + .../tests/manifests/deepseek-ocr-l0.json | 1 + .../tests/manifests/deepseek-ocr.json | 1 + .../tests/manifests/deepseek-v2-lite-tp4.json | 1 + .../tests/manifests/deepseek-v2-lite.json | 1 + families/dinov3/requirements.txt | 4 +- .../distilbert-base-uncased-tp4.json | 1 + .../manifests/distilbert-base-uncased.json | 1 + .../tests/manifests/dpr-ctx-encoder-tp4.json | 1 + .../dpr/tests/manifests/dpr-ctx-encoder.json | 1 + .../nemotron-embed-vl-1b-v2-tp4.json | 1 + .../manifests/nemotron-embed-vl-1b-v2.json | 1 + .../nemotron-rerank-vl-1b-v2-tp4.json | 1 + .../electra-base-discriminator-tp4.json | 1 + .../manifests/electra-base-discriminator.json | 1 + .../tests/manifests/elf-b-de-en-l0.json | 1 + .../tests/manifests/elf-b-owt-l0.json | 1 + .../tests/manifests/elf-b-xsum-l0.json | 1 + .../tests/manifests/falcon-rw-1b-tp4.json | 1 + .../falcon/tests/manifests/falcon-rw-1b.json | 1 + .../fast_foundation_stereo/requirements.txt | 8 +- families/flux/requirements.txt | 6 +- .../manifests/flux-2-dev-fp8-l0-tp4.json | 1 + .../tests/manifests/flux-2-dev-fp8-l0.json | 1 + .../flux/tests/manifests/flux-2-dev-fp8.json | 1 + .../tests/manifests/flux-2-dev-l0-tp4.json | 1 + .../flux/tests/manifests/flux-2-dev-l0.json | 1 + families/flux/tests/manifests/flux-2-dev.json | 1 + .../manifests/flux-schnell-l0-batch2.json | 1 + .../tests/manifests/flux-schnell-l0-cp4.json | 1 + .../tests/manifests/flux-schnell-l0-tp4.json | 1 + .../flux/tests/manifests/flux-schnell-l0.json | 1 + .../flux/tests/manifests/flux-schnell.json | 1 + .../fnet/tests/manifests/fnet-base-tp4.json | 1 + families/fnet/tests/manifests/fnet-base.json | 1 + families/foundationpose/requirements.txt | 2 +- .../gemma/tests/manifests/gemma-2-2b-tp4.json | 1 + .../gemma/tests/manifests/gemma-2-2b.json | 1 + .../glm/tests/manifests/glm-4-9b-l0-tp2.json | 1 + families/glm/tests/manifests/glm-4-9b-l0.json | 1 + families/glm/tests/manifests/glm-4-9b.json | 1 + families/gpt2/tests/manifests/distilgpt2.json | 1 + .../gpt2/tests/manifests/gpt2-125m-tp4.json | 1 + families/gpt2/tests/manifests/gpt2-125m.json | 1 + .../tests/manifests/gpt-neo-125m-tp4.json | 1 + .../gpt_neo/tests/manifests/gpt-neo-125m.json | 1 + .../tests/manifests/pythia-70m-tp4.json | 1 + .../gpt_neox/tests/manifests/pythia-70m.json | 1 + families/gpt_oss/requirements.txt | 2 +- .../tests/manifests/gpt-oss-20b-l0-tp4.json | 1 + .../tests/manifests/granite-3.1-2b-tp4.json | 1 + .../tests/manifests/granite-3.1-2b.json | 1 + .../tests/manifests/internlm2-1.8b-tp4.json | 1 + .../tests/manifests/internlm2-1.8b.json | 1 + families/internvl/requirements.txt | 2 +- .../tests/manifests/internvl3-2b-tp2.json | 1 + .../tests/manifests/internvl3-2b.json | 1 + .../tests/manifests/internvl3-8b-tp4.json | 1 + .../tests/manifests/internvl3-8b.json | 1 + families/lance/requirements.txt | 2 +- families/lerobot_act/requirements.txt | 4 +- .../llama/tests/manifests/falcon3-1b.json | 1 + .../tests/manifests/minitron-4b-depth.json | 1 + .../tests/manifests/nemotron-nano-4b.json | 1 + .../llama/tests/manifests/tinyllama-1.1b.json | 1 + families/locateanything/requirements.txt | 4 +- .../tests/manifests/locateanything-3b.json | 1 + families/ltx_video/requirements.txt | 4 +- .../tests/manifests/ltx-video-l0.json | 1 + families/m2m_100/requirements.txt | 2 +- .../m2m_100/tests/manifests/nllb-200.json | 1 + .../tests/manifests/magpie-tts-357m-tp4.json | 1 + .../mamba/tests/manifests/mamba-130m-tp4.json | 1 + .../mamba/tests/manifests/mamba-130m.json | 1 + .../tests/manifests/marian-en-ru-tp4.json | 1 + .../marian/tests/manifests/marian-en-ru.json | 1 + families/minimax_h3/requirements.txt | 4 +- .../tests/manifests/mistral-7b-l0.json | 1 + .../mistral/tests/manifests/mistral-7b.json | 1 + .../tests/manifests/riva-translate-4b.json | 1 + .../manifests/mixtral-stories-15m-tp2.json | 1 + .../tests/manifests/mixtral-stories-15m.json | 1 + .../tests/manifests/modernbert-base-tp4.json | 1 + .../tests/manifests/modernbert-base.json | 1 + .../manifests/all-mpnet-base-v2-tp4.json | 1 + .../tests/manifests/all-mpnet-base-v2.json | 1 + .../tests/manifests/nemotron-hindi-4b.json | 1 + .../tests/manifests/nemotron-mini-4b.json | 1 + .../manifests/nemotron-h-nano-9b-tp4.json | 1 + .../tests/manifests/nemotron-h-nano-9b.json | 1 + .../nemotron-labs-diffusion-8b-l0.json | 1 + .../manifests/nemotron-labs-diffusion-8b.json | 1 + .../nemotron-3.5-asr-streaming-0.6b.json | 1 + ...nemotron-speech-streaming-en-0.6b-tp4.json | 1 + .../nemotron-speech-streaming-en-0.6b.json | 1 + families/nemotron_voicechat/requirements.txt | 2 +- .../olmo/tests/manifests/olmo-1b-tp4.json | 1 + families/olmo/tests/manifests/olmo-1b.json | 1 + .../olmo2/tests/manifests/olmo2-1b-tp4.json | 1 + .../opt/tests/manifests/opt-125m-tp4.json | 1 + families/opt/tests/manifests/opt-125m.json | 1 + .../patchtsmixer-granite-official-tp4.json | 1 + .../patchtsmixer-granite-official.json | 1 + ...tst-etth1-regression-distribution-tp4.json | 1 + ...atchtst-etth1-regression-distribution.json | 1 + .../manifests/patchtst-granite-official.json | 1 + families/personaplex/requirements.txt | 2 +- .../manifests/personaplex-7b-l0-tp4.json | 1 + .../tests/manifests/personaplex-7b-l0.json | 1 + .../phi/tests/manifests/phi3-mini-tp4.json | 1 + families/phi/tests/manifests/phi3-mini.json | 1 + families/phi4_multimodal/requirements.txt | 4 +- .../tests/manifests/phi4-multimodal.json | 1 + .../tests/manifests/phi-moe-l0-tp4.json | 1 + .../phi_moe/tests/manifests/phi-moe-l0.json | 1 + families/phi_moe/tests/manifests/phi-moe.json | 1 + families/pixart/requirements.txt | 4 +- .../tests/manifests/pixart-sigma-1024-l0.json | 1 + .../manifests/pixart-sigma-1024-tp4.json | 1 + .../tests/manifests/pixart-sigma-1024.json | 1 + .../tests/manifests/qwen3-0.6b-fp16-tp4.json | 1 + .../qwen/tests/manifests/qwen3-0.6b-fp16.json | 1 + .../tests/manifests/qwen3-0.6b-fp8-tp4.json | 1 + .../qwen/tests/manifests/qwen3-0.6b-fp8.json | 1 + .../tests/manifests/qwen3-0.6b-native-l0.json | 1 + .../tests/manifests/qwen3-0.6b-topp-tp4.json | 1 + .../qwen/tests/manifests/qwen3-0.6b-topp.json | 1 + .../manifests/qwen3-4b-instruct-2507-tp4.json | 1 + .../manifests/qwen3-4b-instruct-2507.json | 1 + .../qwen3_5/tests/manifests/qwen35-9b.json | 1 + families/qwen3_8/requirements.txt | 2 +- families/qwen3_omni/requirements.txt | 2 +- families/qwen_image/requirements.txt | 2 +- .../tests/manifests/qwen-image-2512.json | 1 + .../tests/manifests/qwen-image-edit-2511.json | 1 + .../tests/manifests/qwen-image-l0.json | 1 + .../tests/manifests/qwen-image.json | 1 + .../manifests/qwen3-moe-30b-a3b-tp4.json | 1 + .../tests/manifests/qwen3-moe-30b-a3b.json | 1 + .../manifests/qwen3-moe-tiny-random.json | 1 + families/qwen_vl/requirements.txt | 2 +- .../tests/manifests/qwen25vl-3b-tp2.json | 1 + .../qwen_vl/tests/manifests/qwen25vl-3b.json | 1 + .../tests/manifests/qwen3-vl-2b-tp4.json | 1 + .../qwen_vl/tests/manifests/qwen3-vl-2b.json | 1 + .../tests/manifests/camembert-base-tp4.json | 1 + .../tests/manifests/camembert-base.json | 1 + .../tests/manifests/roberta-base-tp4.json | 1 + .../roberta/tests/manifests/roberta-base.json | 1 + .../tests/manifests/roberta-large-tp4.json | 1 + .../tests/manifests/roberta-large.json | 1 + .../tests/manifests/xlm-roberta-base-tp4.json | 1 + .../tests/manifests/xlm-roberta-base.json | 1 + .../rwkv/tests/manifests/rwkv-169m-tp4.json | 1 + families/rwkv/tests/manifests/rwkv-169m.json | 1 + families/sam/requirements.txt | 4 +- .../sam/tests/manifests/sam-vit-base-tp4.json | 1 + .../sam/tests/manifests/sam-vit-base.json | 1 + families/sam2/requirements.txt | 2 +- families/sam3/requirements.txt | 2 +- families/sana_wm/requirements.txt | 26 +-- .../manifests/sana-wm-bidirectional.json | 1 + families/segformer/requirements.txt | 4 +- .../tests/manifests/segformer-b0-ade-tp4.json | 1 + .../tests/manifests/segformer-b0-ade.json | 1 + .../tests/manifests/stablelm2-1.6b-tp4.json | 1 + .../tests/manifests/starcoder2-3b-tp2.json | 1 + .../tests/manifests/starcoder2-3b.json | 1 + families/t5/tests/manifests/t5-small-tp4.json | 1 + families/t5/tests/manifests/t5-small.json | 1 + .../timesfm-2.0-500m-official-tp4.json | 1 + .../manifests/timesfm-2.0-500m-official.json | 1 + families/timm_densenet/requirements.txt | 2 +- .../tests/manifests/densenet121-ra-in1k.json | 1 + families/timm_efficientnet/requirements.txt | 2 +- .../manifests/efficientnet-b0-ra-in1k.json | 1 + families/timm_inception/requirements.txt | 2 +- .../tests/manifests/inception-v3-tv-in1k.json | 1 + families/timm_mnasnet/requirements.txt | 2 +- .../manifests/mnasnet-100-rmsp-in1k.json | 1 + families/timm_mobilenetv3/requirements.txt | 2 +- .../mobilenetv3-large-100-ra-in1k.json | 1 + families/timm_repvgg/requirements.txt | 2 +- families/timm_resnet/requirements.txt | 2 +- .../tests/manifests/resnet50-a1-in1k.json | 1 + families/timm_vgg/requirements.txt | 2 +- .../tests/manifests/vgg16-tv-in1k.json | 1 + families/timm_vit/requirements.txt | 2 +- ...base-p16-224-augreg-in21k-ft-in1k-tp4.json | 1 + ...vit-base-p16-224-augreg-in21k-ft-in1k.json | 1 + families/wan2_2_ti2v/requirements.txt | 28 ++-- families/wan_t2v/requirements.txt | 4 +- .../manifests/wan21-t2v-1.3b-l0-cp4.json | 1 + .../manifests/wan21-t2v-1.3b-l0-tp4.json | 1 + .../tests/manifests/wan21-t2v-1.3b-l0.json | 1 + .../tests/manifests/wan21-t2v-1.3b.json | 1 + families/whisper/requirements.txt | 2 +- .../manifests/whisper-large-v3-turbo-tp4.json | 1 + .../manifests/whisper-large-v3-turbo.json | 1 + .../manifests/whisper-tiny-fp16-tp2.json | 1 + .../tests/manifests/whisper-tiny-fp16.json | 1 + .../xglm/tests/manifests/xglm-564m-tp4.json | 1 + families/xglm/tests/manifests/xglm-564m.json | 1 + .../xlnet/tests/manifests/xlnet-base-tp4.json | 1 + .../xlnet/tests/manifests/xlnet-base.json | 1 + families/z_image/requirements.txt | 4 +- .../tests/manifests/z-image-turbo-l0-tp2.json | 1 + .../tests/manifests/z-image-turbo-l0.json | 1 + .../tests/manifests/z-image-turbo.json | 1 + pyproject.toml | 20 +-- requirements/base.txt | 2 +- tools/tests/test_architecture.py | 57 ++++++- website/docs/api/python-builder.md | 12 +- website/docs/architecture/bundle-format.md | 17 +- website/docs/getting-started/quick-start.md | 6 +- 256 files changed, 981 insertions(+), 140 deletions(-) diff --git a/Dockerfile b/Dockerfile index a925781a07..77465435a6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,7 +39,7 @@ ENV VIRTUAL_ENV=/opt/venv ENV PATH=/opt/venv/bin:$PATH COPY requirements/base.txt /tmp/trtmc-base-requirements.txt RUN python3.12 -m venv "$VIRTUAL_ENV" \ - && pip install --upgrade pip \ + && pip install --upgrade "pip==26.2.1" \ && pip install \ "torch==2.12.0+cu130" \ "torchvision==0.27.0+cu130" \ @@ -53,29 +53,29 @@ RUN python3.12 -m venv "$VIRTUAL_ENV" \ "huggingface_hub==1.21.0" \ "jsonschema==4.26.0" \ "lizard==1.21.2" \ - "ml_dtypes>=0.4" \ - "numpy>=1.24,<2.5" \ - "onnx>=1.16" \ - "Pillow" \ - "protobuf" \ + "ml_dtypes==0.5.4" \ + "numpy==1.26.4" \ + "onnx==1.21.0" \ + "Pillow==12.2.0" \ + "protobuf==7.35.0" \ "pybind11==2.13.6" \ "pybind11-stubgen==2.4.2" \ - "pytest<9" \ - "PyYAML>=6.0" \ + "pytest==8.4.2" \ + "PyYAML==6.0.3" \ "ruff==0.16.4" \ - "safetensors>=0.4" \ + "safetensors==0.8.0" \ "scikit-build-core==0.8.2" \ - "sentencepiece>=0.1.99" \ - "setuptools>=80,<82" \ + "sentencepiece==0.2.2" \ + "setuptools==81.0.0" \ "tensorrt==11.1.0.106" \ - "tokenizers" \ + "tokenizers==0.22.2" \ "transformers==5.2.0" \ && pip install --force-reinstall \ "torch==2.12.0+cu130" \ "torchvision==0.27.0+cu130" \ "torchaudio==2.11.0+cu130" \ --index-url https://download.pytorch.org/whl/cu130 \ - && pip install "setuptools>=80,<82" + && pip install "setuptools==81.0.0" ENV TRT_LIB_DIR=/opt/venv/lib/python3.12/site-packages/tensorrt_libs ENV NCCL_LIB_DIR=/opt/venv/lib/python3.12/site-packages/nvidia/nccl/lib diff --git a/README.md b/README.md index a68e9a7afb..608ea8a4bf 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ ```bash python -m tensorrt_model_connect build Qwen/Qwen3-0.6B \ + --revision c1899de289a04d12100db370d81485cdf75e47ca \ --max-sequence-length 16384 \ --output qwen3-0.6b.bundle trtmc run ./qwen3-0.6b.bundle \ diff --git a/apps/benchmark/trtmc_benchmark/builder.py b/apps/benchmark/trtmc_benchmark/builder.py index fc86b6d653..95b23f0bde 100644 --- a/apps/benchmark/trtmc_benchmark/builder.py +++ b/apps/benchmark/trtmc_benchmark/builder.py @@ -14,6 +14,7 @@ from pathlib import Path from typing import Any, Iterable, Mapping, Sequence +from tensorrt_model_connect import read_bundle_json, resolve_source_revision from tensorrt_model_connect.build_cli import _resolve_model from .types import BenchmarkError, ModelDescriptor, ResolvedCase @@ -119,7 +120,12 @@ def _prepare_group( model = cases[0].model managed = _is_relative_to(requested, self.cache_root) if requested.is_file() and not rebuild: - return requested, BundlePreparation(model.name, "reused", requested) + if _bundle_matches_model(requested, model, cases): + return requested, BundlePreparation(model.name, "reused", requested) + if not allow_build: + raise BenchmarkError( + f"bundle provenance does not match {model.name}: {requested}" + ) if requested.is_file() and not managed: raise BenchmarkError( f"--rebuild cannot overwrite explicit bundle {requested}; " @@ -238,7 +244,7 @@ def _build_command( bundle: Path, cases: Sequence[ResolvedCase], ) -> tuple[str, ...]: - settings = model.build_settings + settings = _build_request_options(model, cases) command = [ sys.executable, "-m", @@ -252,6 +258,10 @@ def _build_command( "--precision", model.precision, ] + if model.hf_id: + command.extend(("--checkpoint-id", model.hf_id)) + if model.hf_revision: + command.extend(("--revision", model.hf_revision)) flags = ( ("max_sequence_length", "--max-sequence-length"), ("image_height", "--image-height"), @@ -272,24 +282,30 @@ def _build_command( if settings.get("dynamic_kv_cache", False): command.append("--dynamic-kv-cache") + return tuple(command) + + +def _build_request_options( + model: ModelDescriptor, cases: Sequence[ResolvedCase] +) -> dict[str, object]: + settings: dict[str, object] = dict(model.build_settings) + settings.setdefault("backend", "trt") + settings.setdefault("max_batch_size", 1) + settings.setdefault("tensor_parallel_size", 1) + settings.setdefault("context_parallel_size", 1) + settings.setdefault("dynamic_kv_cache", False) + image_cases = [case for case in cases if case.operation == "generate_image"] if image_cases: heights = [int(case.request.get("height", 0)) for case in image_cases] widths = [int(case.request.get("width", 0)) for case in image_cases] batches = [int(case.request.get("batch_size", 1)) for case in image_cases] - _replace_value(command, "--image-height", max(heights, default=0)) - _replace_value(command, "--image-width", max(widths, default=0)) - _replace_value(command, "--max-batch-size", max(batches, default=1)) - return tuple(command) - - -def _replace_value(command: list[str], flag: str, value: int) -> None: - if value <= 0: - return - if flag in command: - command[command.index(flag) + 1] = str(value) - else: - command.extend((flag, str(value))) + if max(heights, default=0) > 0: + settings["image_height"] = max(heights) + if max(widths, default=0) > 0: + settings["image_width"] = max(widths) + settings["max_batch_size"] = max(batches, default=1) + return settings def _write(path: Path, value: str) -> None: @@ -308,3 +324,34 @@ def _is_relative_to(path: Path, parent: Path) -> bool: except ValueError: return False return True + + +def _bundle_matches_model( + bundle: Path, model: ModelDescriptor, cases: Sequence[ResolvedCase] +) -> bool: + try: + source_revision = resolve_source_revision() + except ValueError: + return False + try: + provenance = read_bundle_json(bundle, "provenance.json") + except (OSError, UnicodeDecodeError, ValueError): + return False + if not isinstance(provenance, dict) or provenance.get("format") != 1: + return False + expected_request = { + "family": model.family, + "task": model.task, + "precision": model.precision, + **_build_request_options(model, cases), + } + if not expected_request.get("fp32_layers"): + expected_request.pop("fp32_layers", None) + elif isinstance(expected_request["fp32_layers"], tuple): + expected_request["fp32_layers"] = list(expected_request["fp32_layers"]) + return provenance.get("checkpoint") == { + "id": model.hf_id, + "revision": model.hf_revision, + } and provenance.get("build") == { + "source_revision": source_revision + } and provenance.get("request") == expected_request diff --git a/apps/benchmark/trtmc_benchmark/tests/test_benchmark.py b/apps/benchmark/trtmc_benchmark/tests/test_benchmark.py index 75810dd1cf..d35fcbd191 100644 --- a/apps/benchmark/trtmc_benchmark/tests/test_benchmark.py +++ b/apps/benchmark/trtmc_benchmark/tests/test_benchmark.py @@ -21,6 +21,7 @@ from trtmc_benchmark.report import generate_collection_report from trtmc_benchmark.service import BenchmarkService from trtmc_benchmark.types import BenchmarkError +from tensorrt_model_connect import BundleWriter from trtmc_benchmark.worker import find_worker @@ -87,6 +88,21 @@ def test_build_command_is_the_current_closed_build_request(tmp_path: Path) -> No assert "source-revision" not in joined +def test_build_command_preserves_canonical_checkpoint_identity(tmp_path: Path) -> None: + model = ManifestCatalog(REPO / "families").resolve("distilgpt2") + case = resolve_case(model, tmp_path / "model.bundle") + + command = _build_command( + model, + tmp_path / "resolved-checkpoint", + tmp_path / "model.bundle", + (case,), + ) + + assert command[command.index("--checkpoint-id") + 1] == model.hf_id + assert command[command.index("--revision") + 1] == model.hf_revision + + def test_build_command_passes_manifest_backend_and_dynamic_kv_cache(tmp_path: Path) -> None: manifest = json.loads( (REPO / "families/llama/tests/manifests/minitron-4b-width-l0.json").read_text() @@ -153,6 +169,112 @@ def test_bundle_builder_has_no_second_model_resolver() -> None: assert "repository / model.hf_id" not in source +def test_bundle_cache_rejects_mismatched_provenance_when_build_is_disabled( + tmp_path: Path, monkeypatch +) -> None: + source_revision = "a" * 40 + monkeypatch.setenv("TRTMC_ENGINE_BUILD_REVISION", source_revision) + model = ManifestCatalog(REPO / "families").resolve("distilgpt2") + builder = BundleBuilder(tmp_path / "cache") + bundle = builder.provisional_path(model) + bundle.parent.mkdir(parents=True) + writer = BundleWriter(bundle) + writer.set_header(family=model.family, task=model.task, backend="trt") + writer.add_json( + "provenance.json", + { + "format": 1, + "checkpoint": {"id": model.hf_id, "revision": "c" * 40}, + "build": {"source_revision": source_revision}, + "request": {}, + }, + ) + writer.finish() + case = resolve_case(model, bundle) + + with pytest.raises(BenchmarkError, match="bundle provenance does not match"): + builder.prepare( + (case,), + allow_build=False, + rebuild=False, + dry_run=False, + ) + + +def test_bundle_cache_rejects_a_different_build_request(tmp_path: Path, monkeypatch) -> None: + source_revision = "a" * 40 + monkeypatch.setenv("TRTMC_ENGINE_BUILD_REVISION", source_revision) + model = ManifestCatalog(REPO / "families").resolve("distilgpt2") + builder = BundleBuilder(tmp_path / "cache") + bundle = builder.provisional_path(model) + bundle.parent.mkdir(parents=True) + writer = BundleWriter(bundle) + writer.set_header(family=model.family, task=model.task, backend="trt") + writer.add_json( + "provenance.json", + { + "format": 1, + "checkpoint": {"id": model.hf_id, "revision": model.hf_revision}, + "build": {"source_revision": source_revision}, + "request": { + "family": "gpt2", + "task": "text_generation", + "backend": "trt", + "precision": "fp32", + "max_sequence_length": 256, + "max_batch_size": 1, + "tensor_parallel_size": 1, + "context_parallel_size": 1, + "dynamic_kv_cache": False, + }, + }, + ) + writer.finish() + case = resolve_case(model, bundle) + + with pytest.raises(BenchmarkError, match="bundle provenance does not match"): + builder.prepare((case,), allow_build=False, rebuild=False, dry_run=False) + + +def test_bundle_cache_reuses_an_exact_build_identity(tmp_path: Path, monkeypatch) -> None: + source_revision = "a" * 40 + monkeypatch.setenv("TRTMC_ENGINE_BUILD_REVISION", source_revision) + model = ManifestCatalog(REPO / "families").resolve("distilgpt2") + builder = BundleBuilder(tmp_path / "cache") + bundle = builder.provisional_path(model) + bundle.parent.mkdir(parents=True) + writer = BundleWriter(bundle) + writer.set_header(family=model.family, task=model.task, backend="trt") + writer.add_json( + "provenance.json", + { + "format": 1, + "checkpoint": {"id": model.hf_id, "revision": model.hf_revision}, + "build": {"source_revision": source_revision}, + "request": { + "family": "gpt2", + "task": "text_generation", + "backend": "trt", + "precision": "fp16", + "max_sequence_length": 256, + "max_batch_size": 1, + "tensor_parallel_size": 1, + "context_parallel_size": 1, + "dynamic_kv_cache": False, + }, + }, + ) + writer.finish() + case = resolve_case(model, bundle) + + resolved, records = builder.prepare( + (case,), allow_build=False, rebuild=False, dry_run=False + ) + + assert resolved[0].bundle_path == bundle + assert records[0].status == "reused" + + def _worker(tmp_path: Path) -> Path: path = tmp_path / "worker" path.write_text( @@ -248,9 +370,35 @@ def test_collection_rejects_duplicate_run_id_without_content_fingerprints( generate_collection_report((tmp_path,), tmp_path / "report") -def test_cli_dry_run_uses_explicit_bundle_without_runtime(tmp_path: Path, capsys) -> None: +def test_cli_dry_run_uses_explicit_bundle_without_runtime( + tmp_path: Path, capsys, monkeypatch +) -> None: + source_revision = "a" * 40 + monkeypatch.setenv("TRTMC_ENGINE_BUILD_REVISION", source_revision) + model = ManifestCatalog(REPO / "families").resolve("distilgpt2") bundle = tmp_path / "model.bundle" - bundle.write_bytes(b"bundle") + writer = BundleWriter(bundle) + writer.set_header(family=model.family, task=model.task, backend="trt") + writer.add_json( + "provenance.json", + { + "format": 1, + "checkpoint": {"id": model.hf_id, "revision": model.hf_revision}, + "build": {"source_revision": source_revision}, + "request": { + "family": "gpt2", + "task": "text_generation", + "backend": "trt", + "precision": "fp16", + "max_sequence_length": 256, + "max_batch_size": 1, + "tensor_parallel_size": 1, + "context_parallel_size": 1, + "dynamic_kv_cache": False, + }, + }, + ) + writer.finish() assert ( main( [ diff --git a/apps/cli/cli.cpp b/apps/cli/cli.cpp index 7cf58f10d7..59004359ac 100644 --- a/apps/cli/cli.cpp +++ b/apps/cli/cli.cpp @@ -1320,15 +1320,21 @@ int run(int argc, char** argv, std::ostream& output, std::ostream& error) { return EXIT_SUCCESS; } if (command.kind == CommandKind::kInspect) { - const BundleInfo bundle = InspectBundle(command.bundle); + const BundleReader reader(command.bundle); + const BundleInfo& bundle = reader.info(); nlohmann::json sections = nlohmann::json::object(); for (const auto& section : bundle.sections) sections[section.name] = {{"offset", section.offset}, {"length", section.length}}; - write_json(output, {{"format", bundle.format}, - {"family", bundle.family}, - {"task", bundle.task}, - {"backend", bundle.backend}, - {"sections", std::move(sections)}}); + nlohmann::json result = {{"format", bundle.format}, + {"family", bundle.family}, + {"task", bundle.task}, + {"backend", bundle.backend}, + {"sections", std::move(sections)}}; + if (reader.find_section("provenance.json") != nullptr) { + const std::vector provenance = reader.read_section("provenance.json"); + result["provenance"] = nlohmann::json::parse(provenance.begin(), provenance.end()); + } + write_json(output, result); return EXIT_SUCCESS; } const bool has_byok_library = has_option(command, "--byok-library"); diff --git a/apps/cli/tests/test_cli.cpp b/apps/cli/tests/test_cli.cpp index 0824f5c86c..16351cdf1c 100644 --- a/apps/cli/tests/test_cli.cpp +++ b/apps/cli/tests/test_cli.cpp @@ -36,6 +36,30 @@ trtmc::cli::Command parse(std::vector arguments) { return trtmc::cli::parse_args(static_cast(argv.size()), argv.data()); } +int run(std::vector arguments, std::ostream& output, std::ostream& error) { + std::vector argv; + argv.reserve(arguments.size()); + for (auto& argument : arguments) + argv.push_back(argument.data()); + return trtmc::cli::run(static_cast(argv.size()), argv.data(), output, error); +} + +void write_inspect_bundle(const std::filesystem::path& path) { + const std::string provenance = + R"({"format":1,"checkpoint":{"id":"openai-community/gpt2","revision":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"},"build":{"source_revision":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},"request":{}})"; + const std::string header = + R"({"format":1,"family":"gpt2","task":"text_generation","backend":"trt","sections":{"provenance.json":{"offset":0,"length":)" + + std::to_string(provenance.size()) + "}}}"; + constexpr unsigned char magic[8] = {'B', 'U', 'N', 'D', 'L', 'E', '\x01', '\0'}; + std::ofstream output(path, std::ios::binary); + output.write(reinterpret_cast(magic), 8); + const std::uint64_t length = header.size(); + for (int shift = 0; shift < 64; shift += 8) + output.put(static_cast((length >> shift) & 0xffU)); + output.write(header.data(), static_cast(header.size())); + output.write(provenance.data(), static_cast(provenance.size())); +} + bool parse_throws(std::vector arguments) { try { (void)parse(std::move(arguments)); @@ -418,6 +442,18 @@ int main() { "batch transcription inputs preserve repeated option order"); check(parse({"trtmc", "inspect", "model.bundle"}).kind == trtmc::cli::CommandKind::kInspect, "inspect does not require runtime root"); + const std::filesystem::path inspect_bundle = "/tmp/trtmc-cli-inspect.bundle"; + write_inspect_bundle(inspect_bundle); + std::ostringstream inspect_output; + std::ostringstream inspect_error; + check(run({"trtmc", "inspect", inspect_bundle.string()}, inspect_output, inspect_error) == 0, + "inspect reads a valid bundle"); + check(inspect_output.str().find("openai-community/gpt2") != std::string::npos, + "inspect reports checkpoint provenance"); + check(inspect_output.str().find("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") != + std::string::npos, + "inspect reports source revision provenance"); + std::filesystem::remove(inspect_bundle); check(parse({"trtmc", "version"}).kind == trtmc::cli::CommandKind::kVersion, "version parses without bundle"); check(parse_throws({"trtmc", "--version"}), "version flag alias is not accepted"); diff --git a/core/builder/tensorrt_model_connect/__init__.py b/core/builder/tensorrt_model_connect/__init__.py index 101f6dcb4b..cca2ff86c6 100644 --- a/core/builder/tensorrt_model_connect/__init__.py +++ b/core/builder/tensorrt_model_connect/__init__.py @@ -3,8 +3,8 @@ """TensorRT Model Connect build API.""" -from .build import BuildRequest, build -from .bundle_writer import BundleWriter +from .build import BuildRequest, build, resolve_source_revision +from .bundle_writer import BundleWriter, read_bundle_json, read_bundle_section from .graph_transform import GraphTransform __all__ = [ @@ -12,4 +12,7 @@ "BundleWriter", "GraphTransform", "build", + "read_bundle_json", + "read_bundle_section", + "resolve_source_revision", ] diff --git a/core/builder/tensorrt_model_connect/build.py b/core/builder/tensorrt_model_connect/build.py index d0d5d68638..fe4d6db08c 100644 --- a/core/builder/tensorrt_model_connect/build.py +++ b/core/builder/tensorrt_model_connect/build.py @@ -7,7 +7,9 @@ import hashlib import importlib +import os import re +import subprocess import sys from dataclasses import dataclass from pathlib import Path @@ -18,6 +20,7 @@ _ID = re.compile(r"[a-z][a-z0-9_]*\Z") +_EXACT_REVISION = re.compile(r"[0-9a-f]{40}\Z") @dataclass(frozen=True) @@ -30,6 +33,9 @@ class BuildRequest: task: str precision: str backend: str = "trt" + checkpoint_id: str = "" + checkpoint_revision: str = "" + source_revision: str = "" max_sequence_length: int | None = None image_height: int | None = None image_width: int | None = None @@ -46,6 +52,10 @@ class BuildRequest: def __post_init__(self) -> None: if not self.precision: raise ValueError("precision must be non-empty") + for field in ("checkpoint_revision", "source_revision"): + revision = getattr(self, field) + if revision and _EXACT_REVISION.fullmatch(revision) is None: + raise ValueError(f"{field} must be an exact 40-character Git SHA") _validate_id("family", self.family) _validate_id("task", self.task) if self.backend not in {"trt", "trt_rtx"}: @@ -140,7 +150,76 @@ def build(request: BuildRequest) -> None: try: with graph_transform(request.graph_transform): family_module.build(request, writer) + writer.add_json("provenance.json", _build_provenance(request)) writer.finish() except BaseException: writer.abort() raise + + +def resolve_source_revision(explicit: str = "") -> str: + """Return the exact source revision that produced a bundle.""" + + candidates = ( + ("source_revision", explicit), + ("TRTMC_ENGINE_BUILD_REVISION", os.environ.get("TRTMC_ENGINE_BUILD_REVISION", "")), + ("GITHUB_SHA", os.environ.get("GITHUB_SHA", "")), + ) + for field, candidate in candidates: + revision = candidate.strip().lower() + if not revision: + continue + if _EXACT_REVISION.fullmatch(revision) is None: + raise ValueError(f"{field} must be an exact 40-character Git SHA") + return revision + + try: + completed = subprocess.run( + ["git", "-C", str(Path(__file__).resolve().parent), "rev-parse", "HEAD"], + capture_output=True, + text=True, + timeout=5, + check=False, + ) + except (OSError, subprocess.SubprocessError): + completed = None + revision = completed.stdout.strip().lower() if completed and completed.returncode == 0 else "" + if _EXACT_REVISION.fullmatch(revision): + return revision + raise ValueError( + "source revision is unavailable; set TRTMC_ENGINE_BUILD_REVISION to the exact Git SHA" + ) + + +def _build_provenance(request: BuildRequest) -> dict[str, object]: + options: dict[str, object] = { + "family": request.family, + "task": request.task, + "backend": request.backend, + "precision": request.precision, + "max_batch_size": request.max_batch_size, + "tensor_parallel_size": request.tensor_parallel_size, + "context_parallel_size": request.context_parallel_size, + "dynamic_kv_cache": request.dynamic_kv_cache, + } + if request.max_sequence_length is not None: + options["max_sequence_length"] = request.max_sequence_length + if request.image_height is not None: + options["image_height"] = request.image_height + if request.image_width is not None: + options["image_width"] = request.image_width + if request.video_num_frames is not None: + options["video_num_frames"] = request.video_num_frames + if request.quantization is not None: + options["quantization"] = request.quantization + if request.fp32_layers: + options["fp32_layers"] = list(request.fp32_layers) + return { + "format": 1, + "checkpoint": { + "id": request.checkpoint_id or str(request.model_dir.resolve()), + "revision": request.checkpoint_revision or "unknown", + }, + "build": {"source_revision": resolve_source_revision(request.source_revision)}, + "request": options, + } diff --git a/core/builder/tensorrt_model_connect/build_cli.py b/core/builder/tensorrt_model_connect/build_cli.py index 9042a68320..31adc82fe0 100644 --- a/core/builder/tensorrt_model_connect/build_cli.py +++ b/core/builder/tensorrt_model_connect/build_cli.py @@ -7,13 +7,17 @@ import argparse import json +import re from pathlib import Path from typing import Sequence -from .build import BuildRequest, _load_family, build +from .build import BuildRequest, _load_family, build, resolve_source_revision from .model_support import load_model_metadata, resolve_family +_EXACT_REVISION = re.compile(r"[0-9a-f]{40}\Z") + + def _parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(prog="trtmc") commands = parser.add_subparsers(dest="command", required=True) @@ -21,6 +25,10 @@ def _parser() -> argparse.ArgumentParser: build_parser.add_argument("model", help="Hugging Face model ID or local snapshot") build_parser.add_argument("-o", "--output", type=Path, required=True) build_parser.add_argument("--task", help="Override the family-owned default task") + build_parser.add_argument( + "--checkpoint-id", + help="Canonical checkpoint ID when MODEL is an already-resolved local snapshot", + ) build_parser.add_argument("--revision", help="Hugging Face model revision") build_parser.add_argument("--precision", choices=("fp16", "bf16", "fp32")) build_parser.add_argument("--backend", choices=("trt", "trt_rtx"), default="trt") @@ -68,6 +76,12 @@ def main(argv: Sequence[str] | None = None) -> int: return 0 if args.command != "build": raise AssertionError(f"unhandled command: {args.command}") + source_is_local = Path(args.model).is_dir() + checkpoint_revision = _checkpoint_revision( + model_dir, + requested=args.revision, + require_exact=not source_is_local, + ) task = args.task or support.default_task if task not in support.tasks: raise ValueError( @@ -78,6 +92,9 @@ def main(argv: Sequence[str] | None = None) -> int: BuildRequest( model_dir=model_dir, output_path=args.output, + checkpoint_id=args.checkpoint_id or args.model, + checkpoint_revision=checkpoint_revision, + source_revision=_source_revision(), precision=args.precision or support.default_precision, backend=args.backend, family=family, @@ -108,3 +125,23 @@ def _resolve_model(model: str, revision: str | None) -> Path: from huggingface_hub import snapshot_download return Path(snapshot_download(repo_id=model, revision=revision)) + + +def _checkpoint_revision( + model_dir: Path, *, requested: str | None, require_exact: bool +) -> str: + resolved = model_dir.name.lower() if model_dir.parent.name == "snapshots" else "" + if _EXACT_REVISION.fullmatch(resolved): + return resolved + requested = (requested or "").strip().lower() + if _EXACT_REVISION.fullmatch(requested): + return requested + if require_exact: + raise ValueError( + "Hugging Face model resolution did not produce an exact 40-character commit SHA" + ) + return requested + + +def _source_revision() -> str: + return resolve_source_revision() diff --git a/core/builder/tensorrt_model_connect/bundle_writer.py b/core/builder/tensorrt_model_connect/bundle_writer.py index fc0944d807..b9205c9338 100644 --- a/core/builder/tensorrt_model_connect/bundle_writer.py +++ b/core/builder/tensorrt_model_connect/bundle_writer.py @@ -38,6 +38,48 @@ def _validate_nonempty_string(field: str, value: object) -> str: return value +def read_bundle_section(path: str | Path, name: str) -> bytes: + """Read one named section from a validated bundle file.""" + + bundle_path = Path(path) + with bundle_path.open("rb") as bundle: + if bundle.read(len(BUNDLE_MAGIC)) != BUNDLE_MAGIC: + raise ValueError(f"{bundle_path} is not a TRTMC bundle") + raw_header_size = bundle.read(8) + if len(raw_header_size) != 8: + raise ValueError(f"{bundle_path} has a truncated header size") + header_size = struct.unpack(" _MAX_HEADER_SIZE: + raise ValueError(f"{bundle_path} header exceeds the size limit") + raw_header = bundle.read(header_size) + if len(raw_header) != header_size: + raise ValueError(f"{bundle_path} has a truncated header") + header = json.loads(raw_header) + sections = header.get("sections") if isinstance(header, dict) else None + location = sections.get(name) if isinstance(sections, dict) else None + if not isinstance(location, dict): + raise ValueError(f"{bundle_path} has no {name!r} section") + offset = location.get("offset") + length = location.get("length") + if not isinstance(offset, int) or not isinstance(length, int): + raise ValueError(f"{bundle_path} has an invalid {name!r} section") + data_start = len(BUNDLE_MAGIC) + 8 + header_size + file_size = bundle_path.stat().st_size + if offset < 0 or length < 0 or data_start + offset + length > file_size: + raise ValueError(f"{bundle_path} has an invalid {name!r} section range") + bundle.seek(data_start + offset) + data = bundle.read(length) + if len(data) != length: + raise ValueError(f"{bundle_path} has a truncated {name!r} section") + return data + + +def read_bundle_json(path: str | Path, name: str) -> Any: + """Read one named JSON section from a validated bundle file.""" + + return json.loads(read_bundle_section(path, name).decode("utf-8")) + + class BundleWriter: """Stage named sections and atomically publish one bundle.""" diff --git a/core/builder/tests/test_build.py b/core/builder/tests/test_build.py index 5eff69de1b..bd53425fff 100644 --- a/core/builder/tests/test_build.py +++ b/core/builder/tests/test_build.py @@ -4,6 +4,8 @@ from __future__ import annotations import importlib +import json +import struct import sys from dataclasses import FrozenInstanceError, replace from pathlib import Path @@ -57,6 +59,8 @@ def test_build_request_is_a_plain_frozen_dataclass(tmp_path: Path) -> None: ("dynamic_kv_cache", 1), ("graph_transform", object()), ("backend", "unknown"), + ("checkpoint_revision", "main"), + ("source_revision", "dirty"), ], ) def test_build_request_rejects_invalid_direct_inputs( @@ -167,6 +171,9 @@ def __init__(self, destination: Path) -> None: def finish(self) -> None: events.append("finish") + def add_json(self, _name: str, _value: object) -> None: + pass + def abort(self) -> None: events.append("abort") @@ -185,6 +192,65 @@ def family_build(request: BuildRequest, writer: FakeWriter) -> None: assert events[2:] == ["finish"] +def test_build_embeds_checkpoint_and_source_provenance(monkeypatch, tmp_path: Path) -> None: + checkpoint_revision = "b" * 40 + source_revision = "a" * 40 + request = BuildRequest( + model_dir=tmp_path / "model", + output_path=tmp_path / "model.bundle", + checkpoint_id="openai-community/gpt2", + checkpoint_revision=checkpoint_revision, + source_revision=source_revision, + precision="fp16", + family="gpt2", + task="text_generation", + max_sequence_length=128, + ) + + def family_build(seen_request: BuildRequest, writer) -> None: + writer.set_header( + family=seen_request.family, + task=seen_request.task, + backend=seen_request.backend, + ) + writer.add_bytes("engine.plan", b"plan") + + monkeypatch.setattr( + build_core, + "_load_family", + lambda _family: SimpleNamespace(build=family_build), + ) + + build_core.build(request) + + data = request.output_path.read_bytes() + header_size = struct.unpack_from(" None: @@ -208,6 +274,9 @@ def __init__(self, _destination: Path) -> None: def finish(self) -> None: events.append("finish") + def add_json(self, _name: str, _value: object) -> None: + pass + def abort(self) -> None: events.append("abort") @@ -274,6 +343,9 @@ def finish(self) -> None: events.append("finish") raise OSError("publish failed") + def add_json(self, _name: str, _value: object) -> None: + pass + def abort(self) -> None: events.append("abort") diff --git a/core/builder/tests/test_build_cli.py b/core/builder/tests/test_build_cli.py index e082ff1ddc..c14a63892e 100644 --- a/core/builder/tests/test_build_cli.py +++ b/core/builder/tests/test_build_cli.py @@ -5,6 +5,7 @@ import json import sys +import subprocess from pathlib import Path from types import SimpleNamespace @@ -111,6 +112,98 @@ def snapshot_download(**kwargs): assert calls == [{"repo_id": "openai-community/gpt2", "revision": "revision-1"}] +def test_build_command_preserves_resolved_checkpoint_and_source_revisions( + monkeypatch, tmp_path: Path +) -> None: + checkpoint_revision = "b" * 40 + source_revision = "a" * 40 + snapshot = tmp_path / "models--openai-community--gpt2" / "snapshots" / checkpoint_revision + snapshot.mkdir(parents=True) + (snapshot / "config.json").write_text('{"model_type":"gpt2"}', encoding="utf-8") + captured = [] + + monkeypatch.setitem( + sys.modules, + "huggingface_hub", + SimpleNamespace(snapshot_download=lambda **_kwargs: str(snapshot)), + ) + monkeypatch.setenv("TRTMC_ENGINE_BUILD_REVISION", source_revision) + monkeypatch.setattr(build_cli, "build", captured.append) + + assert ( + build_cli.main( + [ + "build", + "openai-community/gpt2", + "--revision", + "main", + "--output", + str(tmp_path / "out.bundle"), + ] + ) + == 0 + ) + request = captured[0] + assert request.model_dir == snapshot + assert request.checkpoint_id == "openai-community/gpt2" + assert request.checkpoint_revision == checkpoint_revision + assert request.source_revision == source_revision + + +def test_local_snapshot_can_preserve_a_canonical_checkpoint_id( + monkeypatch, tmp_path: Path +) -> None: + checkpoint_revision = "b" * 40 + source_revision = "a" * 40 + snapshot = tmp_path / "downloaded-checkpoint" + snapshot.mkdir() + (snapshot / "config.json").write_text('{"model_type":"gpt2"}', encoding="utf-8") + captured = [] + + monkeypatch.setenv("TRTMC_ENGINE_BUILD_REVISION", source_revision) + monkeypatch.setattr(build_cli, "build", captured.append) + + assert ( + build_cli.main( + [ + "build", + str(snapshot), + "--checkpoint-id", + "openai-community/gpt2", + "--revision", + checkpoint_revision, + "--output", + str(tmp_path / "out.bundle"), + ] + ) + == 0 + ) + request = captured[0] + assert request.model_dir == snapshot + assert request.checkpoint_id == "openai-community/gpt2" + assert request.checkpoint_revision == checkpoint_revision + + +def test_build_command_derives_source_revision_from_the_checkout( + monkeypatch, tmp_path: Path +) -> None: + model = tmp_path / "model" + model.mkdir() + (model / "config.json").write_text('{"model_type":"gpt2"}', encoding="utf-8") + captured = [] + monkeypatch.delenv("TRTMC_ENGINE_BUILD_REVISION", raising=False) + monkeypatch.delenv("GITHUB_SHA", raising=False) + monkeypatch.setattr(build_cli, "build", captured.append) + + assert build_cli.main(["build", str(model), "-o", str(tmp_path / "out.bundle")]) == 0 + + repository = Path(__file__).resolve().parents[3] + expected = subprocess.check_output( + ["git", "-C", str(repository), "rev-parse", "HEAD"], text=True + ).strip() + assert captured[0].source_revision == expected + + def test_build_command_rejects_a_task_the_family_does_not_own(monkeypatch, tmp_path: Path) -> None: model = tmp_path / "model" model.mkdir() diff --git a/families/albert/tests/manifests/albert-base-tp4.json b/families/albert/tests/manifests/albert-base-tp4.json index 1fa5a71222..48a9347c90 100644 --- a/families/albert/tests/manifests/albert-base-tp4.json +++ b/families/albert/tests/manifests/albert-base-tp4.json @@ -1,6 +1,7 @@ { "name": "albert-base-tp4", "hf_id": "albert/albert-base-v2", + "hf_revision": "8e2f239c5f8a2c0f253781ca60135db913e5c80c", "bundle": "albert-base-tp4.bundle", "family": "albert", "task": "encoding", diff --git a/families/albert/tests/manifests/albert-base.json b/families/albert/tests/manifests/albert-base.json index 502967ad9e..e2844e8c49 100644 --- a/families/albert/tests/manifests/albert-base.json +++ b/families/albert/tests/manifests/albert-base.json @@ -1,6 +1,7 @@ { "name": "albert-base", "hf_id": "albert/albert-base-v2", + "hf_revision": "8e2f239c5f8a2c0f253781ca60135db913e5c80c", "bundle": "albert-base.bundle", "family": "albert", "task": "encoding", diff --git a/families/bark/requirements.txt b/families/bark/requirements.txt index 2007a85cf3..53f256ec77 100644 --- a/families/bark/requirements.txt +++ b/families/bark/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -librosa -soundfile +librosa==0.11.0 +soundfile==0.14.0 diff --git a/families/bark/tests/manifests/bark-large-tp4.json b/families/bark/tests/manifests/bark-large-tp4.json index 9d7fbec9ae..6a13efefb9 100644 --- a/families/bark/tests/manifests/bark-large-tp4.json +++ b/families/bark/tests/manifests/bark-large-tp4.json @@ -1,6 +1,7 @@ { "name": "bark-large-tp4", "hf_id": "suno/bark", + "hf_revision": "70a8a7d34168586dc5d028fa9666aceade177992", "hf_dependencies": [ { "repo_id": "openai/whisper-large-v3-turbo" diff --git a/families/bark/tests/manifests/bark-large.json b/families/bark/tests/manifests/bark-large.json index acd7a90aa9..152f37c9f2 100644 --- a/families/bark/tests/manifests/bark-large.json +++ b/families/bark/tests/manifests/bark-large.json @@ -1,6 +1,7 @@ { "name": "bark-large", "hf_id": "suno/bark", + "hf_revision": "70a8a7d34168586dc5d028fa9666aceade177992", "hf_dependencies": [ { "repo_id": "openai/whisper-large-v3-turbo" diff --git a/families/bark/tests/manifests/bark-small-fp32-l0.json b/families/bark/tests/manifests/bark-small-fp32-l0.json index 8309e0cabd..7576938f34 100644 --- a/families/bark/tests/manifests/bark-small-fp32-l0.json +++ b/families/bark/tests/manifests/bark-small-fp32-l0.json @@ -1,6 +1,7 @@ { "name": "bark-small-fp32-l0", "hf_id": "suno/bark-small", + "hf_revision": "1dbd7a128513b8ae4a4e2130fed57b7ac9da5bcd", "hf_dependencies": [ { "repo_id": "openai/whisper-large-v3-turbo" diff --git a/families/bark/tests/manifests/bark-small-tp4.json b/families/bark/tests/manifests/bark-small-tp4.json index 5a13647f49..82e9ad8bac 100644 --- a/families/bark/tests/manifests/bark-small-tp4.json +++ b/families/bark/tests/manifests/bark-small-tp4.json @@ -1,6 +1,7 @@ { "name": "bark-small-tp4", "hf_id": "suno/bark-small", + "hf_revision": "1dbd7a128513b8ae4a4e2130fed57b7ac9da5bcd", "hf_dependencies": [ { "repo_id": "openai/whisper-large-v3-turbo" diff --git a/families/bark/tests/manifests/bark-small.json b/families/bark/tests/manifests/bark-small.json index 13f0992466..608d290ef1 100644 --- a/families/bark/tests/manifests/bark-small.json +++ b/families/bark/tests/manifests/bark-small.json @@ -1,6 +1,7 @@ { "name": "bark-small", "hf_id": "suno/bark-small", + "hf_revision": "1dbd7a128513b8ae4a4e2130fed57b7ac9da5bcd", "hf_dependencies": [ { "repo_id": "openai/whisper-large-v3-turbo" diff --git a/families/bart/tests/manifests/bart-base-tp4.json b/families/bart/tests/manifests/bart-base-tp4.json index eea3667128..21ed5541b3 100644 --- a/families/bart/tests/manifests/bart-base-tp4.json +++ b/families/bart/tests/manifests/bart-base-tp4.json @@ -1,6 +1,7 @@ { "name": "bart-base-tp4", "hf_id": "facebook/bart-base", + "hf_revision": "aadd2ab0ae0c8268c7c9693540e9904811f36177", "bundle": "bart-base-tp4.bundle", "family": "bart", "task": "text_generation", diff --git a/families/bart/tests/manifests/bart-base.json b/families/bart/tests/manifests/bart-base.json index a2292f1c3e..448a47e840 100644 --- a/families/bart/tests/manifests/bart-base.json +++ b/families/bart/tests/manifests/bart-base.json @@ -1,6 +1,7 @@ { "name": "bart-base", "hf_id": "facebook/bart-base", + "hf_revision": "aadd2ab0ae0c8268c7c9693540e9904811f36177", "bundle": "bart-base.bundle", "family": "bart", "task": "text_generation", diff --git a/families/bert/tests/manifests/all-minilm-l6-v2.json b/families/bert/tests/manifests/all-minilm-l6-v2.json index 878b4fa764..0ea98a29a2 100644 --- a/families/bert/tests/manifests/all-minilm-l6-v2.json +++ b/families/bert/tests/manifests/all-minilm-l6-v2.json @@ -1,6 +1,7 @@ { "name": "all-minilm-l6-v2", "hf_id": "sentence-transformers/all-MiniLM-L6-v2", + "hf_revision": "1110a243fdf4706b3f48f1d95db1a4f5529b4d41", "bundle": "all-minilm-l6-v2.bundle", "family": "bert", "task": "embedding", diff --git a/families/bert/tests/manifests/bert-base-uncased-tp4.json b/families/bert/tests/manifests/bert-base-uncased-tp4.json index abc04d0d46..a494eebc04 100644 --- a/families/bert/tests/manifests/bert-base-uncased-tp4.json +++ b/families/bert/tests/manifests/bert-base-uncased-tp4.json @@ -1,6 +1,7 @@ { "name": "bert-base-uncased-tp4", "hf_id": "google-bert/bert-base-uncased", + "hf_revision": "86b5e0934494bd15c9632b12f734a8a67f723594", "bundle": "bert-base-uncased-tp4.bundle", "family": "bert", "task": "encoding", diff --git a/families/bert/tests/manifests/bert-base-uncased.json b/families/bert/tests/manifests/bert-base-uncased.json index ed84fa7a8f..e2cf871005 100644 --- a/families/bert/tests/manifests/bert-base-uncased.json +++ b/families/bert/tests/manifests/bert-base-uncased.json @@ -1,6 +1,7 @@ { "name": "bert-base-uncased", "hf_id": "google-bert/bert-base-uncased", + "hf_revision": "86b5e0934494bd15c9632b12f734a8a67f723594", "bundle": "bert-base-uncased.bundle", "family": "bert", "task": "encoding", diff --git a/families/bert/tests/manifests/bge-small-en-v1.5.json b/families/bert/tests/manifests/bge-small-en-v1.5.json index 3c627e4ef3..c661c17af9 100644 --- a/families/bert/tests/manifests/bge-small-en-v1.5.json +++ b/families/bert/tests/manifests/bge-small-en-v1.5.json @@ -1,6 +1,7 @@ { "name": "bge-small-en-v1.5", "hf_id": "BAAI/bge-small-en-v1.5", + "hf_revision": "5c38ec7c405ec4b44b94cc5a9bb96e735b38267a", "bundle": "bge-small-en-v1.5.bundle", "family": "bert", "task": "encoding", diff --git a/families/bert/tests/manifests/paraphrase-multilingual-minilm-l12-v2.json b/families/bert/tests/manifests/paraphrase-multilingual-minilm-l12-v2.json index 28d80c17c1..5ff79514ed 100644 --- a/families/bert/tests/manifests/paraphrase-multilingual-minilm-l12-v2.json +++ b/families/bert/tests/manifests/paraphrase-multilingual-minilm-l12-v2.json @@ -1,6 +1,7 @@ { "name": "paraphrase-multilingual-minilm-l12-v2", "hf_id": "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2", + "hf_revision": "e8f8c211226b894fcb81acc59f3b34ba3efd5f42", "bundle": "paraphrase-multilingual-minilm-l12-v2.bundle", "family": "bert", "task": "encoding", diff --git a/families/bloom/tests/manifests/bloom-560m-tp4.json b/families/bloom/tests/manifests/bloom-560m-tp4.json index 6b2bd0209d..0593c87002 100644 --- a/families/bloom/tests/manifests/bloom-560m-tp4.json +++ b/families/bloom/tests/manifests/bloom-560m-tp4.json @@ -1,6 +1,7 @@ { "name": "bloom-560m-tp4", "hf_id": "bigscience/bloom-560m", + "hf_revision": "ac2ae5fab2ce3f9f40dc79b5ca9f637430d24971", "bundle": "bloom-560m-tp4.bundle", "family": "bloom", "task": "text_generation", diff --git a/families/bloom/tests/manifests/bloom-560m.json b/families/bloom/tests/manifests/bloom-560m.json index 97718536bb..150c140077 100644 --- a/families/bloom/tests/manifests/bloom-560m.json +++ b/families/bloom/tests/manifests/bloom-560m.json @@ -1,6 +1,7 @@ { "name": "bloom-560m", "hf_id": "bigscience/bloom-560m", + "hf_revision": "ac2ae5fab2ce3f9f40dc79b5ca9f637430d24971", "bundle": "bloom-560m.bundle", "family": "bloom", "task": "text_generation", diff --git a/families/canary/tests/manifests/canary-1b-v2-tp4.json b/families/canary/tests/manifests/canary-1b-v2-tp4.json index a47532fcfa..e648668d2d 100644 --- a/families/canary/tests/manifests/canary-1b-v2-tp4.json +++ b/families/canary/tests/manifests/canary-1b-v2-tp4.json @@ -1,6 +1,7 @@ { "name": "canary-1b-v2-tp4", "hf_id": "nvidia/canary-1b-v2", + "hf_revision": "d455706339a6b32e1aa40f82c713a482a0c938e2", "bundle": "canary-1b-v2-tp4.bundle", "family": "canary", "task": "transcription", diff --git a/families/canary/tests/manifests/canary-1b-v2.json b/families/canary/tests/manifests/canary-1b-v2.json index 647984017b..6e512489b5 100644 --- a/families/canary/tests/manifests/canary-1b-v2.json +++ b/families/canary/tests/manifests/canary-1b-v2.json @@ -1,6 +1,7 @@ { "name": "canary-1b-v2", "hf_id": "nvidia/canary-1b-v2", + "hf_revision": "d455706339a6b32e1aa40f82c713a482a0c938e2", "bundle": "canary-1b-v2.bundle", "family": "canary", "task": "transcription", diff --git a/families/chronos_bolt/tests/manifests/chronos-bolt-tiny-official-tp4.json b/families/chronos_bolt/tests/manifests/chronos-bolt-tiny-official-tp4.json index e9304d180e..2f974ad1eb 100644 --- a/families/chronos_bolt/tests/manifests/chronos-bolt-tiny-official-tp4.json +++ b/families/chronos_bolt/tests/manifests/chronos-bolt-tiny-official-tp4.json @@ -1,6 +1,7 @@ { "name": "chronos-bolt-tiny-official-tp4", "hf_id": "amazon/chronos-bolt-tiny", + "hf_revision": "a0e552de83495b5c28c14c71c374f3e33280b340", "bundle": "chronos-bolt-tiny-official-tp4.bundle", "family": "chronos_bolt", "task": "time_series_forecast", diff --git a/families/chronos_bolt/tests/manifests/chronos-bolt-tiny-official.json b/families/chronos_bolt/tests/manifests/chronos-bolt-tiny-official.json index 37a6972786..f84d03bc93 100644 --- a/families/chronos_bolt/tests/manifests/chronos-bolt-tiny-official.json +++ b/families/chronos_bolt/tests/manifests/chronos-bolt-tiny-official.json @@ -1,6 +1,7 @@ { "name": "chronos-bolt-tiny-official", "hf_id": "amazon/chronos-bolt-tiny", + "hf_revision": "a0e552de83495b5c28c14c71c374f3e33280b340", "bundle": "chronos-bolt-tiny-official.bundle", "family": "chronos_bolt", "task": "time_series_forecast", diff --git a/families/codegen/tests/manifests/codegen-350m-tp4.json b/families/codegen/tests/manifests/codegen-350m-tp4.json index 3a728e8d92..64813873f3 100644 --- a/families/codegen/tests/manifests/codegen-350m-tp4.json +++ b/families/codegen/tests/manifests/codegen-350m-tp4.json @@ -1,6 +1,7 @@ { "name": "codegen-350m-tp4", "hf_id": "Salesforce/codegen-350M-mono", + "hf_revision": "d9107f71cca463240db1143f4a75a927a27fcb27", "bundle": "codegen-350m-tp4.bundle", "family": "codegen", "task": "text_generation", diff --git a/families/codegen/tests/manifests/codegen-350m.json b/families/codegen/tests/manifests/codegen-350m.json index fbe0d09c8a..6a62606f66 100644 --- a/families/codegen/tests/manifests/codegen-350m.json +++ b/families/codegen/tests/manifests/codegen-350m.json @@ -1,6 +1,7 @@ { "name": "codegen-350m", "hf_id": "Salesforce/codegen-350M-mono", + "hf_revision": "d9107f71cca463240db1143f4a75a927a27fcb27", "bundle": "codegen-350m.bundle", "family": "codegen", "task": "text_generation", diff --git a/families/convbert/tests/manifests/convbert-base-tp2.json b/families/convbert/tests/manifests/convbert-base-tp2.json index 97dbee4319..f98f15d575 100644 --- a/families/convbert/tests/manifests/convbert-base-tp2.json +++ b/families/convbert/tests/manifests/convbert-base-tp2.json @@ -1,6 +1,7 @@ { "name": "convbert-base-tp2", "hf_id": "YituTech/conv-bert-base", + "hf_revision": "5cb451936b5c4a96562d8b146de85f64f9cf2c22", "bundle": "convbert-base-tp2.bundle", "family": "convbert", "task": "encoding", diff --git a/families/convbert/tests/manifests/convbert-base.json b/families/convbert/tests/manifests/convbert-base.json index 4ec80bc2d3..88d1098fff 100644 --- a/families/convbert/tests/manifests/convbert-base.json +++ b/families/convbert/tests/manifests/convbert-base.json @@ -1,6 +1,7 @@ { "name": "convbert-base", "hf_id": "YituTech/conv-bert-base", + "hf_revision": "5cb451936b5c4a96562d8b146de85f64f9cf2c22", "bundle": "convbert-base.bundle", "family": "convbert", "task": "encoding", diff --git a/families/cosmos3/requirements.txt b/families/cosmos3/requirements.txt index 5018e40516..23dcd0beee 100644 --- a/families/cosmos3/requirements.txt +++ b/families/cosmos3/requirements.txt @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 diff --git a/families/deberta/tests/manifests/deberta-base-tp4.json b/families/deberta/tests/manifests/deberta-base-tp4.json index 7c86417e6f..41df1be4c5 100644 --- a/families/deberta/tests/manifests/deberta-base-tp4.json +++ b/families/deberta/tests/manifests/deberta-base-tp4.json @@ -1,6 +1,7 @@ { "name": "deberta-base-tp4", "hf_id": "microsoft/deberta-base", + "hf_revision": "0d1b43ccf21b5acd9f4e5f7b077fa698f05cf195", "bundle": "deberta-base-tp4.bundle", "family": "deberta", "task": "encoding", diff --git a/families/deberta/tests/manifests/deberta-base.json b/families/deberta/tests/manifests/deberta-base.json index 0ca5d78038..3ba4080434 100644 --- a/families/deberta/tests/manifests/deberta-base.json +++ b/families/deberta/tests/manifests/deberta-base.json @@ -1,6 +1,7 @@ { "name": "deberta-base", "hf_id": "microsoft/deberta-base", + "hf_revision": "0d1b43ccf21b5acd9f4e5f7b077fa698f05cf195", "bundle": "deberta-base.bundle", "family": "deberta", "task": "encoding", diff --git a/families/deepseek_ocr/requirements.txt b/families/deepseek_ocr/requirements.txt index 7d12c4bc74..9af32793ac 100644 --- a/families/deepseek_ocr/requirements.txt +++ b/families/deepseek_ocr/requirements.txt @@ -1,10 +1,10 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 # Required by the checkpoint's trust_remote_code reference. addict==2.4.0 easydict==1.13 einops==0.8.1 -scipy +scipy==1.12.0 transformers==4.46.3 diff --git a/families/deepseek_ocr/tests/manifests/deepseek-ocr-l0-tp2.json b/families/deepseek_ocr/tests/manifests/deepseek-ocr-l0-tp2.json index a21db9687b..64609e138a 100644 --- a/families/deepseek_ocr/tests/manifests/deepseek-ocr-l0-tp2.json +++ b/families/deepseek_ocr/tests/manifests/deepseek-ocr-l0-tp2.json @@ -1,6 +1,7 @@ { "name": "deepseek-ocr-l0-tp2", "hf_id": "deepseek-ai/DeepSeek-OCR-2", + "hf_revision": "aaa02f3811945a91062062994c5c4a3f4c0af2b0", "bundle": "deepseek-ocr-l0-tp2.bundle", "family": "deepseek_ocr", "task": "vision_language_generation", diff --git a/families/deepseek_ocr/tests/manifests/deepseek-ocr-l0.json b/families/deepseek_ocr/tests/manifests/deepseek-ocr-l0.json index f394f8108b..5a48aa7bc2 100644 --- a/families/deepseek_ocr/tests/manifests/deepseek-ocr-l0.json +++ b/families/deepseek_ocr/tests/manifests/deepseek-ocr-l0.json @@ -1,6 +1,7 @@ { "name": "deepseek-ocr-l0", "hf_id": "deepseek-ai/DeepSeek-OCR-2", + "hf_revision": "aaa02f3811945a91062062994c5c4a3f4c0af2b0", "bundle": "deepseek-ocr-l0.bundle", "family": "deepseek_ocr", "task": "vision_language_generation", diff --git a/families/deepseek_ocr/tests/manifests/deepseek-ocr.json b/families/deepseek_ocr/tests/manifests/deepseek-ocr.json index c8aeb5c367..4b26041618 100644 --- a/families/deepseek_ocr/tests/manifests/deepseek-ocr.json +++ b/families/deepseek_ocr/tests/manifests/deepseek-ocr.json @@ -1,6 +1,7 @@ { "name": "deepseek-ocr", "hf_id": "deepseek-ai/DeepSeek-OCR-2", + "hf_revision": "aaa02f3811945a91062062994c5c4a3f4c0af2b0", "bundle": "deepseek-ocr.bundle", "family": "deepseek_ocr", "task": "vision_language_generation", diff --git a/families/deepseek_v2/tests/manifests/deepseek-v2-lite-tp4.json b/families/deepseek_v2/tests/manifests/deepseek-v2-lite-tp4.json index 6df12b727e..7da83d5049 100644 --- a/families/deepseek_v2/tests/manifests/deepseek-v2-lite-tp4.json +++ b/families/deepseek_v2/tests/manifests/deepseek-v2-lite-tp4.json @@ -1,6 +1,7 @@ { "name": "deepseek-v2-lite-tp4", "hf_id": "deepseek-ai/DeepSeek-V2-Lite", + "hf_revision": "604d5664dddd88a0433dbae533b7fe9472482de0", "bundle": "deepseek-v2-lite-tp4.bundle", "family": "deepseek_v2", "task": "text_generation", diff --git a/families/deepseek_v2/tests/manifests/deepseek-v2-lite.json b/families/deepseek_v2/tests/manifests/deepseek-v2-lite.json index e1360588b0..369db36d4e 100644 --- a/families/deepseek_v2/tests/manifests/deepseek-v2-lite.json +++ b/families/deepseek_v2/tests/manifests/deepseek-v2-lite.json @@ -1,6 +1,7 @@ { "name": "deepseek-v2-lite", "hf_id": "deepseek-ai/DeepSeek-V2-Lite", + "hf_revision": "604d5664dddd88a0433dbae533b7fe9472482de0", "bundle": "deepseek-v2-lite.bundle", "family": "deepseek_v2", "task": "text_generation", diff --git a/families/dinov3/requirements.txt b/families/dinov3/requirements.txt index 718a93c119..f75edd6685 100644 --- a/families/dinov3/requirements.txt +++ b/families/dinov3/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow -timm>=1.0 +Pillow==12.2.0 +timm==1.0.28 diff --git a/families/distilbert/tests/manifests/distilbert-base-uncased-tp4.json b/families/distilbert/tests/manifests/distilbert-base-uncased-tp4.json index 739910423e..b9682a9d26 100644 --- a/families/distilbert/tests/manifests/distilbert-base-uncased-tp4.json +++ b/families/distilbert/tests/manifests/distilbert-base-uncased-tp4.json @@ -1,6 +1,7 @@ { "name": "distilbert-base-uncased-tp4", "hf_id": "distilbert/distilbert-base-uncased", + "hf_revision": "12040accade4e8a0f71eabdb258fecc2e7e948be", "bundle": "distilbert-base-uncased-tp4.bundle", "family": "distilbert", "task": "encoding", diff --git a/families/distilbert/tests/manifests/distilbert-base-uncased.json b/families/distilbert/tests/manifests/distilbert-base-uncased.json index 2bf9cb6198..105094ba96 100644 --- a/families/distilbert/tests/manifests/distilbert-base-uncased.json +++ b/families/distilbert/tests/manifests/distilbert-base-uncased.json @@ -1,6 +1,7 @@ { "name": "distilbert-base-uncased", "hf_id": "distilbert/distilbert-base-uncased", + "hf_revision": "12040accade4e8a0f71eabdb258fecc2e7e948be", "bundle": "distilbert-base-uncased.bundle", "family": "distilbert", "task": "encoding", diff --git a/families/dpr/tests/manifests/dpr-ctx-encoder-tp4.json b/families/dpr/tests/manifests/dpr-ctx-encoder-tp4.json index 8677e6d3ca..b7402e05ca 100644 --- a/families/dpr/tests/manifests/dpr-ctx-encoder-tp4.json +++ b/families/dpr/tests/manifests/dpr-ctx-encoder-tp4.json @@ -1,6 +1,7 @@ { "name": "dpr-ctx-encoder-tp4", "hf_id": "facebook/dpr-ctx_encoder-single-nq-base", + "hf_revision": "bb21a3c2b1656d60c6a8e920283bc40dabddadb8", "bundle": "dpr-ctx-encoder-tp4.bundle", "family": "dpr", "task": "encoding", diff --git a/families/dpr/tests/manifests/dpr-ctx-encoder.json b/families/dpr/tests/manifests/dpr-ctx-encoder.json index 204de7576e..ecbe45d6d5 100644 --- a/families/dpr/tests/manifests/dpr-ctx-encoder.json +++ b/families/dpr/tests/manifests/dpr-ctx-encoder.json @@ -1,6 +1,7 @@ { "name": "dpr-ctx-encoder", "hf_id": "facebook/dpr-ctx_encoder-single-nq-base", + "hf_revision": "bb21a3c2b1656d60c6a8e920283bc40dabddadb8", "bundle": "dpr-ctx-encoder.bundle", "family": "dpr", "task": "encoding", diff --git a/families/eagle_vlm/tests/manifests/nemotron-embed-vl-1b-v2-tp4.json b/families/eagle_vlm/tests/manifests/nemotron-embed-vl-1b-v2-tp4.json index c4c1247116..575bbba8fc 100644 --- a/families/eagle_vlm/tests/manifests/nemotron-embed-vl-1b-v2-tp4.json +++ b/families/eagle_vlm/tests/manifests/nemotron-embed-vl-1b-v2-tp4.json @@ -1,6 +1,7 @@ { "name": "nemotron-embed-vl-1b-v2-tp4", "hf_id": "nvidia/llama-nemotron-embed-vl-1b-v2", + "hf_revision": "582e3bf72aee355e3c59ed89de53543c5b0657ee", "bundle": "nemotron-embed-vl-1b-v2-tp4.bundle", "family": "eagle_vlm", "task": "embedding", diff --git a/families/eagle_vlm/tests/manifests/nemotron-embed-vl-1b-v2.json b/families/eagle_vlm/tests/manifests/nemotron-embed-vl-1b-v2.json index 24083d4f17..802f6a564c 100644 --- a/families/eagle_vlm/tests/manifests/nemotron-embed-vl-1b-v2.json +++ b/families/eagle_vlm/tests/manifests/nemotron-embed-vl-1b-v2.json @@ -1,6 +1,7 @@ { "name": "nemotron-embed-vl-1b-v2", "hf_id": "nvidia/llama-nemotron-embed-vl-1b-v2", + "hf_revision": "582e3bf72aee355e3c59ed89de53543c5b0657ee", "bundle": "nemotron-embed-vl-1b-v2.bundle", "family": "eagle_vlm", "task": "embedding", diff --git a/families/eagle_vlm/tests/manifests/nemotron-rerank-vl-1b-v2-tp4.json b/families/eagle_vlm/tests/manifests/nemotron-rerank-vl-1b-v2-tp4.json index 3668fd89a1..910a2530f8 100644 --- a/families/eagle_vlm/tests/manifests/nemotron-rerank-vl-1b-v2-tp4.json +++ b/families/eagle_vlm/tests/manifests/nemotron-rerank-vl-1b-v2-tp4.json @@ -1,6 +1,7 @@ { "name": "nemotron-rerank-vl-1b-v2-tp4", "hf_id": "nvidia/llama-nemotron-rerank-vl-1b-v2", + "hf_revision": "9e95da054312436dfc703319dd2b793a3bee2465", "bundle": "nemotron-rerank-vl-1b-v2-tp4.bundle", "family": "eagle_vlm", "task": "reranking", diff --git a/families/electra/tests/manifests/electra-base-discriminator-tp4.json b/families/electra/tests/manifests/electra-base-discriminator-tp4.json index e07f06af67..a54159413d 100644 --- a/families/electra/tests/manifests/electra-base-discriminator-tp4.json +++ b/families/electra/tests/manifests/electra-base-discriminator-tp4.json @@ -1,6 +1,7 @@ { "name": "electra-base-discriminator-tp4", "hf_id": "google/electra-base-discriminator", + "hf_revision": "1ae76a97c7e84a4e640876a07453fccd636f0667", "bundle": "electra-base-discriminator-tp4.bundle", "family": "electra", "task": "encoding", diff --git a/families/electra/tests/manifests/electra-base-discriminator.json b/families/electra/tests/manifests/electra-base-discriminator.json index c62c273838..d4ac3ead2a 100644 --- a/families/electra/tests/manifests/electra-base-discriminator.json +++ b/families/electra/tests/manifests/electra-base-discriminator.json @@ -1,6 +1,7 @@ { "name": "electra-base-discriminator", "hf_id": "google/electra-base-discriminator", + "hf_revision": "1ae76a97c7e84a4e640876a07453fccd636f0667", "bundle": "electra-base-discriminator.bundle", "family": "electra", "task": "encoding", diff --git a/families/elf_flow/tests/manifests/elf-b-de-en-l0.json b/families/elf_flow/tests/manifests/elf-b-de-en-l0.json index 4c85d22a7b..cc06ac1ec0 100644 --- a/families/elf_flow/tests/manifests/elf-b-de-en-l0.json +++ b/families/elf_flow/tests/manifests/elf-b-de-en-l0.json @@ -1,6 +1,7 @@ { "name": "elf-b-de-en-l0", "hf_id": "embedded-language-flows/ELF-B-de-en", + "hf_revision": "c8120fb80e52d4056abb5378cb9acaef3da6e65a", "hf_dependencies": [ { "repo_id": "embedded-language-flows/t5_small_encoder_jax" diff --git a/families/elf_flow/tests/manifests/elf-b-owt-l0.json b/families/elf_flow/tests/manifests/elf-b-owt-l0.json index 6ee81af357..297d495b78 100644 --- a/families/elf_flow/tests/manifests/elf-b-owt-l0.json +++ b/families/elf_flow/tests/manifests/elf-b-owt-l0.json @@ -1,6 +1,7 @@ { "name": "elf-b-owt-l0", "hf_id": "embedded-language-flows/ELF-B-owt", + "hf_revision": "506a81d3ed3b2475e9ae754bae308e10f765d327", "hf_dependencies": [ { "repo_id": "embedded-language-flows/t5_small_encoder_jax" diff --git a/families/elf_flow/tests/manifests/elf-b-xsum-l0.json b/families/elf_flow/tests/manifests/elf-b-xsum-l0.json index 447fe54554..7c10ed6fa5 100644 --- a/families/elf_flow/tests/manifests/elf-b-xsum-l0.json +++ b/families/elf_flow/tests/manifests/elf-b-xsum-l0.json @@ -1,6 +1,7 @@ { "name": "elf-b-xsum-l0", "hf_id": "embedded-language-flows/ELF-B-xsum", + "hf_revision": "8150551968f826c4421cf6bdeff9d6e7b766e23d", "hf_dependencies": [ { "repo_id": "embedded-language-flows/t5_small_encoder_jax" diff --git a/families/falcon/tests/manifests/falcon-rw-1b-tp4.json b/families/falcon/tests/manifests/falcon-rw-1b-tp4.json index 650486367c..ee10f35ef0 100644 --- a/families/falcon/tests/manifests/falcon-rw-1b-tp4.json +++ b/families/falcon/tests/manifests/falcon-rw-1b-tp4.json @@ -1,6 +1,7 @@ { "name": "falcon-rw-1b-tp4", "hf_id": "tiiuae/falcon-rw-1b", + "hf_revision": "e4b9872bb803165eb22f0a867d4e6a64d34fce19", "bundle": "falcon-rw-1b-tp4.bundle", "family": "falcon", "task": "text_generation", diff --git a/families/falcon/tests/manifests/falcon-rw-1b.json b/families/falcon/tests/manifests/falcon-rw-1b.json index 4961069091..a7b1d2b112 100644 --- a/families/falcon/tests/manifests/falcon-rw-1b.json +++ b/families/falcon/tests/manifests/falcon-rw-1b.json @@ -1,6 +1,7 @@ { "name": "falcon-rw-1b", "hf_id": "tiiuae/falcon-rw-1b", + "hf_revision": "e4b9872bb803165eb22f0a867d4e6a64d34fce19", "bundle": "falcon-rw-1b.bundle", "family": "falcon", "task": "text_generation", diff --git a/families/fast_foundation_stereo/requirements.txt b/families/fast_foundation_stereo/requirements.txt index e6ccd831d7..6f34051c29 100644 --- a/families/fast_foundation_stereo/requirements.txt +++ b/families/fast_foundation_stereo/requirements.txt @@ -1,9 +1,9 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 # Imported by the official checkpoint source used by this family E2E. -imageio>=2.37 +imageio==2.37.4 omegaconf==2.3.0 -opencv-python-headless>=4.11 -timm>=1.0 +opencv-python-headless==4.11.0.86 +timm==1.0.28 diff --git a/families/flux/requirements.txt b/families/flux/requirements.txt index c58339d951..9a8a9fa773 100644 --- a/families/flux/requirements.txt +++ b/families/flux/requirements.txt @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow -accelerate -diffusers +Pillow==12.2.0 +accelerate==1.14.0 +diffusers==0.40.0 diff --git a/families/flux/tests/manifests/flux-2-dev-fp8-l0-tp4.json b/families/flux/tests/manifests/flux-2-dev-fp8-l0-tp4.json index 31e12ac8bf..7d5e22dc15 100644 --- a/families/flux/tests/manifests/flux-2-dev-fp8-l0-tp4.json +++ b/families/flux/tests/manifests/flux-2-dev-fp8-l0-tp4.json @@ -1,6 +1,7 @@ { "name": "flux-2-dev-fp8-l0-tp4", "hf_id": "black-forest-labs/FLUX.2-dev", + "hf_revision": "26afe3a78bb242c0a8bb181dcc8937bb16e5c66c", "bundle": "flux-2-dev-fp8-l0-tp4.bundle", "family": "flux", "task": "image_generation", diff --git a/families/flux/tests/manifests/flux-2-dev-fp8-l0.json b/families/flux/tests/manifests/flux-2-dev-fp8-l0.json index bbbcd82800..5fc5d86c25 100644 --- a/families/flux/tests/manifests/flux-2-dev-fp8-l0.json +++ b/families/flux/tests/manifests/flux-2-dev-fp8-l0.json @@ -1,6 +1,7 @@ { "name": "flux-2-dev-fp8-l0", "hf_id": "black-forest-labs/FLUX.2-dev", + "hf_revision": "26afe3a78bb242c0a8bb181dcc8937bb16e5c66c", "bundle": "flux-2-dev-fp8-l0.bundle", "family": "flux", "task": "image_generation", diff --git a/families/flux/tests/manifests/flux-2-dev-fp8.json b/families/flux/tests/manifests/flux-2-dev-fp8.json index 03d3520a3b..ebf307bef6 100644 --- a/families/flux/tests/manifests/flux-2-dev-fp8.json +++ b/families/flux/tests/manifests/flux-2-dev-fp8.json @@ -1,6 +1,7 @@ { "name": "flux-2-dev-fp8", "hf_id": "black-forest-labs/FLUX.2-dev", + "hf_revision": "26afe3a78bb242c0a8bb181dcc8937bb16e5c66c", "bundle": "flux-2-dev-fp8.bundle", "family": "flux", "task": "image_generation", diff --git a/families/flux/tests/manifests/flux-2-dev-l0-tp4.json b/families/flux/tests/manifests/flux-2-dev-l0-tp4.json index 9d6a26b841..cbbcf31feb 100644 --- a/families/flux/tests/manifests/flux-2-dev-l0-tp4.json +++ b/families/flux/tests/manifests/flux-2-dev-l0-tp4.json @@ -1,6 +1,7 @@ { "name": "flux-2-dev-l0-tp4", "hf_id": "black-forest-labs/FLUX.2-dev", + "hf_revision": "26afe3a78bb242c0a8bb181dcc8937bb16e5c66c", "bundle": "flux-2-dev-l0-tp4.bundle", "family": "flux", "task": "image_generation", diff --git a/families/flux/tests/manifests/flux-2-dev-l0.json b/families/flux/tests/manifests/flux-2-dev-l0.json index b66cd0fcd4..cd8aff216d 100644 --- a/families/flux/tests/manifests/flux-2-dev-l0.json +++ b/families/flux/tests/manifests/flux-2-dev-l0.json @@ -1,6 +1,7 @@ { "name": "flux-2-dev-l0", "hf_id": "black-forest-labs/FLUX.2-dev", + "hf_revision": "26afe3a78bb242c0a8bb181dcc8937bb16e5c66c", "bundle": "flux-2-dev-l0.bundle", "family": "flux", "task": "image_generation", diff --git a/families/flux/tests/manifests/flux-2-dev.json b/families/flux/tests/manifests/flux-2-dev.json index 3949d74dc6..8553581bb2 100644 --- a/families/flux/tests/manifests/flux-2-dev.json +++ b/families/flux/tests/manifests/flux-2-dev.json @@ -1,6 +1,7 @@ { "name": "flux-2-dev", "hf_id": "black-forest-labs/FLUX.2-dev", + "hf_revision": "26afe3a78bb242c0a8bb181dcc8937bb16e5c66c", "bundle": "flux-2-dev.bundle", "family": "flux", "task": "image_generation", diff --git a/families/flux/tests/manifests/flux-schnell-l0-batch2.json b/families/flux/tests/manifests/flux-schnell-l0-batch2.json index 0d035cddcf..f47b70f237 100644 --- a/families/flux/tests/manifests/flux-schnell-l0-batch2.json +++ b/families/flux/tests/manifests/flux-schnell-l0-batch2.json @@ -1,6 +1,7 @@ { "name": "flux-schnell-l0-batch2", "hf_id": "black-forest-labs/FLUX.1-schnell", + "hf_revision": "741f7c3ce8b383c54771c7003378a50191e9efe9", "bundle": "flux-schnell-l0-batch2.bundle", "family": "flux", "task": "image_generation_batch", diff --git a/families/flux/tests/manifests/flux-schnell-l0-cp4.json b/families/flux/tests/manifests/flux-schnell-l0-cp4.json index a6f6801bcc..38553d91a5 100644 --- a/families/flux/tests/manifests/flux-schnell-l0-cp4.json +++ b/families/flux/tests/manifests/flux-schnell-l0-cp4.json @@ -1,6 +1,7 @@ { "name": "flux-schnell-l0-cp4", "hf_id": "black-forest-labs/FLUX.1-schnell", + "hf_revision": "741f7c3ce8b383c54771c7003378a50191e9efe9", "bundle": "flux-schnell-l0-cp4.bundle", "family": "flux", "task": "image_generation", diff --git a/families/flux/tests/manifests/flux-schnell-l0-tp4.json b/families/flux/tests/manifests/flux-schnell-l0-tp4.json index 39ef01d2da..739a95c21d 100644 --- a/families/flux/tests/manifests/flux-schnell-l0-tp4.json +++ b/families/flux/tests/manifests/flux-schnell-l0-tp4.json @@ -1,6 +1,7 @@ { "name": "flux-schnell-l0-tp4", "hf_id": "black-forest-labs/FLUX.1-schnell", + "hf_revision": "741f7c3ce8b383c54771c7003378a50191e9efe9", "bundle": "flux-schnell-l0-tp4.bundle", "family": "flux", "task": "image_generation", diff --git a/families/flux/tests/manifests/flux-schnell-l0.json b/families/flux/tests/manifests/flux-schnell-l0.json index b394ee6000..7f7e373fa2 100644 --- a/families/flux/tests/manifests/flux-schnell-l0.json +++ b/families/flux/tests/manifests/flux-schnell-l0.json @@ -1,6 +1,7 @@ { "name": "flux-schnell-l0", "hf_id": "black-forest-labs/FLUX.1-schnell", + "hf_revision": "741f7c3ce8b383c54771c7003378a50191e9efe9", "bundle": "flux-schnell-l0.bundle", "family": "flux", "task": "image_generation", diff --git a/families/flux/tests/manifests/flux-schnell.json b/families/flux/tests/manifests/flux-schnell.json index 062bcd8763..ec98ae2ce8 100644 --- a/families/flux/tests/manifests/flux-schnell.json +++ b/families/flux/tests/manifests/flux-schnell.json @@ -1,6 +1,7 @@ { "name": "flux-schnell", "hf_id": "black-forest-labs/FLUX.1-schnell", + "hf_revision": "741f7c3ce8b383c54771c7003378a50191e9efe9", "bundle": "flux-schnell.bundle", "family": "flux", "task": "image_generation", diff --git a/families/fnet/tests/manifests/fnet-base-tp4.json b/families/fnet/tests/manifests/fnet-base-tp4.json index c693585ed9..0e4f74f6d0 100644 --- a/families/fnet/tests/manifests/fnet-base-tp4.json +++ b/families/fnet/tests/manifests/fnet-base-tp4.json @@ -1,6 +1,7 @@ { "name": "fnet-base-tp4", "hf_id": "google/fnet-base", + "hf_revision": "d89b6fad3cf5384848b783dc480f9685f49d008c", "bundle": "fnet-base-tp4.bundle", "family": "fnet", "task": "encoding", diff --git a/families/fnet/tests/manifests/fnet-base.json b/families/fnet/tests/manifests/fnet-base.json index af09b55a5c..5a6064adcb 100644 --- a/families/fnet/tests/manifests/fnet-base.json +++ b/families/fnet/tests/manifests/fnet-base.json @@ -1,6 +1,7 @@ { "name": "fnet-base", "hf_id": "google/fnet-base", + "hf_revision": "d89b6fad3cf5384848b783dc480f9685f49d008c", "bundle": "fnet-base.bundle", "family": "fnet", "task": "encoding", diff --git a/families/foundationpose/requirements.txt b/families/foundationpose/requirements.txt index 8767df1261..9a9c5bd39a 100644 --- a/families/foundationpose/requirements.txt +++ b/families/foundationpose/requirements.txt @@ -2,5 +2,5 @@ # SPDX-License-Identifier: Apache-2.0 numpy==1.26.4 -onnx +onnx==1.21.0 onnxruntime==1.29.0 diff --git a/families/gemma/tests/manifests/gemma-2-2b-tp4.json b/families/gemma/tests/manifests/gemma-2-2b-tp4.json index 062fb67bbe..00b2919f5c 100644 --- a/families/gemma/tests/manifests/gemma-2-2b-tp4.json +++ b/families/gemma/tests/manifests/gemma-2-2b-tp4.json @@ -1,6 +1,7 @@ { "name": "gemma-2-2b-tp4", "hf_id": "google/gemma-2-2b-it", + "hf_revision": "299a8560bedf22ed1c72a8a11e7dce4a7f9f51f8", "bundle": "gemma-2-2b-tp4.bundle", "family": "gemma", "task": "text_generation", diff --git a/families/gemma/tests/manifests/gemma-2-2b.json b/families/gemma/tests/manifests/gemma-2-2b.json index d1cbf4d171..a1097c5b8b 100644 --- a/families/gemma/tests/manifests/gemma-2-2b.json +++ b/families/gemma/tests/manifests/gemma-2-2b.json @@ -1,6 +1,7 @@ { "name": "gemma-2-2b", "hf_id": "google/gemma-2-2b-it", + "hf_revision": "299a8560bedf22ed1c72a8a11e7dce4a7f9f51f8", "bundle": "gemma-2-2b.bundle", "family": "gemma", "task": "text_generation", diff --git a/families/glm/tests/manifests/glm-4-9b-l0-tp2.json b/families/glm/tests/manifests/glm-4-9b-l0-tp2.json index e8bb254733..10f8e24caf 100644 --- a/families/glm/tests/manifests/glm-4-9b-l0-tp2.json +++ b/families/glm/tests/manifests/glm-4-9b-l0-tp2.json @@ -1,6 +1,7 @@ { "name": "glm-4-9b-l0-tp2", "hf_id": "THUDM/glm-4-9b-hf", + "hf_revision": "b44e98fcc8df0faba03a48b405356af6b91821e7", "bundle": "glm-4-9b-l0-tp2.bundle", "family": "glm", "task": "text_generation", diff --git a/families/glm/tests/manifests/glm-4-9b-l0.json b/families/glm/tests/manifests/glm-4-9b-l0.json index f367812b51..86c8bbba6c 100644 --- a/families/glm/tests/manifests/glm-4-9b-l0.json +++ b/families/glm/tests/manifests/glm-4-9b-l0.json @@ -1,6 +1,7 @@ { "name": "glm-4-9b-l0", "hf_id": "THUDM/glm-4-9b-hf", + "hf_revision": "b44e98fcc8df0faba03a48b405356af6b91821e7", "bundle": "glm-4-9b-l0.bundle", "family": "glm", "task": "text_generation", diff --git a/families/glm/tests/manifests/glm-4-9b.json b/families/glm/tests/manifests/glm-4-9b.json index bb77669022..16c365e792 100644 --- a/families/glm/tests/manifests/glm-4-9b.json +++ b/families/glm/tests/manifests/glm-4-9b.json @@ -1,6 +1,7 @@ { "name": "glm-4-9b", "hf_id": "THUDM/glm-4-9b-hf", + "hf_revision": "b44e98fcc8df0faba03a48b405356af6b91821e7", "bundle": "glm-4-9b.bundle", "family": "glm", "task": "text_generation", diff --git a/families/gpt2/tests/manifests/distilgpt2.json b/families/gpt2/tests/manifests/distilgpt2.json index 851ba4a5ff..61c510cc2c 100644 --- a/families/gpt2/tests/manifests/distilgpt2.json +++ b/families/gpt2/tests/manifests/distilgpt2.json @@ -1,6 +1,7 @@ { "name": "distilgpt2", "hf_id": "distilbert/distilgpt2", + "hf_revision": "2290a62682d06624634c1f46a6ad5be0f47f38aa", "bundle": "distilgpt2.bundle", "family": "gpt2", "task": "text_generation", diff --git a/families/gpt2/tests/manifests/gpt2-125m-tp4.json b/families/gpt2/tests/manifests/gpt2-125m-tp4.json index 987e182f9a..eee7be39b7 100644 --- a/families/gpt2/tests/manifests/gpt2-125m-tp4.json +++ b/families/gpt2/tests/manifests/gpt2-125m-tp4.json @@ -1,6 +1,7 @@ { "name": "gpt2-125m-tp4", "hf_id": "openai-community/gpt2", + "hf_revision": "607a30d783dfa663caf39e06633721c8d4cfcd7e", "bundle": "gpt2-125m-tp4.bundle", "family": "gpt2", "task": "text_generation", diff --git a/families/gpt2/tests/manifests/gpt2-125m.json b/families/gpt2/tests/manifests/gpt2-125m.json index 463155b64f..7191e7a7a9 100644 --- a/families/gpt2/tests/manifests/gpt2-125m.json +++ b/families/gpt2/tests/manifests/gpt2-125m.json @@ -1,6 +1,7 @@ { "name": "gpt2-125m", "hf_id": "openai-community/gpt2", + "hf_revision": "607a30d783dfa663caf39e06633721c8d4cfcd7e", "bundle": "gpt2-125m.bundle", "family": "gpt2", "task": "text_generation", diff --git a/families/gpt_neo/tests/manifests/gpt-neo-125m-tp4.json b/families/gpt_neo/tests/manifests/gpt-neo-125m-tp4.json index 9433b80c2b..84fbd51f7a 100644 --- a/families/gpt_neo/tests/manifests/gpt-neo-125m-tp4.json +++ b/families/gpt_neo/tests/manifests/gpt-neo-125m-tp4.json @@ -1,6 +1,7 @@ { "name": "gpt-neo-125m-tp4", "hf_id": "EleutherAI/gpt-neo-125m", + "hf_revision": "21def0189f5705e2521767faed922f1f15e7d7db", "bundle": "gpt-neo-125m-tp4.bundle", "family": "gpt_neo", "task": "text_generation", diff --git a/families/gpt_neo/tests/manifests/gpt-neo-125m.json b/families/gpt_neo/tests/manifests/gpt-neo-125m.json index 1a6399a8d2..7da9fc3494 100644 --- a/families/gpt_neo/tests/manifests/gpt-neo-125m.json +++ b/families/gpt_neo/tests/manifests/gpt-neo-125m.json @@ -1,6 +1,7 @@ { "name": "gpt-neo-125m", "hf_id": "EleutherAI/gpt-neo-125m", + "hf_revision": "21def0189f5705e2521767faed922f1f15e7d7db", "bundle": "gpt-neo-125m.bundle", "family": "gpt_neo", "task": "text_generation", diff --git a/families/gpt_neox/tests/manifests/pythia-70m-tp4.json b/families/gpt_neox/tests/manifests/pythia-70m-tp4.json index 043144825b..f99b3821e0 100644 --- a/families/gpt_neox/tests/manifests/pythia-70m-tp4.json +++ b/families/gpt_neox/tests/manifests/pythia-70m-tp4.json @@ -1,6 +1,7 @@ { "name": "pythia-70m-tp4", "hf_id": "EleutherAI/pythia-70m", + "hf_revision": "a39f36b100fe8a5377810d56c3f4789b9c53ac42", "bundle": "pythia-70m-tp4.bundle", "family": "gpt_neox", "task": "text_generation", diff --git a/families/gpt_neox/tests/manifests/pythia-70m.json b/families/gpt_neox/tests/manifests/pythia-70m.json index ff5aff4e87..7646ce1e4e 100644 --- a/families/gpt_neox/tests/manifests/pythia-70m.json +++ b/families/gpt_neox/tests/manifests/pythia-70m.json @@ -1,6 +1,7 @@ { "name": "pythia-70m", "hf_id": "EleutherAI/pythia-70m", + "hf_revision": "a39f36b100fe8a5377810d56c3f4789b9c53ac42", "bundle": "pythia-70m.bundle", "family": "gpt_neox", "task": "text_generation", diff --git a/families/gpt_oss/requirements.txt b/families/gpt_oss/requirements.txt index 40290c9bca..5b5e5d2812 100644 --- a/families/gpt_oss/requirements.txt +++ b/families/gpt_oss/requirements.txt @@ -1 +1 @@ -accelerate>=1.0 +accelerate==1.14.0 diff --git a/families/gpt_oss/tests/manifests/gpt-oss-20b-l0-tp4.json b/families/gpt_oss/tests/manifests/gpt-oss-20b-l0-tp4.json index f8957cfd09..d75dff9bf5 100644 --- a/families/gpt_oss/tests/manifests/gpt-oss-20b-l0-tp4.json +++ b/families/gpt_oss/tests/manifests/gpt-oss-20b-l0-tp4.json @@ -1,6 +1,7 @@ { "name": "gpt-oss-20b-l0-tp4", "hf_id": "openai/gpt-oss-20b", + "hf_revision": "6cee5e81ee83917806bbde320786a8fb61efebee", "bundle": "gpt-oss-20b-l0-tp4.bundle", "family": "gpt_oss", "task": "text_generation", diff --git a/families/granite/tests/manifests/granite-3.1-2b-tp4.json b/families/granite/tests/manifests/granite-3.1-2b-tp4.json index 02099bcaed..f51fdd030e 100644 --- a/families/granite/tests/manifests/granite-3.1-2b-tp4.json +++ b/families/granite/tests/manifests/granite-3.1-2b-tp4.json @@ -1,6 +1,7 @@ { "name": "granite-3.1-2b-tp4", "hf_id": "ibm-granite/granite-3.1-2b-base", + "hf_revision": "bcf4e33e7debde263041db41869f9cdbeaae3f01", "bundle": "granite-3.1-2b-tp4.bundle", "family": "granite", "task": "text_generation", diff --git a/families/granite/tests/manifests/granite-3.1-2b.json b/families/granite/tests/manifests/granite-3.1-2b.json index edb4b02fef..6e4d5f9e9b 100644 --- a/families/granite/tests/manifests/granite-3.1-2b.json +++ b/families/granite/tests/manifests/granite-3.1-2b.json @@ -1,6 +1,7 @@ { "name": "granite-3.1-2b", "hf_id": "ibm-granite/granite-3.1-2b-base", + "hf_revision": "bcf4e33e7debde263041db41869f9cdbeaae3f01", "bundle": "granite-3.1-2b.bundle", "family": "granite", "task": "text_generation", diff --git a/families/internlm/tests/manifests/internlm2-1.8b-tp4.json b/families/internlm/tests/manifests/internlm2-1.8b-tp4.json index b775fea268..c01be92f63 100644 --- a/families/internlm/tests/manifests/internlm2-1.8b-tp4.json +++ b/families/internlm/tests/manifests/internlm2-1.8b-tp4.json @@ -1,6 +1,7 @@ { "name": "internlm2-1.8b-tp4", "hf_id": "internlm/internlm2-math-plus-1_8b", + "hf_revision": "998dd540b92711b855982c0318a39064a1d3ddc1", "hf_dependencies": [ { "repo_id": "internlm/internlm2-step-prover" diff --git a/families/internlm/tests/manifests/internlm2-1.8b.json b/families/internlm/tests/manifests/internlm2-1.8b.json index 7cf3a113da..7adf542c09 100644 --- a/families/internlm/tests/manifests/internlm2-1.8b.json +++ b/families/internlm/tests/manifests/internlm2-1.8b.json @@ -1,6 +1,7 @@ { "name": "internlm2-1.8b", "hf_id": "internlm/internlm2-math-plus-1_8b", + "hf_revision": "998dd540b92711b855982c0318a39064a1d3ddc1", "hf_dependencies": [ { "repo_id": "internlm/internlm2-step-prover" diff --git a/families/internvl/requirements.txt b/families/internvl/requirements.txt index 5018e40516..23dcd0beee 100644 --- a/families/internvl/requirements.txt +++ b/families/internvl/requirements.txt @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 diff --git a/families/internvl/tests/manifests/internvl3-2b-tp2.json b/families/internvl/tests/manifests/internvl3-2b-tp2.json index 0f0f44c08b..508676341d 100644 --- a/families/internvl/tests/manifests/internvl3-2b-tp2.json +++ b/families/internvl/tests/manifests/internvl3-2b-tp2.json @@ -1,6 +1,7 @@ { "name": "internvl3-2b-tp2", "hf_id": "OpenGVLab/InternVL3-2B-hf", + "hf_revision": "cb57a075cb75a2e6d1b668b128d48bb00ae321d2", "bundle": "internvl3-2b-tp2-vl.bundle", "family": "internvl", "task": "vision_language_generation", diff --git a/families/internvl/tests/manifests/internvl3-2b.json b/families/internvl/tests/manifests/internvl3-2b.json index b5edd4c07e..4f2c3f4a28 100644 --- a/families/internvl/tests/manifests/internvl3-2b.json +++ b/families/internvl/tests/manifests/internvl3-2b.json @@ -1,6 +1,7 @@ { "name": "internvl3-2b", "hf_id": "OpenGVLab/InternVL3-2B-hf", + "hf_revision": "cb57a075cb75a2e6d1b668b128d48bb00ae321d2", "bundle": "internvl3-2b-vl.bundle", "family": "internvl", "task": "vision_language_generation", diff --git a/families/internvl/tests/manifests/internvl3-8b-tp4.json b/families/internvl/tests/manifests/internvl3-8b-tp4.json index 4aae28eae6..c0314eb13e 100644 --- a/families/internvl/tests/manifests/internvl3-8b-tp4.json +++ b/families/internvl/tests/manifests/internvl3-8b-tp4.json @@ -1,6 +1,7 @@ { "name": "internvl3-8b-tp4", "hf_id": "OpenGVLab/InternVL3-8B-hf", + "hf_revision": "259a3b64a14623c0ec91a045cb43f7c5af5fa6af", "bundle": "internvl3-8b-tp4-vl.bundle", "family": "internvl", "task": "vision_language_generation", diff --git a/families/internvl/tests/manifests/internvl3-8b.json b/families/internvl/tests/manifests/internvl3-8b.json index bd45b8728b..dd2e8b86dc 100644 --- a/families/internvl/tests/manifests/internvl3-8b.json +++ b/families/internvl/tests/manifests/internvl3-8b.json @@ -1,6 +1,7 @@ { "name": "internvl3-8b", "hf_id": "OpenGVLab/InternVL3-8B-hf", + "hf_revision": "259a3b64a14623c0ec91a045cb43f7c5af5fa6af", "bundle": "internvl3-8b-vl.bundle", "family": "internvl", "task": "vision_language_generation", diff --git a/families/lance/requirements.txt b/families/lance/requirements.txt index 1fe79a4ae3..6ba99be85a 100644 --- a/families/lance/requirements.txt +++ b/families/lance/requirements.txt @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 # Imported by the official image reference checkout. flash-attn==2.8.3 imageio==2.34.0 diff --git a/families/lerobot_act/requirements.txt b/families/lerobot_act/requirements.txt index c076a19822..69fae53beb 100644 --- a/families/lerobot_act/requirements.txt +++ b/families/lerobot_act/requirements.txt @@ -1,3 +1,3 @@ -einops>=0.8.0 +einops==0.8.1 imageio-ffmpeg==0.6.0 -pyarrow>=15 +pyarrow==24.0.0 diff --git a/families/llama/tests/manifests/falcon3-1b.json b/families/llama/tests/manifests/falcon3-1b.json index 368690c3cb..5fbffb7d2e 100644 --- a/families/llama/tests/manifests/falcon3-1b.json +++ b/families/llama/tests/manifests/falcon3-1b.json @@ -1,6 +1,7 @@ { "name": "falcon3-1b", "hf_id": "tiiuae/Falcon3-1B-Base", + "hf_revision": "cb37ef3559b157b5c9d9226296ba01a5162da1f7", "bundle": "falcon3-1b.bundle", "family": "llama", "task": "text_generation", diff --git a/families/llama/tests/manifests/minitron-4b-depth.json b/families/llama/tests/manifests/minitron-4b-depth.json index 65fdacbd89..edeecba98d 100644 --- a/families/llama/tests/manifests/minitron-4b-depth.json +++ b/families/llama/tests/manifests/minitron-4b-depth.json @@ -1,6 +1,7 @@ { "name": "minitron-4b-depth", "hf_id": "nvidia/Llama-3.1-Minitron-4B-Depth-Base", + "hf_revision": "47f17b2c73bbd07a4b643a0382970704d389f737", "bundle": "minitron-4b-depth.bundle", "family": "llama", "task": "text_generation", diff --git a/families/llama/tests/manifests/nemotron-nano-4b.json b/families/llama/tests/manifests/nemotron-nano-4b.json index f6df254c7a..66c68a5069 100644 --- a/families/llama/tests/manifests/nemotron-nano-4b.json +++ b/families/llama/tests/manifests/nemotron-nano-4b.json @@ -1,6 +1,7 @@ { "name": "nemotron-nano-4b", "hf_id": "nvidia/Llama-3.1-Nemotron-Nano-4B-v1.1", + "hf_revision": "d552708a9d575fa8d4a690b988fd870d65279f98", "bundle": "nemotron-nano-4b.bundle", "family": "llama", "task": "text_generation", diff --git a/families/llama/tests/manifests/tinyllama-1.1b.json b/families/llama/tests/manifests/tinyllama-1.1b.json index 2a9467be62..c20ee46c63 100644 --- a/families/llama/tests/manifests/tinyllama-1.1b.json +++ b/families/llama/tests/manifests/tinyllama-1.1b.json @@ -1,6 +1,7 @@ { "name": "tinyllama-1.1b", "hf_id": "TinyLlama/TinyLlama-1.1B-Chat-v1.0", + "hf_revision": "fe8a4ea1ffedaf415f4da2f062534de366a451e6", "bundle": "tinyllama-1.1b.bundle", "family": "llama", "task": "text_generation", diff --git a/families/locateanything/requirements.txt b/families/locateanything/requirements.txt index 7a703b14bf..5cdda2bf6d 100644 --- a/families/locateanything/requirements.txt +++ b/families/locateanything/requirements.txt @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow -peft +Pillow==12.2.0 +peft==0.20.0 transformers==4.57.6 diff --git a/families/locateanything/tests/manifests/locateanything-3b.json b/families/locateanything/tests/manifests/locateanything-3b.json index 9af5bfb464..178a6d3e10 100644 --- a/families/locateanything/tests/manifests/locateanything-3b.json +++ b/families/locateanything/tests/manifests/locateanything-3b.json @@ -1,6 +1,7 @@ { "name": "locateanything-3b", "hf_id": "nvidia/LocateAnything-3B", + "hf_revision": "c32291ca5e996f5a7a485845b4f57a233936bba0", "bundle": "locateanything-3b.bundle", "family": "locateanything", "task": "vision_language_generation", diff --git a/families/ltx_video/requirements.txt b/families/ltx_video/requirements.txt index 18f1c26b2f..a17f59142d 100644 --- a/families/ltx_video/requirements.txt +++ b/families/ltx_video/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow -diffusers +Pillow==12.2.0 +diffusers==0.40.0 diff --git a/families/ltx_video/tests/manifests/ltx-video-l0.json b/families/ltx_video/tests/manifests/ltx-video-l0.json index c40d2aabc9..05826dba06 100644 --- a/families/ltx_video/tests/manifests/ltx-video-l0.json +++ b/families/ltx_video/tests/manifests/ltx-video-l0.json @@ -1,6 +1,7 @@ { "name": "ltx-video-l0", "hf_id": "Lightricks/LTX-Video", + "hf_revision": "8984fa25007f376c1a299016d0957a37a2f797bb", "bundle": "ltx-video-l0.bundle", "family": "ltx_video", "task": "image_generation", diff --git a/families/m2m_100/requirements.txt b/families/m2m_100/requirements.txt index 90b9e8b11d..22b8030a42 100644 --- a/families/m2m_100/requirements.txt +++ b/families/m2m_100/requirements.txt @@ -1 +1 @@ -torch>=2.6 +torch==2.12.0 diff --git a/families/m2m_100/tests/manifests/nllb-200.json b/families/m2m_100/tests/manifests/nllb-200.json index 94036fa358..1ca42154d3 100644 --- a/families/m2m_100/tests/manifests/nllb-200.json +++ b/families/m2m_100/tests/manifests/nllb-200.json @@ -1,6 +1,7 @@ { "name": "nllb-200-distilled-600m", "hf_id": "facebook/nllb-200-distilled-600M", + "hf_revision": "f8d333a098d19b4fd9a8b18f94170487ad3f821d", "bundle": "nllb-200-distilled-600m.bundle", "family": "m2m_100", "task": "text_generation", diff --git a/families/magpie_tts/tests/manifests/magpie-tts-357m-tp4.json b/families/magpie_tts/tests/manifests/magpie-tts-357m-tp4.json index cdc2208512..325f756f45 100644 --- a/families/magpie_tts/tests/manifests/magpie-tts-357m-tp4.json +++ b/families/magpie_tts/tests/manifests/magpie-tts-357m-tp4.json @@ -1,6 +1,7 @@ { "name": "magpie-tts-357m-tp4", "hf_id": "nvidia/magpie_tts_multilingual_357m", + "hf_revision": "34d7e40da85cabc97f92198889b65cea27bc7fd1", "hf_dependencies": [ { "repo_id": "openai/whisper-large-v3-turbo" diff --git a/families/mamba/tests/manifests/mamba-130m-tp4.json b/families/mamba/tests/manifests/mamba-130m-tp4.json index eb7830781a..c6c4f0c2d4 100644 --- a/families/mamba/tests/manifests/mamba-130m-tp4.json +++ b/families/mamba/tests/manifests/mamba-130m-tp4.json @@ -1,6 +1,7 @@ { "name": "mamba-130m-tp4", "hf_id": "state-spaces/mamba-130m-hf", + "hf_revision": "1e76775f628fbf1350fbe4dbb3d971ba64af25a1", "bundle": "mamba-130m-tp4.bundle", "family": "mamba", "task": "text_generation", diff --git a/families/mamba/tests/manifests/mamba-130m.json b/families/mamba/tests/manifests/mamba-130m.json index 84b7b280bc..81a0c757cc 100644 --- a/families/mamba/tests/manifests/mamba-130m.json +++ b/families/mamba/tests/manifests/mamba-130m.json @@ -1,6 +1,7 @@ { "name": "mamba-130m", "hf_id": "state-spaces/mamba-130m-hf", + "hf_revision": "1e76775f628fbf1350fbe4dbb3d971ba64af25a1", "bundle": "mamba-130m.bundle", "family": "mamba", "task": "text_generation", diff --git a/families/marian/tests/manifests/marian-en-ru-tp4.json b/families/marian/tests/manifests/marian-en-ru-tp4.json index f6c382211f..83de6e87a3 100644 --- a/families/marian/tests/manifests/marian-en-ru-tp4.json +++ b/families/marian/tests/manifests/marian-en-ru-tp4.json @@ -1,6 +1,7 @@ { "name": "marian-en-ru-tp4", "hf_id": "Helsinki-NLP/opus-mt-en-ru", + "hf_revision": "bb09c99d180016eac6819df3dae68edb1690fdee", "bundle": "marian-en-ru-tp4.bundle", "family": "marian", "task": "text_generation", diff --git a/families/marian/tests/manifests/marian-en-ru.json b/families/marian/tests/manifests/marian-en-ru.json index eb19099b50..749840a618 100644 --- a/families/marian/tests/manifests/marian-en-ru.json +++ b/families/marian/tests/manifests/marian-en-ru.json @@ -1,6 +1,7 @@ { "name": "marian-en-ru", "hf_id": "Helsinki-NLP/opus-mt-en-ru", + "hf_revision": "bb09c99d180016eac6819df3dae68edb1690fdee", "bundle": "marian-en-ru.bundle", "family": "marian", "task": "text_generation", diff --git a/families/minimax_h3/requirements.txt b/families/minimax_h3/requirements.txt index 4db36e3c2d..775adbf139 100644 --- a/families/minimax_h3/requirements.txt +++ b/families/minimax_h3/requirements.txt @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow -accelerate +Pillow==12.2.0 +accelerate==1.14.0 diffusers==0.40.0 transformers==5.15.0 diff --git a/families/mistral/tests/manifests/mistral-7b-l0.json b/families/mistral/tests/manifests/mistral-7b-l0.json index 6d206ebfff..690ed086d3 100644 --- a/families/mistral/tests/manifests/mistral-7b-l0.json +++ b/families/mistral/tests/manifests/mistral-7b-l0.json @@ -1,6 +1,7 @@ { "name": "mistral-7b-l0", "hf_id": "mistralai/Mistral-7B-Instruct-v0.1", + "hf_revision": "ec5deb64f2c6e6fa90c1abf74a91d5c93a9669ca", "bundle": "mistral-7b-l0.bundle", "family": "mistral", "task": "text_generation", diff --git a/families/mistral/tests/manifests/mistral-7b.json b/families/mistral/tests/manifests/mistral-7b.json index 35b9b3753f..08d4edb242 100644 --- a/families/mistral/tests/manifests/mistral-7b.json +++ b/families/mistral/tests/manifests/mistral-7b.json @@ -1,6 +1,7 @@ { "name": "mistral-7b", "hf_id": "mistralai/Mistral-7B-Instruct-v0.1", + "hf_revision": "ec5deb64f2c6e6fa90c1abf74a91d5c93a9669ca", "bundle": "mistral-7b.bundle", "family": "mistral", "task": "text_generation", diff --git a/families/mistral/tests/manifests/riva-translate-4b.json b/families/mistral/tests/manifests/riva-translate-4b.json index 82df12658d..feaa18abfc 100644 --- a/families/mistral/tests/manifests/riva-translate-4b.json +++ b/families/mistral/tests/manifests/riva-translate-4b.json @@ -1,6 +1,7 @@ { "name": "riva-translate-4b", "hf_id": "nvidia/Riva-Translate-4B-Instruct-v1.1", + "hf_revision": "1eb944ce9f2717d7be6b7b7c2310f7c58b35d10b", "bundle": "riva-translate-4b.bundle", "family": "mistral", "task": "text_generation", diff --git a/families/mixtral/tests/manifests/mixtral-stories-15m-tp2.json b/families/mixtral/tests/manifests/mixtral-stories-15m-tp2.json index 28ec26689a..9abaf7b1fb 100644 --- a/families/mixtral/tests/manifests/mixtral-stories-15m-tp2.json +++ b/families/mixtral/tests/manifests/mixtral-stories-15m-tp2.json @@ -1,6 +1,7 @@ { "name": "mixtral-stories-15m-tp2", "hf_id": "ggml-org/stories15M_MOE", + "hf_revision": "b6dd737497465570b5f5e962dbc9d9454ed1e0eb", "bundle": "mixtral-stories-15m-tp2.bundle", "family": "mixtral", "task": "text_generation", diff --git a/families/mixtral/tests/manifests/mixtral-stories-15m.json b/families/mixtral/tests/manifests/mixtral-stories-15m.json index 24ef14d495..c1d0852d14 100644 --- a/families/mixtral/tests/manifests/mixtral-stories-15m.json +++ b/families/mixtral/tests/manifests/mixtral-stories-15m.json @@ -1,6 +1,7 @@ { "name": "mixtral-stories-15m", "hf_id": "ggml-org/stories15M_MOE", + "hf_revision": "b6dd737497465570b5f5e962dbc9d9454ed1e0eb", "bundle": "mixtral-stories-15m.bundle", "family": "mixtral", "task": "text_generation", diff --git a/families/modernbert/tests/manifests/modernbert-base-tp4.json b/families/modernbert/tests/manifests/modernbert-base-tp4.json index 884a833889..cb48fb4283 100644 --- a/families/modernbert/tests/manifests/modernbert-base-tp4.json +++ b/families/modernbert/tests/manifests/modernbert-base-tp4.json @@ -1,6 +1,7 @@ { "name": "modernbert-base-tp4", "hf_id": "answerdotai/ModernBERT-base", + "hf_revision": "8949b909ec900327062f0ebf497f51aef5e6f0c8", "bundle": "modernbert-base-tp4.bundle", "family": "modernbert", "task": "encoding", diff --git a/families/modernbert/tests/manifests/modernbert-base.json b/families/modernbert/tests/manifests/modernbert-base.json index f7acc3ba7d..a1b4d8be8d 100644 --- a/families/modernbert/tests/manifests/modernbert-base.json +++ b/families/modernbert/tests/manifests/modernbert-base.json @@ -1,6 +1,7 @@ { "name": "modernbert-base", "hf_id": "answerdotai/ModernBERT-base", + "hf_revision": "8949b909ec900327062f0ebf497f51aef5e6f0c8", "bundle": "modernbert-base.bundle", "family": "modernbert", "task": "encoding", diff --git a/families/mpnet/tests/manifests/all-mpnet-base-v2-tp4.json b/families/mpnet/tests/manifests/all-mpnet-base-v2-tp4.json index 698abf1302..c32882fc6e 100644 --- a/families/mpnet/tests/manifests/all-mpnet-base-v2-tp4.json +++ b/families/mpnet/tests/manifests/all-mpnet-base-v2-tp4.json @@ -1,6 +1,7 @@ { "name": "all-mpnet-base-v2-tp4", "hf_id": "sentence-transformers/all-mpnet-base-v2", + "hf_revision": "e8c3b32edf5434bc2275fc9bab85f82640a19130", "bundle": "all-mpnet-base-v2-tp4.bundle", "family": "mpnet", "task": "encoding", diff --git a/families/mpnet/tests/manifests/all-mpnet-base-v2.json b/families/mpnet/tests/manifests/all-mpnet-base-v2.json index bf65cd00f5..69b4422f06 100644 --- a/families/mpnet/tests/manifests/all-mpnet-base-v2.json +++ b/families/mpnet/tests/manifests/all-mpnet-base-v2.json @@ -1,6 +1,7 @@ { "name": "all-mpnet-base-v2", "hf_id": "sentence-transformers/all-mpnet-base-v2", + "hf_revision": "e8c3b32edf5434bc2275fc9bab85f82640a19130", "bundle": "all-mpnet-base-v2.bundle", "family": "mpnet", "task": "encoding", diff --git a/families/nemotron/tests/manifests/nemotron-hindi-4b.json b/families/nemotron/tests/manifests/nemotron-hindi-4b.json index d58b96e283..6850835dd7 100644 --- a/families/nemotron/tests/manifests/nemotron-hindi-4b.json +++ b/families/nemotron/tests/manifests/nemotron-hindi-4b.json @@ -1,6 +1,7 @@ { "name": "nemotron-hindi-4b", "hf_id": "nvidia/Nemotron-4-Mini-Hindi-4B-Base", + "hf_revision": "05c6ef6d2ddaad06bce914990facaf08bc4c581e", "bundle": "nemotron-hindi-4b.bundle", "family": "nemotron", "task": "text_generation", diff --git a/families/nemotron/tests/manifests/nemotron-mini-4b.json b/families/nemotron/tests/manifests/nemotron-mini-4b.json index e66e71c945..4557dd31b2 100644 --- a/families/nemotron/tests/manifests/nemotron-mini-4b.json +++ b/families/nemotron/tests/manifests/nemotron-mini-4b.json @@ -1,6 +1,7 @@ { "name": "nemotron-mini-4b", "hf_id": "nvidia/Nemotron-Mini-4B-Instruct", + "hf_revision": "791833e92ebddb0bc2c1007f6d2b6764f886a2ae", "bundle": "nemotron-mini-4b.bundle", "family": "nemotron", "task": "text_generation", diff --git a/families/nemotron_h/tests/manifests/nemotron-h-nano-9b-tp4.json b/families/nemotron_h/tests/manifests/nemotron-h-nano-9b-tp4.json index 89f37c97b5..8f69516b23 100644 --- a/families/nemotron_h/tests/manifests/nemotron-h-nano-9b-tp4.json +++ b/families/nemotron_h/tests/manifests/nemotron-h-nano-9b-tp4.json @@ -1,6 +1,7 @@ { "name": "nemotron-h-nano-9b-tp4", "hf_id": "nvidia/NVIDIA-Nemotron-Nano-9B-v2", + "hf_revision": "6533e8de2c68e4536bf7c411d7a3ce5734111476", "bundle": "nemotron-h-nano-9b-tp4.bundle", "family": "nemotron_h", "task": "text_generation", diff --git a/families/nemotron_h/tests/manifests/nemotron-h-nano-9b.json b/families/nemotron_h/tests/manifests/nemotron-h-nano-9b.json index ac9519fb18..73b1fe7d10 100644 --- a/families/nemotron_h/tests/manifests/nemotron-h-nano-9b.json +++ b/families/nemotron_h/tests/manifests/nemotron-h-nano-9b.json @@ -1,6 +1,7 @@ { "name": "nemotron-h-nano-9b", "hf_id": "nvidia/NVIDIA-Nemotron-Nano-9B-v2", + "hf_revision": "6533e8de2c68e4536bf7c411d7a3ce5734111476", "bundle": "nemotron-h-nano-9b.bundle", "family": "nemotron_h", "task": "text_generation", diff --git a/families/nemotron_labs_diffusion/tests/manifests/nemotron-labs-diffusion-8b-l0.json b/families/nemotron_labs_diffusion/tests/manifests/nemotron-labs-diffusion-8b-l0.json index a08d9d0792..294be71ddb 100644 --- a/families/nemotron_labs_diffusion/tests/manifests/nemotron-labs-diffusion-8b-l0.json +++ b/families/nemotron_labs_diffusion/tests/manifests/nemotron-labs-diffusion-8b-l0.json @@ -1,6 +1,7 @@ { "name": "nemotron-labs-diffusion-8b-l0", "hf_id": "nvidia/Nemotron-Labs-Diffusion-8B", + "hf_revision": "16c67f0560b912e93e0cabb6e0c4f5c3086d95fc", "bundle": "nemotron-labs-diffusion-8b-l0.bundle", "family": "nemotron_labs_diffusion", "task": "text_generation", diff --git a/families/nemotron_labs_diffusion/tests/manifests/nemotron-labs-diffusion-8b.json b/families/nemotron_labs_diffusion/tests/manifests/nemotron-labs-diffusion-8b.json index da4de031fd..91d1ad6003 100644 --- a/families/nemotron_labs_diffusion/tests/manifests/nemotron-labs-diffusion-8b.json +++ b/families/nemotron_labs_diffusion/tests/manifests/nemotron-labs-diffusion-8b.json @@ -1,6 +1,7 @@ { "name": "nemotron-labs-diffusion-8b", "hf_id": "nvidia/Nemotron-Labs-Diffusion-8B", + "hf_revision": "16c67f0560b912e93e0cabb6e0c4f5c3086d95fc", "bundle": "nemotron-labs-diffusion-8b.bundle", "family": "nemotron_labs_diffusion", "task": "text_generation", diff --git a/families/nemotron_speech_streaming/tests/manifests/nemotron-3.5-asr-streaming-0.6b.json b/families/nemotron_speech_streaming/tests/manifests/nemotron-3.5-asr-streaming-0.6b.json index 5c32c17c65..0e5d9f4591 100644 --- a/families/nemotron_speech_streaming/tests/manifests/nemotron-3.5-asr-streaming-0.6b.json +++ b/families/nemotron_speech_streaming/tests/manifests/nemotron-3.5-asr-streaming-0.6b.json @@ -1,6 +1,7 @@ { "name": "nemotron-3.5-asr-streaming-0.6b", "hf_id": "nvidia/nemotron-3.5-asr-streaming-0.6b", + "hf_revision": "1c8deaecc64b91f034d73e08dd8b64625eb3395d", "bundle": "nemotron-3.5-asr-streaming-0.6b.bundle", "family": "nemotron_speech_streaming", "task": "transcription_streaming", diff --git a/families/nemotron_speech_streaming/tests/manifests/nemotron-speech-streaming-en-0.6b-tp4.json b/families/nemotron_speech_streaming/tests/manifests/nemotron-speech-streaming-en-0.6b-tp4.json index 85c8bf541e..5038c2d633 100644 --- a/families/nemotron_speech_streaming/tests/manifests/nemotron-speech-streaming-en-0.6b-tp4.json +++ b/families/nemotron_speech_streaming/tests/manifests/nemotron-speech-streaming-en-0.6b-tp4.json @@ -1,6 +1,7 @@ { "name": "nemotron-speech-streaming-en-0.6b-tp4", "hf_id": "nvidia/nemotron-speech-streaming-en-0.6b", + "hf_revision": "ebe59e5a817142986528bbbee5dba8db7b38ed50", "bundle": "nemotron-speech-streaming-en-0.6b-tp4.bundle", "family": "nemotron_speech_streaming", "task": "transcription_streaming", diff --git a/families/nemotron_speech_streaming/tests/manifests/nemotron-speech-streaming-en-0.6b.json b/families/nemotron_speech_streaming/tests/manifests/nemotron-speech-streaming-en-0.6b.json index b9e03c3871..1c39a36950 100644 --- a/families/nemotron_speech_streaming/tests/manifests/nemotron-speech-streaming-en-0.6b.json +++ b/families/nemotron_speech_streaming/tests/manifests/nemotron-speech-streaming-en-0.6b.json @@ -1,6 +1,7 @@ { "name": "nemotron-speech-streaming-en-0.6b", "hf_id": "nvidia/nemotron-speech-streaming-en-0.6b", + "hf_revision": "ebe59e5a817142986528bbbee5dba8db7b38ed50", "bundle": "nemotron-speech-streaming-en-0.6b.bundle", "family": "nemotron_speech_streaming", "task": "transcription_streaming", diff --git a/families/nemotron_voicechat/requirements.txt b/families/nemotron_voicechat/requirements.txt index 4b6f57262d..577270ef2e 100644 --- a/families/nemotron_voicechat/requirements.txt +++ b/families/nemotron_voicechat/requirements.txt @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -soundfile +soundfile==0.14.0 diff --git a/families/olmo/tests/manifests/olmo-1b-tp4.json b/families/olmo/tests/manifests/olmo-1b-tp4.json index f20f49e061..c4a18defc3 100644 --- a/families/olmo/tests/manifests/olmo-1b-tp4.json +++ b/families/olmo/tests/manifests/olmo-1b-tp4.json @@ -1,6 +1,7 @@ { "name": "olmo-1b-tp4", "hf_id": "allenai/OLMo-1B-hf", + "hf_revision": "aee7752d9c08ee4775e9b0091426d8410e8f6a89", "bundle": "olmo-1b-tp4.bundle", "family": "olmo", "task": "text_generation", diff --git a/families/olmo/tests/manifests/olmo-1b.json b/families/olmo/tests/manifests/olmo-1b.json index 5f53621cc9..8afbd59e0c 100644 --- a/families/olmo/tests/manifests/olmo-1b.json +++ b/families/olmo/tests/manifests/olmo-1b.json @@ -1,6 +1,7 @@ { "name": "olmo-1b", "hf_id": "allenai/OLMo-1B-hf", + "hf_revision": "aee7752d9c08ee4775e9b0091426d8410e8f6a89", "bundle": "olmo-1b.bundle", "family": "olmo", "task": "text_generation", diff --git a/families/olmo2/tests/manifests/olmo2-1b-tp4.json b/families/olmo2/tests/manifests/olmo2-1b-tp4.json index d6fa0c2b41..e208d1d711 100644 --- a/families/olmo2/tests/manifests/olmo2-1b-tp4.json +++ b/families/olmo2/tests/manifests/olmo2-1b-tp4.json @@ -1,6 +1,7 @@ { "name": "olmo2-1b-tp4", "hf_id": "allenai/OLMo-2-0425-1B", + "hf_revision": "a1847dff35000b4271fa70afc5db10fd29fedbdf", "bundle": "olmo2-1b-tp4.bundle", "family": "olmo2", "task": "text_generation", diff --git a/families/opt/tests/manifests/opt-125m-tp4.json b/families/opt/tests/manifests/opt-125m-tp4.json index 82d85fb7a0..cedb5f6f9b 100644 --- a/families/opt/tests/manifests/opt-125m-tp4.json +++ b/families/opt/tests/manifests/opt-125m-tp4.json @@ -1,6 +1,7 @@ { "name": "opt-125m-tp4", "hf_id": "facebook/opt-125m", + "hf_revision": "27dcfa74d334bc871f3234de431e71c6eeba5dd6", "bundle": "opt-125m-tp4.bundle", "family": "opt", "task": "text_generation", diff --git a/families/opt/tests/manifests/opt-125m.json b/families/opt/tests/manifests/opt-125m.json index 0bd733d03b..542a160951 100644 --- a/families/opt/tests/manifests/opt-125m.json +++ b/families/opt/tests/manifests/opt-125m.json @@ -1,6 +1,7 @@ { "name": "opt-125m", "hf_id": "facebook/opt-125m", + "hf_revision": "27dcfa74d334bc871f3234de431e71c6eeba5dd6", "bundle": "opt-125m.bundle", "family": "opt", "task": "text_generation", diff --git a/families/patchtsmixer/tests/manifests/patchtsmixer-granite-official-tp4.json b/families/patchtsmixer/tests/manifests/patchtsmixer-granite-official-tp4.json index a59cccdf7c..51e52b2112 100644 --- a/families/patchtsmixer/tests/manifests/patchtsmixer-granite-official-tp4.json +++ b/families/patchtsmixer/tests/manifests/patchtsmixer-granite-official-tp4.json @@ -1,6 +1,7 @@ { "name": "patchtsmixer-granite-official-tp4", "hf_id": "ibm-granite/granite-timeseries-patchtsmixer", + "hf_revision": "90dc5a88d45f032b7dceefb5d814ca2af54f2ff9", "bundle": "patchtsmixer-granite-official-tp4.bundle", "family": "patchtsmixer", "task": "time_series_forecast", diff --git a/families/patchtsmixer/tests/manifests/patchtsmixer-granite-official.json b/families/patchtsmixer/tests/manifests/patchtsmixer-granite-official.json index 790456bfbf..fab67c05e4 100644 --- a/families/patchtsmixer/tests/manifests/patchtsmixer-granite-official.json +++ b/families/patchtsmixer/tests/manifests/patchtsmixer-granite-official.json @@ -1,6 +1,7 @@ { "name": "patchtsmixer-granite-official", "hf_id": "ibm-granite/granite-timeseries-patchtsmixer", + "hf_revision": "90dc5a88d45f032b7dceefb5d814ca2af54f2ff9", "bundle": "patchtsmixer-granite-official.bundle", "family": "patchtsmixer", "task": "time_series_forecast", diff --git a/families/patchtst/tests/manifests/patchtst-etth1-regression-distribution-tp4.json b/families/patchtst/tests/manifests/patchtst-etth1-regression-distribution-tp4.json index 6295e1d4b3..ba0e1c869d 100644 --- a/families/patchtst/tests/manifests/patchtst-etth1-regression-distribution-tp4.json +++ b/families/patchtst/tests/manifests/patchtst-etth1-regression-distribution-tp4.json @@ -1,6 +1,7 @@ { "name": "patchtst-etth1-regression-distribution-tp4", "hf_id": "ibm-research/patchtst-etth1-regression-distribution", + "hf_revision": "d5ef731ed80ffcd2f0a3262138b1009bbcedb2c4", "bundle": "patchtst-etth1-regression-distribution-tp4.bundle", "family": "patchtst", "task": "time_series_forecast", diff --git a/families/patchtst/tests/manifests/patchtst-etth1-regression-distribution.json b/families/patchtst/tests/manifests/patchtst-etth1-regression-distribution.json index 114b1a0f76..6f80341753 100644 --- a/families/patchtst/tests/manifests/patchtst-etth1-regression-distribution.json +++ b/families/patchtst/tests/manifests/patchtst-etth1-regression-distribution.json @@ -1,6 +1,7 @@ { "name": "patchtst-etth1-regression-distribution", "hf_id": "ibm-research/patchtst-etth1-regression-distribution", + "hf_revision": "d5ef731ed80ffcd2f0a3262138b1009bbcedb2c4", "bundle": "patchtst-etth1-regression-distribution.bundle", "family": "patchtst", "task": "time_series_forecast", diff --git a/families/patchtst/tests/manifests/patchtst-granite-official.json b/families/patchtst/tests/manifests/patchtst-granite-official.json index c9c1b47888..e869dd27bd 100644 --- a/families/patchtst/tests/manifests/patchtst-granite-official.json +++ b/families/patchtst/tests/manifests/patchtst-granite-official.json @@ -1,6 +1,7 @@ { "name": "patchtst-granite-official", "hf_id": "ibm-granite/granite-timeseries-patchtst", + "hf_revision": "7fe295d8bc8fbac8041b60ab351882634165517f", "bundle": "patchtst-granite-official.bundle", "family": "patchtst", "task": "time_series_forecast", diff --git a/families/personaplex/requirements.txt b/families/personaplex/requirements.txt index 4b6f57262d..577270ef2e 100644 --- a/families/personaplex/requirements.txt +++ b/families/personaplex/requirements.txt @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -soundfile +soundfile==0.14.0 diff --git a/families/personaplex/tests/manifests/personaplex-7b-l0-tp4.json b/families/personaplex/tests/manifests/personaplex-7b-l0-tp4.json index 3dad58c0ad..104b6feef1 100644 --- a/families/personaplex/tests/manifests/personaplex-7b-l0-tp4.json +++ b/families/personaplex/tests/manifests/personaplex-7b-l0-tp4.json @@ -1,6 +1,7 @@ { "name": "personaplex-7b-l0-tp4", "hf_id": "nvidia/personaplex-7b-v1", + "hf_revision": "fdaf4090a61cb315c138a1faee287ffd6c716309", "hf_dependencies": [ { "repo_id": "kyutai/mimi" diff --git a/families/personaplex/tests/manifests/personaplex-7b-l0.json b/families/personaplex/tests/manifests/personaplex-7b-l0.json index 510f6776e1..da57eedeaf 100644 --- a/families/personaplex/tests/manifests/personaplex-7b-l0.json +++ b/families/personaplex/tests/manifests/personaplex-7b-l0.json @@ -1,6 +1,7 @@ { "name": "personaplex-7b-l0", "hf_id": "nvidia/personaplex-7b-v1", + "hf_revision": "fdaf4090a61cb315c138a1faee287ffd6c716309", "hf_dependencies": [ { "repo_id": "kyutai/mimi" diff --git a/families/phi/tests/manifests/phi3-mini-tp4.json b/families/phi/tests/manifests/phi3-mini-tp4.json index 37931101ea..1e38a6a858 100644 --- a/families/phi/tests/manifests/phi3-mini-tp4.json +++ b/families/phi/tests/manifests/phi3-mini-tp4.json @@ -1,6 +1,7 @@ { "name": "phi3-mini-tp4", "hf_id": "microsoft/Phi-3-mini-4k-instruct", + "hf_revision": "f39ac1d28e925b323eae81227eaba4464caced4e", "bundle": "phi3-mini-tp4.bundle", "family": "phi", "task": "text_generation", diff --git a/families/phi/tests/manifests/phi3-mini.json b/families/phi/tests/manifests/phi3-mini.json index 91d8d443b1..4af5d34ba4 100644 --- a/families/phi/tests/manifests/phi3-mini.json +++ b/families/phi/tests/manifests/phi3-mini.json @@ -1,6 +1,7 @@ { "name": "phi3-mini", "hf_id": "microsoft/Phi-3-mini-4k-instruct", + "hf_revision": "f39ac1d28e925b323eae81227eaba4464caced4e", "bundle": "phi3-mini.bundle", "family": "phi", "task": "text_generation", diff --git a/families/phi4_multimodal/requirements.txt b/families/phi4_multimodal/requirements.txt index e4eb4dc81c..1d8956ec22 100644 --- a/families/phi4_multimodal/requirements.txt +++ b/families/phi4_multimodal/requirements.txt @@ -1,11 +1,11 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 # Required by the checkpoint's trust_remote_code reference. accelerate==1.3.0 backoff==2.2.1 Jinja2==3.1.6 peft==0.13.2 -scipy +scipy==1.12.0 transformers==4.48.2 diff --git a/families/phi4_multimodal/tests/manifests/phi4-multimodal.json b/families/phi4_multimodal/tests/manifests/phi4-multimodal.json index 85eca96fc4..94c6dfb332 100644 --- a/families/phi4_multimodal/tests/manifests/phi4-multimodal.json +++ b/families/phi4_multimodal/tests/manifests/phi4-multimodal.json @@ -1,6 +1,7 @@ { "name": "phi4-multimodal", "hf_id": "microsoft/Phi-4-multimodal-instruct", + "hf_revision": "93f923e1a7727d1c4f446756212d9d3e8fcc5d81", "bundle": "phi4-multimodal.bundle", "family": "phi4_multimodal", "task": "vision_language_generation", diff --git a/families/phi_moe/tests/manifests/phi-moe-l0-tp4.json b/families/phi_moe/tests/manifests/phi-moe-l0-tp4.json index 955cb1a40d..f81876964d 100644 --- a/families/phi_moe/tests/manifests/phi-moe-l0-tp4.json +++ b/families/phi_moe/tests/manifests/phi-moe-l0-tp4.json @@ -1,6 +1,7 @@ { "name": "phi-moe-l0-tp4", "hf_id": "microsoft/Phi-tiny-MoE-instruct", + "hf_revision": "2fe50e88d0e2a5a132563815686ea0dcc8e252b5", "bundle": "phi-moe-l0-tp4.bundle", "family": "phi_moe", "task": "text_generation", diff --git a/families/phi_moe/tests/manifests/phi-moe-l0.json b/families/phi_moe/tests/manifests/phi-moe-l0.json index 6bf1ce7c31..899bad4c78 100644 --- a/families/phi_moe/tests/manifests/phi-moe-l0.json +++ b/families/phi_moe/tests/manifests/phi-moe-l0.json @@ -1,6 +1,7 @@ { "name": "phi-moe-l0", "hf_id": "microsoft/Phi-tiny-MoE-instruct", + "hf_revision": "2fe50e88d0e2a5a132563815686ea0dcc8e252b5", "bundle": "phi-moe-l0.bundle", "family": "phi_moe", "task": "text_generation", diff --git a/families/phi_moe/tests/manifests/phi-moe.json b/families/phi_moe/tests/manifests/phi-moe.json index a05e62f04f..781a4a9f93 100644 --- a/families/phi_moe/tests/manifests/phi-moe.json +++ b/families/phi_moe/tests/manifests/phi-moe.json @@ -1,6 +1,7 @@ { "name": "phi-moe", "hf_id": "microsoft/Phi-tiny-MoE-instruct", + "hf_revision": "2fe50e88d0e2a5a132563815686ea0dcc8e252b5", "bundle": "phi-moe.bundle", "family": "phi_moe", "task": "text_generation", diff --git a/families/pixart/requirements.txt b/families/pixart/requirements.txt index 18f1c26b2f..a17f59142d 100644 --- a/families/pixart/requirements.txt +++ b/families/pixart/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow -diffusers +Pillow==12.2.0 +diffusers==0.40.0 diff --git a/families/pixart/tests/manifests/pixart-sigma-1024-l0.json b/families/pixart/tests/manifests/pixart-sigma-1024-l0.json index dbd975ddb6..4ada7e2108 100644 --- a/families/pixart/tests/manifests/pixart-sigma-1024-l0.json +++ b/families/pixart/tests/manifests/pixart-sigma-1024-l0.json @@ -1,6 +1,7 @@ { "name": "pixart-sigma-1024-l0", "hf_id": "PixArt-alpha/PixArt-Sigma-XL-2-1024-MS", + "hf_revision": "e102b3591cc82e97071b8b4cb90d834d0c487207", "bundle": "pixart-sigma-1024-l0.bundle", "family": "pixart", "task": "image_generation", diff --git a/families/pixart/tests/manifests/pixart-sigma-1024-tp4.json b/families/pixart/tests/manifests/pixart-sigma-1024-tp4.json index 5be095a542..aab97a2be1 100644 --- a/families/pixart/tests/manifests/pixart-sigma-1024-tp4.json +++ b/families/pixart/tests/manifests/pixart-sigma-1024-tp4.json @@ -1,6 +1,7 @@ { "name": "pixart-sigma-1024-tp4", "hf_id": "PixArt-alpha/PixArt-Sigma-XL-2-1024-MS", + "hf_revision": "e102b3591cc82e97071b8b4cb90d834d0c487207", "bundle": "pixart-sigma-1024-tp4.bundle", "family": "pixart", "task": "image_generation", diff --git a/families/pixart/tests/manifests/pixart-sigma-1024.json b/families/pixart/tests/manifests/pixart-sigma-1024.json index c1a9be171a..359c7f3f10 100644 --- a/families/pixart/tests/manifests/pixart-sigma-1024.json +++ b/families/pixart/tests/manifests/pixart-sigma-1024.json @@ -1,6 +1,7 @@ { "name": "pixart-sigma-1024", "hf_id": "PixArt-alpha/PixArt-Sigma-XL-2-1024-MS", + "hf_revision": "e102b3591cc82e97071b8b4cb90d834d0c487207", "bundle": "pixart-sigma-1024.bundle", "family": "pixart", "task": "image_generation", diff --git a/families/qwen/tests/manifests/qwen3-0.6b-fp16-tp4.json b/families/qwen/tests/manifests/qwen3-0.6b-fp16-tp4.json index cfe225b5b7..f64c1893d5 100644 --- a/families/qwen/tests/manifests/qwen3-0.6b-fp16-tp4.json +++ b/families/qwen/tests/manifests/qwen3-0.6b-fp16-tp4.json @@ -1,6 +1,7 @@ { "name": "qwen3-0.6b-fp16-tp4", "hf_id": "Qwen/Qwen3-0.6B", + "hf_revision": "c1899de289a04d12100db370d81485cdf75e47ca", "bundle": "qwen3-0.6b-fp16-tp4.bundle", "family": "qwen", "task": "text_generation", diff --git a/families/qwen/tests/manifests/qwen3-0.6b-fp16.json b/families/qwen/tests/manifests/qwen3-0.6b-fp16.json index 2df80b59a7..1d76f4819d 100644 --- a/families/qwen/tests/manifests/qwen3-0.6b-fp16.json +++ b/families/qwen/tests/manifests/qwen3-0.6b-fp16.json @@ -1,6 +1,7 @@ { "name": "qwen3-0.6b-fp16", "hf_id": "Qwen/Qwen3-0.6B", + "hf_revision": "c1899de289a04d12100db370d81485cdf75e47ca", "bundle": "qwen3-0.6b-fp16.bundle", "family": "qwen", "task": "text_generation", diff --git a/families/qwen/tests/manifests/qwen3-0.6b-fp8-tp4.json b/families/qwen/tests/manifests/qwen3-0.6b-fp8-tp4.json index 59416649a7..11b53300fe 100644 --- a/families/qwen/tests/manifests/qwen3-0.6b-fp8-tp4.json +++ b/families/qwen/tests/manifests/qwen3-0.6b-fp8-tp4.json @@ -1,6 +1,7 @@ { "name": "qwen3-0.6b-fp8-tp4", "hf_id": "Qwen/Qwen3-0.6B", + "hf_revision": "c1899de289a04d12100db370d81485cdf75e47ca", "bundle": "qwen3-0.6b-fp8-bf16base-tp4.bundle", "family": "qwen", "task": "text_generation", diff --git a/families/qwen/tests/manifests/qwen3-0.6b-fp8.json b/families/qwen/tests/manifests/qwen3-0.6b-fp8.json index 847259e90a..8ed6df8454 100644 --- a/families/qwen/tests/manifests/qwen3-0.6b-fp8.json +++ b/families/qwen/tests/manifests/qwen3-0.6b-fp8.json @@ -1,6 +1,7 @@ { "name": "qwen3-0.6b-fp8", "hf_id": "Qwen/Qwen3-0.6B", + "hf_revision": "c1899de289a04d12100db370d81485cdf75e47ca", "bundle": "qwen3-0.6b-fp8-fp16base.bundle", "family": "qwen", "task": "text_generation", diff --git a/families/qwen/tests/manifests/qwen3-0.6b-native-l0.json b/families/qwen/tests/manifests/qwen3-0.6b-native-l0.json index bc1e022399..7283dcfd00 100644 --- a/families/qwen/tests/manifests/qwen3-0.6b-native-l0.json +++ b/families/qwen/tests/manifests/qwen3-0.6b-native-l0.json @@ -1,6 +1,7 @@ { "name": "qwen3-0.6b-native-l0", "hf_id": "Qwen/Qwen3-0.6B", + "hf_revision": "c1899de289a04d12100db370d81485cdf75e47ca", "bundle": "qwen3-0.6b-native-l0.bundle", "family": "qwen", "task": "text_generation", diff --git a/families/qwen/tests/manifests/qwen3-0.6b-topp-tp4.json b/families/qwen/tests/manifests/qwen3-0.6b-topp-tp4.json index 1d99f952cf..f4f425ece4 100644 --- a/families/qwen/tests/manifests/qwen3-0.6b-topp-tp4.json +++ b/families/qwen/tests/manifests/qwen3-0.6b-topp-tp4.json @@ -1,6 +1,7 @@ { "name": "qwen3-0.6b-topp-tp4", "hf_id": "Qwen/Qwen3-0.6B", + "hf_revision": "c1899de289a04d12100db370d81485cdf75e47ca", "bundle": "qwen3-0.6b-topp-fp16-tp4.bundle", "family": "qwen", "task": "text_generation", diff --git a/families/qwen/tests/manifests/qwen3-0.6b-topp.json b/families/qwen/tests/manifests/qwen3-0.6b-topp.json index 161f30e68c..23f772a86d 100644 --- a/families/qwen/tests/manifests/qwen3-0.6b-topp.json +++ b/families/qwen/tests/manifests/qwen3-0.6b-topp.json @@ -1,6 +1,7 @@ { "name": "qwen3-0.6b-topp", "hf_id": "Qwen/Qwen3-0.6B", + "hf_revision": "c1899de289a04d12100db370d81485cdf75e47ca", "bundle": "qwen3-0.6b-topp-fp16.bundle", "family": "qwen", "task": "text_generation", diff --git a/families/qwen/tests/manifests/qwen3-4b-instruct-2507-tp4.json b/families/qwen/tests/manifests/qwen3-4b-instruct-2507-tp4.json index 2b7aeacffc..68036bcb0a 100644 --- a/families/qwen/tests/manifests/qwen3-4b-instruct-2507-tp4.json +++ b/families/qwen/tests/manifests/qwen3-4b-instruct-2507-tp4.json @@ -1,6 +1,7 @@ { "name": "qwen3-4b-instruct-2507-tp4", "hf_id": "Qwen/Qwen3-4B-Instruct-2507", + "hf_revision": "cdbee75f17c01a7cc42f958dc650907174af0554", "bundle": "qwen3-4b-instruct-2507-tp4.bundle", "family": "qwen", "task": "text_generation", diff --git a/families/qwen/tests/manifests/qwen3-4b-instruct-2507.json b/families/qwen/tests/manifests/qwen3-4b-instruct-2507.json index 0b313e9bae..0ebb3c2f4c 100644 --- a/families/qwen/tests/manifests/qwen3-4b-instruct-2507.json +++ b/families/qwen/tests/manifests/qwen3-4b-instruct-2507.json @@ -1,6 +1,7 @@ { "name": "qwen3-4b-instruct-2507", "hf_id": "Qwen/Qwen3-4B-Instruct-2507", + "hf_revision": "cdbee75f17c01a7cc42f958dc650907174af0554", "bundle": "qwen3-4b-instruct-2507.bundle", "family": "qwen", "task": "text_generation", diff --git a/families/qwen3_5/tests/manifests/qwen35-9b.json b/families/qwen3_5/tests/manifests/qwen35-9b.json index 1053fc086b..dc1292f7ea 100644 --- a/families/qwen3_5/tests/manifests/qwen35-9b.json +++ b/families/qwen3_5/tests/manifests/qwen35-9b.json @@ -1,6 +1,7 @@ { "name": "qwen35-9b", "hf_id": "Qwen/Qwen3.5-9B", + "hf_revision": "c202236235762e1c871ad0ccb60c8ee5ba337b9a", "bundle": "qwen35-9b.bundle", "family": "qwen3_5", "task": "text_generation", diff --git a/families/qwen3_8/requirements.txt b/families/qwen3_8/requirements.txt index 90b9e8b11d..22b8030a42 100644 --- a/families/qwen3_8/requirements.txt +++ b/families/qwen3_8/requirements.txt @@ -1 +1 @@ -torch>=2.6 +torch==2.12.0 diff --git a/families/qwen3_omni/requirements.txt b/families/qwen3_omni/requirements.txt index 2962a45e43..3c0fc972bf 100644 --- a/families/qwen3_omni/requirements.txt +++ b/families/qwen3_omni/requirements.txt @@ -2,4 +2,4 @@ # SPDX-License-Identifier: Apache-2.0 # Used by the Transformers reference loader. -accelerate>=1.0 +accelerate==1.14.0 diff --git a/families/qwen_image/requirements.txt b/families/qwen_image/requirements.txt index e22d7d435e..7c5866cdb6 100644 --- a/families/qwen_image/requirements.txt +++ b/families/qwen_image/requirements.txt @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 accelerate==1.14.0 diffusers==0.39.0 ftfy==6.3.1 diff --git a/families/qwen_image/tests/manifests/qwen-image-2512.json b/families/qwen_image/tests/manifests/qwen-image-2512.json index 8195104312..a93a645472 100644 --- a/families/qwen_image/tests/manifests/qwen-image-2512.json +++ b/families/qwen_image/tests/manifests/qwen-image-2512.json @@ -1,6 +1,7 @@ { "name": "qwen-image-2512", "hf_id": "Qwen/Qwen-Image-2512", + "hf_revision": "25468b98e3276ca6700de15c6628e51b7de54a26", "bundle": "qwen-image-2512.bundle", "family": "qwen_image", "task": "image_generation", diff --git a/families/qwen_image/tests/manifests/qwen-image-edit-2511.json b/families/qwen_image/tests/manifests/qwen-image-edit-2511.json index 5caa46becc..b63e90010b 100644 --- a/families/qwen_image/tests/manifests/qwen-image-edit-2511.json +++ b/families/qwen_image/tests/manifests/qwen-image-edit-2511.json @@ -1,6 +1,7 @@ { "name": "qwen-image-edit-2511", "hf_id": "Qwen/Qwen-Image-Edit-2511", + "hf_revision": "6f3ccc0b56e431dc6a0c2b2039706d7d26f22cb9", "bundle": "qwen-image-edit-2511.bundle", "family": "qwen_image", "task": "image_edit", diff --git a/families/qwen_image/tests/manifests/qwen-image-l0.json b/families/qwen_image/tests/manifests/qwen-image-l0.json index f5619f685c..619eb9b48b 100644 --- a/families/qwen_image/tests/manifests/qwen-image-l0.json +++ b/families/qwen_image/tests/manifests/qwen-image-l0.json @@ -1,6 +1,7 @@ { "name": "qwen-image-l0", "hf_id": "Qwen/Qwen-Image", + "hf_revision": "75e0b4be04f60ec59a75f475837eced720f823b6", "bundle": "qwen-image-l0.bundle", "family": "qwen_image", "task": "image_generation", diff --git a/families/qwen_image/tests/manifests/qwen-image.json b/families/qwen_image/tests/manifests/qwen-image.json index bcebba3427..ba8f78c449 100644 --- a/families/qwen_image/tests/manifests/qwen-image.json +++ b/families/qwen_image/tests/manifests/qwen-image.json @@ -1,6 +1,7 @@ { "name": "qwen-image", "hf_id": "Qwen/Qwen-Image", + "hf_revision": "75e0b4be04f60ec59a75f475837eced720f823b6", "bundle": "qwen-image.bundle", "family": "qwen_image", "task": "image_generation", diff --git a/families/qwen_moe/tests/manifests/qwen3-moe-30b-a3b-tp4.json b/families/qwen_moe/tests/manifests/qwen3-moe-30b-a3b-tp4.json index 7000369cf8..2730fa1bd6 100644 --- a/families/qwen_moe/tests/manifests/qwen3-moe-30b-a3b-tp4.json +++ b/families/qwen_moe/tests/manifests/qwen3-moe-30b-a3b-tp4.json @@ -1,6 +1,7 @@ { "name": "qwen3-moe-30b-a3b-tp4", "hf_id": "Qwen/Qwen3-30B-A3B", + "hf_revision": "ad44e777bcd18fa416d9da3bd8f70d33ebb85d39", "bundle": "qwen3-moe-30b-a3b-tp4.bundle", "family": "qwen_moe", "task": "text_generation", diff --git a/families/qwen_moe/tests/manifests/qwen3-moe-30b-a3b.json b/families/qwen_moe/tests/manifests/qwen3-moe-30b-a3b.json index 2d58225d61..cd13803fac 100644 --- a/families/qwen_moe/tests/manifests/qwen3-moe-30b-a3b.json +++ b/families/qwen_moe/tests/manifests/qwen3-moe-30b-a3b.json @@ -1,6 +1,7 @@ { "name": "qwen3-moe-30b-a3b", "hf_id": "Qwen/Qwen3-30B-A3B", + "hf_revision": "ad44e777bcd18fa416d9da3bd8f70d33ebb85d39", "bundle": "qwen3-moe-30b-a3b.bundle", "family": "qwen_moe", "task": "text_generation", diff --git a/families/qwen_moe/tests/manifests/qwen3-moe-tiny-random.json b/families/qwen_moe/tests/manifests/qwen3-moe-tiny-random.json index affdb23716..e130adbcea 100644 --- a/families/qwen_moe/tests/manifests/qwen3-moe-tiny-random.json +++ b/families/qwen_moe/tests/manifests/qwen3-moe-tiny-random.json @@ -1,6 +1,7 @@ { "name": "qwen3-moe-tiny-random", "hf_id": "amd-quark/tiny-random-qwen3_moe", + "hf_revision": "ca2aaa9a82e9f86c09c2785b405932fe6c806c90", "bundle": "qwen3-moe-tiny-random.bundle", "family": "qwen_moe", "task": "text_generation", diff --git a/families/qwen_vl/requirements.txt b/families/qwen_vl/requirements.txt index 5018e40516..23dcd0beee 100644 --- a/families/qwen_vl/requirements.txt +++ b/families/qwen_vl/requirements.txt @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 diff --git a/families/qwen_vl/tests/manifests/qwen25vl-3b-tp2.json b/families/qwen_vl/tests/manifests/qwen25vl-3b-tp2.json index 4178cdc1a6..940ab104dc 100644 --- a/families/qwen_vl/tests/manifests/qwen25vl-3b-tp2.json +++ b/families/qwen_vl/tests/manifests/qwen25vl-3b-tp2.json @@ -1,6 +1,7 @@ { "name": "qwen25vl-3b-tp2", "hf_id": "Qwen/Qwen2.5-VL-3B-Instruct", + "hf_revision": "66285546d2b821cf421d4f5eb2576359d3770cd3", "bundle": "qwen25vl-3b-vl-tp2.bundle", "family": "qwen_vl", "task": "vision_language_generation", diff --git a/families/qwen_vl/tests/manifests/qwen25vl-3b.json b/families/qwen_vl/tests/manifests/qwen25vl-3b.json index 3f2aaa93e2..1153ddf52e 100644 --- a/families/qwen_vl/tests/manifests/qwen25vl-3b.json +++ b/families/qwen_vl/tests/manifests/qwen25vl-3b.json @@ -1,6 +1,7 @@ { "name": "qwen25vl-3b", "hf_id": "Qwen/Qwen2.5-VL-3B-Instruct", + "hf_revision": "66285546d2b821cf421d4f5eb2576359d3770cd3", "bundle": "qwen25vl-3b-vl.bundle", "family": "qwen_vl", "task": "vision_language_generation", diff --git a/families/qwen_vl/tests/manifests/qwen3-vl-2b-tp4.json b/families/qwen_vl/tests/manifests/qwen3-vl-2b-tp4.json index d216ba6c9c..bd445ac477 100644 --- a/families/qwen_vl/tests/manifests/qwen3-vl-2b-tp4.json +++ b/families/qwen_vl/tests/manifests/qwen3-vl-2b-tp4.json @@ -1,6 +1,7 @@ { "name": "qwen3-vl-2b-tp4", "hf_id": "Qwen/Qwen3-VL-2B-Instruct", + "hf_revision": "89644892e4d85e24eaac8bacfd4f463576704203", "bundle": "qwen3-vl-2b-tp4.bundle", "family": "qwen_vl", "task": "vision_language_generation", diff --git a/families/qwen_vl/tests/manifests/qwen3-vl-2b.json b/families/qwen_vl/tests/manifests/qwen3-vl-2b.json index aeb9cd5921..f6f97eee3e 100644 --- a/families/qwen_vl/tests/manifests/qwen3-vl-2b.json +++ b/families/qwen_vl/tests/manifests/qwen3-vl-2b.json @@ -1,6 +1,7 @@ { "name": "qwen3-vl-2b", "hf_id": "Qwen/Qwen3-VL-2B-Instruct", + "hf_revision": "89644892e4d85e24eaac8bacfd4f463576704203", "bundle": "qwen3-vl-2b.bundle", "family": "qwen_vl", "task": "vision_language_generation", diff --git a/families/roberta/tests/manifests/camembert-base-tp4.json b/families/roberta/tests/manifests/camembert-base-tp4.json index a15a8081c9..e3c9554d70 100644 --- a/families/roberta/tests/manifests/camembert-base-tp4.json +++ b/families/roberta/tests/manifests/camembert-base-tp4.json @@ -1,6 +1,7 @@ { "name": "camembert-base-tp4", "hf_id": "almanach/camembert-base", + "hf_revision": "a75967561c78f2aa81cc41045378d3b4ee25af9e", "bundle": "camembert-base-tp4.bundle", "family": "roberta", "task": "encoding", diff --git a/families/roberta/tests/manifests/camembert-base.json b/families/roberta/tests/manifests/camembert-base.json index 856c417817..dffe24ea3c 100644 --- a/families/roberta/tests/manifests/camembert-base.json +++ b/families/roberta/tests/manifests/camembert-base.json @@ -1,6 +1,7 @@ { "name": "camembert-base", "hf_id": "almanach/camembert-base", + "hf_revision": "a75967561c78f2aa81cc41045378d3b4ee25af9e", "bundle": "camembert-base.bundle", "family": "roberta", "task": "encoding", diff --git a/families/roberta/tests/manifests/roberta-base-tp4.json b/families/roberta/tests/manifests/roberta-base-tp4.json index 16d7e08445..9cd585fdf6 100644 --- a/families/roberta/tests/manifests/roberta-base-tp4.json +++ b/families/roberta/tests/manifests/roberta-base-tp4.json @@ -1,6 +1,7 @@ { "name": "roberta-base-tp4", "hf_id": "FacebookAI/roberta-base", + "hf_revision": "e2da8e2f811d1448a5b465c236feacd80ffbac7b", "bundle": "roberta-base-tp4.bundle", "family": "roberta", "task": "encoding", diff --git a/families/roberta/tests/manifests/roberta-base.json b/families/roberta/tests/manifests/roberta-base.json index ee02a4bb56..f9c7fd60ce 100644 --- a/families/roberta/tests/manifests/roberta-base.json +++ b/families/roberta/tests/manifests/roberta-base.json @@ -1,6 +1,7 @@ { "name": "roberta-base", "hf_id": "FacebookAI/roberta-base", + "hf_revision": "e2da8e2f811d1448a5b465c236feacd80ffbac7b", "bundle": "roberta-base.bundle", "family": "roberta", "task": "encoding", diff --git a/families/roberta/tests/manifests/roberta-large-tp4.json b/families/roberta/tests/manifests/roberta-large-tp4.json index fa97282790..3db50f9cfb 100644 --- a/families/roberta/tests/manifests/roberta-large-tp4.json +++ b/families/roberta/tests/manifests/roberta-large-tp4.json @@ -1,6 +1,7 @@ { "name": "roberta-large-tp4", "hf_id": "FacebookAI/roberta-large", + "hf_revision": "722cf37b1afa9454edce342e7895e588b6ff1d59", "bundle": "roberta-large-tp4.bundle", "family": "roberta", "task": "encoding", diff --git a/families/roberta/tests/manifests/roberta-large.json b/families/roberta/tests/manifests/roberta-large.json index a3b1601ed3..7b39340f4f 100644 --- a/families/roberta/tests/manifests/roberta-large.json +++ b/families/roberta/tests/manifests/roberta-large.json @@ -1,6 +1,7 @@ { "name": "roberta-large", "hf_id": "FacebookAI/roberta-large", + "hf_revision": "722cf37b1afa9454edce342e7895e588b6ff1d59", "bundle": "roberta-large.bundle", "family": "roberta", "task": "encoding", diff --git a/families/roberta/tests/manifests/xlm-roberta-base-tp4.json b/families/roberta/tests/manifests/xlm-roberta-base-tp4.json index f03ccef5ff..2d43a43591 100644 --- a/families/roberta/tests/manifests/xlm-roberta-base-tp4.json +++ b/families/roberta/tests/manifests/xlm-roberta-base-tp4.json @@ -1,6 +1,7 @@ { "name": "xlm-roberta-base-tp4", "hf_id": "FacebookAI/xlm-roberta-base", + "hf_revision": "e73636d4f797dec63c3081bb6ed5c7b0bb3f2089", "bundle": "xlm-roberta-base-tp4.bundle", "family": "roberta", "task": "encoding", diff --git a/families/roberta/tests/manifests/xlm-roberta-base.json b/families/roberta/tests/manifests/xlm-roberta-base.json index 4055d523c6..64cd121a86 100644 --- a/families/roberta/tests/manifests/xlm-roberta-base.json +++ b/families/roberta/tests/manifests/xlm-roberta-base.json @@ -1,6 +1,7 @@ { "name": "xlm-roberta-base", "hf_id": "FacebookAI/xlm-roberta-base", + "hf_revision": "e73636d4f797dec63c3081bb6ed5c7b0bb3f2089", "bundle": "xlm-roberta-base.bundle", "family": "roberta", "task": "encoding", diff --git a/families/rwkv/tests/manifests/rwkv-169m-tp4.json b/families/rwkv/tests/manifests/rwkv-169m-tp4.json index afbdeaa669..8ea2ba214c 100644 --- a/families/rwkv/tests/manifests/rwkv-169m-tp4.json +++ b/families/rwkv/tests/manifests/rwkv-169m-tp4.json @@ -1,6 +1,7 @@ { "name": "rwkv-169m-tp4", "hf_id": "RWKV/rwkv-4-169m-pile", + "hf_revision": "46bdc280eb97b6141d5d51a935e0c4870ecaefcc", "bundle": "rwkv-169m-tp4.bundle", "family": "rwkv", "task": "text_generation", diff --git a/families/rwkv/tests/manifests/rwkv-169m.json b/families/rwkv/tests/manifests/rwkv-169m.json index 975ca11f97..fc00943008 100644 --- a/families/rwkv/tests/manifests/rwkv-169m.json +++ b/families/rwkv/tests/manifests/rwkv-169m.json @@ -1,6 +1,7 @@ { "name": "rwkv-169m", "hf_id": "RWKV/rwkv-4-169m-pile", + "hf_revision": "46bdc280eb97b6141d5d51a935e0c4870ecaefcc", "bundle": "rwkv-169m.bundle", "family": "rwkv", "task": "text_generation", diff --git a/families/sam/requirements.txt b/families/sam/requirements.txt index 1fc852c84d..d70ef21a5b 100644 --- a/families/sam/requirements.txt +++ b/families/sam/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow -scipy +Pillow==12.2.0 +scipy==1.12.0 diff --git a/families/sam/tests/manifests/sam-vit-base-tp4.json b/families/sam/tests/manifests/sam-vit-base-tp4.json index a2a2a4e741..c8b3bc58bf 100644 --- a/families/sam/tests/manifests/sam-vit-base-tp4.json +++ b/families/sam/tests/manifests/sam-vit-base-tp4.json @@ -1,6 +1,7 @@ { "name": "sam-vit-base-tp4", "hf_id": "facebook/sam-vit-base", + "hf_revision": "70c1a07f894ebb5b307fd9eaaee97b9dfc16068f", "bundle": "sam-vit-base-tp4.bundle", "family": "sam", "task": "prompted_segmentation", diff --git a/families/sam/tests/manifests/sam-vit-base.json b/families/sam/tests/manifests/sam-vit-base.json index ceb86c414d..bcd7428872 100644 --- a/families/sam/tests/manifests/sam-vit-base.json +++ b/families/sam/tests/manifests/sam-vit-base.json @@ -1,6 +1,7 @@ { "name": "sam-vit-base", "hf_id": "facebook/sam-vit-base", + "hf_revision": "70c1a07f894ebb5b307fd9eaaee97b9dfc16068f", "bundle": "sam-vit-base.bundle", "family": "sam", "task": "prompted_segmentation", diff --git a/families/sam2/requirements.txt b/families/sam2/requirements.txt index 5018e40516..23dcd0beee 100644 --- a/families/sam2/requirements.txt +++ b/families/sam2/requirements.txt @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 diff --git a/families/sam3/requirements.txt b/families/sam3/requirements.txt index 5018e40516..23dcd0beee 100644 --- a/families/sam3/requirements.txt +++ b/families/sam3/requirements.txt @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 diff --git a/families/sana_wm/requirements.txt b/families/sana_wm/requirements.txt index 2ffc91cb52..731c79f59a 100644 --- a/families/sana_wm/requirements.txt +++ b/families/sana_wm/requirements.txt @@ -1,23 +1,23 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow -accelerate>=1.3 -diffusers +Pillow==12.2.0 +accelerate==1.14.0 +diffusers==0.40.0 PyYAML==6.0.3 einops==0.8.2 -ftfy +ftfy==6.3.1 huggingface-hub==1.26.0 -imageio[pyav] -flash-linear-attention>=0.4.2 +imageio[pyav]==2.37.4 +flash-linear-attention==0.5.2 mmcv==1.7.2 -omegaconf -pyrallis -pytz -qwen-vl-utils -scipy -termcolor +omegaconf==2.3.0 +pyrallis==0.3.1 +pytz==2026.3.post1 +qwen-vl-utils==0.0.14 +scipy==1.15.3 +termcolor==3.3.0 timm==0.6.13 tokenizers==0.22.2 -tqdm +tqdm==4.67.3 transformers==5.2.0 diff --git a/families/sana_wm/tests/manifests/sana-wm-bidirectional.json b/families/sana_wm/tests/manifests/sana-wm-bidirectional.json index f998bc7c9a..eccc1b8936 100644 --- a/families/sana_wm/tests/manifests/sana-wm-bidirectional.json +++ b/families/sana_wm/tests/manifests/sana-wm-bidirectional.json @@ -1,6 +1,7 @@ { "name": "sana-wm-bidirectional", "hf_id": "Efficient-Large-Model/SANA-WM_bidirectional", + "hf_revision": "e96271d77398def8ebb9fc595e7c0056dc625ab7", "hf_dependencies": [ { "repo_id": "Efficient-Large-Model/gemma-2-2b-it" diff --git a/families/segformer/requirements.txt b/families/segformer/requirements.txt index 718a93c119..f75edd6685 100644 --- a/families/segformer/requirements.txt +++ b/families/segformer/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow -timm>=1.0 +Pillow==12.2.0 +timm==1.0.28 diff --git a/families/segformer/tests/manifests/segformer-b0-ade-tp4.json b/families/segformer/tests/manifests/segformer-b0-ade-tp4.json index 88c554de75..112534d38f 100644 --- a/families/segformer/tests/manifests/segformer-b0-ade-tp4.json +++ b/families/segformer/tests/manifests/segformer-b0-ade-tp4.json @@ -1,6 +1,7 @@ { "name": "segformer-b0-ade-tp4", "hf_id": "nvidia/segformer-b0-finetuned-ade-512-512", + "hf_revision": "489d5cd81a0b59fab9b7ea758d3548ebe99677da", "bundle": "segformer-b0-ade-tp4.bundle", "family": "segformer", "task": "segmentation", diff --git a/families/segformer/tests/manifests/segformer-b0-ade.json b/families/segformer/tests/manifests/segformer-b0-ade.json index d472e0b61a..2afa602654 100644 --- a/families/segformer/tests/manifests/segformer-b0-ade.json +++ b/families/segformer/tests/manifests/segformer-b0-ade.json @@ -1,6 +1,7 @@ { "name": "segformer-b0-ade", "hf_id": "nvidia/segformer-b0-finetuned-ade-512-512", + "hf_revision": "489d5cd81a0b59fab9b7ea758d3548ebe99677da", "bundle": "segformer-b0-ade.bundle", "family": "segformer", "task": "segmentation", diff --git a/families/stablelm/tests/manifests/stablelm2-1.6b-tp4.json b/families/stablelm/tests/manifests/stablelm2-1.6b-tp4.json index e26d8d6340..2bdcb71800 100644 --- a/families/stablelm/tests/manifests/stablelm2-1.6b-tp4.json +++ b/families/stablelm/tests/manifests/stablelm2-1.6b-tp4.json @@ -1,6 +1,7 @@ { "name": "stablelm2-1.6b-tp4", "hf_id": "stabilityai/stablelm-2-1_6b", + "hf_revision": "f499ead74c53749bd93cebc6ce8bc0d7bdf1eaef", "bundle": "stablelm2-1.6b-tp4.bundle", "family": "stablelm", "task": "text_generation", diff --git a/families/starcoder2/tests/manifests/starcoder2-3b-tp2.json b/families/starcoder2/tests/manifests/starcoder2-3b-tp2.json index b295e08efc..ebf80cc232 100644 --- a/families/starcoder2/tests/manifests/starcoder2-3b-tp2.json +++ b/families/starcoder2/tests/manifests/starcoder2-3b-tp2.json @@ -1,6 +1,7 @@ { "name": "starcoder2-3b-tp2", "hf_id": "bigcode/starcoder2-3b", + "hf_revision": "733247c55e3f73af49ce8e9c7949bf14af205928", "bundle": "starcoder2-3b-tp2.bundle", "family": "starcoder2", "task": "text_generation", diff --git a/families/starcoder2/tests/manifests/starcoder2-3b.json b/families/starcoder2/tests/manifests/starcoder2-3b.json index 9639130f8a..3d5ce297f5 100644 --- a/families/starcoder2/tests/manifests/starcoder2-3b.json +++ b/families/starcoder2/tests/manifests/starcoder2-3b.json @@ -1,6 +1,7 @@ { "name": "starcoder2-3b", "hf_id": "bigcode/starcoder2-3b", + "hf_revision": "733247c55e3f73af49ce8e9c7949bf14af205928", "bundle": "starcoder2-3b.bundle", "family": "starcoder2", "task": "text_generation", diff --git a/families/t5/tests/manifests/t5-small-tp4.json b/families/t5/tests/manifests/t5-small-tp4.json index 840ac34372..72cdfa06df 100644 --- a/families/t5/tests/manifests/t5-small-tp4.json +++ b/families/t5/tests/manifests/t5-small-tp4.json @@ -1,6 +1,7 @@ { "name": "t5-small-tp4", "hf_id": "google-t5/t5-small", + "hf_revision": "df1b051c49625cf57a3d0d8d3863ed4d13564fe4", "bundle": "t5-small-tp4.bundle", "family": "t5", "task": "text_generation", diff --git a/families/t5/tests/manifests/t5-small.json b/families/t5/tests/manifests/t5-small.json index 03aa4b84e9..7d8f14bc0f 100644 --- a/families/t5/tests/manifests/t5-small.json +++ b/families/t5/tests/manifests/t5-small.json @@ -1,6 +1,7 @@ { "name": "t5-small", "hf_id": "google-t5/t5-small", + "hf_revision": "df1b051c49625cf57a3d0d8d3863ed4d13564fe4", "bundle": "t5-small.bundle", "family": "t5", "task": "text_generation", diff --git a/families/timesfm/tests/manifests/timesfm-2.0-500m-official-tp4.json b/families/timesfm/tests/manifests/timesfm-2.0-500m-official-tp4.json index 345b22594e..5beb149fa8 100644 --- a/families/timesfm/tests/manifests/timesfm-2.0-500m-official-tp4.json +++ b/families/timesfm/tests/manifests/timesfm-2.0-500m-official-tp4.json @@ -1,6 +1,7 @@ { "name": "timesfm-2.0-500m-official-tp4", "hf_id": "google/timesfm-2.0-500m-pytorch", + "hf_revision": "dc2443792ce5516872b89b37cf1bc058c3bf0c10", "bundle": "timesfm-2.0-500m-official-tp4.bundle", "family": "timesfm", "task": "time_series_forecast", diff --git a/families/timesfm/tests/manifests/timesfm-2.0-500m-official.json b/families/timesfm/tests/manifests/timesfm-2.0-500m-official.json index c6f2c71a9a..76c16a84dd 100644 --- a/families/timesfm/tests/manifests/timesfm-2.0-500m-official.json +++ b/families/timesfm/tests/manifests/timesfm-2.0-500m-official.json @@ -1,6 +1,7 @@ { "name": "timesfm-2.0-500m-official", "hf_id": "google/timesfm-2.0-500m-pytorch", + "hf_revision": "dc2443792ce5516872b89b37cf1bc058c3bf0c10", "bundle": "timesfm-2.0-500m-official.bundle", "family": "timesfm", "task": "time_series_forecast", diff --git a/families/timm_densenet/requirements.txt b/families/timm_densenet/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_densenet/requirements.txt +++ b/families/timm_densenet/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_densenet/tests/manifests/densenet121-ra-in1k.json b/families/timm_densenet/tests/manifests/densenet121-ra-in1k.json index 67e4295811..0ef62b4daf 100644 --- a/families/timm_densenet/tests/manifests/densenet121-ra-in1k.json +++ b/families/timm_densenet/tests/manifests/densenet121-ra-in1k.json @@ -1,6 +1,7 @@ { "name": "densenet121-ra-in1k", "hf_id": "timm/densenet121.ra_in1k", + "hf_revision": "92007b6200e0b4a4fe68cb4e3947022a928aaaae", "bundle": "densenet121-ra-in1k.bundle", "family": "timm_densenet", "task": "classification", diff --git a/families/timm_efficientnet/requirements.txt b/families/timm_efficientnet/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_efficientnet/requirements.txt +++ b/families/timm_efficientnet/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_efficientnet/tests/manifests/efficientnet-b0-ra-in1k.json b/families/timm_efficientnet/tests/manifests/efficientnet-b0-ra-in1k.json index ce0047e9d0..85ff075cb1 100644 --- a/families/timm_efficientnet/tests/manifests/efficientnet-b0-ra-in1k.json +++ b/families/timm_efficientnet/tests/manifests/efficientnet-b0-ra-in1k.json @@ -1,6 +1,7 @@ { "name": "efficientnet-b0-ra-in1k", "hf_id": "timm/efficientnet_b0.ra_in1k", + "hf_revision": "1b5383e5f79cc0f7fc067e372f8f26a5fa73f26a", "bundle": "efficientnet-b0-ra-in1k.bundle", "family": "timm_efficientnet", "task": "classification", diff --git a/families/timm_inception/requirements.txt b/families/timm_inception/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_inception/requirements.txt +++ b/families/timm_inception/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_inception/tests/manifests/inception-v3-tv-in1k.json b/families/timm_inception/tests/manifests/inception-v3-tv-in1k.json index 815d23ea94..9be1f20b76 100644 --- a/families/timm_inception/tests/manifests/inception-v3-tv-in1k.json +++ b/families/timm_inception/tests/manifests/inception-v3-tv-in1k.json @@ -1,6 +1,7 @@ { "name": "inception-v3-tv-in1k", "hf_id": "timm/inception_v3.tv_in1k", + "hf_revision": "393d84cc85c467d8fbc0dc81a65c04e87a32572c", "bundle": "inception-v3-tv-in1k.bundle", "family": "timm_inception", "task": "classification", diff --git a/families/timm_mnasnet/requirements.txt b/families/timm_mnasnet/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_mnasnet/requirements.txt +++ b/families/timm_mnasnet/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_mnasnet/tests/manifests/mnasnet-100-rmsp-in1k.json b/families/timm_mnasnet/tests/manifests/mnasnet-100-rmsp-in1k.json index 758cb24c16..cf9465dcb6 100644 --- a/families/timm_mnasnet/tests/manifests/mnasnet-100-rmsp-in1k.json +++ b/families/timm_mnasnet/tests/manifests/mnasnet-100-rmsp-in1k.json @@ -1,6 +1,7 @@ { "name": "mnasnet-100-rmsp-in1k", "hf_id": "timm/mnasnet_100.rmsp_in1k", + "hf_revision": "a30af72360c7a4871b0156cc11d7b767208273d7", "bundle": "mnasnet-100-rmsp-in1k.bundle", "family": "timm_mnasnet", "task": "classification", diff --git a/families/timm_mobilenetv3/requirements.txt b/families/timm_mobilenetv3/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_mobilenetv3/requirements.txt +++ b/families/timm_mobilenetv3/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_mobilenetv3/tests/manifests/mobilenetv3-large-100-ra-in1k.json b/families/timm_mobilenetv3/tests/manifests/mobilenetv3-large-100-ra-in1k.json index 1ed03ce548..c68f1b1bc6 100644 --- a/families/timm_mobilenetv3/tests/manifests/mobilenetv3-large-100-ra-in1k.json +++ b/families/timm_mobilenetv3/tests/manifests/mobilenetv3-large-100-ra-in1k.json @@ -1,6 +1,7 @@ { "name": "mobilenetv3-large-100-ra-in1k", "hf_id": "timm/mobilenetv3_large_100.ra_in1k", + "hf_revision": "96f46a1c52932f27492dff66c72378eb99b443a7", "bundle": "mobilenetv3-large-100-ra-in1k.bundle", "family": "timm_mobilenetv3", "task": "classification", diff --git a/families/timm_repvgg/requirements.txt b/families/timm_repvgg/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_repvgg/requirements.txt +++ b/families/timm_repvgg/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_resnet/requirements.txt b/families/timm_resnet/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_resnet/requirements.txt +++ b/families/timm_resnet/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_resnet/tests/manifests/resnet50-a1-in1k.json b/families/timm_resnet/tests/manifests/resnet50-a1-in1k.json index 9f64046e95..6b5b08992f 100644 --- a/families/timm_resnet/tests/manifests/resnet50-a1-in1k.json +++ b/families/timm_resnet/tests/manifests/resnet50-a1-in1k.json @@ -1,6 +1,7 @@ { "name": "resnet50-a1-in1k", "hf_id": "timm/resnet50.a1_in1k", + "hf_revision": "767268603ca0cb0bfe326fa87277f19c419566ef", "bundle": "resnet50-a1-in1k.bundle", "family": "timm_resnet", "task": "classification", diff --git a/families/timm_vgg/requirements.txt b/families/timm_vgg/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_vgg/requirements.txt +++ b/families/timm_vgg/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_vgg/tests/manifests/vgg16-tv-in1k.json b/families/timm_vgg/tests/manifests/vgg16-tv-in1k.json index 6e94e1192e..80e3077258 100644 --- a/families/timm_vgg/tests/manifests/vgg16-tv-in1k.json +++ b/families/timm_vgg/tests/manifests/vgg16-tv-in1k.json @@ -1,6 +1,7 @@ { "name": "vgg16-tv-in1k", "hf_id": "timm/vgg16.tv_in1k", + "hf_revision": "b8d8aa2dd860af9233c8c67385a8097fd6c35d3f", "bundle": "vgg16-tv-in1k.bundle", "family": "timm_vgg", "task": "classification", diff --git a/families/timm_vit/requirements.txt b/families/timm_vit/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_vit/requirements.txt +++ b/families/timm_vit/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_vit/tests/manifests/timm-vit-base-p16-224-augreg-in21k-ft-in1k-tp4.json b/families/timm_vit/tests/manifests/timm-vit-base-p16-224-augreg-in21k-ft-in1k-tp4.json index 41a952899b..51fd13cc73 100644 --- a/families/timm_vit/tests/manifests/timm-vit-base-p16-224-augreg-in21k-ft-in1k-tp4.json +++ b/families/timm_vit/tests/manifests/timm-vit-base-p16-224-augreg-in21k-ft-in1k-tp4.json @@ -1,6 +1,7 @@ { "name": "timm-vit-base-p16-224-augreg-in21k-ft-in1k-tp4", "hf_id": "timm/vit_base_patch16_224.augreg_in21k_ft_in1k", + "hf_revision": "2ec9fb3d7bb664aac471ac44582c94d18de33780", "bundle": "timm-vit-base-p16-224-augreg-in21k-ft-in1k-tp4.bundle", "family": "timm_vit", "task": "classification", diff --git a/families/timm_vit/tests/manifests/timm-vit-base-p16-224-augreg-in21k-ft-in1k.json b/families/timm_vit/tests/manifests/timm-vit-base-p16-224-augreg-in21k-ft-in1k.json index 0e90261943..3eb5856ee9 100644 --- a/families/timm_vit/tests/manifests/timm-vit-base-p16-224-augreg-in21k-ft-in1k.json +++ b/families/timm_vit/tests/manifests/timm-vit-base-p16-224-augreg-in21k-ft-in1k.json @@ -1,6 +1,7 @@ { "name": "timm-vit-base-p16-224-augreg-in21k-ft-in1k", "hf_id": "timm/vit_base_patch16_224.augreg_in21k_ft_in1k", + "hf_revision": "2ec9fb3d7bb664aac471ac44582c94d18de33780", "bundle": "timm-vit-base-p16-224-augreg-in21k-ft-in1k.bundle", "family": "timm_vit", "task": "classification", diff --git a/families/wan2_2_ti2v/requirements.txt b/families/wan2_2_ti2v/requirements.txt index 5e31a23082..b232d488fe 100644 --- a/families/wan2_2_ti2v/requirements.txt +++ b/families/wan2_2_ti2v/requirements.txt @@ -1,19 +1,19 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow -accelerate>=1.1.1 -dashscope -diffusers>=0.31.0 -easydict +Pillow==12.2.0 +accelerate==1.14.0 +dashscope==1.27.4 +diffusers==0.40.0 +easydict==1.13 einops==0.8.1 -flash-attn +flash-attn==2.8.3 ftfy==6.3.1 -imageio[ffmpeg] -librosa -numpy>=1.23.5,<2 -opencv-python>=4.9.0.80 -peft -tokenizers>=0.20.3 -tqdm -transformers>=4.49.0,<=4.51.3 +imageio[ffmpeg]==2.37.4 +librosa==0.11.0 +numpy==1.26.4 +opencv-python==4.11.0.86 +peft==0.20.0 +tokenizers==0.21.4 +tqdm==4.67.3 +transformers==4.51.3 diff --git a/families/wan_t2v/requirements.txt b/families/wan_t2v/requirements.txt index 18f1c26b2f..a17f59142d 100644 --- a/families/wan_t2v/requirements.txt +++ b/families/wan_t2v/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow -diffusers +Pillow==12.2.0 +diffusers==0.40.0 diff --git a/families/wan_t2v/tests/manifests/wan21-t2v-1.3b-l0-cp4.json b/families/wan_t2v/tests/manifests/wan21-t2v-1.3b-l0-cp4.json index 0e85cf1169..9d1fe508c7 100644 --- a/families/wan_t2v/tests/manifests/wan21-t2v-1.3b-l0-cp4.json +++ b/families/wan_t2v/tests/manifests/wan21-t2v-1.3b-l0-cp4.json @@ -1,6 +1,7 @@ { "name": "wan21-t2v-1.3b-l0-cp4", "hf_id": "Wan-AI/Wan2.1-T2V-1.3B-Diffusers", + "hf_revision": "0fad780a534b6463e45facd96134c9f345acfa5b", "bundle": "wan21-t2v-1.3b-l0-cp4.bundle", "family": "wan_t2v", "task": "image_generation", diff --git a/families/wan_t2v/tests/manifests/wan21-t2v-1.3b-l0-tp4.json b/families/wan_t2v/tests/manifests/wan21-t2v-1.3b-l0-tp4.json index a91365077f..ff63207803 100644 --- a/families/wan_t2v/tests/manifests/wan21-t2v-1.3b-l0-tp4.json +++ b/families/wan_t2v/tests/manifests/wan21-t2v-1.3b-l0-tp4.json @@ -1,6 +1,7 @@ { "name": "wan21-t2v-1.3b-l0-tp4", "hf_id": "Wan-AI/Wan2.1-T2V-1.3B-Diffusers", + "hf_revision": "0fad780a534b6463e45facd96134c9f345acfa5b", "bundle": "wan21-t2v-1.3b-l0-tp4.bundle", "family": "wan_t2v", "task": "image_generation", diff --git a/families/wan_t2v/tests/manifests/wan21-t2v-1.3b-l0.json b/families/wan_t2v/tests/manifests/wan21-t2v-1.3b-l0.json index e11c8ef0d5..dfad8ab980 100644 --- a/families/wan_t2v/tests/manifests/wan21-t2v-1.3b-l0.json +++ b/families/wan_t2v/tests/manifests/wan21-t2v-1.3b-l0.json @@ -1,6 +1,7 @@ { "name": "wan21-t2v-1.3b-l0", "hf_id": "Wan-AI/Wan2.1-T2V-1.3B-Diffusers", + "hf_revision": "0fad780a534b6463e45facd96134c9f345acfa5b", "bundle": "wan21-t2v-1.3b-l0.bundle", "family": "wan_t2v", "task": "image_generation", diff --git a/families/wan_t2v/tests/manifests/wan21-t2v-1.3b.json b/families/wan_t2v/tests/manifests/wan21-t2v-1.3b.json index 89e60def42..e32eaadbd2 100644 --- a/families/wan_t2v/tests/manifests/wan21-t2v-1.3b.json +++ b/families/wan_t2v/tests/manifests/wan21-t2v-1.3b.json @@ -1,6 +1,7 @@ { "name": "wan21-t2v-1.3b", "hf_id": "Wan-AI/Wan2.1-T2V-1.3B-Diffusers", + "hf_revision": "0fad780a534b6463e45facd96134c9f345acfa5b", "bundle": "wan21-t2v-1.3b.bundle", "family": "wan_t2v", "task": "image_generation", diff --git a/families/whisper/requirements.txt b/families/whisper/requirements.txt index 860aa73c19..391ad564c8 100644 --- a/families/whisper/requirements.txt +++ b/families/whisper/requirements.txt @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -scipy +scipy==1.15.3 diff --git a/families/whisper/tests/manifests/whisper-large-v3-turbo-tp4.json b/families/whisper/tests/manifests/whisper-large-v3-turbo-tp4.json index 295df73880..b092e07a86 100644 --- a/families/whisper/tests/manifests/whisper-large-v3-turbo-tp4.json +++ b/families/whisper/tests/manifests/whisper-large-v3-turbo-tp4.json @@ -1,6 +1,7 @@ { "name": "whisper-large-v3-turbo-tp4", "hf_id": "openai/whisper-large-v3-turbo", + "hf_revision": "41f01f3fe87f28c78e2fbf8b568835947dd65ed9", "bundle": "whisper-large-v3-turbo-tp4.bundle", "family": "whisper", "task": "transcription", diff --git a/families/whisper/tests/manifests/whisper-large-v3-turbo.json b/families/whisper/tests/manifests/whisper-large-v3-turbo.json index 879945e7d8..b492919249 100644 --- a/families/whisper/tests/manifests/whisper-large-v3-turbo.json +++ b/families/whisper/tests/manifests/whisper-large-v3-turbo.json @@ -1,6 +1,7 @@ { "name": "whisper-large-v3-turbo", "hf_id": "openai/whisper-large-v3-turbo", + "hf_revision": "41f01f3fe87f28c78e2fbf8b568835947dd65ed9", "bundle": "whisper-large-v3-turbo.bundle", "family": "whisper", "task": "transcription", diff --git a/families/whisper/tests/manifests/whisper-tiny-fp16-tp2.json b/families/whisper/tests/manifests/whisper-tiny-fp16-tp2.json index 946928950a..ad3101f5bb 100644 --- a/families/whisper/tests/manifests/whisper-tiny-fp16-tp2.json +++ b/families/whisper/tests/manifests/whisper-tiny-fp16-tp2.json @@ -1,6 +1,7 @@ { "name": "whisper-tiny-fp16-tp2", "hf_id": "openai/whisper-tiny", + "hf_revision": "169d4a4341b33bc18d8881c4b69c2e104e1cc0af", "bundle": "whisper-tiny-fp16-tp2.bundle", "family": "whisper", "task": "transcription", diff --git a/families/whisper/tests/manifests/whisper-tiny-fp16.json b/families/whisper/tests/manifests/whisper-tiny-fp16.json index b8a6281c30..eb9978d121 100644 --- a/families/whisper/tests/manifests/whisper-tiny-fp16.json +++ b/families/whisper/tests/manifests/whisper-tiny-fp16.json @@ -1,6 +1,7 @@ { "name": "whisper-tiny-fp16", "hf_id": "openai/whisper-tiny", + "hf_revision": "169d4a4341b33bc18d8881c4b69c2e104e1cc0af", "bundle": "whisper-tiny-fp16.bundle", "family": "whisper", "task": "transcription", diff --git a/families/xglm/tests/manifests/xglm-564m-tp4.json b/families/xglm/tests/manifests/xglm-564m-tp4.json index 102b3ff93d..cc2e974a1c 100644 --- a/families/xglm/tests/manifests/xglm-564m-tp4.json +++ b/families/xglm/tests/manifests/xglm-564m-tp4.json @@ -1,6 +1,7 @@ { "name": "xglm-564m-tp4", "hf_id": "facebook/xglm-564M", + "hf_revision": "f3059f01b98ccc877c673149e0178c0e957660f9", "bundle": "xglm-564m-tp4.bundle", "family": "xglm", "task": "text_generation", diff --git a/families/xglm/tests/manifests/xglm-564m.json b/families/xglm/tests/manifests/xglm-564m.json index bb6ec8654f..7f7a450d4f 100644 --- a/families/xglm/tests/manifests/xglm-564m.json +++ b/families/xglm/tests/manifests/xglm-564m.json @@ -1,6 +1,7 @@ { "name": "xglm-564m", "hf_id": "facebook/xglm-564M", + "hf_revision": "f3059f01b98ccc877c673149e0178c0e957660f9", "bundle": "xglm-564m.bundle", "family": "xglm", "task": "text_generation", diff --git a/families/xlnet/tests/manifests/xlnet-base-tp4.json b/families/xlnet/tests/manifests/xlnet-base-tp4.json index 9efdca63f8..795f952e0a 100644 --- a/families/xlnet/tests/manifests/xlnet-base-tp4.json +++ b/families/xlnet/tests/manifests/xlnet-base-tp4.json @@ -1,6 +1,7 @@ { "name": "xlnet-base-tp4", "hf_id": "xlnet/xlnet-base-cased", + "hf_revision": "ceaa69c7bc5e512b5007106a7ccbb7daf24b2c79", "bundle": "xlnet-base-tp4.bundle", "family": "xlnet", "task": "encoding", diff --git a/families/xlnet/tests/manifests/xlnet-base.json b/families/xlnet/tests/manifests/xlnet-base.json index 7c13a65c68..36829933a0 100644 --- a/families/xlnet/tests/manifests/xlnet-base.json +++ b/families/xlnet/tests/manifests/xlnet-base.json @@ -1,6 +1,7 @@ { "name": "xlnet-base", "hf_id": "xlnet/xlnet-base-cased", + "hf_revision": "ceaa69c7bc5e512b5007106a7ccbb7daf24b2c79", "bundle": "xlnet-base.bundle", "family": "xlnet", "task": "encoding", diff --git a/families/z_image/requirements.txt b/families/z_image/requirements.txt index 18f1c26b2f..a17f59142d 100644 --- a/families/z_image/requirements.txt +++ b/families/z_image/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow -diffusers +Pillow==12.2.0 +diffusers==0.40.0 diff --git a/families/z_image/tests/manifests/z-image-turbo-l0-tp2.json b/families/z_image/tests/manifests/z-image-turbo-l0-tp2.json index 3f5cb13547..9e05ec9190 100644 --- a/families/z_image/tests/manifests/z-image-turbo-l0-tp2.json +++ b/families/z_image/tests/manifests/z-image-turbo-l0-tp2.json @@ -1,6 +1,7 @@ { "name": "z-image-turbo-l0-tp2", "hf_id": "Tongyi-MAI/Z-Image-Turbo", + "hf_revision": "f332072aa78be7aecdf3ee76d5c247082da564a6", "bundle": "z-image-turbo-l0-tp2.bundle", "family": "z_image", "task": "image_generation", diff --git a/families/z_image/tests/manifests/z-image-turbo-l0.json b/families/z_image/tests/manifests/z-image-turbo-l0.json index a23bcb45af..5764365c49 100644 --- a/families/z_image/tests/manifests/z-image-turbo-l0.json +++ b/families/z_image/tests/manifests/z-image-turbo-l0.json @@ -1,6 +1,7 @@ { "name": "z-image-turbo-l0", "hf_id": "Tongyi-MAI/Z-Image-Turbo", + "hf_revision": "f332072aa78be7aecdf3ee76d5c247082da564a6", "bundle": "z-image-turbo-l0.bundle", "family": "z_image", "task": "image_generation", diff --git a/families/z_image/tests/manifests/z-image-turbo.json b/families/z_image/tests/manifests/z-image-turbo.json index 7bead16ef9..26d12eaccb 100644 --- a/families/z_image/tests/manifests/z-image-turbo.json +++ b/families/z_image/tests/manifests/z-image-turbo.json @@ -1,6 +1,7 @@ { "name": "z-image-turbo", "hf_id": "Tongyi-MAI/Z-Image-Turbo", + "hf_revision": "f332072aa78be7aecdf3ee76d5c247082da564a6", "bundle": "z-image-turbo.bundle", "family": "z_image", "task": "image_generation", diff --git a/pyproject.toml b/pyproject.toml index 873a507476..dc637c322f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ requires = [ "apache-tvm-ffi==0.1.12", "conan-py-build==0.4.3", - "torch>=2.6", + "torch==2.12.0", ] build-backend = "conan_py_build.build" @@ -18,24 +18,24 @@ license = "Apache-2.0" license-files = ["LICENSE", "NOTICE", "ASSET_LICENSES.md"] requires-python = ">=3.12" dependencies = [ - "safetensors>=0.4", - "numpy>=1.24", - "ml_dtypes>=0.4", - "onnx>=1.16", + "safetensors==0.8.0", + "numpy==1.26.4", + "ml_dtypes==0.5.4", + "onnx==1.21.0", "transformers==5.2.0", - "huggingface_hub>=0.23", - "sentencepiece>=0.1.99", - "cuda-python>=13.0.3,<14", + "huggingface_hub==1.21.0", + "sentencepiece==0.2.2", + "cuda-python==13.0.3", "apache-tvm-ffi==0.1.12", "tensorrt==11.1.0.106", - "PyYAML>=6.0", + "PyYAML==6.0.3", ] [project.scripts] trtmc-bench = "trtmc_benchmark.cli:main" [project.optional-dependencies] -test = ["pytest>=7.0", "torch>=2.0", "jsonschema>=4.23,<5"] +test = ["pytest==8.4.2", "torch==2.12.0", "jsonschema==4.26.0"] cutedsl = ["nvidia-cutlass-dsl==4.7.1"] [tool.conan-py-build.wheel] diff --git a/requirements/base.txt b/requirements/base.txt index 254d410576..fcbd7e789a 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -2,5 +2,5 @@ # SPDX-License-Identifier: Apache-2.0 # Thin source-build delta over the pinned base image. -build>=1.2 +build==1.5.0 conan-py-build==0.4.3 diff --git a/tools/tests/test_architecture.py b/tools/tests/test_architecture.py index 98b6c95b7c..b2e5e7ec1a 100644 --- a/tools/tests/test_architecture.py +++ b/tools/tests/test_architecture.py @@ -7,6 +7,7 @@ import importlib.util import json import re +import tomllib from pathlib import Path @@ -546,9 +547,12 @@ def test_every_builder_handles_every_family_owned_request_field() -> None: # The core consumes these before dispatch. Every other field belongs to the # selected family's build function, including explicit unsupported checks. family_owned_fields = request_fields - { + "checkpoint_id", + "checkpoint_revision", "family", "output_path", "graph_transform", + "source_revision", } violations: list[str] = [] @@ -750,14 +754,30 @@ def dependency_lines(path: Path) -> list[str]: if line.strip() and not line.lstrip().startswith("#") ] - assert dependency_lines(REPO / "requirements/base.txt") == [ - "build>=1.2", + exact_requirement = re.compile( + r"[A-Za-z0-9_.-]+(?:\[[A-Za-z0-9_.,-]+\])?==[^,;*\s]+(?:\s*;\s*.+)?\Z" + ) + base_requirements = dependency_lines(REPO / "requirements/base.txt") + assert base_requirements == [ + "build==1.5.0", "conan-py-build==0.4.3", ] + assert all(exact_requirement.fullmatch(line) for line in base_requirements) pyproject = (REPO / "pyproject.toml").read_text(encoding="utf-8") + project_metadata = tomllib.loads(pyproject) assert 'requires-python = ">=3.12"' in pyproject assert "tomli" not in pyproject + declared_dependencies = [ + *project_metadata["build-system"]["requires"], + *project_metadata["project"]["dependencies"], + *( + requirement + for requirements_group in project_metadata["project"]["optional-dependencies"].values() + for requirement in requirements_group + ), + ] + assert all(exact_requirement.fullmatch(line) for line in declared_dependencies) optional = pyproject.split("[project.optional-dependencies]", 1)[1].split("\n[", 1)[0] assert set(re.findall(r"^([a-z][a-z0-9_-]*)\s*=", optional, re.MULTILINE)) == { "cutedsl", @@ -771,6 +791,9 @@ def dependency_lines(path: Path) -> list[str]: assert lines, f"empty family dependency declaration: {path.relative_to(REPO)}" for line in lines: normalized = line.lower() + assert exact_requirement.fullmatch(line), ( + f"family dependency must use one exact version: {path.relative_to(REPO)}:{line}" + ) assert not normalized.startswith(("-r", "--requirement", "-c", "--constraint")) assert not normalized.startswith(("-e", "--editable", "./", "../", "/", "file:")) assert " @ file:" not in normalized @@ -789,6 +812,22 @@ def dependency_lines(path: Path) -> list[str]: dockerfile = (REPO / "Dockerfile").read_text(encoding="utf-8") assert "COPY requirements/base.txt" in dockerfile assert "families/" not in dockerfile + for requirement in ( + "pip==26.2.1", + "ml_dtypes==0.5.4", + "numpy==1.26.4", + "onnx==1.21.0", + "Pillow==12.2.0", + "protobuf==7.35.0", + "pytest==8.4.2", + "PyYAML==6.0.3", + "safetensors==0.8.0", + "sentencepiece==0.2.2", + "setuptools==81.0.0", + "tokenizers==0.22.2", + ): + assert f'"{requirement}"' in dockerfile + assert "pip install --upgrade pip" not in dockerfile package_validation = (REPO / "tools/ci/package.py").read_text(encoding="utf-8") assert 'import_module(f"families.{family}.model")' not in package_validation @@ -807,6 +846,20 @@ def test_family_reference_consumers_declare_their_source() -> None: assert missing == [] +def test_remote_checkpoint_manifests_pin_exact_revisions() -> None: + violations: list[str] = [] + exact_revision = re.compile(r"[0-9a-f]{40}\Z") + for family in family_dirs(): + for path in (family / "tests/manifests").glob("*.json"): + manifest = json.loads(path.read_text(encoding="utf-8")) + if not manifest.get("hf_id"): + continue + revision = manifest.get("hf_revision") + if not isinstance(revision, str) or exact_revision.fullmatch(revision) is None: + violations.append(str(path.relative_to(REPO))) + assert violations == [] + + def test_ci_base_image_is_pinned_by_its_from_reference() -> None: dockerfile = (REPO / "Dockerfile").read_text(encoding="utf-8") first_from = next( diff --git a/website/docs/api/python-builder.md b/website/docs/api/python-builder.md index 980b803521..f901bd668f 100644 --- a/website/docs/api/python-builder.md +++ b/website/docs/api/python-builder.md @@ -9,11 +9,14 @@ optional build-time graph transform. ```python from pathlib import Path -from tensorrt_model_connect import BuildRequest, build +from tensorrt_model_connect import BuildRequest, build, resolve_source_revision build(BuildRequest( model_dir=Path("/models/gpt2"), output_path=Path("gpt2.bundle"), + checkpoint_id="openai-community/gpt2", + checkpoint_revision="607a30d783dfa663caf39e06633721c8d4cfcd7e", + source_revision=resolve_source_revision(), family="gpt2", task="text_generation", precision="fp16", @@ -28,6 +31,10 @@ resolved API directly. `model_dir` is already local at this boundary. The selected family alone decides whether that directory is a Hugging Face snapshot or a prepared checkpoint; `BuildRequest` does not perform another discovery pass. +Callers of this low-level API should pass the canonical checkpoint ID and exact +checkpoint revision. `resolve_source_revision()` accepts an explicit SHA, +`TRTMC_ENGINE_BUILD_REVISION`, `GITHUB_SHA`, or a Git checkout and fails when +none yields an exact source commit. ## Optional graph transform @@ -47,6 +54,9 @@ def replace_subgraph(network, engine_index): build(BuildRequest( model_dir=Path("/models/gpt2"), output_path=Path("gpt2.bundle"), + checkpoint_id="openai-community/gpt2", + checkpoint_revision="607a30d783dfa663caf39e06633721c8d4cfcd7e", + source_revision=resolve_source_revision(), family="gpt2", task="text_generation", precision="fp16", diff --git a/website/docs/architecture/bundle-format.md b/website/docs/architecture/bundle-format.md index fa9dd49a68..a5e4de352a 100644 --- a/website/docs/architecture/bundle-format.md +++ b/website/docs/architecture/bundle-format.md @@ -12,8 +12,9 @@ header length, the UTF-8 JSON header, and concatenated named sections. "task": "text_generation", "backend": "trt", "sections": { - "runtime.json": {"offset": 0, "length": 42}, - "engine.plan": {"offset": 42, "length": 1234} + "provenance.json": {"offset": 0, "length": 391}, + "runtime.json": {"offset": 391, "length": 42}, + "engine.plan": {"offset": 433, "length": 1234} } } ``` @@ -23,5 +24,17 @@ constructed. It owns the normalized bundle path and immutable section table, then reads a requested section directly from the file. It has no write API and does not eagerly load section contents. +Every newly built bundle contains a `provenance.json` section. It records the +canonical checkpoint ID, the exact checkpoint commit, the exact TRTMC source +commit, and every build-affecting request option. `trtmc inspect BUNDLE` +returns this provenance alongside the fixed header and section table. A build +fails instead of publishing a bundle when its TRTMC source commit cannot be +resolved exactly. + +Benchmark-managed bundles are reused only when all of this provenance matches +the selected manifest and current source revision. Bundles without provenance, +or with only a partial match, are rebuilt when builds are enabled and rejected +when `--no-build` is set. + The core does not interpret family sections or compute section hashes. Only format 1 is supported. diff --git a/website/docs/getting-started/quick-start.md b/website/docs/getting-started/quick-start.md index 26f29757ae..f4f6910e78 100644 --- a/website/docs/getting-started/quick-start.md +++ b/website/docs/getting-started/quick-start.md @@ -30,8 +30,10 @@ Build a bundle directly from a Hugging Face model ID: ```bash python -m tensorrt_model_connect build openai-community/gpt2 \ + --revision 607a30d783dfa663caf39e06633721c8d4cfcd7e \ --precision fp16 \ --output gpt2.bundle +trtmc inspect gpt2.bundle ``` The CLI downloads the snapshot, reads `config.json` or `model_index.json`, and @@ -39,7 +41,9 @@ asks every dependency-free family `support.py`. Exactly one family must claim the checkpoint. That family supplies the default task; pass `--task` only when selecting another task supported by the same family. The build then imports only the selected `families.gpt2.model` and calls `build(request, writer)` once. -A prepared local snapshot can be passed in place of the model ID. +A prepared local snapshot can be passed in place of the model ID. Pass its +canonical model name with `--checkpoint-id` and its exact commit with +`--revision` so the resulting provenance is equivalent to a direct download. For a wheel install, resolve its native runtime directory directly from the installed package: From 4ade404051deecbb9e3b4e2c8a66036e3fb55e78 Mon Sep 17 00:00:00 2001 From: chaofengw Date: Mon, 7 Sep 2026 10:43:09 +0000 Subject: [PATCH 2/5] fix(build): freeze provenance before compilation Resolve the source revision before family build work starts and reject non-exact local checkpoint revisions at the CLI boundary. Keep the generic builder tests independent of concrete model families. Signed-off-by: chaofengw --- core/builder/tensorrt_model_connect/build.py | 3 +- .../tensorrt_model_connect/build_cli.py | 2 + core/builder/tests/test_build.py | 54 ++++++++++++++++--- core/builder/tests/test_build_cli.py | 38 ++++++++++--- 4 files changed, 82 insertions(+), 15 deletions(-) diff --git a/core/builder/tensorrt_model_connect/build.py b/core/builder/tensorrt_model_connect/build.py index fe4d6db08c..2c752a259b 100644 --- a/core/builder/tensorrt_model_connect/build.py +++ b/core/builder/tensorrt_model_connect/build.py @@ -148,9 +148,10 @@ def build(request: BuildRequest) -> None: family_module = _load_family(family) writer = BundleWriter(request.output_path) try: + provenance = _build_provenance(request) with graph_transform(request.graph_transform): family_module.build(request, writer) - writer.add_json("provenance.json", _build_provenance(request)) + writer.add_json("provenance.json", provenance) writer.finish() except BaseException: writer.abort() diff --git a/core/builder/tensorrt_model_connect/build_cli.py b/core/builder/tensorrt_model_connect/build_cli.py index 31adc82fe0..a27277c875 100644 --- a/core/builder/tensorrt_model_connect/build_cli.py +++ b/core/builder/tensorrt_model_connect/build_cli.py @@ -136,6 +136,8 @@ def _checkpoint_revision( requested = (requested or "").strip().lower() if _EXACT_REVISION.fullmatch(requested): return requested + if requested: + raise ValueError("checkpoint revision must be an exact 40-character Git SHA") if require_exact: raise ValueError( "Hugging Face model resolution did not produce an exact 40-character commit SHA" diff --git a/core/builder/tests/test_build.py b/core/builder/tests/test_build.py index bd53425fff..3b9a0815e6 100644 --- a/core/builder/tests/test_build.py +++ b/core/builder/tests/test_build.py @@ -198,12 +198,12 @@ def test_build_embeds_checkpoint_and_source_provenance(monkeypatch, tmp_path: Pa request = BuildRequest( model_dir=tmp_path / "model", output_path=tmp_path / "model.bundle", - checkpoint_id="openai-community/gpt2", + checkpoint_id="example-org/example-model", checkpoint_revision=checkpoint_revision, source_revision=source_revision, precision="fp16", - family="gpt2", - task="text_generation", + family="example", + task="example_task", max_sequence_length=128, ) @@ -233,13 +233,13 @@ def family_build(seen_request: BuildRequest, writer) -> None: assert provenance == { "format": 1, "checkpoint": { - "id": "openai-community/gpt2", + "id": "example-org/example-model", "revision": checkpoint_revision, }, "build": {"source_revision": source_revision}, "request": { - "family": "gpt2", - "task": "text_generation", + "family": "example", + "task": "example_task", "backend": "trt", "precision": "fp16", "max_sequence_length": 128, @@ -251,6 +251,48 @@ def family_build(seen_request: BuildRequest, writer) -> None: } +def test_build_freezes_source_revision_before_family_build( + monkeypatch, tmp_path: Path +) -> None: + events: list[str] = [] + source_revision = "a" * 40 + request = BuildRequest( + model_dir=tmp_path / "model", + output_path=tmp_path / "model.bundle", + checkpoint_id="example-org/example-model", + checkpoint_revision="b" * 40, + source_revision=source_revision, + precision="fp16", + family="example", + task="example_task", + ) + + def resolve_source_revision(explicit: str = "") -> str: + assert explicit == source_revision + events.append("resolve_source_revision") + return source_revision + + def family_build(seen_request: BuildRequest, writer) -> None: + events.append("family_build") + writer.set_header( + family=seen_request.family, + task=seen_request.task, + backend=seen_request.backend, + ) + writer.add_bytes("engine.plan", b"plan") + + monkeypatch.setattr(build_core, "resolve_source_revision", resolve_source_revision) + monkeypatch.setattr( + build_core, + "_load_family", + lambda _family: SimpleNamespace(build=family_build), + ) + + build_core.build(request) + + assert events == ["resolve_source_revision", "family_build"] + + def test_build_runs_graph_transform_before_family_engine_serialization( monkeypatch, tmp_path: Path ) -> None: diff --git a/core/builder/tests/test_build_cli.py b/core/builder/tests/test_build_cli.py index c14a63892e..943516dc52 100644 --- a/core/builder/tests/test_build_cli.py +++ b/core/builder/tests/test_build_cli.py @@ -14,6 +14,16 @@ from tensorrt_model_connect import build_cli +def _stub_family_resolution(monkeypatch) -> None: + support = SimpleNamespace(tasks=("example_task",), default_task="example_task") + monkeypatch.setattr(build_cli, "load_model_metadata", lambda _model_dir: object()) + monkeypatch.setattr( + build_cli, + "resolve_family", + lambda _metadata: ("example", support), + ) + + def test_build_command_forwards_only_direct_inputs(monkeypatch, tmp_path: Path) -> None: captured = [] monkeypatch.setattr(build_cli, "build", captured.append) @@ -117,9 +127,9 @@ def test_build_command_preserves_resolved_checkpoint_and_source_revisions( ) -> None: checkpoint_revision = "b" * 40 source_revision = "a" * 40 - snapshot = tmp_path / "models--openai-community--gpt2" / "snapshots" / checkpoint_revision + snapshot = tmp_path / "models--example-org--example-model" / "snapshots" / checkpoint_revision snapshot.mkdir(parents=True) - (snapshot / "config.json").write_text('{"model_type":"gpt2"}', encoding="utf-8") + (snapshot / "metadata.json").write_text("{}", encoding="utf-8") captured = [] monkeypatch.setitem( @@ -129,12 +139,13 @@ def test_build_command_preserves_resolved_checkpoint_and_source_revisions( ) monkeypatch.setenv("TRTMC_ENGINE_BUILD_REVISION", source_revision) monkeypatch.setattr(build_cli, "build", captured.append) + _stub_family_resolution(monkeypatch) assert ( build_cli.main( [ "build", - "openai-community/gpt2", + "example-org/example-model", "--revision", "main", "--output", @@ -145,7 +156,7 @@ def test_build_command_preserves_resolved_checkpoint_and_source_revisions( ) request = captured[0] assert request.model_dir == snapshot - assert request.checkpoint_id == "openai-community/gpt2" + assert request.checkpoint_id == "example-org/example-model" assert request.checkpoint_revision == checkpoint_revision assert request.source_revision == source_revision @@ -157,11 +168,12 @@ def test_local_snapshot_can_preserve_a_canonical_checkpoint_id( source_revision = "a" * 40 snapshot = tmp_path / "downloaded-checkpoint" snapshot.mkdir() - (snapshot / "config.json").write_text('{"model_type":"gpt2"}', encoding="utf-8") + (snapshot / "metadata.json").write_text("{}", encoding="utf-8") captured = [] monkeypatch.setenv("TRTMC_ENGINE_BUILD_REVISION", source_revision) monkeypatch.setattr(build_cli, "build", captured.append) + _stub_family_resolution(monkeypatch) assert ( build_cli.main( @@ -169,7 +181,7 @@ def test_local_snapshot_can_preserve_a_canonical_checkpoint_id( "build", str(snapshot), "--checkpoint-id", - "openai-community/gpt2", + "example-org/example-model", "--revision", checkpoint_revision, "--output", @@ -180,7 +192,7 @@ def test_local_snapshot_can_preserve_a_canonical_checkpoint_id( ) request = captured[0] assert request.model_dir == snapshot - assert request.checkpoint_id == "openai-community/gpt2" + assert request.checkpoint_id == "example-org/example-model" assert request.checkpoint_revision == checkpoint_revision @@ -189,11 +201,12 @@ def test_build_command_derives_source_revision_from_the_checkout( ) -> None: model = tmp_path / "model" model.mkdir() - (model / "config.json").write_text('{"model_type":"gpt2"}', encoding="utf-8") + (model / "metadata.json").write_text("{}", encoding="utf-8") captured = [] monkeypatch.delenv("TRTMC_ENGINE_BUILD_REVISION", raising=False) monkeypatch.delenv("GITHUB_SHA", raising=False) monkeypatch.setattr(build_cli, "build", captured.append) + _stub_family_resolution(monkeypatch) assert build_cli.main(["build", str(model), "-o", str(tmp_path / "out.bundle")]) == 0 @@ -204,6 +217,15 @@ def test_build_command_derives_source_revision_from_the_checkout( assert captured[0].source_revision == expected +def test_local_checkpoint_rejects_a_non_exact_requested_revision(tmp_path: Path) -> None: + with pytest.raises(ValueError, match="exact 40-character Git SHA"): + build_cli._checkpoint_revision( + tmp_path / "local-checkpoint", + requested="main", + require_exact=False, + ) + + def test_build_command_rejects_a_task_the_family_does_not_own(monkeypatch, tmp_path: Path) -> None: model = tmp_path / "model" model.mkdir() From 93cd0c2397679adb3a9339078b4c941ce5bf44cd Mon Sep 17 00:00:00 2001 From: chaofengw Date: Mon, 7 Sep 2026 12:40:09 +0000 Subject: [PATCH 3/5] fix(build): preserve provenance isolation Move model-agnostic provenance to a backward-compatible trailer so the fixed v1 header and family-owned section namespace remain unchanged. Reject ambiguous local checkpoint identities and dirty source checkouts, version graph transforms, verify benchmark snapshot overrides, and keep package metadata compatible with family-owned exact pins. Signed-off-by: chaofengw --- Dockerfile | 1 + apps/benchmark/trtmc_benchmark/builder.py | 24 ++++-- apps/benchmark/trtmc_benchmark/catalog.py | 18 ++++- .../trtmc_benchmark/tests/test_benchmark.py | 30 ++++--- apps/benchmark/trtmc_benchmark/types.py | 4 + apps/cli/cli.cpp | 7 +- apps/cli/tests/test_cli.cpp | 8 +- .../tensorrt_model_connect/__init__.py | 5 +- core/builder/tensorrt_model_connect/build.py | 51 ++++++++++-- .../tensorrt_model_connect/build_cli.py | 28 +++---- .../tensorrt_model_connect/bundle_writer.py | 68 ++++++++++------ core/builder/tests/test_build.py | 78 +++++++++++++++---- core/builder/tests/test_build_cli.py | 77 ++++++++++++++---- core/builder/tests/test_bundle_writer.py | 45 ++++++++++- core/runtime/bundle/bundle_format.cpp | 60 +++++++++++++- core/runtime/bundle/bundle_format.h | 5 +- core/runtime/include/trtmc/bundle.h | 4 + core/runtime/tests/test_bundle_format_v1.cpp | 31 +++++++- .../manifests/foundationpose-ngc-1.0.1.json | 2 + families/foundationpose/tests/test_e2e.py | 2 + families/timm_mobilenetv2/requirements.txt | 2 +- .../manifests/mobilenetv2-100-ra-in1k.json | 1 + pyproject.toml | 10 +-- tools/tests/test_architecture.py | 28 ++++++- website/docs/api/python-builder.md | 13 +++- .../ai-native-horizontal-scaling.md | 11 ++- website/docs/architecture/bundle-format.md | 32 +++++--- website/docs/getting-started/quick-start.md | 4 +- 28 files changed, 514 insertions(+), 135 deletions(-) diff --git a/Dockerfile b/Dockerfile index 77465435a6..51c8e17063 100644 --- a/Dockerfile +++ b/Dockerfile @@ -56,6 +56,7 @@ RUN python3.12 -m venv "$VIRTUAL_ENV" \ "ml_dtypes==0.5.4" \ "numpy==1.26.4" \ "onnx==1.21.0" \ + "packaging==26.2" \ "Pillow==12.2.0" \ "protobuf==7.35.0" \ "pybind11==2.13.6" \ diff --git a/apps/benchmark/trtmc_benchmark/builder.py b/apps/benchmark/trtmc_benchmark/builder.py index 95b23f0bde..9341c7b291 100644 --- a/apps/benchmark/trtmc_benchmark/builder.py +++ b/apps/benchmark/trtmc_benchmark/builder.py @@ -14,7 +14,7 @@ from pathlib import Path from typing import Any, Iterable, Mapping, Sequence -from tensorrt_model_connect import read_bundle_json, resolve_source_revision +from tensorrt_model_connect import read_bundle_provenance, resolve_source_revision from tensorrt_model_connect.build_cli import _resolve_model from .types import BenchmarkError, ModelDescriptor, ResolvedCase @@ -157,6 +157,16 @@ def _plan(self, model: ModelDescriptor, cases: Sequence[ResolvedCase]) -> _Build raise BenchmarkError(f"model directory does not exist: {explicit}") if explicit is None and not model.hf_id: raise BenchmarkError(f"{model.name} has no hf_id; pass --model-dir") + if explicit is not None and model.hf_id: + resolved_explicit = explicit.resolve() + if ( + resolved_explicit.parent.name != "snapshots" + or resolved_explicit.name.lower() != model.hf_revision.lower() + ): + raise BenchmarkError( + f"explicit model directory for {model.name} must be the exact Hugging Face " + f"snapshot ending in /snapshots/{model.hf_revision}" + ) try: model_dir = _resolve_model( str(explicit) if explicit is not None else model.hf_id, @@ -258,10 +268,8 @@ def _build_command( "--precision", model.precision, ] - if model.hf_id: - command.extend(("--checkpoint-id", model.hf_id)) - if model.hf_revision: - command.extend(("--revision", model.hf_revision)) + command.extend(("--checkpoint-id", model.checkpoint_id)) + command.extend(("--revision", model.checkpoint_revision)) flags = ( ("max_sequence_length", "--max-sequence-length"), ("image_height", "--image-height"), @@ -334,7 +342,7 @@ def _bundle_matches_model( except ValueError: return False try: - provenance = read_bundle_json(bundle, "provenance.json") + provenance = read_bundle_provenance(bundle) except (OSError, UnicodeDecodeError, ValueError): return False if not isinstance(provenance, dict) or provenance.get("format") != 1: @@ -350,8 +358,8 @@ def _bundle_matches_model( elif isinstance(expected_request["fp32_layers"], tuple): expected_request["fp32_layers"] = list(expected_request["fp32_layers"]) return provenance.get("checkpoint") == { - "id": model.hf_id, - "revision": model.hf_revision, + "id": model.checkpoint_id, + "revision": model.checkpoint_revision, } and provenance.get("build") == { "source_revision": source_revision } and provenance.get("request") == expected_request diff --git a/apps/benchmark/trtmc_benchmark/catalog.py b/apps/benchmark/trtmc_benchmark/catalog.py index 41ac7a3e61..22a5823aa5 100644 --- a/apps/benchmark/trtmc_benchmark/catalog.py +++ b/apps/benchmark/trtmc_benchmark/catalog.py @@ -166,10 +166,24 @@ def _load(path: Path) -> ModelDescriptor: settings.setdefault("max_batch_size", 1) settings.setdefault("tensor_parallel_size", 1) settings.setdefault("context_parallel_size", 1) + hf_id = _optional_string(raw.get("hf_id", ""), "hf_id", path) + hf_revision = _optional_string(raw.get("hf_revision", ""), "hf_revision", path) + checkpoint_id = _optional_string( + raw.get("checkpoint_id", hf_id), "checkpoint_id", path + ) + checkpoint_revision = _optional_string( + raw.get("checkpoint_revision", hf_revision), "checkpoint_revision", path + ) + if not checkpoint_id or not checkpoint_revision: + raise BenchmarkError( + f"model manifest must declare an immutable checkpoint identity: {path}" + ) return ModelDescriptor( name=_string(raw["name"], "name", path), - hf_id=_optional_string(raw.get("hf_id", ""), "hf_id", path), - hf_revision=_optional_string(raw.get("hf_revision", ""), "hf_revision", path), + hf_id=hf_id, + hf_revision=hf_revision, + checkpoint_id=checkpoint_id, + checkpoint_revision=checkpoint_revision, bundle_name=_string(raw["bundle"], "bundle", path), family=_string(raw["family"], "family", path), task=_string(raw["task"], "task", path), diff --git a/apps/benchmark/trtmc_benchmark/tests/test_benchmark.py b/apps/benchmark/trtmc_benchmark/tests/test_benchmark.py index d35fcbd191..0c142d9667 100644 --- a/apps/benchmark/trtmc_benchmark/tests/test_benchmark.py +++ b/apps/benchmark/trtmc_benchmark/tests/test_benchmark.py @@ -146,8 +146,8 @@ def test_bundle_builder_keeps_explicit_model_dir_cli_behavior( ) -> None: model = ManifestCatalog(REPO / "families").resolve("distilgpt2") case = resolve_case(model, tmp_path / "model.bundle") - checkpoint = tmp_path / "checkpoint" - checkpoint.mkdir() + checkpoint = tmp_path / "models--distilbert--distilgpt2" / "snapshots" / model.hf_revision + checkpoint.mkdir(parents=True) calls = [] def resolve_model(value: str, revision: str | None) -> Path: @@ -162,6 +162,20 @@ def resolve_model(value: str, revision: str | None) -> Path: assert plan.model_dir == checkpoint.resolve() +def test_bundle_builder_rejects_an_unverified_explicit_hugging_face_directory( + tmp_path: Path, +) -> None: + model = ManifestCatalog(REPO / "families").resolve("distilgpt2") + case = resolve_case(model, tmp_path / "model.bundle") + checkpoint = tmp_path / "arbitrary-checkpoint" + checkpoint.mkdir() + + with pytest.raises(BenchmarkError, match="exact Hugging Face snapshot"): + BundleBuilder( + tmp_path / "cache", model_dirs={model.name: checkpoint} + )._plan(model, (case,)) + + def test_bundle_builder_has_no_second_model_resolver() -> None: source = (REPO / "apps/benchmark/trtmc_benchmark/builder.py").read_text() assert "snapshot_download" not in source @@ -180,8 +194,7 @@ def test_bundle_cache_rejects_mismatched_provenance_when_build_is_disabled( bundle.parent.mkdir(parents=True) writer = BundleWriter(bundle) writer.set_header(family=model.family, task=model.task, backend="trt") - writer.add_json( - "provenance.json", + writer.set_provenance( { "format": 1, "checkpoint": {"id": model.hf_id, "revision": "c" * 40}, @@ -210,8 +223,7 @@ def test_bundle_cache_rejects_a_different_build_request(tmp_path: Path, monkeypa bundle.parent.mkdir(parents=True) writer = BundleWriter(bundle) writer.set_header(family=model.family, task=model.task, backend="trt") - writer.add_json( - "provenance.json", + writer.set_provenance( { "format": 1, "checkpoint": {"id": model.hf_id, "revision": model.hf_revision}, @@ -245,8 +257,7 @@ def test_bundle_cache_reuses_an_exact_build_identity(tmp_path: Path, monkeypatch bundle.parent.mkdir(parents=True) writer = BundleWriter(bundle) writer.set_header(family=model.family, task=model.task, backend="trt") - writer.add_json( - "provenance.json", + writer.set_provenance( { "format": 1, "checkpoint": {"id": model.hf_id, "revision": model.hf_revision}, @@ -379,8 +390,7 @@ def test_cli_dry_run_uses_explicit_bundle_without_runtime( bundle = tmp_path / "model.bundle" writer = BundleWriter(bundle) writer.set_header(family=model.family, task=model.task, backend="trt") - writer.add_json( - "provenance.json", + writer.set_provenance( { "format": 1, "checkpoint": {"id": model.hf_id, "revision": model.hf_revision}, diff --git a/apps/benchmark/trtmc_benchmark/types.py b/apps/benchmark/trtmc_benchmark/types.py index 3d3c0258da..370fba26aa 100644 --- a/apps/benchmark/trtmc_benchmark/types.py +++ b/apps/benchmark/trtmc_benchmark/types.py @@ -53,6 +53,8 @@ class ModelDescriptor: name: str hf_id: str hf_revision: str + checkpoint_id: str + checkpoint_revision: str bundle_name: str family: str task: str @@ -65,6 +67,8 @@ def summary(self) -> dict[str, Any]: value = { "name": self.name, "hf_id": self.hf_id, + "checkpoint_id": self.checkpoint_id, + "checkpoint_revision": self.checkpoint_revision, "bundle_name": self.bundle_name, "family": self.family, "task": self.task, diff --git a/apps/cli/cli.cpp b/apps/cli/cli.cpp index 59004359ac..d4230cd721 100644 --- a/apps/cli/cli.cpp +++ b/apps/cli/cli.cpp @@ -1330,10 +1330,9 @@ int run(int argc, char** argv, std::ostream& output, std::ostream& error) { {"task", bundle.task}, {"backend", bundle.backend}, {"sections", std::move(sections)}}; - if (reader.find_section("provenance.json") != nullptr) { - const std::vector provenance = reader.read_section("provenance.json"); - result["provenance"] = nlohmann::json::parse(provenance.begin(), provenance.end()); - } + const std::string provenance = InspectBundleProvenance(command.bundle); + if (!provenance.empty()) + result["provenance"] = nlohmann::json::parse(provenance); write_json(output, result); return EXIT_SUCCESS; } diff --git a/apps/cli/tests/test_cli.cpp b/apps/cli/tests/test_cli.cpp index 16351cdf1c..b4ce769042 100644 --- a/apps/cli/tests/test_cli.cpp +++ b/apps/cli/tests/test_cli.cpp @@ -48,9 +48,9 @@ void write_inspect_bundle(const std::filesystem::path& path) { const std::string provenance = R"({"format":1,"checkpoint":{"id":"openai-community/gpt2","revision":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"},"build":{"source_revision":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},"request":{}})"; const std::string header = - R"({"format":1,"family":"gpt2","task":"text_generation","backend":"trt","sections":{"provenance.json":{"offset":0,"length":)" + - std::to_string(provenance.size()) + "}}}"; + R"({"format":1,"family":"gpt2","task":"text_generation","backend":"trt","sections":{}})"; constexpr unsigned char magic[8] = {'B', 'U', 'N', 'D', 'L', 'E', '\x01', '\0'}; + constexpr unsigned char provenance_magic[8] = {'P', 'R', 'O', 'V', '\x01', '\0', '\0', '\0'}; std::ofstream output(path, std::ios::binary); output.write(reinterpret_cast(magic), 8); const std::uint64_t length = header.size(); @@ -58,6 +58,10 @@ void write_inspect_bundle(const std::filesystem::path& path) { output.put(static_cast((length >> shift) & 0xffU)); output.write(header.data(), static_cast(header.size())); output.write(provenance.data(), static_cast(provenance.size())); + const std::uint64_t provenance_length = provenance.size(); + for (int shift = 0; shift < 64; shift += 8) + output.put(static_cast((provenance_length >> shift) & 0xffU)); + output.write(reinterpret_cast(provenance_magic), 8); } bool parse_throws(std::vector arguments) { diff --git a/core/builder/tensorrt_model_connect/__init__.py b/core/builder/tensorrt_model_connect/__init__.py index cca2ff86c6..f7f1dbce26 100644 --- a/core/builder/tensorrt_model_connect/__init__.py +++ b/core/builder/tensorrt_model_connect/__init__.py @@ -4,7 +4,7 @@ """TensorRT Model Connect build API.""" from .build import BuildRequest, build, resolve_source_revision -from .bundle_writer import BundleWriter, read_bundle_json, read_bundle_section +from .bundle_writer import BundleWriter, read_bundle_provenance from .graph_transform import GraphTransform __all__ = [ @@ -12,7 +12,6 @@ "BundleWriter", "GraphTransform", "build", - "read_bundle_json", - "read_bundle_section", + "read_bundle_provenance", "resolve_source_revision", ] diff --git a/core/builder/tensorrt_model_connect/build.py b/core/builder/tensorrt_model_connect/build.py index 2c752a259b..dd0405a7f5 100644 --- a/core/builder/tensorrt_model_connect/build.py +++ b/core/builder/tensorrt_model_connect/build.py @@ -21,6 +21,9 @@ _ID = re.compile(r"[a-z][a-z0-9_]*\Z") _EXACT_REVISION = re.compile(r"[0-9a-f]{40}\Z") +_IMMUTABLE_CHECKPOINT_REVISION = re.compile( + r"(?:[0-9a-f]{40}|[a-z][a-z0-9_.-]*:[A-Za-z0-9][A-Za-z0-9_.-]*)\Z" +) @dataclass(frozen=True) @@ -48,14 +51,20 @@ class BuildRequest: dynamic_kv_cache: bool = False verbose: bool = False graph_transform: GraphTransform | None = None + graph_transform_id: str = "" def __post_init__(self) -> None: if not self.precision: raise ValueError("precision must be non-empty") - for field in ("checkpoint_revision", "source_revision"): - revision = getattr(self, field) - if revision and _EXACT_REVISION.fullmatch(revision) is None: - raise ValueError(f"{field} must be an exact 40-character Git SHA") + if ( + self.checkpoint_revision + and _IMMUTABLE_CHECKPOINT_REVISION.fullmatch(self.checkpoint_revision) is None + ): + raise ValueError( + "checkpoint_revision must be an exact Git SHA or namespaced immutable revision" + ) + if self.source_revision and _EXACT_REVISION.fullmatch(self.source_revision) is None: + raise ValueError("source_revision must be an exact 40-character Git SHA") _validate_id("family", self.family) _validate_id("task", self.task) if self.backend not in {"trt", "trt_rtx"}: @@ -80,6 +89,15 @@ def __post_init__(self) -> None: raise ValueError("dynamic_kv_cache must be a bool") if self.graph_transform is not None and not callable(self.graph_transform): raise ValueError("graph_transform must be callable when provided") + if (self.graph_transform is not None) != bool(self.graph_transform_id.strip()): + raise ValueError("graph_transform and graph_transform_id must be provided together") + if ( + self.graph_transform_id + and _IMMUTABLE_CHECKPOINT_REVISION.fullmatch(self.graph_transform_id) is None + ): + raise ValueError( + "graph_transform_id must be an exact Git SHA or namespaced immutable revision" + ) def _validate_id(field: str, value: object) -> str: @@ -149,9 +167,9 @@ def build(request: BuildRequest) -> None: writer = BundleWriter(request.output_path) try: provenance = _build_provenance(request) + writer.set_provenance(provenance) with graph_transform(request.graph_transform): family_module.build(request, writer) - writer.add_json("provenance.json", provenance) writer.finish() except BaseException: writer.abort() @@ -174,9 +192,10 @@ def resolve_source_revision(explicit: str = "") -> str: raise ValueError(f"{field} must be an exact 40-character Git SHA") return revision + repository = str(Path(__file__).resolve().parent) try: completed = subprocess.run( - ["git", "-C", str(Path(__file__).resolve().parent), "rev-parse", "HEAD"], + ["git", "-C", repository, "rev-parse", "HEAD"], capture_output=True, text=True, timeout=5, @@ -186,7 +205,23 @@ def resolve_source_revision(explicit: str = "") -> str: completed = None revision = completed.stdout.strip().lower() if completed and completed.returncode == 0 else "" if _EXACT_REVISION.fullmatch(revision): - return revision + try: + status = subprocess.run( + ["git", "-C", repository, "status", "--porcelain", "--untracked-files=normal"], + capture_output=True, + text=True, + timeout=5, + check=False, + ) + except (OSError, subprocess.SubprocessError): + status = None + if status and status.returncode == 0: + if status.stdout: + raise ValueError( + "source checkout is dirty; commit the changes or set " + "TRTMC_ENGINE_BUILD_REVISION from a controlled build" + ) + return revision raise ValueError( "source revision is unavailable; set TRTMC_ENGINE_BUILD_REVISION to the exact Git SHA" ) @@ -215,6 +250,8 @@ def _build_provenance(request: BuildRequest) -> dict[str, object]: options["quantization"] = request.quantization if request.fp32_layers: options["fp32_layers"] = list(request.fp32_layers) + if request.graph_transform_id: + options["graph_transform_id"] = request.graph_transform_id return { "format": 1, "checkpoint": { diff --git a/core/builder/tensorrt_model_connect/build_cli.py b/core/builder/tensorrt_model_connect/build_cli.py index a27277c875..235fefbdd8 100644 --- a/core/builder/tensorrt_model_connect/build_cli.py +++ b/core/builder/tensorrt_model_connect/build_cli.py @@ -11,7 +11,13 @@ from pathlib import Path from typing import Sequence -from .build import BuildRequest, _load_family, build, resolve_source_revision +from .build import ( + BuildRequest, + _IMMUTABLE_CHECKPOINT_REVISION, + _load_family, + build, + resolve_source_revision, +) from .model_support import load_model_metadata, resolve_family @@ -77,11 +83,9 @@ def main(argv: Sequence[str] | None = None) -> int: if args.command != "build": raise AssertionError(f"unhandled command: {args.command}") source_is_local = Path(args.model).is_dir() - checkpoint_revision = _checkpoint_revision( - model_dir, - requested=args.revision, - require_exact=not source_is_local, - ) + if source_is_local and not args.checkpoint_id: + raise ValueError("--checkpoint-id is required when MODEL is a local directory") + checkpoint_revision = _checkpoint_revision(model_dir, requested=args.revision) task = args.task or support.default_task if task not in support.tasks: raise ValueError( @@ -127,22 +131,18 @@ def _resolve_model(model: str, revision: str | None) -> Path: return Path(snapshot_download(repo_id=model, revision=revision)) -def _checkpoint_revision( - model_dir: Path, *, requested: str | None, require_exact: bool -) -> str: +def _checkpoint_revision(model_dir: Path, *, requested: str | None) -> str: resolved = model_dir.name.lower() if model_dir.parent.name == "snapshots" else "" if _EXACT_REVISION.fullmatch(resolved): return resolved requested = (requested or "").strip().lower() - if _EXACT_REVISION.fullmatch(requested): + if _IMMUTABLE_CHECKPOINT_REVISION.fullmatch(requested): return requested if requested: - raise ValueError("checkpoint revision must be an exact 40-character Git SHA") - if require_exact: raise ValueError( - "Hugging Face model resolution did not produce an exact 40-character commit SHA" + "checkpoint revision must be an exact Git SHA or namespaced immutable revision" ) - return requested + raise ValueError("checkpoint revision is required and must identify immutable content") def _source_revision() -> str: diff --git a/core/builder/tensorrt_model_connect/bundle_writer.py b/core/builder/tensorrt_model_connect/bundle_writer.py index b9205c9338..4b8d6464f2 100644 --- a/core/builder/tensorrt_model_connect/bundle_writer.py +++ b/core/builder/tensorrt_model_connect/bundle_writer.py @@ -17,6 +17,7 @@ BUNDLE_MAGIC = b"BUNDLE\x01\x00" +BUNDLE_PROVENANCE_MAGIC = b"PROV\x01\x00\x00\x00" _FORMAT = 1 _MAX_UINT64 = (1 << 64) - 1 _MAX_HEADER_SIZE = 100 * 1024 * 1024 @@ -38,8 +39,8 @@ def _validate_nonempty_string(field: str, value: object) -> str: return value -def read_bundle_section(path: str | Path, name: str) -> bytes: - """Read one named section from a validated bundle file.""" +def read_bundle_provenance(path: str | Path) -> Any: + """Read the core-owned provenance trailer from a bundle file.""" bundle_path = Path(path) with bundle_path.open("rb") as bundle: @@ -55,29 +56,29 @@ def read_bundle_section(path: str | Path, name: str) -> bytes: if len(raw_header) != header_size: raise ValueError(f"{bundle_path} has a truncated header") header = json.loads(raw_header) - sections = header.get("sections") if isinstance(header, dict) else None - location = sections.get(name) if isinstance(sections, dict) else None - if not isinstance(location, dict): - raise ValueError(f"{bundle_path} has no {name!r} section") - offset = location.get("offset") - length = location.get("length") - if not isinstance(offset, int) or not isinstance(length, int): - raise ValueError(f"{bundle_path} has an invalid {name!r} section") - data_start = len(BUNDLE_MAGIC) + 8 + header_size + if not isinstance(header, dict): + raise ValueError(f"{bundle_path} has an invalid header") + minimum_start = len(BUNDLE_MAGIC) + 8 + header_size file_size = bundle_path.stat().st_size - if offset < 0 or length < 0 or data_start + offset + length > file_size: - raise ValueError(f"{bundle_path} has an invalid {name!r} section range") - bundle.seek(data_start + offset) - data = bundle.read(length) - if len(data) != length: - raise ValueError(f"{bundle_path} has a truncated {name!r} section") - return data - - -def read_bundle_json(path: str | Path, name: str) -> Any: - """Read one named JSON section from a validated bundle file.""" - - return json.loads(read_bundle_section(path, name).decode("utf-8")) + footer_size = 8 + len(BUNDLE_PROVENANCE_MAGIC) + if file_size < minimum_start + footer_size: + raise ValueError(f"{bundle_path} has no provenance trailer") + bundle.seek(file_size - len(BUNDLE_PROVENANCE_MAGIC)) + if bundle.read(len(BUNDLE_PROVENANCE_MAGIC)) != BUNDLE_PROVENANCE_MAGIC: + raise ValueError(f"{bundle_path} has no provenance trailer") + bundle.seek(file_size - footer_size) + provenance_size = struct.unpack(" _MAX_HEADER_SIZE or provenance_start < minimum_start: + raise ValueError(f"{bundle_path} has an invalid provenance trailer") + bundle.seek(provenance_start) + raw_provenance = bundle.read(provenance_size) + if len(raw_provenance) != provenance_size: + raise ValueError(f"{bundle_path} has a truncated provenance trailer") + provenance = json.loads(raw_provenance.decode("utf-8")) + if not isinstance(provenance, dict): + raise ValueError(f"{bundle_path} provenance must be a JSON object") + return provenance class BundleWriter: @@ -90,6 +91,7 @@ def __init__(self, destination: str | Path) -> None: f"bundle output directory does not exist: {self._destination.parent}" ) self._header: dict[str, Any] | None = None + self._provenance: bytes | None = None self._sections: list[tuple[str, Path]] = [] self._section_names: set[str] = set() self._staging_dir: Path | None = None @@ -131,6 +133,20 @@ def set_header(self, *, family: str, task: str, backend: str) -> None: "backend": _validate_id("backend", backend), } + def set_provenance(self, value: Any) -> None: + """Set the core-owned provenance trailer exactly once.""" + + self._ensure_writable() + if self._provenance is not None: + raise RuntimeError("bundle provenance is already set") + if not isinstance(value, dict): + raise TypeError("bundle provenance must be a JSON object") + self._provenance = json.dumps( + value, ensure_ascii=False, separators=(",", ":") + ).encode("utf-8") + if len(self._provenance) > _MAX_HEADER_SIZE: + raise ValueError("bundle provenance exceeds the 100 MiB runtime limit") + @contextmanager def open_section(self, name: str) -> Iterator[BinaryIO]: """Open one file-backed section for incremental binary writes.""" @@ -207,6 +223,10 @@ def finish(self) -> None: for _, section_path in self._sections: with section_path.open("rb") as section: shutil.copyfileobj(section, output) + if self._provenance is not None: + output.write(self._provenance) + output.write(struct.pack(" BuildRequest: return BuildRequest( model_dir=tmp_path / "model", output_path=tmp_path / "model.bundle", + checkpoint_id="example/model", + checkpoint_revision="b" * 40, + source_revision="a" * 40, precision="fp16", family=family, task="text_generation", @@ -78,6 +79,47 @@ def test_build_request_rejects_invalid_direct_inputs( BuildRequest(**kwargs) # type: ignore[arg-type] +def test_graph_transform_requires_a_stable_identity(tmp_path: Path) -> None: + with pytest.raises(ValueError, match="provided together"): + replace(_request(tmp_path), graph_transform=lambda _network, _index: None) + with pytest.raises(ValueError, match="provided together"): + replace(_request(tmp_path), graph_transform_id="example:transform-v1") + with pytest.raises(ValueError, match="namespaced immutable revision"): + replace( + _request(tmp_path), + graph_transform=lambda _network, _index: None, + graph_transform_id="mutable", + ) + + +def test_source_revision_rejects_a_dirty_checkout(monkeypatch) -> None: + monkeypatch.delenv("TRTMC_ENGINE_BUILD_REVISION", raising=False) + monkeypatch.delenv("GITHUB_SHA", raising=False) + + def run(arguments, **_kwargs): + if arguments[-2:] == ["rev-parse", "HEAD"]: + return SimpleNamespace(returncode=0, stdout="a" * 40 + "\n") + return SimpleNamespace(returncode=0, stdout=" M core/builder/build.py\n") + + monkeypatch.setattr(build_core.subprocess, "run", run) + + with pytest.raises(ValueError, match="checkout is dirty"): + build_core.resolve_source_revision() + + +def test_source_revision_accepts_a_clean_checkout(monkeypatch) -> None: + monkeypatch.delenv("TRTMC_ENGINE_BUILD_REVISION", raising=False) + monkeypatch.delenv("GITHUB_SHA", raising=False) + + def run(arguments, **_kwargs): + stdout = "a" * 40 + "\n" if arguments[-2:] == ["rev-parse", "HEAD"] else "" + return SimpleNamespace(returncode=0, stdout=stdout) + + monkeypatch.setattr(build_core.subprocess, "run", run) + + assert build_core.resolve_source_revision() == "a" * 40 + + def test_resolver_returns_only_the_explicit_family(tmp_path: Path) -> None: assert build_core._resolve_family(_request(tmp_path, family="exact_family")) == "exact_family" @@ -171,8 +213,8 @@ def __init__(self, destination: Path) -> None: def finish(self) -> None: events.append("finish") - def add_json(self, _name: str, _value: object) -> None: - pass + def set_provenance(self, value: object) -> None: + events.append(("provenance", value)) def abort(self) -> None: events.append("abort") @@ -188,8 +230,9 @@ def family_build(request: BuildRequest, writer: FakeWriter) -> None: assert build_core.build(request) is None assert events[0] == ("writer", request.output_path) - assert events[1][0:2] == ("build", request) - assert events[2:] == ["finish"] + assert events[1][0] == "provenance" + assert events[2][0:2] == ("build", request) + assert events[3:] == ["finish"] def test_build_embeds_checkpoint_and_source_provenance(monkeypatch, tmp_path: Path) -> None: @@ -223,13 +266,7 @@ def family_build(seen_request: BuildRequest, writer) -> None: build_core.build(request) - data = request.output_path.read_bytes() - header_size = struct.unpack_from(" None: def finish(self) -> None: events.append("finish") - def add_json(self, _name: str, _value: object) -> None: + def set_provenance(self, _value: object) -> None: pass def abort(self) -> None: @@ -330,7 +367,11 @@ def transform(network: object, engine_index: int) -> None: setattr(network, "replaced", True) events.append(("transform", network, engine_index)) - request = replace(_request(tmp_path), graph_transform=transform) + request = replace( + _request(tmp_path), + graph_transform=transform, + graph_transform_id="example:replace-subgraph-v1", + ) monkeypatch.setattr(build_core, "BundleWriter", FakeWriter) monkeypatch.setattr( build_core, "_load_family", lambda family: SimpleNamespace(build=family_build) @@ -357,6 +398,9 @@ def __init__(self, _destination: Path) -> None: def finish(self) -> None: events.append("finish") + def set_provenance(self, _value: object) -> None: + pass + def abort(self) -> None: events.append("abort") @@ -385,7 +429,7 @@ def finish(self) -> None: events.append("finish") raise OSError("publish failed") - def add_json(self, _name: str, _value: object) -> None: + def set_provenance(self, _value: object) -> None: pass def abort(self) -> None: diff --git a/core/builder/tests/test_build_cli.py b/core/builder/tests/test_build_cli.py index 943516dc52..bbba7219ac 100644 --- a/core/builder/tests/test_build_cli.py +++ b/core/builder/tests/test_build_cli.py @@ -5,7 +5,6 @@ import json import sys -import subprocess from pathlib import Path from types import SimpleNamespace @@ -26,6 +25,7 @@ def _stub_family_resolution(monkeypatch) -> None: def test_build_command_forwards_only_direct_inputs(monkeypatch, tmp_path: Path) -> None: captured = [] + monkeypatch.setenv("TRTMC_ENGINE_BUILD_REVISION", "a" * 40) monkeypatch.setattr(build_cli, "build", captured.append) model = tmp_path / "model" model.mkdir() @@ -37,6 +37,10 @@ def test_build_command_forwards_only_direct_inputs(monkeypatch, tmp_path: Path) [ "build", str(model), + "--checkpoint-id", + "example/model", + "--revision", + "b" * 40, "--output", str(output), "--task", @@ -93,12 +97,27 @@ def test_build_command_forwards_only_direct_inputs(monkeypatch, tmp_path: Path) def test_build_command_uses_the_family_owned_default_task(monkeypatch, tmp_path: Path) -> None: captured = [] + monkeypatch.setenv("TRTMC_ENGINE_BUILD_REVISION", "a" * 40) monkeypatch.setattr(build_cli, "build", captured.append) model = tmp_path / "model" model.mkdir() (model / "config.json").write_text('{"model_type":"gpt2"}', encoding="utf-8") - assert build_cli.main(["build", str(model), "--output", str(tmp_path / "out.bundle")]) == 0 + assert ( + build_cli.main( + [ + "build", + str(model), + "--checkpoint-id", + "example/model", + "--revision", + "b" * 40, + "--output", + str(tmp_path / "out.bundle"), + ] + ) + == 0 + ) assert captured[0].family == "gpt2" assert captured[0].task == "text_generation" @@ -196,33 +215,60 @@ def test_local_snapshot_can_preserve_a_canonical_checkpoint_id( assert request.checkpoint_revision == checkpoint_revision -def test_build_command_derives_source_revision_from_the_checkout( +def test_build_command_forwards_resolved_source_revision( monkeypatch, tmp_path: Path ) -> None: model = tmp_path / "model" model.mkdir() (model / "metadata.json").write_text("{}", encoding="utf-8") captured = [] - monkeypatch.delenv("TRTMC_ENGINE_BUILD_REVISION", raising=False) - monkeypatch.delenv("GITHUB_SHA", raising=False) + monkeypatch.setattr(build_cli, "resolve_source_revision", lambda: "a" * 40) monkeypatch.setattr(build_cli, "build", captured.append) _stub_family_resolution(monkeypatch) - assert build_cli.main(["build", str(model), "-o", str(tmp_path / "out.bundle")]) == 0 + assert ( + build_cli.main( + [ + "build", + str(model), + "--checkpoint-id", + "example/model", + "--revision", + "b" * 40, + "-o", + str(tmp_path / "out.bundle"), + ] + ) + == 0 + ) - repository = Path(__file__).resolve().parents[3] - expected = subprocess.check_output( - ["git", "-C", str(repository), "rev-parse", "HEAD"], text=True - ).strip() - assert captured[0].source_revision == expected + assert captured[0].source_revision == "a" * 40 def test_local_checkpoint_rejects_a_non_exact_requested_revision(tmp_path: Path) -> None: - with pytest.raises(ValueError, match="exact 40-character Git SHA"): + with pytest.raises(ValueError, match="namespaced immutable revision"): build_cli._checkpoint_revision( tmp_path / "local-checkpoint", requested="main", - require_exact=False, + ) + + +def test_local_checkpoint_requires_canonical_id_and_revision(tmp_path: Path) -> None: + model = tmp_path / "model" + model.mkdir() + + with pytest.raises(ValueError, match="--checkpoint-id"): + build_cli.main(["build", str(model), "-o", str(tmp_path / "out.bundle")]) + with pytest.raises(ValueError, match="checkpoint revision is required"): + build_cli.main( + [ + "build", + str(model), + "--checkpoint-id", + "example/model", + "-o", + str(tmp_path / "out.bundle"), + ] ) @@ -231,12 +277,17 @@ def test_build_command_rejects_a_task_the_family_does_not_own(monkeypatch, tmp_p model.mkdir() (model / "config.json").write_text('{"model_type":"gpt2"}', encoding="utf-8") monkeypatch.setattr(build_cli, "build", lambda request: None) + monkeypatch.setenv("TRTMC_ENGINE_BUILD_REVISION", "a" * 40) with pytest.raises(ValueError, match="does not support task 'embedding'"): build_cli.main( [ "build", str(model), + "--checkpoint-id", + "example/model", + "--revision", + "b" * 40, "--output", str(tmp_path / "out.bundle"), "--task", diff --git a/core/builder/tests/test_bundle_writer.py b/core/builder/tests/test_bundle_writer.py index b5406b4cec..5b41c35ff8 100644 --- a/core/builder/tests/test_bundle_writer.py +++ b/core/builder/tests/test_bundle_writer.py @@ -10,7 +10,12 @@ import pytest -from tensorrt_model_connect.bundle_writer import BUNDLE_MAGIC, BundleWriter +from tensorrt_model_connect.bundle_writer import ( + BUNDLE_MAGIC, + BUNDLE_PROVENANCE_MAGIC, + BundleWriter, + read_bundle_provenance, +) def _read_bundle(path: Path) -> tuple[dict, bytes]: @@ -50,6 +55,44 @@ def test_writer_streams_sections_and_emits_only_the_fixed_header(tmp_path: Path) assert payload == b'engine-bytes{"size":7}tokens' +def test_writer_appends_provenance_outside_family_sections(tmp_path: Path) -> None: + destination = tmp_path / "model.bundle" + provenance = { + "format": 1, + "checkpoint": {"id": "example/model", "revision": "b" * 40}, + "build": {"source_revision": "a" * 40}, + "request": {}, + } + writer = BundleWriter(destination) + writer.set_header(family="family", task="text_generation", backend="trt") + writer.add_bytes("engine.plan", b"plan") + writer.set_provenance(provenance) + + writer.finish() + + header, payload_and_trailer = _read_bundle(destination) + raw_provenance = json.dumps(provenance, separators=(",", ":")).encode() + assert header["sections"] == {"engine.plan": {"offset": 0, "length": 4}} + assert "provenance.json" not in header["sections"] + assert payload_and_trailer == ( + b"plan" + + raw_provenance + + struct.pack(" None: + writer = BundleWriter(tmp_path / "model.bundle") + with pytest.raises(TypeError, match="JSON object"): + writer.set_provenance([]) + writer.set_provenance({"format": 1}) + with pytest.raises(RuntimeError, match="already set"): + writer.set_provenance({"format": 1}) + writer.abort() + + def test_writer_rejects_duplicate_and_empty_section_names(tmp_path: Path) -> None: writer = BundleWriter(tmp_path / "model.bundle") writer.add_bytes("engine.plan", b"one") diff --git a/core/runtime/bundle/bundle_format.cpp b/core/runtime/bundle/bundle_format.cpp index eb11f20674..1520bce20a 100644 --- a/core/runtime/bundle/bundle_format.cpp +++ b/core/runtime/bundle/bundle_format.cpp @@ -23,6 +23,13 @@ namespace { using BundleSectionLocation = std::pair; using BundleSectionEntry = std::pair; using BundleSectionTable = std::vector; +constexpr std::uint64_t kProvenanceFooterSize = 16; +constexpr std::uint64_t kMaxJsonSize = 100 * 1024 * 1024; + +struct ProvenanceTrailer { + std::uint64_t payload_end{0}; + std::string json; +}; uint64_t read_u64_le(std::ifstream& in) { unsigned char bytes[8]; @@ -37,6 +44,42 @@ uint64_t read_u64_le(std::ifstream& in) { return value; } +ProvenanceTrailer read_provenance_trailer(std::ifstream& in, std::uint64_t file_size, + std::uint64_t minimum_start, const std::string& path) { + ProvenanceTrailer result{file_size, {}}; + if (file_size < minimum_start + kProvenanceFooterSize) + return result; + + in.clear(); + in.seekg(static_cast(file_size - sizeof(kBundleProvenanceMagic))); + unsigned char magic[sizeof(kBundleProvenanceMagic)]; + in.read(reinterpret_cast(magic), sizeof(magic)); + if (!in || std::memcmp(magic, kBundleProvenanceMagic, sizeof(magic)) != 0) { + in.clear(); + return result; + } + + in.seekg(static_cast(file_size - kProvenanceFooterSize)); + const std::uint64_t length = read_u64_le(in); + if (length > kMaxJsonSize || length > file_size - minimum_start - kProvenanceFooterSize) + throw std::runtime_error("Invalid bundle provenance trailer in: " + path); + const std::uint64_t start = file_size - kProvenanceFooterSize - length; + in.seekg(static_cast(start)); + result.json.assign(static_cast(length), '\0'); + in.read(result.json.data(), static_cast(length)); + if (!in) + throw std::runtime_error("Failed to read bundle provenance trailer from: " + path); + try { + const nlohmann::json provenance = nlohmann::json::parse(result.json); + if (!provenance.is_object()) + throw std::runtime_error("Bundle provenance must be a JSON object: " + path); + } catch (const nlohmann::json::exception& error) { + throw std::runtime_error("Invalid bundle provenance JSON: " + std::string(error.what())); + } + result.payload_end = start; + return result; +} + void require_exact_keys(const nlohmann::json& object, std::initializer_list expected, const std::string& context) { @@ -159,7 +202,7 @@ BundleReader::BundleReader(std::string bundle_path) { } const uint64_t header_length = read_u64_le(in); - if (header_length > 100 * 1024 * 1024) { + if (header_length > kMaxJsonSize) { throw std::runtime_error("Bundle header too large: " + path_); } @@ -178,6 +221,7 @@ BundleReader::BundleReader(std::string bundle_path) { throw std::runtime_error("Failed to determine bundle size: " + path_); file_size_ = static_cast(file_end); data_offset_ = kBundleHeaderOffset + header_length; + file_size_ = read_provenance_trailer(in, file_size_, data_offset_, path_).payload_end; for (const auto& section : info_.sections) (void)checked_section_file_offset(section, data_offset_, file_size_, path_); } @@ -219,4 +263,18 @@ BundleInfo InspectBundle(const std::string& bundle_path) { return BundleReader(bundle_path).info(); } +std::string InspectBundleProvenance(const std::string& bundle_path) { + const BundleReader reader(bundle_path); + std::ifstream in(reader.path(), std::ios::binary); + if (!in) + throw std::runtime_error("Failed to open bundle file: " + reader.path()); + in.seekg(0, std::ios::end); + const auto file_end = in.tellg(); + if (file_end < 0) + throw std::runtime_error("Failed to determine bundle size: " + reader.path()); + return read_provenance_trailer(in, static_cast(file_end), kBundleHeaderOffset, + reader.path()) + .json; +} + } // namespace trtmc diff --git a/core/runtime/bundle/bundle_format.h b/core/runtime/bundle/bundle_format.h index 1e4701b8ea..6b4a44314c 100644 --- a/core/runtime/bundle/bundle_format.h +++ b/core/runtime/bundle/bundle_format.h @@ -10,7 +10,8 @@ // Bytes 0-7: Magic "BUNDLE\x01\x00" // Bytes 8-15: uint64_t json_header_length (LE) // Bytes 16..N: JSON metadata header (UTF-8) -// Bytes N..EOF: Binary sections referenced by offset in the header +// Bytes N..M: Family-owned binary sections referenced by offset in the header +// Optional: provenance JSON, uint64_t provenance length (LE), provenance magic #include "trtmc/bundle.h" @@ -22,6 +23,8 @@ namespace trtmc { // Magic bytes for .bundle files. static constexpr unsigned char kBundleMagic[8] = {'B', 'U', 'N', 'D', 'L', 'E', '\x01', '\0'}; +static constexpr unsigned char kBundleProvenanceMagic[8] = {'P', 'R', 'O', 'V', + '\x01', '\0', '\0', '\0'}; static constexpr std::size_t kBundleHeaderOffset = 16; // 8 magic + 8 length } // namespace trtmc diff --git a/core/runtime/include/trtmc/bundle.h b/core/runtime/include/trtmc/bundle.h index 154d697ef1..bbd2c8b5df 100644 --- a/core/runtime/include/trtmc/bundle.h +++ b/core/runtime/include/trtmc/bundle.h @@ -54,4 +54,8 @@ class BundleReader { // Read metadata without loading the engine. BundleInfo InspectBundle(const std::string& bundle_path); +// Read the core-owned provenance trailer without interpreting family sections. +// Returns an empty string for bundles created before provenance was added. +std::string InspectBundleProvenance(const std::string& bundle_path); + } // namespace trtmc diff --git a/core/runtime/tests/test_bundle_format_v1.cpp b/core/runtime/tests/test_bundle_format_v1.cpp index 0da636b49b..086278467a 100644 --- a/core/runtime/tests/test_bundle_format_v1.cpp +++ b/core/runtime/tests/test_bundle_format_v1.cpp @@ -33,7 +33,7 @@ std::filesystem::path temp_dir() { } void write_bundle(const std::filesystem::path& path, const std::string& header, - const std::string& payload = {}) { + const std::string& payload = {}, const std::string& provenance = {}) { std::ofstream output(path, std::ios::binary); output.write(reinterpret_cast(trtmc::kBundleMagic), 8); const std::uint64_t length = header.size(); @@ -41,6 +41,13 @@ void write_bundle(const std::filesystem::path& path, const std::string& header, output.put(static_cast((length >> shift) & 0xffU)); output.write(header.data(), static_cast(header.size())); output.write(payload.data(), static_cast(payload.size())); + if (!provenance.empty()) { + output.write(provenance.data(), static_cast(provenance.size())); + const std::uint64_t provenance_length = provenance.size(); + for (int shift = 0; shift < 64; shift += 8) + output.put(static_cast((provenance_length >> shift) & 0xffU)); + output.write(reinterpret_cast(trtmc::kBundleProvenanceMagic), 8); + } } bool read_throws(const std::filesystem::path& path) { @@ -70,6 +77,28 @@ int main() { check(valid_reader.info().sections.size() == 1, "one section descriptor"); check(valid_reader.info().sections.front().length == 4, "section length parsed"); check(valid_reader.read_section("engine.plan").size() == 4, "section payload read"); + check(trtmc::InspectBundleProvenance(valid.string()).empty(), + "legacy bundle has no provenance"); + + const auto provenance_bundle = directory / "provenance.bundle"; + const std::string provenance = + R"({"format":1,"checkpoint":{"id":"example/model","revision":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"},"build":{"source_revision":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},"request":{}})"; + write_bundle( + provenance_bundle, + R"({"format":1,"family":"fake","task":"time_series_forecast","backend":"fake","sections":{"engine.plan":{"offset":0,"length":4}}})", + "PLAN", provenance); + const trtmc::BundleReader provenance_reader(provenance_bundle.string()); + check(provenance_reader.read_section("engine.plan").size() == 4, + "provenance is outside family section payload"); + check(trtmc::InspectBundleProvenance(provenance_bundle.string()) == provenance, + "core provenance trailer parsed"); + + const auto overlapping_provenance = directory / "overlapping-provenance.bundle"; + write_bundle( + overlapping_provenance, + R"({"format":1,"family":"fake","task":"time_series_forecast","backend":"fake","sections":{"engine.plan":{"offset":0,"length":5}}})", + "PLAN", provenance); + check(read_throws(overlapping_provenance), "family section cannot overlap provenance"); const auto original_directory = std::filesystem::current_path(); std::filesystem::current_path(directory); diff --git a/families/foundationpose/tests/manifests/foundationpose-ngc-1.0.1.json b/families/foundationpose/tests/manifests/foundationpose-ngc-1.0.1.json index 7cd68f7171..95c111c602 100644 --- a/families/foundationpose/tests/manifests/foundationpose-ngc-1.0.1.json +++ b/families/foundationpose/tests/manifests/foundationpose-ngc-1.0.1.json @@ -4,6 +4,8 @@ "family": "foundationpose", "task": "pose_hypothesis_refinement", "precision": "fp16", + "checkpoint_id": "nvidia/isaac/foundationpose", + "checkpoint_revision": "ngc:1.0.1_onnx", "external_files": [ { "path": "refine_model.onnx", diff --git a/families/foundationpose/tests/test_e2e.py b/families/foundationpose/tests/test_e2e.py index f25db34acf..4233facf13 100644 --- a/families/foundationpose/tests/test_e2e.py +++ b/families/foundationpose/tests/test_e2e.py @@ -131,6 +131,8 @@ def _build(model_dir: Path, bundle: Path, manifest: dict) -> None: BuildRequest( model_dir=model_dir, output_path=bundle, + checkpoint_id=manifest["checkpoint_id"], + checkpoint_revision=manifest["checkpoint_revision"], family=FAMILY, task=manifest["task"], precision=manifest["precision"], diff --git a/families/timm_mobilenetv2/requirements.txt b/families/timm_mobilenetv2/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_mobilenetv2/requirements.txt +++ b/families/timm_mobilenetv2/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_mobilenetv2/tests/manifests/mobilenetv2-100-ra-in1k.json b/families/timm_mobilenetv2/tests/manifests/mobilenetv2-100-ra-in1k.json index 67380e9c24..5d2e7e05ee 100644 --- a/families/timm_mobilenetv2/tests/manifests/mobilenetv2-100-ra-in1k.json +++ b/families/timm_mobilenetv2/tests/manifests/mobilenetv2-100-ra-in1k.json @@ -1,6 +1,7 @@ { "name": "mobilenetv2-100-ra-in1k", "hf_id": "timm/mobilenetv2_100.ra_in1k", + "hf_revision": "5afa12513b048c79b9147a5d210e9bdc50035481", "bundle": "mobilenetv2-100-ra-in1k.bundle", "family": "timm_mobilenetv2", "task": "classification", diff --git a/pyproject.toml b/pyproject.toml index dc637c322f..2389b0ac61 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,11 +20,11 @@ requires-python = ">=3.12" dependencies = [ "safetensors==0.8.0", "numpy==1.26.4", - "ml_dtypes==0.5.4", + "ml_dtypes>=0.4,<1", "onnx==1.21.0", - "transformers==5.2.0", - "huggingface_hub==1.21.0", - "sentencepiece==0.2.2", + "transformers>=4.46,<6", + "huggingface_hub>=0.23,<2", + "sentencepiece>=0.1.99,<1", "cuda-python==13.0.3", "apache-tvm-ffi==0.1.12", "tensorrt==11.1.0.106", @@ -35,7 +35,7 @@ dependencies = [ trtmc-bench = "trtmc_benchmark.cli:main" [project.optional-dependencies] -test = ["pytest==8.4.2", "torch==2.12.0", "jsonschema==4.26.0"] +test = ["pytest==8.4.2", "torch==2.12.0", "jsonschema==4.26.0", "packaging==26.2"] cutedsl = ["nvidia-cutlass-dsl==4.7.1"] [tool.conan-py-build.wheel] diff --git a/tools/tests/test_architecture.py b/tools/tests/test_architecture.py index b2e5e7ec1a..0f3c6bc69b 100644 --- a/tools/tests/test_architecture.py +++ b/tools/tests/test_architecture.py @@ -10,6 +10,8 @@ import tomllib from pathlib import Path +from packaging.requirements import Requirement + REPO = Path(__file__).resolve().parents[2] FAMILIES = REPO / "families" @@ -552,6 +554,7 @@ def test_every_builder_handles_every_family_owned_request_field() -> None: "family", "output_path", "graph_transform", + "graph_transform_id", "source_revision", } @@ -768,16 +771,20 @@ def dependency_lines(path: Path) -> list[str]: project_metadata = tomllib.loads(pyproject) assert 'requires-python = ">=3.12"' in pyproject assert "tomli" not in pyproject - declared_dependencies = [ + locked_metadata_dependencies = [ *project_metadata["build-system"]["requires"], - *project_metadata["project"]["dependencies"], *( requirement for requirements_group in project_metadata["project"]["optional-dependencies"].values() for requirement in requirements_group ), ] - assert all(exact_requirement.fullmatch(line) for line in declared_dependencies) + assert all(exact_requirement.fullmatch(line) for line in locked_metadata_dependencies) + project_dependencies = { + Requirement(line).name.lower().replace("-", "_"): Requirement(line) + for line in project_metadata["project"]["dependencies"] + } + assert all(requirement.specifier for requirement in project_dependencies.values()) optional = pyproject.split("[project.optional-dependencies]", 1)[1].split("\n[", 1)[0] assert set(re.findall(r"^([a-z][a-z0-9_-]*)\s*=", optional, re.MULTILINE)) == { "cutedsl", @@ -794,6 +801,20 @@ def dependency_lines(path: Path) -> list[str]: assert exact_requirement.fullmatch(line), ( f"family dependency must use one exact version: {path.relative_to(REPO)}:{line}" ) + family_requirement = Requirement(line) + shared_requirement = project_dependencies.get( + family_requirement.name.lower().replace("-", "_") + ) + if shared_requirement is not None: + family_version = next( + specifier.version + for specifier in family_requirement.specifier + if specifier.operator == "==" + ) + assert shared_requirement.specifier.contains(family_version), ( + f"family dependency conflicts with project compatibility contract: " + f"{path.relative_to(REPO)}:{line} vs {shared_requirement}" + ) assert not normalized.startswith(("-r", "--requirement", "-c", "--constraint")) assert not normalized.startswith(("-e", "--editable", "./", "../", "/", "file:")) assert " @ file:" not in normalized @@ -817,6 +838,7 @@ def dependency_lines(path: Path) -> list[str]: "ml_dtypes==0.5.4", "numpy==1.26.4", "onnx==1.21.0", + "packaging==26.2", "Pillow==12.2.0", "protobuf==7.35.0", "pytest==8.4.2", diff --git a/website/docs/api/python-builder.md b/website/docs/api/python-builder.md index f901bd668f..b9857e9170 100644 --- a/website/docs/api/python-builder.md +++ b/website/docs/api/python-builder.md @@ -31,10 +31,13 @@ resolved API directly. `model_dir` is already local at this boundary. The selected family alone decides whether that directory is a Hugging Face snapshot or a prepared checkpoint; `BuildRequest` does not perform another discovery pass. -Callers of this low-level API should pass the canonical checkpoint ID and exact -checkpoint revision. `resolve_source_revision()` accepts an explicit SHA, +Callers of this low-level API must pass the canonical checkpoint ID and an +immutable checkpoint revision. Hugging Face inputs use an exact commit SHA; +other stores use a namespaced immutable revision such as `ngc:1.0.1_onnx`. +`resolve_source_revision()` accepts an explicit SHA, `TRTMC_ENGINE_BUILD_REVISION`, `GITHUB_SHA`, or a Git checkout and fails when -none yields an exact source commit. +none yields an exact source commit. Automatic checkout resolution also rejects +a dirty worktree. ## Optional graph transform @@ -61,6 +64,7 @@ build(BuildRequest( task="text_generation", precision="fp16", graph_transform=replace_subgraph, + graph_transform_id="example:replace-subgraph-v1", )) ``` @@ -69,6 +73,9 @@ subgraph TensorRT can express. It must reconnect the replacement in place and raise on an invalid graph; a failure stops serialization and aborts bundle publication. Normal builds do not install the hook. There is no graph IR, registry, fingerprint, hash, fallback, or runtime Python path. +`graph_transform_id` is a required stable identity for the callback and is part +of provenance, so two transform implementations cannot silently share a cache +identity. `tensor_parallel_size` and `context_parallel_size` are direct request fields, not an options bag. Every family must either implement the requested value or diff --git a/website/docs/architecture/ai-native-horizontal-scaling.md b/website/docs/architecture/ai-native-horizontal-scaling.md index f975ff1c79..60370be290 100644 --- a/website/docs/architecture/ai-native-horizontal-scaling.md +++ b/website/docs/architecture/ai-native-horizontal-scaling.md @@ -312,8 +312,8 @@ Engine backend -> concrete family The closed shared set consists of model-support and build contracts, family resolver/loader mechanics, bundle container I/O, Core Load API, abstract Task and Engine APIs, stable device/engine primitives, one graph-transform callback, -and the already exercised model-agnostic BYOK bridge. Everything else remains -family-local or application-local. +the model-agnostic provenance trailer, and the already exercised BYOK bridge. +Everything else remains family-local or application-local. ## Minimal repository ownership @@ -372,6 +372,9 @@ pinned base image Rules: - `requirements/base.txt` contains only genuinely shared build/test tools. +- `pyproject.toml` is an installation compatibility contract, not a central + environment lock. Its bounds must admit every exact version selected by a + family; the pinned base image supplies the default shared versions. - A family declares extra build, reference, or test packages in its own plain `requirements.txt`. - A family with no extra dependency omits the file. @@ -486,6 +489,10 @@ The container additionally stores section name, offset, and length. A family owns section names, order, schema, and semantics. `BundleWriter` supports streaming large sections without requiring another complete host copy. +The core may append its bounded provenance trailer after all family sections. +The trailer is not a named section, cannot be read through `BundleReader`'s +family section API, and does not change the fixed header or section offsets. + The runtime creates a bounded, read-only `BundleReader` and transfers it to the selected family factory. A pipeline that needs deferred section loading copies the reader value; it does not retain a factory-context reference. diff --git a/website/docs/architecture/bundle-format.md b/website/docs/architecture/bundle-format.md index a5e4de352a..61a6a5bd75 100644 --- a/website/docs/architecture/bundle-format.md +++ b/website/docs/architecture/bundle-format.md @@ -3,7 +3,8 @@ title: Bundle Format --- A bundle contains eight magic bytes, an unsigned little-endian 64-bit JSON -header length, the UTF-8 JSON header, and concatenated named sections. +header length, the UTF-8 JSON header, concatenated family-owned named sections, +and an optional core-owned provenance trailer. ```json { @@ -12,9 +13,8 @@ header length, the UTF-8 JSON header, and concatenated named sections. "task": "text_generation", "backend": "trt", "sections": { - "provenance.json": {"offset": 0, "length": 391}, - "runtime.json": {"offset": 391, "length": 42}, - "engine.plan": {"offset": 433, "length": 1234} + "runtime.json": {"offset": 0, "length": 42}, + "engine.plan": {"offset": 42, "length": 1234} } } ``` @@ -24,17 +24,25 @@ constructed. It owns the normalized bundle path and immutable section table, then reads a requested section directly from the file. It has no write API and does not eagerly load section contents. -Every newly built bundle contains a `provenance.json` section. It records the -canonical checkpoint ID, the exact checkpoint commit, the exact TRTMC source -commit, and every build-affecting request option. `trtmc inspect BUNDLE` -returns this provenance alongside the fixed header and section table. A build -fails instead of publishing a bundle when its TRTMC source commit cannot be -resolved exactly. +Every bundle produced through the CLI contains a provenance JSON +trailer followed by its unsigned little-endian 64-bit length and the eight-byte +`PROV\x01\x00\x00\x00` marker. The trailer is outside the section payload, so +it does not reserve a family section name or change the fixed v1 header. It +records the canonical checkpoint ID, its immutable revision, the exact TRTMC +source commit, and every build-affecting request option. A Hugging Face revision +is an exact commit; another source uses a namespaced immutable revision such as +`ngc:1.0.1_onnx`. + +`trtmc inspect BUNDLE` returns the trailer alongside the fixed header and +section table. The CLI fails instead of publishing a bundle when checkpoint +identity is missing. Every build rejects a missing source identity, a dirty +locally inferred source checkout, or a graph transform without a stable +identity. Benchmark-managed bundles are reused only when all of this provenance matches the selected manifest and current source revision. Bundles without provenance, or with only a partial match, are rebuilt when builds are enabled and rejected when `--no-build` is set. -The core does not interpret family sections or compute section hashes. Only -format 1 is supported. +The core owns and validates the provenance envelope. It does not interpret +family sections or compute section hashes. Only format 1 is supported. diff --git a/website/docs/getting-started/quick-start.md b/website/docs/getting-started/quick-start.md index f4f6910e78..4f81b9a3ac 100644 --- a/website/docs/getting-started/quick-start.md +++ b/website/docs/getting-started/quick-start.md @@ -43,7 +43,9 @@ selecting another task supported by the same family. The build then imports only the selected `families.gpt2.model` and calls `build(request, writer)` once. A prepared local snapshot can be passed in place of the model ID. Pass its canonical model name with `--checkpoint-id` and its exact commit with -`--revision` so the resulting provenance is equivalent to a direct download. +`--revision`; both are required so the resulting provenance is equivalent to a +direct download. Non-Hugging-Face stores may use a namespaced immutable revision +such as `ngc:1.0.1_onnx`. For a wheel install, resolve its native runtime directory directly from the installed package: From 8cd7e2ed73dd013b87482a49a03e011ca5137748 Mon Sep 17 00:00:00 2001 From: chaofengw Date: Mon, 7 Sep 2026 13:25:27 +0000 Subject: [PATCH 4/5] fix(build): reject ambiguous provenance identities Require exact Git SHAs or explicit provider version-object IDs at build and benchmark catalog boundaries. Validate cached bundle headers and section bounds before accepting a matching provenance trailer. Signed-off-by: chaofengw --- apps/benchmark/trtmc_benchmark/catalog.py | 8 ++ .../trtmc_benchmark/tests/test_benchmark.py | 16 ++++ .../tensorrt_model_connect/__init__.py | 8 +- core/builder/tensorrt_model_connect/build.py | 41 +++++++--- .../tensorrt_model_connect/build_cli.py | 10 +-- .../tensorrt_model_connect/bundle_writer.py | 71 +++++++++++++++- core/builder/tests/test_build.py | 14 +++- core/builder/tests/test_build_cli.py | 23 +++++- core/builder/tests/test_bundle_writer.py | 81 +++++++++++++++++++ .../manifests/foundationpose-ngc-1.0.1.json | 2 +- website/docs/api/python-builder.md | 6 +- website/docs/architecture/bundle-format.md | 5 +- website/docs/getting-started/quick-start.md | 5 +- 13 files changed, 258 insertions(+), 32 deletions(-) diff --git a/apps/benchmark/trtmc_benchmark/catalog.py b/apps/benchmark/trtmc_benchmark/catalog.py index 22a5823aa5..13d87913db 100644 --- a/apps/benchmark/trtmc_benchmark/catalog.py +++ b/apps/benchmark/trtmc_benchmark/catalog.py @@ -11,6 +11,8 @@ from pathlib import Path from typing import Any, Iterable, Mapping +from tensorrt_model_connect import validate_checkpoint_revision + from .task_adapters import default_operation, resolve_task_case, supported_tasks from .types import BenchmarkError, MeasurementSpec, ModelDescriptor, ResolvedCase @@ -178,6 +180,12 @@ def _load(path: Path) -> ModelDescriptor: raise BenchmarkError( f"model manifest must declare an immutable checkpoint identity: {path}" ) + try: + validate_checkpoint_revision(checkpoint_revision) + except ValueError as error: + raise BenchmarkError( + f"model manifest has a mutable checkpoint_revision in {path}: {error}" + ) from error return ModelDescriptor( name=_string(raw["name"], "name", path), hf_id=hf_id, diff --git a/apps/benchmark/trtmc_benchmark/tests/test_benchmark.py b/apps/benchmark/trtmc_benchmark/tests/test_benchmark.py index 0c142d9667..38759ae41d 100644 --- a/apps/benchmark/trtmc_benchmark/tests/test_benchmark.py +++ b/apps/benchmark/trtmc_benchmark/tests/test_benchmark.py @@ -40,6 +40,18 @@ def test_catalog_reads_family_owned_manifests_without_a_registry() -> None: assert distilgpt2.status == "ready" +def test_catalog_rejects_a_mutable_checkpoint_revision(tmp_path: Path) -> None: + manifest = json.loads( + (REPO / "families/gpt2/tests/manifests/distilgpt2.json").read_text() + ) + manifest["hf_revision"] = "main" + manifest_path = tmp_path / "model.json" + manifest_path.write_text(json.dumps(manifest)) + + with pytest.raises(BenchmarkError, match="mutable checkpoint_revision"): + ManifestCatalog(tmp_path).resolve(str(manifest_path)) + + def test_case_resolves_current_task_and_manifest_fields(tmp_path: Path) -> None: model = ManifestCatalog(REPO / "families").resolve("distilgpt2") case = resolve_case(model, tmp_path / "model.bundle") @@ -285,6 +297,10 @@ def test_bundle_cache_reuses_an_exact_build_identity(tmp_path: Path, monkeypatch assert resolved[0].bundle_path == bundle assert records[0].status == "reused" + bundle.write_bytes(bundle.read_bytes().replace(b'"sections"', b'"sectionz"', 1)) + with pytest.raises(BenchmarkError, match="bundle provenance does not match"): + builder.prepare((case,), allow_build=False, rebuild=False, dry_run=False) + def _worker(tmp_path: Path) -> Path: path = tmp_path / "worker" diff --git a/core/builder/tensorrt_model_connect/__init__.py b/core/builder/tensorrt_model_connect/__init__.py index f7f1dbce26..e39de3936b 100644 --- a/core/builder/tensorrt_model_connect/__init__.py +++ b/core/builder/tensorrt_model_connect/__init__.py @@ -3,7 +3,12 @@ """TensorRT Model Connect build API.""" -from .build import BuildRequest, build, resolve_source_revision +from .build import ( + BuildRequest, + build, + resolve_source_revision, + validate_checkpoint_revision, +) from .bundle_writer import BundleWriter, read_bundle_provenance from .graph_transform import GraphTransform @@ -14,4 +19,5 @@ "build", "read_bundle_provenance", "resolve_source_revision", + "validate_checkpoint_revision", ] diff --git a/core/builder/tensorrt_model_connect/build.py b/core/builder/tensorrt_model_connect/build.py index dd0405a7f5..c9d33bac1a 100644 --- a/core/builder/tensorrt_model_connect/build.py +++ b/core/builder/tensorrt_model_connect/build.py @@ -21,9 +21,32 @@ _ID = re.compile(r"[a-z][a-z0-9_]*\Z") _EXACT_REVISION = re.compile(r"[0-9a-f]{40}\Z") -_IMMUTABLE_CHECKPOINT_REVISION = re.compile( - r"(?:[0-9a-f]{40}|[a-z][a-z0-9_.-]*:[A-Za-z0-9][A-Za-z0-9_.-]*)\Z" +_PROVIDER_VERSION_REVISION = re.compile( + r"[a-z][a-z0-9_.-]*:version:(?P[A-Za-z0-9][A-Za-z0-9_.-]*)\Z" ) +_MUTABLE_REVISION_ALIASES = frozenset( + {"dev", "head", "latest", "main", "master", "nightly", "release", "stable"} +) + + +def _is_exact_artifact_revision(value: str) -> bool: + if _EXACT_REVISION.fullmatch(value): + return True + match = _PROVIDER_VERSION_REVISION.fullmatch(value) + return bool( + match and match.group("version").lower() not in _MUTABLE_REVISION_ALIASES + ) + + +def validate_checkpoint_revision(value: object) -> str: + """Return one resolved checkpoint identity or reject mutable labels.""" + + if not isinstance(value, str) or not _is_exact_artifact_revision(value): + raise ValueError( + "checkpoint revision must be an exact Git SHA or resolved provider version " + "ID formatted as ':version:'" + ) + return value @dataclass(frozen=True) @@ -56,13 +79,8 @@ class BuildRequest: def __post_init__(self) -> None: if not self.precision: raise ValueError("precision must be non-empty") - if ( - self.checkpoint_revision - and _IMMUTABLE_CHECKPOINT_REVISION.fullmatch(self.checkpoint_revision) is None - ): - raise ValueError( - "checkpoint_revision must be an exact Git SHA or namespaced immutable revision" - ) + if self.checkpoint_revision: + validate_checkpoint_revision(self.checkpoint_revision) if self.source_revision and _EXACT_REVISION.fullmatch(self.source_revision) is None: raise ValueError("source_revision must be an exact 40-character Git SHA") _validate_id("family", self.family) @@ -93,10 +111,11 @@ def __post_init__(self) -> None: raise ValueError("graph_transform and graph_transform_id must be provided together") if ( self.graph_transform_id - and _IMMUTABLE_CHECKPOINT_REVISION.fullmatch(self.graph_transform_id) is None + and not _is_exact_artifact_revision(self.graph_transform_id) ): raise ValueError( - "graph_transform_id must be an exact Git SHA or namespaced immutable revision" + "graph_transform_id must be an exact Git SHA or resolved provider version " + "ID formatted as ':version:'" ) diff --git a/core/builder/tensorrt_model_connect/build_cli.py b/core/builder/tensorrt_model_connect/build_cli.py index 235fefbdd8..7231f3cdb1 100644 --- a/core/builder/tensorrt_model_connect/build_cli.py +++ b/core/builder/tensorrt_model_connect/build_cli.py @@ -13,10 +13,10 @@ from .build import ( BuildRequest, - _IMMUTABLE_CHECKPOINT_REVISION, _load_family, build, resolve_source_revision, + validate_checkpoint_revision, ) from .model_support import load_model_metadata, resolve_family @@ -135,13 +135,9 @@ def _checkpoint_revision(model_dir: Path, *, requested: str | None) -> str: resolved = model_dir.name.lower() if model_dir.parent.name == "snapshots" else "" if _EXACT_REVISION.fullmatch(resolved): return resolved - requested = (requested or "").strip().lower() - if _IMMUTABLE_CHECKPOINT_REVISION.fullmatch(requested): - return requested + requested = (requested or "").strip() if requested: - raise ValueError( - "checkpoint revision must be an exact Git SHA or namespaced immutable revision" - ) + return validate_checkpoint_revision(requested) raise ValueError("checkpoint revision is required and must identify immutable content") diff --git a/core/builder/tensorrt_model_connect/bundle_writer.py b/core/builder/tensorrt_model_connect/bundle_writer.py index 4b8d6464f2..35038e8dce 100644 --- a/core/builder/tensorrt_model_connect/bundle_writer.py +++ b/core/builder/tensorrt_model_connect/bundle_writer.py @@ -39,6 +39,66 @@ def _validate_nonempty_string(field: str, value: object) -> str: return value +def _require_exact_keys( + value: object, expected: frozenset[str], *, context: str +) -> dict[str, Any]: + if not isinstance(value, dict): + raise ValueError(f"{context} must be a JSON object") + actual = set(value) + unsupported = sorted(actual - expected) + if unsupported: + raise ValueError(f"{context} contains unsupported field {unsupported[0]!r}") + missing = sorted(expected - actual) + if missing: + raise ValueError(f"{context} missing required field {missing[0]!r}") + return value + + +def _require_uint64(value: object, *, field: str) -> int: + if ( + isinstance(value, bool) + or not isinstance(value, int) + or not 0 <= value <= _MAX_UINT64 + ): + raise ValueError(f"{field} must be a non-negative uint64 integer") + return value + + +def _validate_bundle_header( + header: object, *, data_start: int, payload_end: int, path: Path +) -> None: + parsed = _require_exact_keys( + header, + frozenset({"format", "family", "task", "backend", "sections"}), + context="bundle header", + ) + if _require_uint64(parsed["format"], field="bundle format") != _FORMAT: + raise ValueError(f"{path} has an unsupported bundle format") + for field in ("family", "task", "backend"): + _validate_nonempty_string(f"bundle header {field}", parsed[field]) + sections = parsed["sections"] + if not isinstance(sections, dict): + raise ValueError("bundle header sections must be a JSON object") + if data_start > payload_end: + raise ValueError(f"{path} has an invalid section payload range") + payload_size = payload_end - data_start + for name, raw_descriptor in sections.items(): + _validate_nonempty_string("bundle section name", name) + descriptor = _require_exact_keys( + raw_descriptor, + frozenset({"offset", "length"}), + context=f"bundle section {name!r}", + ) + offset = _require_uint64( + descriptor["offset"], field=f"bundle section {name!r} offset" + ) + length = _require_uint64( + descriptor["length"], field=f"bundle section {name!r} length" + ) + if offset > payload_size or length > payload_size - offset: + raise ValueError(f"bundle section {name!r} extends outside {path}") + + def read_bundle_provenance(path: str | Path) -> Any: """Read the core-owned provenance trailer from a bundle file.""" @@ -56,10 +116,9 @@ def read_bundle_provenance(path: str | Path) -> Any: if len(raw_header) != header_size: raise ValueError(f"{bundle_path} has a truncated header") header = json.loads(raw_header) - if not isinstance(header, dict): - raise ValueError(f"{bundle_path} has an invalid header") minimum_start = len(BUNDLE_MAGIC) + 8 + header_size - file_size = bundle_path.stat().st_size + bundle.seek(0, os.SEEK_END) + file_size = bundle.tell() footer_size = 8 + len(BUNDLE_PROVENANCE_MAGIC) if file_size < minimum_start + footer_size: raise ValueError(f"{bundle_path} has no provenance trailer") @@ -71,6 +130,12 @@ def read_bundle_provenance(path: str | Path) -> Any: provenance_start = file_size - footer_size - provenance_size if provenance_size > _MAX_HEADER_SIZE or provenance_start < minimum_start: raise ValueError(f"{bundle_path} has an invalid provenance trailer") + _validate_bundle_header( + header, + data_start=minimum_start, + payload_end=provenance_start, + path=bundle_path, + ) bundle.seek(provenance_start) raw_provenance = bundle.read(provenance_size) if len(raw_provenance) != provenance_size: diff --git a/core/builder/tests/test_build.py b/core/builder/tests/test_build.py index d5c310b2c5..05a8f501e2 100644 --- a/core/builder/tests/test_build.py +++ b/core/builder/tests/test_build.py @@ -45,6 +45,14 @@ def test_build_request_is_a_plain_frozen_dataclass(tmp_path: Path) -> None: assert request.dynamic_kv_cache is False +def test_build_request_accepts_a_resolved_provider_version(tmp_path: Path) -> None: + request = replace( + _request(tmp_path), checkpoint_revision="ngc:version:1.0.1_onnx" + ) + + assert request.checkpoint_revision == "ngc:version:1.0.1_onnx" + + @pytest.mark.parametrize( ("field", "value"), [ @@ -61,6 +69,8 @@ def test_build_request_is_a_plain_frozen_dataclass(tmp_path: Path) -> None: ("graph_transform", object()), ("backend", "unknown"), ("checkpoint_revision", "main"), + ("checkpoint_revision", "hf:main"), + ("checkpoint_revision", "ngc:version:latest"), ("source_revision", "dirty"), ], ) @@ -84,7 +94,7 @@ def test_graph_transform_requires_a_stable_identity(tmp_path: Path) -> None: replace(_request(tmp_path), graph_transform=lambda _network, _index: None) with pytest.raises(ValueError, match="provided together"): replace(_request(tmp_path), graph_transform_id="example:transform-v1") - with pytest.raises(ValueError, match="namespaced immutable revision"): + with pytest.raises(ValueError, match="resolved provider version"): replace( _request(tmp_path), graph_transform=lambda _network, _index: None, @@ -370,7 +380,7 @@ def transform(network: object, engine_index: int) -> None: request = replace( _request(tmp_path), graph_transform=transform, - graph_transform_id="example:replace-subgraph-v1", + graph_transform_id="c" * 40, ) monkeypatch.setattr(build_core, "BundleWriter", FakeWriter) monkeypatch.setattr( diff --git a/core/builder/tests/test_build_cli.py b/core/builder/tests/test_build_cli.py index bbba7219ac..8de1278959 100644 --- a/core/builder/tests/test_build_cli.py +++ b/core/builder/tests/test_build_cli.py @@ -246,13 +246,34 @@ def test_build_command_forwards_resolved_source_revision( def test_local_checkpoint_rejects_a_non_exact_requested_revision(tmp_path: Path) -> None: - with pytest.raises(ValueError, match="namespaced immutable revision"): + with pytest.raises(ValueError, match="resolved provider version"): build_cli._checkpoint_revision( tmp_path / "local-checkpoint", requested="main", ) +@pytest.mark.parametrize("revision", ["hf:main", "ngc:version:latest"]) +def test_local_checkpoint_rejects_a_mutable_namespaced_revision( + tmp_path: Path, revision: str +) -> None: + with pytest.raises(ValueError, match="resolved provider version"): + build_cli._checkpoint_revision( + tmp_path / "local-checkpoint", + requested=revision, + ) + + +def test_local_checkpoint_accepts_a_resolved_provider_version(tmp_path: Path) -> None: + assert ( + build_cli._checkpoint_revision( + tmp_path / "local-checkpoint", + requested="ngc:version:1.0.1_onnx", + ) + == "ngc:version:1.0.1_onnx" + ) + + def test_local_checkpoint_requires_canonical_id_and_revision(tmp_path: Path) -> None: model = tmp_path / "model" model.mkdir() diff --git a/core/builder/tests/test_bundle_writer.py b/core/builder/tests/test_bundle_writer.py index 5b41c35ff8..d8dcb3bb95 100644 --- a/core/builder/tests/test_bundle_writer.py +++ b/core/builder/tests/test_bundle_writer.py @@ -27,6 +27,25 @@ def _read_bundle(path: Path) -> tuple[dict, bytes]: return json.loads(data[header_start:header_end]), data[header_end:] +def _write_raw_bundle( + path: Path, header: object, *, payload: bytes = b"", provenance: object | None = None +) -> None: + raw_header = json.dumps(header, separators=(",", ":")).encode() + raw_provenance = json.dumps( + provenance if provenance is not None else {"format": 1}, + separators=(",", ":"), + ).encode() + path.write_bytes( + BUNDLE_MAGIC + + struct.pack(" None: destination = tmp_path / "model.bundle" writer = BundleWriter(destination) @@ -83,6 +102,68 @@ def test_writer_appends_provenance_outside_family_sections(tmp_path: Path) -> No assert read_bundle_provenance(destination) == provenance +@pytest.mark.parametrize( + "header", + [ + { + "format": 1, + "family": "family", + "task": "text_generation", + "backend": "trt", + }, + { + "format": 1, + "family": "family", + "task": "text_generation", + "backend": "trt", + "sections": {}, + "model_id": "legacy", + }, + { + "format": 1, + "family": "family", + "task": "text_generation", + "backend": "trt", + "sections": {"engine.plan": {"offset": 0}}, + }, + { + "format": 1, + "family": "family", + "task": "text_generation", + "backend": "trt", + "sections": {"engine.plan": {"offset": 0, "length": 1}}, + }, + ], + ids=("missing-sections", "unsupported-field", "incomplete-section", "section-bounds"), +) +def test_provenance_reader_rejects_headers_the_runtime_rejects( + tmp_path: Path, header: object +) -> None: + destination = tmp_path / "model.bundle" + _write_raw_bundle(destination, header) + + with pytest.raises(ValueError): + read_bundle_provenance(destination) + + +def test_provenance_reader_rejects_a_non_object_trailer(tmp_path: Path) -> None: + destination = tmp_path / "model.bundle" + _write_raw_bundle( + destination, + { + "format": 1, + "family": "family", + "task": "text_generation", + "backend": "trt", + "sections": {}, + }, + provenance=[], + ) + + with pytest.raises(ValueError, match="JSON object"): + read_bundle_provenance(destination) + + def test_provenance_must_be_one_json_object(tmp_path: Path) -> None: writer = BundleWriter(tmp_path / "model.bundle") with pytest.raises(TypeError, match="JSON object"): diff --git a/families/foundationpose/tests/manifests/foundationpose-ngc-1.0.1.json b/families/foundationpose/tests/manifests/foundationpose-ngc-1.0.1.json index 95c111c602..56b445d664 100644 --- a/families/foundationpose/tests/manifests/foundationpose-ngc-1.0.1.json +++ b/families/foundationpose/tests/manifests/foundationpose-ngc-1.0.1.json @@ -5,7 +5,7 @@ "task": "pose_hypothesis_refinement", "precision": "fp16", "checkpoint_id": "nvidia/isaac/foundationpose", - "checkpoint_revision": "ngc:1.0.1_onnx", + "checkpoint_revision": "ngc:version:1.0.1_onnx", "external_files": [ { "path": "refine_model.onnx", diff --git a/website/docs/api/python-builder.md b/website/docs/api/python-builder.md index b9857e9170..655b135774 100644 --- a/website/docs/api/python-builder.md +++ b/website/docs/api/python-builder.md @@ -33,7 +33,9 @@ decides whether that directory is a Hugging Face snapshot or a prepared checkpoint; `BuildRequest` does not perform another discovery pass. Callers of this low-level API must pass the canonical checkpoint ID and an immutable checkpoint revision. Hugging Face inputs use an exact commit SHA; -other stores use a namespaced immutable revision such as `ngc:1.0.1_onnx`. +other stores use the provider's resolved version-object ID, explicitly tagged +as such, for example `ngc:version:1.0.1_onnx`. Branches, channels, and aliases +such as `main` or `latest` are rejected. `resolve_source_revision()` accepts an explicit SHA, `TRTMC_ENGINE_BUILD_REVISION`, `GITHUB_SHA`, or a Git checkout and fails when none yields an exact source commit. Automatic checkout resolution also rejects @@ -64,7 +66,7 @@ build(BuildRequest( task="text_generation", precision="fp16", graph_transform=replace_subgraph, - graph_transform_id="example:replace-subgraph-v1", + graph_transform_id="94f6e5764b3ae57f775c759ca16e617adcdd28ee", )) ``` diff --git a/website/docs/architecture/bundle-format.md b/website/docs/architecture/bundle-format.md index 61a6a5bd75..a1431be09c 100644 --- a/website/docs/architecture/bundle-format.md +++ b/website/docs/architecture/bundle-format.md @@ -30,8 +30,9 @@ trailer followed by its unsigned little-endian 64-bit length and the eight-byte it does not reserve a family section name or change the fixed v1 header. It records the canonical checkpoint ID, its immutable revision, the exact TRTMC source commit, and every build-affecting request option. A Hugging Face revision -is an exact commit; another source uses a namespaced immutable revision such as -`ngc:1.0.1_onnx`. +is an exact commit; another source uses the provider's resolved version-object +ID, for example `ngc:version:1.0.1_onnx`. Mutable branches, channels, and aliases +are not valid provenance identities. `trtmc inspect BUNDLE` returns the trailer alongside the fixed header and section table. The CLI fails instead of publishing a bundle when checkpoint diff --git a/website/docs/getting-started/quick-start.md b/website/docs/getting-started/quick-start.md index 4f81b9a3ac..237deafdb8 100644 --- a/website/docs/getting-started/quick-start.md +++ b/website/docs/getting-started/quick-start.md @@ -44,8 +44,9 @@ only the selected `families.gpt2.model` and calls `build(request, writer)` once. A prepared local snapshot can be passed in place of the model ID. Pass its canonical model name with `--checkpoint-id` and its exact commit with `--revision`; both are required so the resulting provenance is equivalent to a -direct download. Non-Hugging-Face stores may use a namespaced immutable revision -such as `ngc:1.0.1_onnx`. +direct download. Non-Hugging-Face stores may use a resolved provider +version-object ID such as `ngc:version:1.0.1_onnx`; mutable aliases such as +`latest` are rejected. For a wheel install, resolve its native runtime directory directly from the installed package: From 818d34c86e17eb524dc354f10e68055dd20ea052 Mon Sep 17 00:00:00 2001 From: chaofengw Date: Thu, 10 Sep 2026 02:47:40 +0000 Subject: [PATCH 5/5] fix(build): align provenance with current main Preserve the family default precision while recording build provenance. Pin Pillow for model families added since the original PR base so the repository-wide exact dependency contract remains valid. Signed-off-by: chaofengw --- core/builder/tensorrt_model_connect/build_cli.py | 9 +++++---- core/builder/tests/test_build_cli.py | 6 +++++- families/timm_convnext/requirements.txt | 2 +- families/timm_crossvit/requirements.txt | 2 +- families/timm_dpn/requirements.txt | 2 +- families/timm_ghostnet/requirements.txt | 2 +- families/timm_hrnet/requirements.txt | 2 +- families/timm_inception_resnet/requirements.txt | 2 +- families/timm_inception_v4/requirements.txt | 2 +- families/timm_regnet/requirements.txt | 2 +- families/timm_res2net/requirements.txt | 2 +- families/timm_resnest/requirements.txt | 2 +- families/timm_senet/requirements.txt | 2 +- families/timm_seresnet/requirements.txt | 2 +- families/timm_swin/requirements.txt | 2 +- families/timm_xception/requirements.txt | 2 +- families/yolov10/requirements.txt | 2 +- 17 files changed, 25 insertions(+), 20 deletions(-) diff --git a/core/builder/tensorrt_model_connect/build_cli.py b/core/builder/tensorrt_model_connect/build_cli.py index 7231f3cdb1..b7ad9b8fca 100644 --- a/core/builder/tensorrt_model_connect/build_cli.py +++ b/core/builder/tensorrt_model_connect/build_cli.py @@ -63,7 +63,12 @@ def _parser() -> argparse.ArgumentParser: def main(argv: Sequence[str] | None = None) -> int: args = _parser().parse_args(argv) + source_is_local = Path(args.model).is_dir() + if args.command == "build" and source_is_local and not args.checkpoint_id: + raise ValueError("--checkpoint-id is required when MODEL is a local directory") model_dir = _resolve_model(args.model, args.revision) + if args.command == "build": + checkpoint_revision = _checkpoint_revision(model_dir, requested=args.revision) family, support = resolve_family(load_model_metadata(model_dir)) if args.command == "prepare-structure": if "structure_prediction" not in support.tasks: @@ -82,10 +87,6 @@ def main(argv: Sequence[str] | None = None) -> int: return 0 if args.command != "build": raise AssertionError(f"unhandled command: {args.command}") - source_is_local = Path(args.model).is_dir() - if source_is_local and not args.checkpoint_id: - raise ValueError("--checkpoint-id is required when MODEL is a local directory") - checkpoint_revision = _checkpoint_revision(model_dir, requested=args.revision) task = args.task or support.default_task if task not in support.tasks: raise ValueError( diff --git a/core/builder/tests/test_build_cli.py b/core/builder/tests/test_build_cli.py index 8de1278959..621c4fbbf9 100644 --- a/core/builder/tests/test_build_cli.py +++ b/core/builder/tests/test_build_cli.py @@ -14,7 +14,11 @@ def _stub_family_resolution(monkeypatch) -> None: - support = SimpleNamespace(tasks=("example_task",), default_task="example_task") + support = SimpleNamespace( + tasks=("example_task",), + default_task="example_task", + default_precision="fp32", + ) monkeypatch.setattr(build_cli, "load_model_metadata", lambda _model_dir: object()) monkeypatch.setattr( build_cli, diff --git a/families/timm_convnext/requirements.txt b/families/timm_convnext/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_convnext/requirements.txt +++ b/families/timm_convnext/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_crossvit/requirements.txt b/families/timm_crossvit/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_crossvit/requirements.txt +++ b/families/timm_crossvit/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_dpn/requirements.txt b/families/timm_dpn/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_dpn/requirements.txt +++ b/families/timm_dpn/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_ghostnet/requirements.txt b/families/timm_ghostnet/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_ghostnet/requirements.txt +++ b/families/timm_ghostnet/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_hrnet/requirements.txt b/families/timm_hrnet/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_hrnet/requirements.txt +++ b/families/timm_hrnet/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_inception_resnet/requirements.txt b/families/timm_inception_resnet/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_inception_resnet/requirements.txt +++ b/families/timm_inception_resnet/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_inception_v4/requirements.txt b/families/timm_inception_v4/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_inception_v4/requirements.txt +++ b/families/timm_inception_v4/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_regnet/requirements.txt b/families/timm_regnet/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_regnet/requirements.txt +++ b/families/timm_regnet/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_res2net/requirements.txt b/families/timm_res2net/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_res2net/requirements.txt +++ b/families/timm_res2net/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_resnest/requirements.txt b/families/timm_resnest/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_resnest/requirements.txt +++ b/families/timm_resnest/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_senet/requirements.txt b/families/timm_senet/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_senet/requirements.txt +++ b/families/timm_senet/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_seresnet/requirements.txt b/families/timm_seresnet/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_seresnet/requirements.txt +++ b/families/timm_seresnet/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_swin/requirements.txt b/families/timm_swin/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_swin/requirements.txt +++ b/families/timm_swin/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/timm_xception/requirements.txt b/families/timm_xception/requirements.txt index b963a278a0..f75edd6685 100644 --- a/families/timm_xception/requirements.txt +++ b/families/timm_xception/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 timm==1.0.28 diff --git a/families/yolov10/requirements.txt b/families/yolov10/requirements.txt index 000a6d6dd8..151db89fac 100644 --- a/families/yolov10/requirements.txt +++ b/families/yolov10/requirements.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -Pillow +Pillow==12.2.0 ultralytics==8.3.0