Skip to content

fix: discover installed adapter descriptors - #110

Closed
zhongxuanwang-nv wants to merge 1 commit into
mainfrom
fix/installed-adapter-descriptors
Closed

fix: discover installed adapter descriptors#110
zhongxuanwang-nv wants to merge 1 commit into
mainfrom
fix/installed-adapter-descriptors

Conversation

@zhongxuanwang-nv

@zhongxuanwang-nv zhongxuanwang-nv commented Jul 24, 2026

Copy link
Copy Markdown
Member

Overview

Fix installed Python adapter packages not being visible to the native adapter registry. This is the cause of unknown adapter 'nvidia.fabric.hermes'; available adapters: [] when the SDK and Hermes adapter are installed from wheels outside a NeMo Fabric source checkout.

Details
  • Discover installed fabric-adapter.json files through Python distribution metadata and pass their resolved paths into the native planner and doctor.
  • Extend the internal Rust resolution bridge to register those explicit descriptor files while preserving the existing repository and local base_dir/adapters discovery paths.
  • Keep the native arguments optional and append-only for compatibility.
  • Add focused Python and Rust coverage plus a wheel smoke test that temporarily removes the source adapters/ directory, preventing the compile-time checkout fallback from masking packaging regressions.
  • Add no dependencies and make no schema or CLI changes. There are no breaking changes.
Scope

This fix discovers adapter distributions installed in the same Python environment as nemo_fabric, which covers the published-wheel notebook failure. It intentionally does not inspect a separate interpreter selected through ADAPTER_PYTHON; cross-interpreter discovery remains outside this minimal fix.

Validation
  • cargo fmt --all -- --check
  • just --fmt --check
  • cargo check -p fabric-python --locked
  • just build-python
  • just test-rust (39 passed)
  • just test-python (401 passed, 44 skipped)
  • just wheels
  • Scoped pre-commit hooks, including Ruff and actionlint
  • Local clean-venv wheel smoke test with the source adapters/ directory hidden; Hermes resolved successfully from installed distribution metadata

Where should the reviewer start?

Start with _installed_adapter_descriptor_paths() in python/src/nemo_fabric/client.py, then follow the optional descriptor list through crates/fabric-python/src/lib.rs into crates/fabric-core/src/config.rs. The regression boundary is exercised by Test installed adapter discovery in .github/workflows/ci_python.yml.

Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to)

  • Relates to docs: Reafactor the README.md #103

  • I confirm this contribution is my own work, or I have the right to submit it under this project's license.

  • I searched existing issues and open pull requests, and this does not duplicate existing work.

Summary by CodeRabbit

  • New Features

    • Installed adapter packages are now discovered automatically, allowing their adapters to be used without manual registration.
    • Planning, diagnosis, and execution can accept optional adapter descriptor file paths.
    • Adapter resolution supports descriptors supplied directly by applications.
  • Bug Fixes

    • Improved adapter resolution for adapters provided through installed packages or caller-specified descriptor files.
  • Tests

    • Added coverage verifying installed and explicitly supplied adapters are correctly discovered and resolved.

Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The change adds caller-supplied adapter descriptor paths to core plan resolution, exposes them through Python bindings, discovers descriptors from installed distributions, and validates installed adapter discovery in tests and the wheel-building workflow.

Changes

Installed adapter descriptor resolution

