From 2ee80e3ed1495b27097563c404ae68607033fa7e Mon Sep 17 00:00:00 2001 From: titaiwang Date: Sun, 25 Oct 2026 00:50:07 +0000 Subject: [PATCH 1/2] Fix CI dependency resolution for pinned Transformers and VibeVoice Using --no-deps for Transformers 5.16 left the VibeVoice Hub 2 dependency incompatible. Resolve the pinned Transformers requirements together with the editable project before installing only VibeVoice with --no-deps, preserving both revisions. Add five AutoConfig smokes and six offline contract tests; the tests pass. A local fresh-environment resolver run was not performed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9a2a5b82-7cd3-4a76-bb94-0998527ea723 Signed-off-by: titaiwang --- .github/workflows/gpu_l4_golden_parity.yml | 3 +- .github/workflows/gpu_l5_generation_e2e.yml | 3 +- .github/workflows/main.yml | 6 +- .github/workflows/nightly_l2.yml | 3 +- requirements/ci/transformers.txt | 3 + requirements/ci/vibevoice.txt | 6 +- tests/ci_dependencies_test.py | 64 +++++++++++++++++++++ 7 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 requirements/ci/transformers.txt create mode 100644 tests/ci_dependencies_test.py diff --git a/.github/workflows/gpu_l4_golden_parity.yml b/.github/workflows/gpu_l4_golden_parity.yml index 5e74b7fb2..bae580e1b 100644 --- a/.github/workflows/gpu_l4_golden_parity.yml +++ b/.github/workflows/gpu_l4_golden_parity.yml @@ -74,8 +74,9 @@ jobs: run: | pip install -r requirements/ci/requirements.txt pip install soundfile librosa ml_dtypes flatbuffers numpy packaging protobuf sympy coloredlogs - pip install -e '.[testing,transformers]' + pip install -e '.[testing,transformers]' -r requirements/ci/transformers.txt pip install --force-reinstall --no-deps -r requirements/ci/vibevoice.txt + python -c "from transformers import AutoConfig" # PyPI's ORT 1.27+ wheel requires CUDA 13, while these runners use CUDA 12. pip install --pre --no-deps --index-url https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/onnxruntime-cuda-12/pypi/simple/ onnxruntime-gpu pip install --no-deps onnxruntime-genai-cuda diff --git a/.github/workflows/gpu_l5_generation_e2e.yml b/.github/workflows/gpu_l5_generation_e2e.yml index 0c377f75d..3c5b957d2 100644 --- a/.github/workflows/gpu_l5_generation_e2e.yml +++ b/.github/workflows/gpu_l5_generation_e2e.yml @@ -74,8 +74,9 @@ jobs: run: | pip install -r requirements/ci/requirements.txt pip install soundfile librosa ml_dtypes flatbuffers numpy packaging protobuf sympy coloredlogs - pip install -e '.[testing,transformers]' + pip install -e '.[testing,transformers]' -r requirements/ci/transformers.txt pip install --force-reinstall --no-deps -r requirements/ci/vibevoice.txt + python -c "from transformers import AutoConfig" # PyPI's ORT 1.27+ wheel requires CUDA 13, while these runners use CUDA 12. pip install --pre --no-deps --index-url https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/onnxruntime-cuda-12/pypi/simple/ onnxruntime-gpu pip install --no-deps onnxruntime-genai-cuda diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a04d16ed4..950fc48cf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -148,8 +148,9 @@ jobs: run: | pip install -r requirements/ci/requirements.txt pip install onnxruntime - pip install -e '.[testing,transformers]' + pip install -e '.[testing,transformers]' -r requirements/ci/transformers.txt pip install --force-reinstall --no-deps -r requirements/ci/vibevoice.txt + python -c "from transformers import AutoConfig" - name: Run L3 synthetic parity tests env: HF_TOKEN: ${{ secrets.HF_TOKEN }} @@ -257,8 +258,9 @@ jobs: run: | pip install -r requirements/ci/requirements.txt pip install onnxruntime - pip install -e '.[testing]' + pip install -e '.[testing]' -r requirements/ci/transformers.txt pip install --force-reinstall --no-deps -r requirements/ci/vibevoice.txt + python -c "from transformers import AutoConfig" - name: Run tests run: | pytest -n auto -m 'not integration and not arch_validation' --cov=src --cov-report=xml --cov-branch --junitxml junit.xml diff --git a/.github/workflows/nightly_l2.yml b/.github/workflows/nightly_l2.yml index 55899f71a..31aaa27b9 100644 --- a/.github/workflows/nightly_l2.yml +++ b/.github/workflows/nightly_l2.yml @@ -51,8 +51,9 @@ jobs: - name: Install dependencies run: | pip install -r requirements/ci/requirements.txt - pip install -e '.[testing]' + pip install -e '.[testing]' -r requirements/ci/transformers.txt pip install --force-reinstall --no-deps -r requirements/ci/vibevoice.txt + python -c "from transformers import AutoConfig" # Run sequentially (-p no:xdist) to stay under 2GB RAM - name: Run L2 architecture validation tests diff --git a/requirements/ci/transformers.txt b/requirements/ci/transformers.txt new file mode 100644 index 000000000..5eed633b9 --- /dev/null +++ b/requirements/ci/transformers.txt @@ -0,0 +1,3 @@ +# VibeVoice support requires this source revision. Resolve its dependencies +# together with the project before installing VibeVoice with --no-deps. +transformers @ git+https://github.com/huggingface/transformers.git@640a08a597034221ca1c4fc0c129cf0118179225 diff --git a/requirements/ci/vibevoice.txt b/requirements/ci/vibevoice.txt index 541e8026d..74e822a99 100644 --- a/requirements/ci/vibevoice.txt +++ b/requirements/ci/vibevoice.txt @@ -1,5 +1,5 @@ -# VibeVoice is upstream but not yet available in a released Transformers wheel. -transformers @ git+https://github.com/huggingface/transformers.git@640a08a597034221ca1c4fc0c129cf0118179225 # Exact source used by VibeVoice Realtime L3 synthetic parity tests. CI installs -# this file with --no-deps, retaining the test environment's Transformers build. +# this file with --no-deps after resolving requirements/ci/transformers.txt. +# Upstream still declares Transformers <5; the CI reference uses the pinned +# Transformers source above rather than downgrading to that older API. vibevoice @ git+https://github.com/microsoft/VibeVoice.git@79e516a3e20b599f137c9da03410a2a0b473b63b diff --git a/tests/ci_dependencies_test.py b/tests/ci_dependencies_test.py new file mode 100644 index 000000000..93413ef02 --- /dev/null +++ b/tests/ci_dependencies_test.py @@ -0,0 +1,64 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +"""Keep pinned Transformers dependency resolution separate from VibeVoice.""" + +from __future__ import annotations + +import shlex +from pathlib import Path + +import pytest +import yaml + +_ROOT = Path(__file__).resolve().parents[1] +_TRANSFORMERS = "requirements/ci/transformers.txt" +_VIBEVOICE = "requirements/ci/vibevoice.txt" +_WORKFLOWS = sorted( + path + for path in (_ROOT / ".github/workflows").glob("*.yml") + if _VIBEVOICE in path.read_text(encoding="utf-8") +) + + +@pytest.mark.parametrize("path", _WORKFLOWS, ids=lambda path: path.name) +def test_vibevoice_install_resolves_transformers_first(path): + workflow = yaml.safe_load(path.read_text(encoding="utf-8")) + checked = 0 + for job in workflow["jobs"].values(): + for step in job.get("steps", []): + script = step.get("run", "") + if _VIBEVOICE not in script: + continue + commands = [shlex.split(line, comments=True) for line in script.splitlines()] + for index, command in enumerate(commands): + if _VIBEVOICE not in command: + continue + assert "--no-deps" in command + assert command[command.index("-r") + 1] == _VIBEVOICE + resolved = [prior for prior in commands[:index] if _TRANSFORMERS in prior] + assert resolved, f"{path.name}: resolve pinned Transformers first" + assert all("--no-deps" not in prior for prior in resolved) + assert all("-e" in prior for prior in resolved) + assert any( + "from transformers import AutoConfig" in later + for later in commands[index + 1 :] + ) + checked += 1 + assert checked, f"{path.name}: no VibeVoice installation was checked" + + +@pytest.mark.parametrize( + ("requirements", "package"), [(_TRANSFORMERS, "transformers"), (_VIBEVOICE, "vibevoice")] +) +def test_ci_source_requirements_contain_only_the_intended_package(requirements, package): + lines = [ + line.strip() + for line in (_ROOT / requirements).read_text(encoding="utf-8").splitlines() + if line.strip() and not line.lstrip().startswith("#") + ] + assert len(lines) == 1 + assert lines[0].startswith(f"{package} @ git+https://github.com/") + revision = lines[0].rsplit("@", 1)[1] + assert len(revision) == 40 + assert all(character in "0123456789abcdef" for character in revision) From 84151a18170214b47a30304a0c39d4fe0719f84e Mon Sep 17 00:00:00 2001 From: titaiwang Date: Sun, 25 Oct 2026 18:16:02 +0000 Subject: [PATCH 2/2] Remove CI workflow structure tests Real dependency installation and AutoConfig import smokes remain. The removed YAML-string checks overconstrain workflow structure. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9a2a5b82-7cd3-4a76-bb94-0998527ea723 Signed-off-by: titaiwang --- tests/ci_dependencies_test.py | 64 ----------------------------------- 1 file changed, 64 deletions(-) delete mode 100644 tests/ci_dependencies_test.py diff --git a/tests/ci_dependencies_test.py b/tests/ci_dependencies_test.py deleted file mode 100644 index 93413ef02..000000000 --- a/tests/ci_dependencies_test.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -"""Keep pinned Transformers dependency resolution separate from VibeVoice.""" - -from __future__ import annotations - -import shlex -from pathlib import Path - -import pytest -import yaml - -_ROOT = Path(__file__).resolve().parents[1] -_TRANSFORMERS = "requirements/ci/transformers.txt" -_VIBEVOICE = "requirements/ci/vibevoice.txt" -_WORKFLOWS = sorted( - path - for path in (_ROOT / ".github/workflows").glob("*.yml") - if _VIBEVOICE in path.read_text(encoding="utf-8") -) - - -@pytest.mark.parametrize("path", _WORKFLOWS, ids=lambda path: path.name) -def test_vibevoice_install_resolves_transformers_first(path): - workflow = yaml.safe_load(path.read_text(encoding="utf-8")) - checked = 0 - for job in workflow["jobs"].values(): - for step in job.get("steps", []): - script = step.get("run", "") - if _VIBEVOICE not in script: - continue - commands = [shlex.split(line, comments=True) for line in script.splitlines()] - for index, command in enumerate(commands): - if _VIBEVOICE not in command: - continue - assert "--no-deps" in command - assert command[command.index("-r") + 1] == _VIBEVOICE - resolved = [prior for prior in commands[:index] if _TRANSFORMERS in prior] - assert resolved, f"{path.name}: resolve pinned Transformers first" - assert all("--no-deps" not in prior for prior in resolved) - assert all("-e" in prior for prior in resolved) - assert any( - "from transformers import AutoConfig" in later - for later in commands[index + 1 :] - ) - checked += 1 - assert checked, f"{path.name}: no VibeVoice installation was checked" - - -@pytest.mark.parametrize( - ("requirements", "package"), [(_TRANSFORMERS, "transformers"), (_VIBEVOICE, "vibevoice")] -) -def test_ci_source_requirements_contain_only_the_intended_package(requirements, package): - lines = [ - line.strip() - for line in (_ROOT / requirements).read_text(encoding="utf-8").splitlines() - if line.strip() and not line.lstrip().startswith("#") - ] - assert len(lines) == 1 - assert lines[0].startswith(f"{package} @ git+https://github.com/") - revision = lines[0].rsplit("@", 1)[1] - assert len(revision) == 40 - assert all(character in "0123456789abcdef" for character in revision)