mirror of
https://github.com/NVIDIA/Model-Optimizer.git
synced 2026-10-02 03:14:52 +08:00
### What does this PR do? Type of change: new feature Packages the existing ModelOpt agent skills as installable Codex and Claude plugins: - Adds a repo-scoped Codex marketplace and Claude-compatible marketplace. - Adds the canonical `plugins/modelopt/` plugin tree and manifests. - Moves the skill tree into the plugin and keeps `.agents/skills` as a compatibility symlink. - Adds a minimal `common` placeholder skill required by Codex validation. - Documents installation from this repository. ### Usage ```bash codex plugin marketplace add NVIDIA/Model-Optimizer ``` Then open `/plugins`, select the `modelopt` marketplace, and install `modelopt`. For Claude Code: ```bash claude plugin marketplace add https://github.com/NVIDIA/Model-Optimizer.git claude plugin install modelopt@modelopt ``` ### Testing - Codex plugin validator - `claude plugin validate . --strict` - `claude plugin validate plugins/modelopt --strict` 1. Install the marketplace plugin with Codex and Claude from an unrelated temporary workspace. 2. Exercise packaged evaluation helpers, a day-0 gate, and the shared remote helper from that workspace. 3. Run `uv run --frozen --extra dev python -m pytest -q plugins/modelopt/skills/day0-release/tests/test_gates.py plugins/modelopt/skills/benchmark-model-kernels/tests`. 4. Run pre-commit hooks for all changed files. ### Before your PR is "*Ready for review*" - Is this change backward compatible?: ✅ - If you copied code from any other sources or added a new PIP dependency, did you follow guidance in `CONTRIBUTING.md`: N/A - Did you write any new necessary tests?: ✅ — added a plugin-path validator; existing focused skill tests and installed-plugin smoke tests pass. - Did you update Changelog?: N/A — agent tooling and distribution only. - Did you get Claude approval on this PR?: N/A ### Additional Information Skills remain available through `.agents/skills`; bundled helpers are packaged under the plugin and resolved from `$SKILL_DIR` so installed workflows do not depend on the current workspace. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added installable ModelOpt plugins for Claude Code and Codex. * Added skills for PTQ, deployment, evaluation, monitoring, debugging, benchmarking, MLflow access, EAGLE3 workflows, and release management. * Added deployment helpers, evaluation recipes, checkpoint validation, and release-gating tools. * **Documentation** * Expanded setup, credential, SLURM, benchmarking, deployment, evaluation, troubleshooting, and workspace guidance. * Added installation instructions and updated agent-skill discovery guidance. * **Maintenance** * Updated skill references and compatibility links for reliable use across supported plugin environments. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Chad Voegele <cvoegele@nvidia.com>
213 lines
7.9 KiB
YAML
213 lines
7.9 KiB
YAML
name: Unit tests
|
|
|
|
on:
|
|
pull_request:
|
|
branches: [main, release/*, feature/*]
|
|
push:
|
|
branches: [main, release/*, feature/*]
|
|
paths:
|
|
- ".github/workflows/unit_tests.yml"
|
|
- "modelopt/**"
|
|
- "noxfile.py"
|
|
- "pyproject.toml"
|
|
- "tests/unit/**"
|
|
- "tools/launcher/**"
|
|
- "tools/mcp/**"
|
|
- "tools/resource_monitor.py"
|
|
- ".agents/skills/**"
|
|
- "plugins/modelopt/skills/**"
|
|
schedule:
|
|
- cron: "0 0 * * *" # Nightly
|
|
workflow_dispatch:
|
|
# On-demand
|
|
|
|
concurrency:
|
|
# Cancel previous runs if new commit is pushed
|
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
check-file-changes:
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
any_changed: ${{ steps.changed.outputs.any_modified || steps.non-pr.outputs.any_changed }}
|
|
steps:
|
|
- id: non-pr
|
|
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
|
|
run: echo "any_changed=true" >> $GITHUB_OUTPUT
|
|
- if: github.event_name == 'pull_request'
|
|
uses: actions/checkout@v6
|
|
with:
|
|
fetch-depth: 0
|
|
- if: github.event_name == 'pull_request'
|
|
name: Check for changes in test-relevant paths
|
|
id: changed
|
|
uses: step-security/changed-files@v47.0.5
|
|
with:
|
|
files: |
|
|
.github/workflows/unit_tests.yml
|
|
modelopt/**
|
|
modelopt_recipes/**
|
|
noxfile.py
|
|
pyproject.toml
|
|
tests/unit/**
|
|
tests/_test_utils/**
|
|
tools/launcher/**
|
|
tools/mcp/**
|
|
tools/resource_monitor.py
|
|
.agents/skills/**
|
|
plugins/modelopt/skills/**
|
|
linux:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
- uses: ./.github/actions/ubuntu-setup
|
|
- name: Run unit tests
|
|
env:
|
|
COVERAGE_PROCESS_START: ${{ github.workspace }}/pyproject.toml
|
|
COVERAGE_FILE: ${{ github.workspace }}/.coverage
|
|
run: pip install nox uv && nox -s "unit-3.12(torch_213, tf_latest)"
|
|
- name: Upload coverage reports to Codecov
|
|
uses: codecov/codecov-action@v7
|
|
with:
|
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
flags: unit
|
|
fail_ci_if_error: true
|
|
# Skip GPG/SHASUM integrity check of the Codecov CLI: its key import
|
|
# intermittently fails (codecov/codecov-action#1876), which would
|
|
# otherwise hard-fail this required job on a transient infra blip.
|
|
skip_validation: true
|
|
verbose: true
|
|
windows:
|
|
if: needs.check-file-changes.outputs.any_changed == 'true'
|
|
needs: [linux, check-file-changes]
|
|
runs-on: windows-latest
|
|
timeout-minutes: 15
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
- uses: actions/setup-python@v6
|
|
with:
|
|
python-version: "3.12"
|
|
- name: Run unit tests (without coverage)
|
|
run: pip install nox uv && nox -s "unit-3.12(torch_213, tf_latest)"
|
|
multi-version:
|
|
if: needs.check-file-changes.outputs.any_changed == 'true'
|
|
needs: [linux, check-file-changes]
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
# Default torch (2.13) across the other supported Python versions
|
|
- {nox_session: "unit-3.10(torch_213, tf_latest)", python_version: "3.10"}
|
|
- {nox_session: "unit-3.11(torch_213, tf_latest)", python_version: "3.11"}
|
|
- {nox_session: "unit-3.13(torch_213, tf_latest)", python_version: "3.13"}
|
|
- {nox_session: "unit-3.14(torch_213, tf_latest)", python_version: "3.14"}
|
|
# Older torch versions on the default Python (3.12) for back-compat.
|
|
- {nox_session: "unit-3.12(torch_28, tf_latest)", python_version: "3.12"}
|
|
- {nox_session: "unit-3.12(torch_29, tf_latest)", python_version: "3.12"}
|
|
- {nox_session: "unit-3.12(torch_210, tf_latest)", python_version: "3.12"}
|
|
- {nox_session: "unit-3.12(torch_211, tf_latest)", python_version: "3.12"}
|
|
- {nox_session: "unit-3.12(torch_212, tf_latest)", python_version: "3.12"}
|
|
# Minimum supported transformers on the default torch.
|
|
- {nox_session: "unit-3.12(torch_213, tf_min)", python_version: "3.12"}
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
- uses: ./.github/actions/ubuntu-setup
|
|
with:
|
|
python-version: ${{ matrix.python_version }}
|
|
- name: Run unit tests
|
|
run: pip install nox uv && nox -s "${{ matrix.nox_session }}"
|
|
partial-install:
|
|
if: needs.check-file-changes.outputs.any_changed == 'true'
|
|
needs: [linux, check-file-changes]
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
test-env: [onnx, torch]
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
- uses: ./.github/actions/ubuntu-setup
|
|
- name: Run unit tests
|
|
run: pip install nox uv && nox -s "partial_unit(subset='${{ matrix.test-env }}')"
|
|
launcher:
|
|
if: needs.check-file-changes.outputs.any_changed == 'true'
|
|
needs: [linux, check-file-changes]
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
submodules: recursive
|
|
- name: Run launcher tests
|
|
working-directory: tools/launcher
|
|
run: |
|
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
export PATH="$HOME/.local/bin:$PATH"
|
|
uv venv .venv
|
|
uv pip install -e . pytest
|
|
uv run python3 -m pytest -v
|
|
mcp:
|
|
if: needs.check-file-changes.outputs.any_changed == 'true'
|
|
needs: [linux, check-file-changes]
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
submodules: recursive
|
|
- name: Run modelopt-mcp tests
|
|
working-directory: tools/mcp
|
|
run: |
|
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
export PATH="$HOME/.local/bin:$PATH"
|
|
uv venv .venv
|
|
# Install the sibling launcher package first; it's a runtime
|
|
# dep declared in tools/mcp/pyproject.toml as `modelopt-launcher`
|
|
# but uv resolves the source via [tool.uv.sources] to a local
|
|
# editable path. -e on both packages keeps the install cheap
|
|
# and matches the dev-mode install in tools/mcp/README.md.
|
|
uv pip install -e ../launcher
|
|
uv pip install -e . pytest
|
|
uv run python3 -m pytest -v
|
|
skills:
|
|
if: needs.check-file-changes.outputs.any_changed == 'true'
|
|
needs: [linux, check-file-changes]
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
- uses: actions/setup-python@v6
|
|
with:
|
|
python-version: "3.12"
|
|
- name: Run skill gate tests
|
|
# Skill gate tests are stdlib-only and hermetic (no GPU/cluster/network),
|
|
# so they run in their own lightweight job rather than the main unit lane.
|
|
# Override addopts to drop the repo's coverage/instafail plugins (not installed here).
|
|
run: |
|
|
pip install pytest
|
|
python -m pytest plugins/modelopt/skills/ -o addopts="" -p no:cacheprovider -v
|
|
unit-pr-required-check:
|
|
# Run even if some jobs are skipped
|
|
if: ${{ github.event_name == 'pull_request' && always() }}
|
|
needs: [check-file-changes, linux, windows, multi-version, partial-install, launcher, mcp, skills]
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Required unit tests did not succeed
|
|
if: >-
|
|
${{ needs.linux.result != 'success' || (needs.check-file-changes.outputs.any_changed == 'true' && (
|
|
needs.windows.result != 'success' ||
|
|
needs.multi-version.result != 'success' ||
|
|
needs.partial-install.result != 'success' ||
|
|
needs.launcher.result != 'success' ||
|
|
needs.mcp.result != 'success' ||
|
|
needs.skills.result != 'success'
|
|
)) }}
|
|
run: exit 1
|