Layer / File(s) Summary
Core descriptor registration and resolution
crates/fabric-core/src/config.rs
Adapter registry and run-plan resolution accept caller-provided descriptor paths, register them as local descriptors, and test canonical path and source handling.
Python native resolver wiring
crates/fabric-python/src/lib.rs, python/src/nemo_fabric/_native.pyi
Planning, diagnosis, and execution APIs accept optional adapter descriptor lists and pass them through shared native resolution.
Installed discovery and validation
python/src/nemo_fabric/client.py, tests/python/*, .github/workflows/ci_python.yml
The SDK discovers fabric-adapter.json files from installed distributions, forwards them during planning and diagnosis, and validates discovery with unit tests and a wheel smoke test.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant FabricPlan as Fabric.plan()
  participant Metadata as Installed distributions
  participant Native as Native bindings
  participant Core as Core adapter registry

  FabricPlan->>Metadata: Discover fabric-adapter.json paths
  Metadata-->>FabricPlan: Return resolved descriptor paths
  FabricPlan->>Native: Pass adapter_descriptors
  Native->>Core: Resolve run plan with descriptor paths
  Core-->>Native: Resolve configured adapter
  Native-->>FabricPlan: Return plan
Loading

Possibly related PRs

  • NVIDIA/NeMo-Fabric#108: Modifies the same adapter descriptor resolution pipeline with directory-based adapter inputs.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title uses valid Conventional Commits form and accurately summarizes the main change.
Description check ✅ Passed The description includes all required template sections, related issue info, and confirmation checkboxes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/installed-adapter-descriptors

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci_python.yml:
- Around line 156-187: Set shell: bash on the “Test installed adapter discovery”
workflow step so its Bash-specific commands run correctly on the windows-2022
matrix job, while preserving the existing smoke test commands.

In `@tests/python/test_runtime.py`:
- Around line 98-100: Update the lambda assigned to
mock_native.plan_config.side_effect so all three callback parameters use
underscore-prefixed names to satisfy Ruff ARG005, while retaining the required
three-argument signature and existing return behavior.

In `@tests/python/test_sdk_contract.py`:
- Around line 1149-1180: Add analogous coverage to
test_plan_registers_installed_adapter_descriptors for Fabric.doctor(): reuse the
installed descriptor setup and NativeRecorder, invoke client.doctor(), and
assert native.adapter_descriptor_calls contains the resolved descriptor path,
confirming doctor forwards the same descriptor list as plan.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 078ace12-08f1-48ca-9559-4bfd6f6db9e0

📥 Commits

Reviewing files that changed from the base of the PR and between e0c8d87 and 4a083e8.

📒 Files selected for processing (7)
  • .github/workflows/ci_python.yml
  • crates/fabric-core/src/config.rs
  • crates/fabric-python/src/lib.rs
  • python/src/nemo_fabric/_native.pyi
  • python/src/nemo_fabric/client.py
  • tests/python/test_runtime.py
  • tests/python/test_sdk_contract.py
📜 Review details
⏰ Context from checks skipped due to timeout. (13)
  • GitHub Check: Preview docs
  • GitHub Check: Test (Python 3.14, linux-amd64)
  • GitHub Check: Test (Python 3.13, linux-arm64)
  • GitHub Check: Test (Python 3.13, linux-amd64)
  • GitHub Check: Test (Python 3.14, windows-amd64)
  • GitHub Check: Test (Python 3.12, windows-amd64)
  • GitHub Check: Test (Python 3.12, macos-arm64)
  • GitHub Check: Test (Python 3.12, linux-arm64)
  • GitHub Check: Test (Python 3.13, macos-arm64)
  • GitHub Check: Test (Python 3.13, windows-amd64)
  • GitHub Check: Test (Python 3.11, windows-amd64)
  • GitHub Check: Test (Python 3.14, macos-arm64)
  • GitHub Check: Pre-commit
🧰 Additional context used
📓 Path-based instructions (25)
**/.github/workflows/*.{yml,yaml}

📄 CodeRabbit inference engine (.agents/skills/maintain-ci/SKILL.md)

**/.github/workflows/*.{yml,yaml}: Define permissions: per job that needs token access, using the minimum required scopes; avoid workflow-level permissions unless centralized inheritance is intentionally documented.
Pin every third-party GitHub Action to a full commit SHA and retain a readable version comment after the SHA.
Use action-native or ecosystem-native caching instead of generic actions/cache when available.
Tie cache invalidation to lockfiles, dependency manifests, or explicit tool versions; avoid caching generated outputs unless deliberate repository behavior requires it.
Use astral-sh/setup-uv cache support with cache-dependency-glob anchored to uv.lock.
Use Swatinem/rust-cache with explicit shared-key and workspaces instead of ad hoc target-directory caching.
Keep deploy and publish permissions isolated to only the jobs that require them; restrict pages: write and id-token: write to Pages deployment jobs and their reusable-workflow callers.
Use contents: read as the minimum permission for checkout-based build, test, documentation, and packaging jobs.
Grant pull-requests: read only to jobs that perform pull-request metadata lookups.
When using workflow_call, inspect both caller and callee, and ensure the caller grants every permission required by the called jobs because the callee cannot elevate permissions.
Keep local workflow commands aligned with equivalent justfile recipes, and keep Python, Rust, and documentation jobs aligned with their lockfiles.
Preserve intended concurrency settings, branch filters, and documentation publish guards when modifying workflows.
Before editing workflows, inspect workflow relationships and settings with searches covering uses:, permissions:, secrets:, concurrency:, cache, and just.

Files:

  • .github/workflows/ci_python.yml
{docs/package.json,docs/package-lock.json,.github/workflows/*.yml,justfile}

📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)

Keep documentation tooling, CI workflows, install commands, build/test/clean recipes, and examples consistent with current package names and commands.

Files:

  • .github/workflows/ci_python.yml
{pyproject.toml,python/pyproject.toml,Cargo.toml,docs/package.json,.github/workflows/*.yml,justfile}

📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)

Reflect public packaging changes in release-facing documentation and ensure CI references the same package names and commands used by local workflows.

Files:

  • .github/workflows/ci_python.yml
**/*.{rs,py,pyi,json,yaml,yml}

📄 CodeRabbit inference engine (.agents/skills/contribute-api/SKILL.md)

Determine and update every affected public surface, including the CLI, PyO3 bindings, Python SDK, type stubs, schemas, and adapter contract, so they remain in parity.

Files:

  • tests/python/test_runtime.py
  • python/src/nemo_fabric/client.py
  • python/src/nemo_fabric/_native.pyi
  • tests/python/test_sdk_contract.py
  • crates/fabric-python/src/lib.rs
  • crates/fabric-core/src/config.rs
**/*

📄 CodeRabbit inference engine (.agents/skills/karpathy-guidelines/SKILL.md)

**/*: Before implementing, explicitly state assumptions, surface ambiguity and tradeoffs, present multiple interpretations when relevant, and ask for clarification rather than silently deciding or proceeding when requirements are unclear.
Prefer the minimum code needed to solve the requested problem: avoid speculative features, unnecessary abstractions, unrequested flexibility, and handling of impossible scenarios; simplify overcomplicated solutions.
When editing existing code, make surgical changes only: do not modify unrelated code, comments, formatting, or pre-existing dead code; match the existing style, and remove only unused imports, variables, or functions introduced by your changes.
Define verifiable success criteria for each task, such as writing regression tests for bugs and invalid-input tests for validation, then verify the implementation against those criteria. For multi-step work, state a brief plan with a verification check for each step.

**/*: Always spell NVIDIA in all caps; do not use Nvidia, nvidia, nVidia, nVIDIA, or NV.
Use an NVIDIA before a noun, because the name begins with an “en” sound.
Do not add a registered trademark symbol after NVIDIA when referring to the company; use trademark symbols with product names only when required by the document type or legal guidance.
Verify official capitalization, spacing, hyphenation, and spelling for NVIDIA and third-party product names; do not rewrite official product names for grammar or title-case rules.
Precede NVIDIA product names with NVIDIA on first mention when natural and accurate, and link the first mention when the destination helps the reader.
On first use, include the company name and full model qualifier when it helps identify the model; preserve official capitalization and punctuation, and use shorter family names only after establishing the full name.
For learning-oriented and developer content, do not force trademark symbols unless explicitly required; for press, ...

Files:

  • tests/python/test_runtime.py
  • python/src/nemo_fabric/client.py
  • python/src/nemo_fabric/_native.pyi
  • tests/python/test_sdk_contract.py
  • crates/fabric-python/src/lib.rs
  • crates/fabric-core/src/config.rs
**/*.{rs,py}

📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)

For native binding changes, run cargo check -p fabric-python --locked.

Files:

  • tests/python/test_runtime.py
  • python/src/nemo_fabric/client.py
  • tests/python/test_sdk_contract.py
  • crates/fabric-python/src/lib.rs
  • crates/fabric-core/src/config.rs
**/*.{py,pyi}

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

If Python code or a Python-facing adapter changes, run just test-python.

Use type annotations for public Python APIs and keep native Python binding declarations synchronized with their Rust implementations.

Files:

  • tests/python/test_runtime.py
  • python/src/nemo_fabric/client.py
  • python/src/nemo_fabric/_native.pyi
  • tests/python/test_sdk_contract.py
**/*.{rs,py,pyi}

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

**/*.{rs,py,pyi}: If public configuration types change, confirm schema snapshot tests in just test-rust pass and review generated schema diffs.
For schema or public contract changes, run both language suites and review changes under schemas/ and generated API references.

**/*.{rs,py,pyi}: Use snake_case for Rust and Python functions and variables; use PascalCase for Rust types and Python classes.
Keep native Python binding declarations synchronized with their Rust implementations when public contracts change.

Files:

  • tests/python/test_runtime.py
  • python/src/nemo_fabric/client.py
  • python/src/nemo_fabric/_native.pyi
  • tests/python/test_sdk_contract.py
  • crates/fabric-python/src/lib.rs
  • crates/fabric-core/src/config.rs
**/*.{py,pyi,rs}

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

For Python SDK or PyO3 binding changes, use python-tests, run focused pytest tests first, then just test-python; rebuild with just build-python when native code or packaging changes.

Files:

  • tests/python/test_runtime.py
  • python/src/nemo_fabric/client.py
  • python/src/nemo_fabric/_native.pyi
  • tests/python/test_sdk_contract.py
  • crates/fabric-python/src/lib.rs
  • crates/fabric-core/src/config.rs
tests/**/*.{rs,py}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

When adding functionality, include tests in the corresponding Rust crate or the relevant area under tests/.

Files:

  • tests/python/test_runtime.py
  • tests/python/test_sdk_contract.py
tests/**/*.py

📄 CodeRabbit inference engine (.agents/skills/python-tests/SKILL.md)

tests/**/*.py: Use Pytest to run Python tests.
Do not add @pytest.mark.asyncio to tests; async tests are automatically detected and run by the async runner.
Do not add -> None return type annotations to test functions.
When mocking a class, use unittest.mock.MagicMock or unittest.mock.AsyncMock, using the spec argument when necessary, rather than defining a new class.
Prefix mocked class names with mock, not fake.
Prefer pytest fixtures over helper methods.
Do not repeat fixtures; place fixtures needed by multiple test files in conftest.py.
Define fixtures using @pytest.fixture(name="<fixture_name>"[, scope="<scope>"]) and a function named <fixture_name>_fixture; specify scope only when it is not function.
Prefer pytest.mark.parametrize over separate tests for different input types.
Use @pytest.mark.usefixtures when a fixture is needed but its return value is unused or it does not return a value.
Use the autouse restore_environ_fixture from tests/conftest.py to restore environment variables; modify variables with os.environ and do not use monkeypatch.setenv.
Avoid defensive programming in tests; access expected data directly so missing data raises a clear failure, such as using results["data"] instead of results.get("data").

Files:

  • tests/python/test_runtime.py
  • tests/python/test_sdk_contract.py
**/*.{rs,py,toml}

📄 CodeRabbit inference engine (.agents/skills/update-project-version/SKILL.md)

When editing version helpers, verify every nemo-fabric-* workspace package through Cargo metadata and reject a static version in python/pyproject.toml.

Files:

  • tests/python/test_runtime.py
  • python/src/nemo_fabric/client.py
  • tests/python/test_sdk_contract.py
  • crates/fabric-python/src/lib.rs
  • crates/fabric-core/src/config.rs
**/*.{toml,rs,py}

📄 CodeRabbit inference engine (.agents/skills/update-project-version/SKILL.md)

Avoid blind repository-wide replacement of version-like strings; distinguish package-version references from examples and unrelated dependency versions.

Files:

  • tests/python/test_runtime.py
  • python/src/nemo_fabric/client.py
  • tests/python/test_sdk_contract.py
  • crates/fabric-python/src/lib.rs
  • crates/fabric-core/src/config.rs
{tests/**,python/tests/**}

⚙️ CodeRabbit configuration file

{tests/**,python/tests/**}: Tests should cover the behavior promised by the changed API surface, including error paths, lifecycle cleanup, and SDK/native parity where relevant.

Files:

  • tests/python/test_runtime.py
  • tests/python/test_sdk_contract.py
python/src/nemo_fabric/**

📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)

Ensure the editable maturin build continues to produce the native extension at nemo_fabric._native, with generated artifacts placed where downstream consumers expect.

Files:

  • python/src/nemo_fabric/client.py
  • python/src/nemo_fabric/_native.pyi
python/src/nemo_fabric/**/*.py

📄 CodeRabbit inference engine (.agents/skills/review-doc-style/SKILL.md)

For Python API reference changes, update source docstrings under python/src/nemo_fabric/ instead of editing generated reference output.

Files:

  • python/src/nemo_fabric/client.py
python/src/nemo_fabric/**/*

⚙️ CodeRabbit configuration file

python/src/nemo_fabric/**/*: Review Python SDK changes for typed API consistency, import-time dependency neutrality, async/session behavior, and parity with the native extension.
Stubs and runtime implementations should stay aligned.

Files:

  • python/src/nemo_fabric/client.py
  • python/src/nemo_fabric/_native.pyi
**/*.rs

📄 CodeRabbit inference engine (.agents/skills/contribute-api/SKILL.md)

Implement new runtime or binding behavior in the shared Rust core first.

Files:

  • crates/fabric-python/src/lib.rs
  • crates/fabric-core/src/config.rs
**/*.{rs,toml}

📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)

For any Rust change, run just test-rust and cargo fmt --all -- --check.

For Rust core, CLI, or shared runtime semantic changes, run Rust formatting and tests, and add Python tests when behavior is exposed through the SDK.

Use Rust stable tooling; format Rust code with cargo fmt --all, check formatting with cargo fmt --all -- --check, and compile with cargo check --workspace --locked.

Files:

  • crates/fabric-python/src/lib.rs
  • crates/fabric-core/src/config.rs
**/*.{rs,rmeta}

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

If Rust code changes, run cargo fmt --all -- --check and just test-rust.

Files:

  • crates/fabric-python/src/lib.rs
  • crates/fabric-core/src/config.rs
crates/fabric-python/**/*.{rs,toml}

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

If the PyO3 bridge or package metadata changes, run just build-python and cargo check -p fabric-python --locked.

Files:

  • crates/fabric-python/src/lib.rs
crates/fabric-python/**/*

⚙️ CodeRabbit configuration file

crates/fabric-python/**/*: Treat native binding changes as public API changes. Check JSON/type conversion, error propagation, GIL/thread behavior, and parity with the Python SDK.

Files:

  • crates/fabric-python/src/lib.rs
crates/fabric-core/**/*.{rs,py}

📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)

Changes under crates/fabric-core must run both the Rust and Python test suites.

Files:

  • crates/fabric-core/src/config.rs
crates/fabric-core/**/*.rs

📄 CodeRabbit inference engine (.agents/skills/review-doc-style/SKILL.md)

For Rust API reference changes, update Rust documentation comments under crates/fabric-core/ instead of editing generated reference output.

If crates/fabric-core changes in a way exposed through Python, run both the Rust and Python suites.

Files:

  • crates/fabric-core/src/config.rs
crates/fabric-core/src/**/*.rs

⚙️ CodeRabbit configuration file

crates/fabric-core/src/**/*.rs: Review the Rust core for runtime lifecycle correctness, handle validation, capability routing accuracy, schema stability, and error semantics.
Public API changes should match committed schemas, tests, and documentation.

Files:

  • crates/fabric-core/src/config.rs
🧠 Learnings (1)
📚 Learning: 2026-06-28T04:03:32.877Z
Learnt from: AjayThorve
Repo: NVIDIA/NeMo-Fabric PR: 26
File: python/tests/smoke_typed_config.py:163-177
Timestamp: 2026-06-28T04:03:32.877Z
Learning: In NVIDIA NeMo Fabric Python SDK serialization of `RuntimeCapabilities` (to satisfy the “parity contract” with Rust core and the CLI), do not emit metadata keys when the corresponding metadata is absent. Instead, omit those fields entirely so the produced JSON matches the Rust/CLI output (e.g., avoid `null`, empty objects, or placeholder metadata). During review, verify the serializer/builders follow this omission rule and that Python outputs/parity tests reflect the same shape.

Applied to files:

  • python/src/nemo_fabric/client.py
🪛 ast-grep (0.44.1)
tests/python/test_runtime.py

[info] 98-98: use jsonify instead of json.dumps for JSON output
Context: json.dumps(_plan())
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[info] 100-100: use jsonify instead of json.dumps for JSON output
Context: json.dumps(_runtime())
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

tests/python/test_sdk_contract.py

[info] 644-644: use jsonify instead of json.dumps for JSON output
Context: json.dumps(_plan())
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🪛 Ruff (0.15.21)
tests/python/test_runtime.py

[warning] 99-99: Unused lambda argument: config_json

(ARG005)


[warning] 99-99: Unused lambda argument: base_dir

(ARG005)


[warning] 99-99: Unused lambda argument: adapter_descriptors

(ARG005)

🔇 Additional comments (8)
crates/fabric-core/src/config.rs (3)

167-179: LGTM!

Also applies to: 214-226


1004-1026: LGTM!

Also applies to: 1043-1048, 1071-1077


1746-1764: LGTM!

crates/fabric-python/src/lib.rs (2)

8-10: LGTM!

Also applies to: 23-69


160-175: LGTM!

python/src/nemo_fabric/_native.pyi (1)

5-23: LGTM!

python/src/nemo_fabric/client.py (1)

10-14: LGTM!

Also applies to: 88-92, 127-131, 280-289

tests/python/test_sdk_contract.py (1)

13-16: LGTM!

Also applies to: 632-645

Comment on lines +156 to +187
- name: Test installed adapter discovery
run: |
set -euo pipefail
uv venv .wheel-test-venv
if [[ -x .wheel-test-venv/bin/python ]]; then
test_python="$PWD/.wheel-test-venv/bin/python"
else
test_python="$PWD/.wheel-test-venv/Scripts/python.exe"
fi
uv pip install \
--python "$test_python" \
--find-links dist \
"nemo-fabric[hermes]"

source_adapters="$GITHUB_WORKSPACE/adapters"
staged_source_adapters="$RUNNER_TEMP/nemo-fabric-source-adapters"
mv "$source_adapters" "$staged_source_adapters"
trap 'mv "$staged_source_adapters" "$source_adapters"' EXIT

smoke_dir="$(mktemp -d)"
cd "$smoke_dir"
"$test_python" - <<'PY'
from nemo_fabric import Fabric, FabricConfig, HarnessConfig, MetadataConfig

config = FabricConfig(
metadata=MetadataConfig(name="installed-adapter-smoke"),
harness=HarnessConfig(adapter_id="nvidia.fabric.hermes"),
)
plan = Fabric().plan(config)
assert plan.adapter.adapter_id == "nvidia.fabric.hermes"
PY

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Run the smoke script with Bash.

The matrix includes windows-2022, where run defaults to PowerShell. Lines 158-186 use Bash syntax, so that wheel job fails before testing. Set shell: bash on this step.

Proposed fix
       - name: Test installed adapter discovery
+        shell: bash
         run: |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Test installed adapter discovery
run: |
set -euo pipefail
uv venv .wheel-test-venv
if [[ -x .wheel-test-venv/bin/python ]]; then
test_python="$PWD/.wheel-test-venv/bin/python"
else
test_python="$PWD/.wheel-test-venv/Scripts/python.exe"
fi
uv pip install \
--python "$test_python" \
--find-links dist \
"nemo-fabric[hermes]"
source_adapters="$GITHUB_WORKSPACE/adapters"
staged_source_adapters="$RUNNER_TEMP/nemo-fabric-source-adapters"
mv "$source_adapters" "$staged_source_adapters"
trap 'mv "$staged_source_adapters" "$source_adapters"' EXIT
smoke_dir="$(mktemp -d)"
cd "$smoke_dir"
"$test_python" - <<'PY'
from nemo_fabric import Fabric, FabricConfig, HarnessConfig, MetadataConfig
config = FabricConfig(
metadata=MetadataConfig(name="installed-adapter-smoke"),
harness=HarnessConfig(adapter_id="nvidia.fabric.hermes"),
)
plan = Fabric().plan(config)
assert plan.adapter.adapter_id == "nvidia.fabric.hermes"
PY
- name: Test installed adapter discovery
shell: bash
run: |
set -euo pipefail
uv venv .wheel-test-venv
if [[ -x .wheel-test-venv/bin/python ]]; then
test_python="$PWD/.wheel-test-venv/bin/python"
else
test_python="$PWD/.wheel-test-venv/Scripts/python.exe"
fi
uv pip install \
--python "$test_python" \
--find-links dist \
"nemo-fabric[hermes]"
source_adapters="$GITHUB_WORKSPACE/adapters"
staged_source_adapters="$RUNNER_TEMP/nemo-fabric-source-adapters"
mv "$source_adapters" "$staged_source_adapters"
trap 'mv "$staged_source_adapters" "$source_adapters"' EXIT
smoke_dir="$(mktemp -d)"
cd "$smoke_dir"
"$test_python" - <<'PY'
from nemo_fabric import Fabric, FabricConfig, HarnessConfig, MetadataConfig
config = FabricConfig(
metadata=MetadataConfig(name="installed-adapter-smoke"),
harness=HarnessConfig(adapter_id="nvidia.fabric.hermes"),
)
plan = Fabric().plan(config)
assert plan.adapter.adapter_id == "nvidia.fabric.hermes"
PY
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci_python.yml around lines 156 - 187, Set shell: bash on
the “Test installed adapter discovery” workflow step so its Bash-specific
commands run correctly on the windows-2022 matrix job, while preserving the
existing smoke test commands.

Comment on lines +98 to +100
mock_native.plan_config.side_effect = (
lambda config_json, base_dir, adapter_descriptors: json.dumps(_plan())
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Avoid the new Ruff violations.

Line 99 reports ARG005 for all callback parameters. Prefix them with _ while retaining the fixed three-argument mock signature.

Proposed fix
-        lambda config_json, base_dir, adapter_descriptors: json.dumps(_plan())
+        lambda _config_json, _base_dir, _adapter_descriptors: json.dumps(_plan())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
mock_native.plan_config.side_effect = (
lambda config_json, base_dir, adapter_descriptors: json.dumps(_plan())
)
mock_native.plan_config.side_effect = (
lambda _config_json, _base_dir, _adapter_descriptors: json.dumps(_plan())
)
🧰 Tools
🪛 ast-grep (0.44.1)

[info] 98-98: use jsonify instead of json.dumps for JSON output
Context: json.dumps(_plan())
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[info] 100-100: use jsonify instead of json.dumps for JSON output
Context: json.dumps(_runtime())
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🪛 Ruff (0.15.21)

[warning] 99-99: Unused lambda argument: config_json

(ARG005)


[warning] 99-99: Unused lambda argument: base_dir

(ARG005)


[warning] 99-99: Unused lambda argument: adapter_descriptors

(ARG005)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/python/test_runtime.py` around lines 98 - 100, Update the lambda
assigned to mock_native.plan_config.side_effect so all three callback parameters
use underscore-prefixed names to satisfy Ruff ARG005, while retaining the
required three-argument signature and existing return behavior.

Source: Linters/SAST tools

Comment on lines +1149 to +1180
def test_plan_registers_installed_adapter_descriptors(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
):
descriptor = (
tmp_path
/ "share"
/ "nemo-fabric"
/ "adapters"
/ "shim"
/ "fabric-adapter.json"
)
descriptor.parent.mkdir(parents=True)
descriptor.write_text("{}")

mock_distribution = MagicMock()
mock_distribution.files = [
Path("share/nemo-fabric/adapters/shim/fabric-adapter.json")
]
mock_distribution.locate_file.side_effect = lambda file: tmp_path / file

monkeypatch.setattr(
client_mod.importlib.metadata,
"distributions",
lambda: [mock_distribution],
)
native = NativeRecorder()
client = NativeClient(native)

client.plan(_fabric_config())

assert native.adapter_descriptor_calls == [[str(descriptor.resolve())]]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add SDK doctor forwarding coverage.

This verifies Fabric.plan() only, although Fabric.doctor() now forwards the same descriptor list. Add an analogous doctor assertion using the recorder.

As per path instructions, “Tests should cover the behavior promised by the changed API surface, including error paths, lifecycle cleanup, and SDK/native parity where relevant.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/python/test_sdk_contract.py` around lines 1149 - 1180, Add analogous
coverage to test_plan_registers_installed_adapter_descriptors for
Fabric.doctor(): reuse the installed descriptor setup and NativeRecorder, invoke
client.doctor(), and assert native.adapter_descriptor_calls contains the
resolved descriptor path, confirming doctor forwards the same descriptor list as
plan.

Source: Path instructions

@zhongxuanwang-nv

Copy link
Copy Markdown
Member Author

Closing this draft as a duplicate of #108. For the immediate notebook failure in #103, the narrower correction is to pass the already-computed repository root as base_dir to the four Fabric lifecycle calls.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant